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