• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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          */
onShutdown()57         void onShutdown();
58 
59         /**
60          * Entering deep sleep.
61          */
onSleepEntry()62         void onSleepEntry();
63 
64         /**
65          * Got out of deep sleep.
66          */
onSleepExit()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          */
onPrepareShutdown(boolean shuttingDown)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          */
onPowerOn(boolean displayOn)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          */
getWakeupTime()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
onCallbackDied(ICarPowerStateListener listener)141         public void onCallbackDied(ICarPowerStateListener listener) {
142             Log.i(CarLog.TAG_POWER, "binderDied " + listener.asBinder());
143             CarPowerManagementService.this.doUnregisterListener(listener);
144         }
145     }
146 
CarPowerManagementService(Context context, PowerHalService powerHal, SystemInterface systemInterface)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
CarPowerManagementService()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
init()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
release()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      */
registerPowerEventListener(PowerServiceEventListener listener)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      */
registerPowerEventProcessingHandler( PowerEventProcessingHandler handler)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      */
notifyPowerEventProcessingCompletion(PowerEventProcessingHandler handler)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
dump(PrintWriter writer)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
onBootReasonReceived(int bootReason)303     public void onBootReasonReceived(int bootReason) {
304         mBootReason = bootReason;
305     }
306 
307     @Override
onApPowerStateChange(PowerState state)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 
doHandlePowerStateChange()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 
handleDisplayOff(PowerState newState)351     private void handleDisplayOff(PowerState newState) {
352         setCurrentState(newState);
353         mSystemInterface.setDisplayState(false);
354     }
355 
handleFullOn(PowerState newState)356     private void handleFullOn(PowerState newState) {
357         setCurrentState(newState);
358         mSystemInterface.setDisplayState(true);
359     }
360 
361     @VisibleForTesting
notifyPowerOn(boolean displayOn)362     protected void notifyPowerOn(boolean displayOn) {
363         for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
364             wrapper.callOnPowerOn(displayOn);
365         }
366     }
367 
368     @VisibleForTesting
notifyPrepareShutdown(boolean shuttingDown)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 
handleShutdownPrepare(PowerState newState)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")
releaseTimerLocked()405     private void releaseTimerLocked() {
406         if (mTimer != null) {
407             mTimer.cancel();
408         }
409         mTimer = null;
410     }
411 
doHandlePreprocessing(boolean shuttingDown)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 
sendPowerManagerEvent(boolean shuttingDown)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 
doHandleDeepSleep()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 
doHandleNotifyPowerOn()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 
needPowerStateChange(PowerState newState)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 
doHandleShutdown()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 
getWakeupTime()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 
doHandleProcessingComplete(boolean shutdownWhenCompleted)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 
setCurrentState(PowerState state)589     private synchronized void setCurrentState(PowerState state) {
590         mCurrentState = state;
591     }
592 
593     @Override
onDisplayBrightnessChange(int brightness)594     public void onDisplayBrightnessChange(int brightness) {
595         PowerHandler handler;
596         synchronized (this) {
597             handler = mHandler;
598         }
599         handler.handleDisplayBrightnessChange(brightness);
600     }
601 
doHandleDisplayBrightnessChange(int brightness)602     private void doHandleDisplayBrightnessChange(int brightness) {
603         mSystemInterface.setDisplayBrightness(brightness);
604     }
605 
doHandleMainDisplayStateChange(boolean on)606     private void doHandleMainDisplayStateChange(boolean on) {
607         Log.w(CarLog.TAG_POWER, "Unimplemented:  doHandleMainDisplayStateChange() - on = " + on);
608     }
609 
handleMainDisplayChanged(boolean on)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      */
sendDisplayBrightness(int brightness)622     public void sendDisplayBrightness(int brightness) {
623         mHal.sendDisplayBrightness(brightness);
624     }
625 
getHandler()626     public synchronized Handler getHandler() {
627         return mHandler;
628     }
629 
630     // Binder interface for CarPowerManager
631     @Override
registerListener(ICarPowerStateListener listener)632     public void registerListener(ICarPowerStateListener listener) {
633         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
634         mPowerManagerListeners.register(listener);
635     }
636 
637     @Override
unregisterListener(ICarPowerStateListener listener)638     public void unregisterListener(ICarPowerStateListener listener) {
639         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
640         doUnregisterListener(listener);
641     }
642 
doUnregisterListener(ICarPowerStateListener listener)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
requestShutdownOnNextSuspend()659     public void requestShutdownOnNextSuspend() {
660         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
661         mShutdownOnNextSuspend = true;
662     }
663 
664     @Override
getBootReason()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
finished(ICarPowerStateListener listener, int token)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 
finishedLocked(IBinder binder, int token)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 
PowerHandler(Looper looper)704         private PowerHandler(Looper looper) {
705             super(looper);
706         }
707 
handlePowerStateChange()708         private void handlePowerStateChange() {
709             Message msg = obtainMessage(MSG_POWER_STATE_CHANGE);
710             sendMessage(msg);
711         }
712 
handleDisplayBrightnessChange(int brightness)713         private void handleDisplayBrightnessChange(int brightness) {
714             Message msg = obtainMessage(MSG_DISPLAY_BRIGHTNESS_CHANGE, brightness, 0);
715             sendMessage(msg);
716         }
717 
handleMainDisplayStateChange(boolean on)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 
handleProcessingComplete(boolean shutdownWhenCompleted)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 
handlePowerOn()730         private void handlePowerOn() {
731             Message msg = obtainMessage(MSG_NOTIFY_POWER_ON);
732             sendMessage(msg);
733         }
734 
cancelProcessingComplete()735         private void cancelProcessingComplete() {
736             removeMessages(MSG_PROCESSING_COMPLETE);
737         }
738 
cancelAll()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
handleMessage(Message msg)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 
ShutdownProcessingTimerTask(boolean shutdownWhenCompleted, int expirationCount)774         private ShutdownProcessingTimerTask(boolean shutdownWhenCompleted, int expirationCount) {
775             mShutdownWhenCompleted = shutdownWhenCompleted;
776             mExpirationCount = expirationCount;
777             mCurrentCount = 0;
778         }
779 
780         @Override
run()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 
PowerEventProcessingHandlerWrapper(PowerEventProcessingHandler handler)803         public PowerEventProcessingHandlerWrapper(PowerEventProcessingHandler handler) {
804             this.handler = handler;
805         }
806 
setProcessingTimeAndResetProcessingDone(long processingTime)807         public synchronized void setProcessingTimeAndResetProcessingDone(long processingTime) {
808             mProcessingTime = processingTime;
809             mProcessingDone = false;
810         }
811 
getProcessingTime()812         public synchronized long getProcessingTime() {
813             return mProcessingTime;
814         }
815 
markProcessingDone()816         public synchronized void markProcessingDone() {
817             mProcessingDone = true;
818         }
819 
isProcessingDone()820         public synchronized boolean isProcessingDone() {
821             return mProcessingDone;
822         }
823 
callOnPowerOn(boolean displayOn)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
toString()840         public String toString() {
841             return "PowerEventProcessingHandlerWrapper [handler=" + handler + ", mProcessingTime="
842                     + mProcessingTime + ", mProcessingDone=" + mProcessingDone + "]";
843         }
844     }
845 }
846