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.os.Handler;
     19 import android.os.HandlerThread;
     20 import android.os.Looper;
     21 import android.os.Message;
     22 import android.os.SystemClock;
     23 import android.util.Log;
     24 
     25 import com.android.car.hal.PowerHalService;
     26 import com.android.car.hal.PowerHalService.PowerState;
     27 import com.android.internal.annotations.GuardedBy;
     28 import com.android.internal.annotations.VisibleForTesting;
     29 
     30 import java.io.PrintWriter;
     31 import java.util.LinkedList;
     32 import java.util.Timer;
     33 import java.util.TimerTask;
     34 import java.util.concurrent.CopyOnWriteArrayList;
     35 
     36 public class CarPowerManagementService implements CarServiceBase,
     37     PowerHalService.PowerEventListener {
     38 
     39     /**
     40      * Listener for other services to monitor power events.
     41      */
     42     public interface PowerServiceEventListener {
     43         /**
     44          * Shutdown is happening
     45          */
     46         void onShutdown();
     47 
     48         /**
     49          * Entering deep sleep.
     50          */
     51         void onSleepEntry();
     52 
     53         /**
     54          * Got out of deep sleep.
     55          */
     56         void onSleepExit();
     57     }
     58 
     59     /**
     60      * Interface for components requiring processing time before shutting-down or
     61      * entering sleep, and wake-up after shut-down.
     62      */
     63     public interface PowerEventProcessingHandler {
     64         /**
     65          * Called before shutdown or sleep entry to allow running some processing. This call
     66          * should only queue such task in different thread and should return quickly.
     67          * Blocking inside this call can trigger watchdog timer which can terminate the
     68          * whole system.
     69          * @param shuttingDown whether system is shutting down or not (= sleep entry).
     70          * @return time necessary to run processing in ms. should return 0 if there is no
     71          *         processing necessary.
     72          */
     73         long onPrepareShutdown(boolean shuttingDown);
     74 
     75         /**
     76          * Called when power state is changed to ON state. Display can be either on or off.
     77          * @param displayOn
     78          */
     79         void onPowerOn(boolean displayOn);
     80 
     81         /**
     82          * Returns wake up time after system is fully shutdown. Power controller will power on
     83          * the system after this time. This power on is meant for regular maintenance kind of
     84          * operation.
     85          * @return 0 of wake up is not necessary.
     86          */
     87         int getWakeupTime();
     88     }
     89 
     90     private final PowerHalService mHal;
     91     private final SystemInterface mSystemInterface;
     92 
     93     private final CopyOnWriteArrayList<PowerServiceEventListener> mListeners =
     94             new CopyOnWriteArrayList<>();
     95     private final CopyOnWriteArrayList<PowerEventProcessingHandlerWrapper>
     96             mPowerEventProcessingHandlers = new CopyOnWriteArrayList<>();
     97 
     98     @GuardedBy("this")
     99     private PowerState mCurrentState;
    100     @GuardedBy("this")
    101     private Timer mTimer;
    102     @GuardedBy("this")
    103     private long mProcessingStartTime;
    104     @GuardedBy("this")
    105     private long mLastSleepEntryTime;
    106     @GuardedBy("this")
    107     private final LinkedList<PowerState> mPendingPowerStates = new LinkedList<>();
    108     @GuardedBy("this")
    109     private HandlerThread mHandlerThread;
    110     @GuardedBy("this")
    111     private PowerHandler mHandler;
    112 
    113     private final static int SHUTDOWN_POLLING_INTERVAL_MS = 2000;
    114     private final static int SHUTDOWN_EXTEND_MAX_MS = 5000;
    115 
    116     public CarPowerManagementService(PowerHalService powerHal, SystemInterface systemInterface) {
    117         mHal = powerHal;
    118         mSystemInterface = systemInterface;
    119     }
    120 
    121     /**
    122      * Create a dummy instance for unit testing purpose only. Instance constructed in this way
    123      * is not safe as members expected to be non-null are null.
    124      */
    125     @VisibleForTesting
    126     protected CarPowerManagementService() {
    127         mHal = null;
    128         mSystemInterface = null;
    129         mHandlerThread = null;
    130         mHandler = new PowerHandler(Looper.getMainLooper());
    131     }
    132 
    133     @Override
    134     public void init() {
    135         synchronized (this) {
    136             mHandlerThread = new HandlerThread(CarLog.TAG_POWER);
    137             mHandlerThread.start();
    138             mHandler = new PowerHandler(mHandlerThread.getLooper());
    139         }
    140 
    141         mHal.setListener(this);
    142         if (mHal.isPowerStateSupported()) {
    143             mHal.sendBootComplete();
    144             PowerState currentState = mHal.getCurrentPowerState();
    145             if (currentState != null) {
    146                 onApPowerStateChange(currentState);
    147             } else {
    148                 Log.w(CarLog.TAG_POWER, "Unable to get get current power state during "
    149                         + "initialization");
    150             }
    151         } else {
    152             Log.w(CarLog.TAG_POWER, "Vehicle hal does not support power state yet.");
    153             onApPowerStateChange(new PowerState(PowerHalService.STATE_ON_FULL, 0));
    154             mSystemInterface.switchToFullWakeLock();
    155         }
    156         mSystemInterface.startDisplayStateMonitoring(this);
    157     }
    158 
    159     @Override
    160     public void release() {
    161         HandlerThread handlerThread;
    162         synchronized (this) {
    163             releaseTimerLocked();
    164             mCurrentState = null;
    165             mHandler.cancelAll();
    166             handlerThread = mHandlerThread;
    167         }
    168         handlerThread.quitSafely();
    169         try {
    170             handlerThread.join(1000);
    171         } catch (InterruptedException e) {
    172             Log.e(CarLog.TAG_POWER, "Timeout while joining for handler thread to join.");
    173         }
    174         mSystemInterface.stopDisplayStateMonitoring();
    175         mListeners.clear();
    176         mPowerEventProcessingHandlers.clear();
    177         mSystemInterface.releaseAllWakeLocks();
    178     }
    179 
    180     /**
    181      * Register listener to monitor power event. There is no unregister counter-part and the list
    182      * will be cleared when the service is released.
    183      * @param listener
    184      */
    185     public synchronized void registerPowerEventListener(PowerServiceEventListener listener) {
    186         mListeners.add(listener);
    187     }
    188 
    189     /**
    190      * Register PowerEventPreprocessingHandler to run pre-processing before shutdown or
    191      * sleep entry. There is no unregister counter-part and the list
    192      * will be cleared when the service is released.
    193      * @param handler
    194      */
    195     public synchronized void registerPowerEventProcessingHandler(
    196             PowerEventProcessingHandler handler) {
    197         mPowerEventProcessingHandlers.add(new PowerEventProcessingHandlerWrapper(handler));
    198         // onPowerOn will not be called if power on notification is already done inside the
    199         // handler thread. So request it once again here. Wrapper will have its own
    200         // gatekeeping to prevent calling onPowerOn twice.
    201         mHandler.handlePowerOn();
    202     }
    203 
    204     /**
    205      * Notifies earlier completion of power event processing. PowerEventProcessingHandler quotes
    206      * time necessary from onPrePowerEvent() call, but actual processing can finish earlier than
    207      * that, and this call can be called in such case to trigger shutdown without waiting further.
    208      *
    209      * @param handler PowerEventProcessingHandler that was already registered with
    210      *        {@link #registerPowerEventListener(PowerServiceEventListener)} call. If it was not
    211      *        registered before, this call will be ignored.
    212      */
    213     public void notifyPowerEventProcessingCompletion(PowerEventProcessingHandler handler) {
    214         long processingTime = 0;
    215         for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
    216             if (wrapper.handler == handler) {
    217                 wrapper.markProcessingDone();
    218             } else if (!wrapper.isProcessingDone()) {
    219                 processingTime = Math.max(processingTime, wrapper.getProcessingTime());
    220             }
    221         }
    222         long now = SystemClock.elapsedRealtime();
    223         long startTime;
    224         boolean shouldShutdown = true;
    225         PowerHandler powerHandler;
    226         synchronized (this) {
    227             startTime = mProcessingStartTime;
    228             if (mCurrentState == null) {
    229                 return;
    230             }
    231             if (mCurrentState.mState != PowerHalService.STATE_SHUTDOWN_PREPARE) {
    232                 return;
    233             }
    234             if (mCurrentState.canEnterDeepSleep()) {
    235                 shouldShutdown = false;
    236                 if (mLastSleepEntryTime > mProcessingStartTime && mLastSleepEntryTime < now) {
    237                     // already slept
    238                     return;
    239                 }
    240             }
    241             powerHandler = mHandler;
    242         }
    243         if ((startTime + processingTime) <= now) {
    244             Log.i(CarLog.TAG_POWER, "Processing all done");
    245             powerHandler.handleProcessingComplete(shouldShutdown);
    246         }
    247     }
    248 
    249     @Override
    250     public void dump(PrintWriter writer) {
    251         writer.println("*PowerManagementService*");
    252         writer.print("mCurrentState:" + mCurrentState);
    253         writer.print(",mProcessingStartTime:" + mProcessingStartTime);
    254         writer.println(",mLastSleepEntryTime:" + mLastSleepEntryTime);
    255         writer.println("**PowerEventProcessingHandlers");
    256         for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
    257             writer.println(wrapper.toString());
    258         }
    259     }
    260 
    261     @Override
    262     public void onApPowerStateChange(PowerState state) {
    263         PowerHandler handler;
    264         synchronized (this) {
    265             mPendingPowerStates.addFirst(state);
    266             handler = mHandler;
    267         }
    268         handler.handlePowerStateChange();
    269     }
    270 
    271     private void doHandlePowerStateChange() {
    272         PowerState state = null;
    273         PowerHandler handler;
    274         synchronized (this) {
    275             state = mPendingPowerStates.peekFirst();
    276             mPendingPowerStates.clear();
    277             if (state == null) {
    278                 return;
    279             }
    280             if (!needPowerStateChange(state)) {
    281                 return;
    282             }
    283             // now real power change happens. Whatever was queued before should be all cancelled.
    284             releaseTimerLocked();
    285             handler = mHandler;
    286         }
    287         handler.cancelProcessingComplete();
    288 
    289         Log.i(CarLog.TAG_POWER, "Power state change:" + state);
    290         switch (state.mState) {
    291             case PowerHalService.STATE_ON_DISP_OFF:
    292                 handleDisplayOff(state);
    293                 notifyPowerOn(false);
    294                 break;
    295             case PowerHalService.STATE_ON_FULL:
    296                 handleFullOn(state);
    297                 notifyPowerOn(true);
    298                 break;
    299             case PowerHalService.STATE_SHUTDOWN_PREPARE:
    300                 handleShutdownPrepare(state);
    301                 break;
    302         }
    303     }
    304 
    305     private void handleDisplayOff(PowerState newState) {
    306         setCurrentState(newState);
    307         mSystemInterface.setDisplayState(false);
    308     }
    309 
    310     private void handleFullOn(PowerState newState) {
    311         setCurrentState(newState);
    312         mSystemInterface.setDisplayState(true);
    313     }
    314 
    315     @VisibleForTesting
    316     protected void notifyPowerOn(boolean displayOn) {
    317         for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
    318             wrapper.callOnPowerOn(displayOn);
    319         }
    320     }
    321 
    322     @VisibleForTesting
    323     protected long notifyPrepareShutdown(boolean shuttingDown) {
    324         long processingTimeMs = 0;
    325         for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
    326             long handlerProcessingTime = wrapper.handler.onPrepareShutdown(shuttingDown);
    327             if (handlerProcessingTime > processingTimeMs) {
    328                 processingTimeMs = handlerProcessingTime;
    329             }
    330         }
    331         return processingTimeMs;
    332     }
    333 
    334     private void handleShutdownPrepare(PowerState newState) {
    335         setCurrentState(newState);
    336         mSystemInterface.setDisplayState(false);;
    337         boolean shouldShutdown = true;
    338         if (mHal.isDeepSleepAllowed() && mSystemInterface.isSystemSupportingDeepSleep() &&
    339                 newState.canEnterDeepSleep()) {
    340             Log.i(CarLog.TAG_POWER, "starting sleep");
    341             shouldShutdown = false;
    342             doHandlePreprocessing(shouldShutdown);
    343             return;
    344         } else if (newState.canPostponeShutdown()) {
    345             Log.i(CarLog.TAG_POWER, "starting shutdown with processing");
    346             doHandlePreprocessing(shouldShutdown);
    347         } else {
    348             Log.i(CarLog.TAG_POWER, "starting shutdown immediately");
    349             synchronized (this) {
    350                 releaseTimerLocked();
    351             }
    352             doHandleShutdown();
    353         }
    354     }
    355 
    356     private void releaseTimerLocked() {
    357         if (mTimer != null) {
    358             mTimer.cancel();
    359         }
    360         mTimer = null;
    361     }
    362 
    363     private void doHandlePreprocessing(boolean shuttingDown) {
    364         long processingTimeMs = 0;
    365         for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
    366             long handlerProcessingTime = wrapper.handler.onPrepareShutdown(shuttingDown);
    367             if (handlerProcessingTime > 0) {
    368                 wrapper.setProcessingTimeAndResetProcessingDone(handlerProcessingTime);
    369             }
    370             if (handlerProcessingTime > processingTimeMs) {
    371                 processingTimeMs = handlerProcessingTime;
    372             }
    373         }
    374         if (processingTimeMs > 0) {
    375             int pollingCount = (int)(processingTimeMs / SHUTDOWN_POLLING_INTERVAL_MS) + 1;
    376             Log.i(CarLog.TAG_POWER, "processing before shutdown expected for :" + processingTimeMs +
    377                     " ms, adding polling:" + pollingCount);
    378             synchronized (this) {
    379                 mProcessingStartTime = SystemClock.elapsedRealtime();
    380                 releaseTimerLocked();
    381                 mTimer = new Timer();
    382                 mTimer.scheduleAtFixedRate(new ShutdownProcessingTimerTask(shuttingDown,
    383                         pollingCount),
    384                         0 /*delay*/,
    385                         SHUTDOWN_POLLING_INTERVAL_MS);
    386             }
    387         } else {
    388             PowerHandler handler;
    389             synchronized (this) {
    390                 handler = mHandler;
    391             }
    392             handler.handleProcessingComplete(shuttingDown);
    393         }
    394     }
    395 
    396     private void doHandleDeepSleep() {
    397         // keep holding partial wakelock to prevent entering sleep before enterDeepSleep call
    398         // enterDeepSleep should force sleep entry even if wake lock is kept.
    399         mSystemInterface.switchToPartialWakeLock();
    400         PowerHandler handler;
    401         synchronized (this) {
    402             handler = mHandler;
    403         }
    404         handler.cancelProcessingComplete();
    405         for (PowerServiceEventListener listener : mListeners) {
    406             listener.onSleepEntry();
    407         }
    408         int wakeupTimeSec = getWakeupTime();
    409         mHal.sendSleepEntry();
    410         synchronized (this) {
    411             mLastSleepEntryTime = SystemClock.elapsedRealtime();
    412         }
    413         mSystemInterface.enterDeepSleep(wakeupTimeSec);
    414         mHal.sendSleepExit();
    415         for (PowerServiceEventListener listener : mListeners) {
    416             listener.onSleepExit();
    417         }
    418         if (mSystemInterface.isWakeupCausedByTimer()) {
    419             doHandlePreprocessing(false /*shuttingDown*/);
    420         } else {
    421             PowerState currentState = mHal.getCurrentPowerState();
    422             if (currentState != null && needPowerStateChange(currentState)) {
    423                 onApPowerStateChange(currentState);
    424             } else { // power controller woke-up but no power state change. Just shutdown.
    425                 Log.w(CarLog.TAG_POWER, "external sleep wake up, but no power state change:" +
    426                         currentState);
    427                 doHandleShutdown();
    428             }
    429         }
    430     }
    431 
    432     private void doHandleNotifyPowerOn() {
    433         boolean displayOn = false;
    434         synchronized (this) {
    435             if (mCurrentState != null && mCurrentState.mState == PowerHalService.STATE_ON_FULL) {
    436                 displayOn = true;
    437             }
    438         }
    439         for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
    440             // wrapper will not send it forward if it is already called.
    441             wrapper.callOnPowerOn(displayOn);
    442         }
    443     }
    444 
    445     private boolean needPowerStateChange(PowerState newState) {
    446         synchronized (this) {
    447             if (mCurrentState != null && mCurrentState.equals(newState)) {
    448                 return false;
    449             }
    450             return true;
    451         }
    452     }
    453 
    454     private void doHandleShutdown() {
    455         // now shutdown
    456         for (PowerServiceEventListener listener : mListeners) {
    457             listener.onShutdown();
    458         }
    459         int wakeupTimeSec = 0;
    460         if (mHal.isTimedWakeupAllowed()) {
    461             wakeupTimeSec = getWakeupTime();
    462         }
    463         mHal.sendShutdownStart(wakeupTimeSec);
    464         mSystemInterface.shutdown();
    465     }
    466 
    467     private int getWakeupTime() {
    468         int wakeupTimeSec = 0;
    469         for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
    470             int t = wrapper.handler.getWakeupTime();
    471             if (t > wakeupTimeSec) {
    472                 wakeupTimeSec = t;
    473             }
    474         }
    475         return wakeupTimeSec;
    476     }
    477 
    478     private void doHandleProcessingComplete(boolean shutdownWhenCompleted) {
    479         synchronized (this) {
    480             releaseTimerLocked();
    481             if (!shutdownWhenCompleted && mLastSleepEntryTime > mProcessingStartTime) {
    482                 // entered sleep after processing start. So this could be duplicate request.
    483                 Log.w(CarLog.TAG_POWER, "Duplicate sleep entry request, ignore");
    484                 return;
    485             }
    486         }
    487         if (shutdownWhenCompleted) {
    488             doHandleShutdown();
    489         } else {
    490             doHandleDeepSleep();
    491         }
    492     }
    493 
    494     private synchronized void setCurrentState(PowerState state) {
    495         mCurrentState = state;
    496     }
    497 
    498     @Override
    499     public void onDisplayBrightnessChange(int brightness) {
    500         // TODO bug: 32065231
    501     }
    502 
    503     private void doHandleDisplayBrightnessChange(int brightness) {
    504         //TODO bug: 32065231
    505     }
    506 
    507     private void doHandleMainDisplayStateChange(boolean on) {
    508         //TODO bug: 32065231
    509     }
    510 
    511     public void handleMainDisplayChanged(boolean on) {
    512         PowerHandler handler;
    513         synchronized (this) {
    514             handler = mHandler;
    515         }
    516         handler.handleMainDisplayStateChange(on);
    517     }
    518 
    519     public synchronized Handler getHandler() {
    520         return mHandler;
    521     }
    522 
    523     private class PowerHandler extends Handler {
    524 
    525         private final int MSG_POWER_STATE_CHANGE = 0;
    526         private final int MSG_DISPLAY_BRIGHTNESS_CHANGE = 1;
    527         private final int MSG_MAIN_DISPLAY_STATE_CHANGE = 2;
    528         private final int MSG_PROCESSING_COMPLETE = 3;
    529         private final int MSG_NOTIFY_POWER_ON = 4;
    530 
    531         // Do not handle this immediately but with some delay as there can be a race between
    532         // display off due to rear view camera and delivery to here.
    533         private final long MAIN_DISPLAY_EVENT_DELAY_MS = 500;
    534 
    535         private PowerHandler(Looper looper) {
    536             super(looper);
    537         }
    538 
    539         private void handlePowerStateChange() {
    540             Message msg = obtainMessage(MSG_POWER_STATE_CHANGE);
    541             sendMessage(msg);
    542         }
    543 
    544         private void handleDisplayBrightnessChange(int brightness) {
    545             Message msg = obtainMessage(MSG_DISPLAY_BRIGHTNESS_CHANGE, brightness, 0);
    546             sendMessage(msg);
    547         }
    548 
    549         private void handleMainDisplayStateChange(boolean on) {
    550             removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
    551             Message msg = obtainMessage(MSG_MAIN_DISPLAY_STATE_CHANGE, Boolean.valueOf(on));
    552             sendMessageDelayed(msg, MAIN_DISPLAY_EVENT_DELAY_MS);
    553         }
    554 
    555         private void handleProcessingComplete(boolean shutdownWhenCompleted) {
    556             removeMessages(MSG_PROCESSING_COMPLETE);
    557             Message msg = obtainMessage(MSG_PROCESSING_COMPLETE, shutdownWhenCompleted ? 1 : 0, 0);
    558             sendMessage(msg);
    559         }
    560 
    561         private void handlePowerOn() {
    562             Message msg = obtainMessage(MSG_NOTIFY_POWER_ON);
    563             sendMessage(msg);
    564         }
    565 
    566         private void cancelProcessingComplete() {
    567             removeMessages(MSG_PROCESSING_COMPLETE);
    568         }
    569 
    570         private void cancelAll() {
    571             removeMessages(MSG_POWER_STATE_CHANGE);
    572             removeMessages(MSG_DISPLAY_BRIGHTNESS_CHANGE);
    573             removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
    574             removeMessages(MSG_PROCESSING_COMPLETE);
    575             removeMessages(MSG_NOTIFY_POWER_ON);
    576         }
    577 
    578         @Override
    579         public void handleMessage(Message msg) {
    580             switch (msg.what) {
    581                 case MSG_POWER_STATE_CHANGE:
    582                     doHandlePowerStateChange();
    583                     break;
    584                 case MSG_DISPLAY_BRIGHTNESS_CHANGE:
    585                     doHandleDisplayBrightnessChange(msg.arg1);
    586                     break;
    587                 case MSG_MAIN_DISPLAY_STATE_CHANGE:
    588                     doHandleMainDisplayStateChange((Boolean) msg.obj);
    589                     break;
    590                 case MSG_PROCESSING_COMPLETE:
    591                     doHandleProcessingComplete(msg.arg1 == 1);
    592                     break;
    593                 case MSG_NOTIFY_POWER_ON:
    594                     doHandleNotifyPowerOn();
    595                     break;
    596             }
    597         }
    598     }
    599 
    600     private class ShutdownProcessingTimerTask extends TimerTask {
    601         private final boolean mShutdownWhenCompleted;
    602         private final int mExpirationCount;
    603         private int mCurrentCount;
    604 
    605         private ShutdownProcessingTimerTask(boolean shutdownWhenCompleted, int expirationCount) {
    606             mShutdownWhenCompleted = shutdownWhenCompleted;
    607             mExpirationCount = expirationCount;
    608             mCurrentCount = 0;
    609         }
    610 
    611         @Override
    612         public void run() {
    613             mCurrentCount++;
    614             if (mCurrentCount > mExpirationCount) {
    615                 PowerHandler handler;
    616                 synchronized (CarPowerManagementService.this) {
    617                     releaseTimerLocked();
    618                     handler = mHandler;
    619                 }
    620                 handler.handleProcessingComplete(mShutdownWhenCompleted);
    621             } else {
    622                 mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS);
    623             }
    624         }
    625     }
    626 
    627     private static class PowerEventProcessingHandlerWrapper {
    628         public final PowerEventProcessingHandler handler;
    629         private long mProcessingTime = 0;
    630         private boolean mProcessingDone = true;
    631         private boolean mPowerOnSent = false;
    632         private int mLastDisplayState = -1;
    633 
    634         public PowerEventProcessingHandlerWrapper(PowerEventProcessingHandler handler) {
    635             this.handler = handler;
    636         }
    637 
    638         public synchronized void setProcessingTimeAndResetProcessingDone(long processingTime) {
    639             mProcessingTime = processingTime;
    640             mProcessingDone = false;
    641         }
    642 
    643         public synchronized long getProcessingTime() {
    644             return mProcessingTime;
    645         }
    646 
    647         public synchronized void markProcessingDone() {
    648             mProcessingDone = true;
    649         }
    650 
    651         public synchronized boolean isProcessingDone() {
    652             return mProcessingDone;
    653         }
    654 
    655         public void callOnPowerOn(boolean displayOn) {
    656             int newDisplayState = displayOn ? 1 : 0;
    657             boolean shouldCall = false;
    658             synchronized (this) {
    659                 if (!mPowerOnSent || (mLastDisplayState != newDisplayState)) {
    660                     shouldCall = true;
    661                     mPowerOnSent = true;
    662                     mLastDisplayState = newDisplayState;
    663                 }
    664             }
    665             if (shouldCall) {
    666                 handler.onPowerOn(displayOn);
    667             }
    668         }
    669 
    670         @Override
    671         public String toString() {
    672             return "PowerEventProcessingHandlerWrapper [handler=" + handler + ", mProcessingTime="
    673                     + mProcessingTime + ", mProcessingDone=" + mProcessingDone + "]";
    674         }
    675     }
    676 }
    677