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