• 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.car.userlib.CarUserManagerHelper;
23 import android.content.Context;
24 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateReq;
25 import android.os.Build;
26 import android.os.Handler;
27 import android.os.HandlerThread;
28 import android.os.IBinder;
29 import android.os.Looper;
30 import android.os.Message;
31 import android.os.RemoteCallbackList;
32 import android.os.RemoteException;
33 import android.os.SystemClock;
34 import android.os.SystemProperties;
35 import android.os.UserHandle;
36 import android.util.Log;
37 
38 import com.android.car.hal.PowerHalService;
39 import com.android.car.hal.PowerHalService.PowerState;
40 import com.android.car.systeminterface.SystemInterface;
41 import com.android.internal.annotations.GuardedBy;
42 import com.android.internal.annotations.VisibleForTesting;
43 
44 import java.io.PrintWriter;
45 import java.util.HashSet;
46 import java.util.LinkedList;
47 import java.util.Set;
48 import java.util.Timer;
49 import java.util.TimerTask;
50 
51 /**
52  * Power Management service class for cars. Controls the power states and interacts with other
53  * parts of the system to ensure its own state.
54  */
55 public class CarPowerManagementService extends ICarPower.Stub implements
56         CarServiceBase, PowerHalService.PowerEventListener {
57     private final Context mContext;
58     private final PowerHalService mHal;
59     private final SystemInterface mSystemInterface;
60     // The listeners that complete simply by returning from onStateChanged()
61     private final PowerManagerCallbackList mPowerManagerListeners = new PowerManagerCallbackList();
62     // The listeners that must indicate asynchronous completion by calling finished().
63     private final PowerManagerCallbackList mPowerManagerListenersWithCompletion =
64                           new PowerManagerCallbackList();
65     private final Set<IBinder> mListenersWeAreWaitingFor = new HashSet<>();
66     private final Object mSimulationSleepObject = new Object();
67 
68     @GuardedBy("this")
69     private CpmsState mCurrentState;
70     @GuardedBy("this")
71     private Timer mTimer;
72     @GuardedBy("this")
73     private long mProcessingStartTime;
74     @GuardedBy("this")
75     private long mLastSleepEntryTime;
76     @GuardedBy("this")
77     private final LinkedList<CpmsState> mPendingPowerStates = new LinkedList<>();
78     @GuardedBy("this")
79     private HandlerThread mHandlerThread;
80     @GuardedBy("this")
81     private PowerHandler mHandler;
82     @GuardedBy("this")
83     private boolean mTimerActive;
84     @GuardedBy("mSimulationSleepObject")
85     private boolean mInSimulatedDeepSleepMode = false;
86     @GuardedBy("mSimulationSleepObject")
87     private boolean mWakeFromSimulatedSleep = false;
88     private int mNextWakeupSec = 0;
89     private boolean mShutdownOnFinish = false;
90     private boolean mIsBooting = true;
91 
92     private final CarUserManagerHelper mCarUserManagerHelper;
93 
94     // TODO:  Make this OEM configurable.
95     private static final int SHUTDOWN_POLLING_INTERVAL_MS = 2000;
96     private static final int SHUTDOWN_EXTEND_MAX_MS = 5000;
97 
98     // maxGarageModeRunningDurationInSecs should be equal or greater than this. 15 min for now.
99     private static final int MIN_MAX_GARAGE_MODE_DURATION_MS = 15 * 60 * 1000;
100 
101     private static int sShutdownPrepareTimeMs = MIN_MAX_GARAGE_MODE_DURATION_MS;
102 
103     // in secs
104     private static final String PROP_MAX_GARAGE_MODE_DURATION_OVERRIDE =
105             "android.car.garagemodeduration";
106 
107     private class PowerManagerCallbackList extends RemoteCallbackList<ICarPowerStateListener> {
108         /**
109          * Old version of {@link #onCallbackDied(E, Object)} that
110          * does not provide a cookie.
111          */
112         @Override
onCallbackDied(ICarPowerStateListener listener)113         public void onCallbackDied(ICarPowerStateListener listener) {
114             Log.i(CarLog.TAG_POWER, "binderDied " + listener.asBinder());
115             CarPowerManagementService.this.doUnregisterListener(listener);
116         }
117     }
118 
CarPowerManagementService( Context context, PowerHalService powerHal, SystemInterface systemInterface, CarUserManagerHelper carUserManagerHelper)119     public CarPowerManagementService(
120             Context context, PowerHalService powerHal, SystemInterface systemInterface,
121             CarUserManagerHelper carUserManagerHelper) {
122         mContext = context;
123         mHal = powerHal;
124         mSystemInterface = systemInterface;
125         mCarUserManagerHelper = carUserManagerHelper;
126         sShutdownPrepareTimeMs = mContext.getResources().getInteger(
127                 R.integer.maxGarageModeRunningDurationInSecs) * 1000;
128         if (sShutdownPrepareTimeMs < MIN_MAX_GARAGE_MODE_DURATION_MS) {
129             Log.w(CarLog.TAG_POWER,
130                     "maxGarageModeRunningDurationInSecs smaller than minimum required, resource:"
131                     + sShutdownPrepareTimeMs + "(ms) while should exceed:"
132                     +  MIN_MAX_GARAGE_MODE_DURATION_MS + "(ms), Ignore resource.");
133             sShutdownPrepareTimeMs = MIN_MAX_GARAGE_MODE_DURATION_MS;
134         }
135     }
136 
137     /**
138      * Create a dummy instance for unit testing purpose only. Instance constructed in this way
139      * is not safe as members expected to be non-null are null.
140      */
141     @VisibleForTesting
CarPowerManagementService()142     protected CarPowerManagementService() {
143         mContext = null;
144         mHal = null;
145         mSystemInterface = null;
146         mHandlerThread = null;
147         mHandler = new PowerHandler(Looper.getMainLooper());
148         mCarUserManagerHelper = null;
149     }
150 
151     @VisibleForTesting
setShutdownPrepareTimeout(int timeoutMs)152     protected static void setShutdownPrepareTimeout(int timeoutMs) {
153         // Override the timeout to keep testing time short
154         if (timeoutMs < SHUTDOWN_EXTEND_MAX_MS) {
155             sShutdownPrepareTimeMs = SHUTDOWN_EXTEND_MAX_MS;
156         } else {
157             sShutdownPrepareTimeMs = timeoutMs;
158         }
159     }
160 
161     @Override
init()162     public void init() {
163         synchronized (CarPowerManagementService.this) {
164             mHandlerThread = new HandlerThread(CarLog.TAG_POWER);
165             mHandlerThread.start();
166             mHandler = new PowerHandler(mHandlerThread.getLooper());
167         }
168 
169         mHal.setListener(this);
170         if (mHal.isPowerStateSupported()) {
171             // Initialize CPMS in WAIT_FOR_VHAL state
172             onApPowerStateChange(CpmsState.WAIT_FOR_VHAL, CarPowerStateListener.WAIT_FOR_VHAL);
173         } else {
174             Log.w(CarLog.TAG_POWER, "Vehicle hal does not support power state yet.");
175             onApPowerStateChange(CpmsState.ON, CarPowerStateListener.ON);
176         }
177         mSystemInterface.startDisplayStateMonitoring(this);
178     }
179 
180     @Override
release()181     public void release() {
182         HandlerThread handlerThread;
183         synchronized (CarPowerManagementService.this) {
184             releaseTimerLocked();
185             mCurrentState = null;
186             mHandler.cancelAll();
187             handlerThread = mHandlerThread;
188         }
189         handlerThread.quitSafely();
190         try {
191             handlerThread.join(1000);
192         } catch (InterruptedException e) {
193             Log.e(CarLog.TAG_POWER, "Timeout while joining for handler thread to join.");
194         }
195         mSystemInterface.stopDisplayStateMonitoring();
196         mPowerManagerListeners.kill();
197         mListenersWeAreWaitingFor.clear();
198         mSystemInterface.releaseAllWakeLocks();
199     }
200 
201     @Override
dump(PrintWriter writer)202     public void dump(PrintWriter writer) {
203         writer.println("*PowerManagementService*");
204         writer.print("mCurrentState:" + mCurrentState);
205         writer.print(",mProcessingStartTime:" + mProcessingStartTime);
206         writer.print(",mLastSleepEntryTime:" + mLastSleepEntryTime);
207         writer.print(",mNextWakeupSec:" + mNextWakeupSec);
208         writer.print(",mShutdownOnFinish:" + mShutdownOnFinish);
209         writer.println(",sShutdownPrepareTimeMs:" + sShutdownPrepareTimeMs);
210     }
211 
212     @Override
onApPowerStateChange(PowerState state)213     public void onApPowerStateChange(PowerState state) {
214         PowerHandler handler;
215         synchronized (CarPowerManagementService.this) {
216             mPendingPowerStates.addFirst(new CpmsState(state));
217             handler = mHandler;
218         }
219         handler.handlePowerStateChange();
220     }
221 
222     @VisibleForTesting
clearIsBooting()223     protected void clearIsBooting() {
224         mIsBooting = false;
225     }
226 
227     /**
228      * Initiate state change from CPMS directly.
229      */
onApPowerStateChange(int apState, int carPowerStateListenerState)230     private void onApPowerStateChange(int apState, int carPowerStateListenerState) {
231         CpmsState newState = new CpmsState(apState, carPowerStateListenerState);
232         PowerHandler handler;
233         synchronized (CarPowerManagementService.this) {
234             mPendingPowerStates.addFirst(newState);
235             handler = mHandler;
236         }
237         handler.handlePowerStateChange();
238     }
239 
doHandlePowerStateChange()240     private void doHandlePowerStateChange() {
241         CpmsState state;
242         PowerHandler handler;
243         synchronized (CarPowerManagementService.this) {
244             state = mPendingPowerStates.peekFirst();
245             mPendingPowerStates.clear();
246             if (state == null) {
247                 return;
248             }
249             Log.i(CarLog.TAG_POWER, "doHandlePowerStateChange: newState=" + state.name());
250             if (!needPowerStateChangeLocked(state)) {
251                 Log.d(CarLog.TAG_POWER, "doHandlePowerStateChange no change needed");
252                 return;
253             }
254             // now real power change happens. Whatever was queued before should be all cancelled.
255             releaseTimerLocked();
256             handler = mHandler;
257         }
258         handler.cancelProcessingComplete();
259         Log.i(CarLog.TAG_POWER, "setCurrentState " + state.toString());
260         CarStatsLog.logPowerState(state.mState);
261         mCurrentState = state;
262         switch (state.mState) {
263             case CpmsState.WAIT_FOR_VHAL:
264                 handleWaitForVhal(state);
265                 break;
266             case CpmsState.ON:
267                 handleOn();
268                 break;
269             case CpmsState.SHUTDOWN_PREPARE:
270                 handleShutdownPrepare(state);
271                 break;
272             case CpmsState.SIMULATE_SLEEP:
273                 simulateShutdownPrepare();
274                 break;
275             case CpmsState.WAIT_FOR_FINISH:
276                 handleWaitForFinish(state);
277                 break;
278             case CpmsState.SUSPEND:
279                 // Received FINISH from VHAL
280                 handleFinish();
281                 break;
282             default:
283                 // Illegal state
284                 // TODO:  Throw exception?
285                 break;
286         }
287     }
288 
handleWaitForVhal(CpmsState state)289     private void handleWaitForVhal(CpmsState state) {
290         int carPowerStateListenerState = state.mCarPowerStateListenerState;
291         sendPowerManagerEvent(carPowerStateListenerState);
292         // Inspect CarPowerStateListenerState to decide which message to send via VHAL
293         switch (carPowerStateListenerState) {
294             case CarPowerStateListener.WAIT_FOR_VHAL:
295                 mHal.sendWaitForVhal();
296                 break;
297             case CarPowerStateListener.SHUTDOWN_CANCELLED:
298                 mHal.sendShutdownCancel();
299                 break;
300             case CarPowerStateListener.SUSPEND_EXIT:
301                 mHal.sendSleepExit();
302                 break;
303         }
304     }
305 
handleOn()306     private void handleOn() {
307         // Do not switch user if it is booting as there can be a race with CarServiceHelperService
308         if (mIsBooting) {
309             mIsBooting = false;
310         } else {
311             int targetUserId = mCarUserManagerHelper.getInitialUser();
312             if (targetUserId != UserHandle.USER_SYSTEM
313                     && targetUserId != mCarUserManagerHelper.getCurrentForegroundUserId()) {
314                 Log.i(CarLog.TAG_POWER, "Desired user changed, switching to user:" + targetUserId);
315                 mCarUserManagerHelper.switchToUserId(targetUserId);
316             }
317         }
318         mSystemInterface.setDisplayState(true);
319         sendPowerManagerEvent(CarPowerStateListener.ON);
320         mHal.sendOn();
321     }
322 
handleShutdownPrepare(CpmsState newState)323     private void handleShutdownPrepare(CpmsState newState) {
324         mSystemInterface.setDisplayState(false);
325         // Shutdown on finish if the system doesn't support deep sleep or doesn't allow it.
326         mShutdownOnFinish |= !mHal.isDeepSleepAllowed()
327                 || !mSystemInterface.isSystemSupportingDeepSleep()
328                 || !newState.mCanSleep;
329         if (newState.mCanPostpone) {
330             Log.i(CarLog.TAG_POWER, "starting shutdown prepare");
331             sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE);
332             mHal.sendShutdownPrepare();
333             doHandlePreprocessing();
334         } else {
335             Log.i(CarLog.TAG_POWER, "starting shutdown immediately");
336             synchronized (CarPowerManagementService.this) {
337                 releaseTimerLocked();
338             }
339             // Notify hal that we are shutting down and since it is immediate, don't schedule next
340             // wake up
341             mHal.sendShutdownStart(0);
342             // shutdown HU
343             mSystemInterface.shutdown();
344         }
345     }
346 
347     // Simulate system shutdown to Deep Sleep
simulateShutdownPrepare()348     private void simulateShutdownPrepare() {
349         mSystemInterface.setDisplayState(false);
350         Log.i(CarLog.TAG_POWER, "starting shutdown prepare");
351         sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE);
352         mHal.sendShutdownPrepare();
353         doHandlePreprocessing();
354     }
355 
handleWaitForFinish(CpmsState state)356     private void handleWaitForFinish(CpmsState state) {
357         sendPowerManagerEvent(state.mCarPowerStateListenerState);
358         switch (state.mCarPowerStateListenerState) {
359             case CarPowerStateListener.SUSPEND_ENTER:
360                 mHal.sendSleepEntry(mNextWakeupSec);
361                 break;
362             case CarPowerStateListener.SHUTDOWN_ENTER:
363                 mHal.sendShutdownStart(mNextWakeupSec);
364                 break;
365         }
366     }
367 
handleFinish()368     private void handleFinish() {
369         boolean mustShutDown;
370         boolean simulatedMode;
371         synchronized (mSimulationSleepObject) {
372             simulatedMode = mInSimulatedDeepSleepMode;
373             mustShutDown = mShutdownOnFinish && !simulatedMode;
374         }
375         if (mustShutDown) {
376             // shutdown HU
377             mSystemInterface.shutdown();
378         } else {
379             doHandleDeepSleep(simulatedMode);
380         }
381     }
382 
383     @GuardedBy("this")
releaseTimerLocked()384     private void releaseTimerLocked() {
385         synchronized (CarPowerManagementService.this) {
386             if (mTimer != null) {
387                 mTimer.cancel();
388             }
389             mTimer = null;
390             mTimerActive = false;
391         }
392     }
393 
doHandlePreprocessing()394     private void doHandlePreprocessing() {
395         int pollingCount = (sShutdownPrepareTimeMs / SHUTDOWN_POLLING_INTERVAL_MS) + 1;
396         if (Build.IS_USERDEBUG || Build.IS_ENG) {
397             int shutdownPrepareTimeOverrideInSecs =
398                     SystemProperties.getInt(PROP_MAX_GARAGE_MODE_DURATION_OVERRIDE, -1);
399             if (shutdownPrepareTimeOverrideInSecs >= 0) {
400                 pollingCount =
401                         (shutdownPrepareTimeOverrideInSecs * 1000 / SHUTDOWN_POLLING_INTERVAL_MS)
402                                 + 1;
403                 Log.i(CarLog.TAG_POWER,
404                         "Garage mode duration overridden secs:"
405                                 + shutdownPrepareTimeOverrideInSecs);
406             }
407         }
408         Log.i(CarLog.TAG_POWER, "processing before shutdown expected for: "
409                 + sShutdownPrepareTimeMs + " ms, adding polling:" + pollingCount);
410         synchronized (CarPowerManagementService.this) {
411             mProcessingStartTime = SystemClock.elapsedRealtime();
412             releaseTimerLocked();
413             mTimer = new Timer();
414             mTimerActive = true;
415             mTimer.scheduleAtFixedRate(
416                     new ShutdownProcessingTimerTask(pollingCount),
417                     0 /*delay*/,
418                     SHUTDOWN_POLLING_INTERVAL_MS);
419         }
420     }
421 
sendPowerManagerEvent(int newState)422     private void sendPowerManagerEvent(int newState) {
423         // Broadcast to the listeners that do not signal completion
424         notifyListeners(mPowerManagerListeners, newState);
425 
426         // SHUTDOWN_PREPARE is the only state where we need
427         // to maintain callbacks from listener components.
428         boolean allowCompletion = (newState == CarPowerStateListener.SHUTDOWN_PREPARE);
429 
430         // Fully populate mListenersWeAreWaitingFor before calling any onStateChanged()
431         // for the listeners that signal completion.
432         // Otherwise, if the first listener calls finish() synchronously, we will
433         // see the list go empty and we will think that we are done.
434         boolean haveSomeCompleters = false;
435         PowerManagerCallbackList completingListeners = new PowerManagerCallbackList();
436         synchronized (mListenersWeAreWaitingFor) {
437             mListenersWeAreWaitingFor.clear();
438             int idx = mPowerManagerListenersWithCompletion.beginBroadcast();
439             while (idx-- > 0) {
440                 ICarPowerStateListener listener =
441                         mPowerManagerListenersWithCompletion.getBroadcastItem(idx);
442                 completingListeners.register(listener);
443                 if (allowCompletion) {
444                     mListenersWeAreWaitingFor.add(listener.asBinder());
445                     haveSomeCompleters = true;
446                 }
447             }
448             mPowerManagerListenersWithCompletion.finishBroadcast();
449         }
450         // Broadcast to the listeners that DO signal completion
451         notifyListeners(completingListeners, newState);
452 
453         if (allowCompletion && !haveSomeCompleters) {
454             // No jobs need to signal completion. So we are now complete.
455             signalComplete();
456         }
457     }
458 
notifyListeners(PowerManagerCallbackList listenerList, int newState)459     private void notifyListeners(PowerManagerCallbackList listenerList, int newState) {
460         int idx = listenerList.beginBroadcast();
461         while (idx-- > 0) {
462             ICarPowerStateListener listener = listenerList.getBroadcastItem(idx);
463             try {
464                 listener.onStateChanged(newState);
465             } catch (RemoteException e) {
466                 // It's likely the connection snapped. Let binder death handle the situation.
467                 Log.e(CarLog.TAG_POWER, "onStateChanged() call failed: " + e, e);
468             }
469         }
470         listenerList.finishBroadcast();
471     }
472 
doHandleDeepSleep(boolean simulatedMode)473     private void doHandleDeepSleep(boolean simulatedMode) {
474         // keep holding partial wakelock to prevent entering sleep before enterDeepSleep call
475         // enterDeepSleep should force sleep entry even if wake lock is kept.
476         mSystemInterface.switchToPartialWakeLock();
477         PowerHandler handler;
478         synchronized (CarPowerManagementService.this) {
479             handler = mHandler;
480         }
481         handler.cancelProcessingComplete();
482         synchronized (CarPowerManagementService.this) {
483             mLastSleepEntryTime = SystemClock.elapsedRealtime();
484         }
485         int nextListenerState;
486         if (simulatedMode) {
487             simulateSleepByLooping();
488             nextListenerState = CarPowerStateListener.SHUTDOWN_CANCELLED;
489         } else {
490             boolean sleepSucceeded = mSystemInterface.enterDeepSleep();
491             if (!sleepSucceeded) {
492                 // VHAL should transition CPMS to shutdown.
493                 Log.e(CarLog.TAG_POWER, "Sleep did not succeed. Now attempting to shut down.");
494                 mSystemInterface.shutdown();
495             }
496             nextListenerState = CarPowerStateListener.SUSPEND_EXIT;
497         }
498         // On wake, reset nextWakeup time. If not set again, system will suspend/shutdown forever.
499         mNextWakeupSec = 0;
500         mSystemInterface.refreshDisplayBrightness();
501         onApPowerStateChange(CpmsState.WAIT_FOR_VHAL, nextListenerState);
502     }
503 
needPowerStateChangeLocked(CpmsState newState)504     private boolean needPowerStateChangeLocked(CpmsState newState) {
505         if (newState == null) {
506             return false;
507         } else if (mCurrentState == null) {
508             return true;
509         } else if (mCurrentState.equals(newState)) {
510             return false;
511         }
512 
513         // The following switch/case enforces the allowed state transitions.
514         switch (mCurrentState.mState) {
515             case CpmsState.WAIT_FOR_VHAL:
516                 return (newState.mState == CpmsState.ON)
517                     || (newState.mState == CpmsState.SHUTDOWN_PREPARE);
518             case CpmsState.SUSPEND:
519                 return newState.mState == CpmsState.WAIT_FOR_VHAL;
520             case CpmsState.ON:
521                 return (newState.mState == CpmsState.SHUTDOWN_PREPARE)
522                     || (newState.mState == CpmsState.SIMULATE_SLEEP);
523             case CpmsState.SHUTDOWN_PREPARE:
524                 // If VHAL sends SHUTDOWN_IMMEDIATELY while in SHUTDOWN_PREPARE state, do it.
525                 return ((newState.mState == CpmsState.SHUTDOWN_PREPARE) && !newState.mCanPostpone)
526                     || (newState.mState == CpmsState.WAIT_FOR_FINISH)
527                     || (newState.mState == CpmsState.WAIT_FOR_VHAL);
528             case CpmsState.SIMULATE_SLEEP:
529                 return true;
530             case CpmsState.WAIT_FOR_FINISH:
531                 return newState.mState == CpmsState.SUSPEND;
532             default:
533                 Log.e(CarLog.TAG_POWER, "Unhandled state transition:  currentState="
534                         + mCurrentState.name() + ", newState=" + newState.name());
535                 return false;
536         }
537     }
538 
doHandleProcessingComplete()539     private void doHandleProcessingComplete() {
540         synchronized (CarPowerManagementService.this) {
541             releaseTimerLocked();
542             if (!mShutdownOnFinish && mLastSleepEntryTime > mProcessingStartTime) {
543                 // entered sleep after processing start. So this could be duplicate request.
544                 Log.w(CarLog.TAG_POWER, "Duplicate sleep entry request, ignore");
545                 return;
546             }
547         }
548 
549         if (mShutdownOnFinish) {
550             onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, CarPowerStateListener.SHUTDOWN_ENTER);
551         } else {
552             onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, CarPowerStateListener.SUSPEND_ENTER);
553         }
554     }
555 
556     @Override
onDisplayBrightnessChange(int brightness)557     public void onDisplayBrightnessChange(int brightness) {
558         PowerHandler handler;
559         synchronized (CarPowerManagementService.this) {
560             handler = mHandler;
561         }
562         handler.handleDisplayBrightnessChange(brightness);
563     }
564 
doHandleDisplayBrightnessChange(int brightness)565     private void doHandleDisplayBrightnessChange(int brightness) {
566         mSystemInterface.setDisplayBrightness(brightness);
567     }
568 
doHandleMainDisplayStateChange(boolean on)569     private void doHandleMainDisplayStateChange(boolean on) {
570         Log.w(CarLog.TAG_POWER, "Unimplemented:  doHandleMainDisplayStateChange() - on = " + on);
571     }
572 
handleMainDisplayChanged(boolean on)573     public void handleMainDisplayChanged(boolean on) {
574         PowerHandler handler;
575         synchronized (CarPowerManagementService.this) {
576             handler = mHandler;
577         }
578         handler.handleMainDisplayStateChange(on);
579     }
580 
581     /**
582      * Send display brightness to VHAL.
583      * @param brightness value 0-100%
584      */
sendDisplayBrightness(int brightness)585     public void sendDisplayBrightness(int brightness) {
586         mHal.sendDisplayBrightness(brightness);
587     }
588 
getHandler()589     public synchronized Handler getHandler() {
590         return mHandler;
591     }
592 
593     // Binder interface for general use.
594     // The listener is not required (or allowed) to call finished().
595     @Override
registerListener(ICarPowerStateListener listener)596     public void registerListener(ICarPowerStateListener listener) {
597         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
598         mPowerManagerListeners.register(listener);
599     }
600 
601     // Binder interface for Car services only.
602     // After the listener completes its processing, it must call finished().
603     @Override
registerListenerWithCompletion(ICarPowerStateListener listener)604     public void registerListenerWithCompletion(ICarPowerStateListener listener) {
605         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
606         ICarImpl.assertCallingFromSystemProcessOrSelf();
607 
608         mPowerManagerListenersWithCompletion.register(listener);
609         // TODO: Need to send current state to newly registered listener? If so, need to handle
610         //       completion for SHUTDOWN_PREPARE state
611     }
612 
613     @Override
unregisterListener(ICarPowerStateListener listener)614     public void unregisterListener(ICarPowerStateListener listener) {
615         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
616         doUnregisterListener(listener);
617     }
618 
doUnregisterListener(ICarPowerStateListener listener)619     private void doUnregisterListener(ICarPowerStateListener listener) {
620         mPowerManagerListeners.unregister(listener);
621         boolean found = mPowerManagerListenersWithCompletion.unregister(listener);
622         if (found) {
623             // Remove this from the completion list (if it's there)
624             finishedImpl(listener.asBinder());
625         }
626     }
627 
628     @Override
requestShutdownOnNextSuspend()629     public void requestShutdownOnNextSuspend() {
630         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
631         mShutdownOnFinish = true;
632     }
633 
634     @Override
finished(ICarPowerStateListener listener)635     public void finished(ICarPowerStateListener listener) {
636         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
637         ICarImpl.assertCallingFromSystemProcessOrSelf();
638         finishedImpl(listener.asBinder());
639     }
640 
641     @Override
scheduleNextWakeupTime(int seconds)642     public synchronized void scheduleNextWakeupTime(int seconds) {
643         if (seconds < 0) {
644             Log.w(CarLog.TAG_POWER, "Next wake up can not be in negative time. Ignoring!");
645             return;
646         }
647         if (!mHal.isTimedWakeupAllowed()) {
648             Log.w(CarLog.TAG_POWER, "Setting timed wakeups are disabled in HAL. Skipping");
649             mNextWakeupSec = 0;
650             return;
651         }
652         if (mNextWakeupSec == 0 || mNextWakeupSec > seconds) {
653             mNextWakeupSec = seconds;
654         } else {
655             Log.d(CarLog.TAG_POWER, "Tried to schedule next wake up, but already had shorter "
656                     + "scheduled time");
657         }
658     }
659 
finishedImpl(IBinder binder)660     private void finishedImpl(IBinder binder) {
661         boolean allAreComplete = false;
662         synchronized (mListenersWeAreWaitingFor) {
663             boolean oneWasRemoved = mListenersWeAreWaitingFor.remove(binder);
664             allAreComplete = oneWasRemoved && mListenersWeAreWaitingFor.isEmpty();
665         }
666         if (allAreComplete) {
667             signalComplete();
668         }
669     }
670 
signalComplete()671     private void signalComplete() {
672         if (mCurrentState.mState == CpmsState.SHUTDOWN_PREPARE
673                 || mCurrentState.mState == CpmsState.SIMULATE_SLEEP) {
674             PowerHandler powerHandler;
675             // All apps are ready to shutdown/suspend.
676             synchronized (CarPowerManagementService.this) {
677                 if (!mShutdownOnFinish) {
678                     if (mLastSleepEntryTime > mProcessingStartTime
679                             && mLastSleepEntryTime < SystemClock.elapsedRealtime()) {
680                         Log.i(CarLog.TAG_POWER, "signalComplete: Already slept!");
681                         return;
682                     }
683                 }
684                 powerHandler = mHandler;
685             }
686             Log.i(CarLog.TAG_POWER, "Apps are finished, call handleProcessingComplete()");
687             powerHandler.handleProcessingComplete();
688         }
689     }
690 
691     private class PowerHandler extends Handler {
692         private final int MSG_POWER_STATE_CHANGE = 0;
693         private final int MSG_DISPLAY_BRIGHTNESS_CHANGE = 1;
694         private final int MSG_MAIN_DISPLAY_STATE_CHANGE = 2;
695         private final int MSG_PROCESSING_COMPLETE = 3;
696 
697         // Do not handle this immediately but with some delay as there can be a race between
698         // display off due to rear view camera and delivery to here.
699         private final long MAIN_DISPLAY_EVENT_DELAY_MS = 500;
700 
PowerHandler(Looper looper)701         private PowerHandler(Looper looper) {
702             super(looper);
703         }
704 
handlePowerStateChange()705         private void handlePowerStateChange() {
706             Message msg = obtainMessage(MSG_POWER_STATE_CHANGE);
707             sendMessage(msg);
708         }
709 
handleDisplayBrightnessChange(int brightness)710         private void handleDisplayBrightnessChange(int brightness) {
711             Message msg = obtainMessage(MSG_DISPLAY_BRIGHTNESS_CHANGE, brightness, 0);
712             sendMessage(msg);
713         }
714 
handleMainDisplayStateChange(boolean on)715         private void handleMainDisplayStateChange(boolean on) {
716             removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
717             Message msg = obtainMessage(MSG_MAIN_DISPLAY_STATE_CHANGE, Boolean.valueOf(on));
718             sendMessageDelayed(msg, MAIN_DISPLAY_EVENT_DELAY_MS);
719         }
720 
handleProcessingComplete()721         private void handleProcessingComplete() {
722             removeMessages(MSG_PROCESSING_COMPLETE);
723             Message msg = obtainMessage(MSG_PROCESSING_COMPLETE);
724             sendMessage(msg);
725         }
726 
cancelProcessingComplete()727         private void cancelProcessingComplete() {
728             removeMessages(MSG_PROCESSING_COMPLETE);
729         }
730 
cancelAll()731         private void cancelAll() {
732             removeMessages(MSG_POWER_STATE_CHANGE);
733             removeMessages(MSG_DISPLAY_BRIGHTNESS_CHANGE);
734             removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
735             removeMessages(MSG_PROCESSING_COMPLETE);
736         }
737 
738         @Override
handleMessage(Message msg)739         public void handleMessage(Message msg) {
740             switch (msg.what) {
741                 case MSG_POWER_STATE_CHANGE:
742                     doHandlePowerStateChange();
743                     break;
744                 case MSG_DISPLAY_BRIGHTNESS_CHANGE:
745                     doHandleDisplayBrightnessChange(msg.arg1);
746                     break;
747                 case MSG_MAIN_DISPLAY_STATE_CHANGE:
748                     doHandleMainDisplayStateChange((Boolean) msg.obj);
749                     break;
750                 case MSG_PROCESSING_COMPLETE:
751                     doHandleProcessingComplete();
752                     break;
753             }
754         }
755     }
756 
757     private class ShutdownProcessingTimerTask extends TimerTask {
758         private final int mExpirationCount;
759         private int mCurrentCount;
760 
ShutdownProcessingTimerTask(int expirationCount)761         private ShutdownProcessingTimerTask(int expirationCount) {
762             mExpirationCount = expirationCount;
763             mCurrentCount = 0;
764         }
765 
766         @Override
run()767         public void run() {
768             synchronized (CarPowerManagementService.this) {
769                 if (!mTimerActive) {
770                     // Ignore timer expiration since we got cancelled
771                     return;
772                 }
773                 mCurrentCount++;
774                 if (mCurrentCount > mExpirationCount) {
775                     PowerHandler handler;
776                     releaseTimerLocked();
777                     handler = mHandler;
778                     handler.handleProcessingComplete();
779                 } else {
780                     mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS);
781                 }
782             }
783         }
784     }
785 
786     private static class CpmsState {
787         // NOTE: When modifying states below, make sure to update CarPowerStateChanged.State in
788         //   frameworks/base/cmds/statsd/src/atoms.proto also.
789         public static final int WAIT_FOR_VHAL = 0;
790         public static final int ON = 1;
791         public static final int SHUTDOWN_PREPARE = 2;
792         public static final int WAIT_FOR_FINISH = 3;
793         public static final int SUSPEND = 4;
794         public static final int SIMULATE_SLEEP = 5;
795 
796         /* Config values from AP_POWER_STATE_REQ */
797         public final boolean mCanPostpone;
798         public final boolean mCanSleep;
799         /* Message sent to CarPowerStateListener in response to this state */
800         public final int mCarPowerStateListenerState;
801         /* One of the above state variables */
802         public final int mState;
803 
804         /**
805           * This constructor takes a PowerHalService.PowerState object and creates the corresponding
806           * CPMS state from it.
807           */
CpmsState(PowerState halPowerState)808         CpmsState(PowerState halPowerState) {
809             switch (halPowerState.mState) {
810                 case VehicleApPowerStateReq.ON:
811                     this.mCanPostpone = false;
812                     this.mCanSleep = false;
813                     this.mCarPowerStateListenerState = cpmsStateToPowerStateListenerState(ON);
814                     this.mState = ON;
815                     break;
816                 case VehicleApPowerStateReq.SHUTDOWN_PREPARE:
817                     this.mCanPostpone = halPowerState.canPostponeShutdown();
818                     this.mCanSleep = halPowerState.canEnterDeepSleep();
819                     this.mCarPowerStateListenerState = cpmsStateToPowerStateListenerState(
820                             SHUTDOWN_PREPARE);
821                     this.mState = SHUTDOWN_PREPARE;
822                     break;
823                 case VehicleApPowerStateReq.CANCEL_SHUTDOWN:
824                     this.mCanPostpone = false;
825                     this.mCanSleep = false;
826                     this.mCarPowerStateListenerState = CarPowerStateListener.SHUTDOWN_CANCELLED;
827                     this.mState = WAIT_FOR_VHAL;
828                     break;
829                 case VehicleApPowerStateReq.FINISHED:
830                     this.mCanPostpone = false;
831                     this.mCanSleep = false;
832                     this.mCarPowerStateListenerState = cpmsStateToPowerStateListenerState(SUSPEND);
833                     this.mState = SUSPEND;
834                     break;
835                 default:
836                     // Illegal state from PowerState.  Throw an exception?
837                     this.mCanPostpone = false;
838                     this.mCanSleep = false;
839                     this.mCarPowerStateListenerState = 0;
840                     this.mState = 0;
841                     break;
842             }
843         }
844 
CpmsState(int state)845         CpmsState(int state) {
846             this(state, cpmsStateToPowerStateListenerState(state));
847         }
848 
CpmsState(int state, int carPowerStateListenerState)849         CpmsState(int state, int carPowerStateListenerState) {
850             this.mCanPostpone = (state == SIMULATE_SLEEP);
851             this.mCanSleep = (state == SIMULATE_SLEEP);
852             this.mCarPowerStateListenerState = carPowerStateListenerState;
853             this.mState = state;
854         }
855 
name()856         public String name() {
857             String baseName;
858             switch(mState) {
859                 case WAIT_FOR_VHAL:     baseName = "WAIT_FOR_VHAL";    break;
860                 case ON:                baseName = "ON";               break;
861                 case SHUTDOWN_PREPARE:  baseName = "SHUTDOWN_PREPARE"; break;
862                 case WAIT_FOR_FINISH:   baseName = "WAIT_FOR_FINISH";  break;
863                 case SUSPEND:           baseName = "SUSPEND";          break;
864                 case SIMULATE_SLEEP:    baseName = "SIMULATE_SLEEP";   break;
865                 default:                baseName = "<unknown>";        break;
866             }
867             return baseName + "(" + mState + ")";
868         }
869 
cpmsStateToPowerStateListenerState(int state)870         private static int cpmsStateToPowerStateListenerState(int state) {
871             int powerStateListenerState = 0;
872 
873             // Set the CarPowerStateListenerState based on current state
874             switch (state) {
875                 case ON:
876                     powerStateListenerState = CarPowerStateListener.ON;
877                     break;
878                 case SHUTDOWN_PREPARE:
879                     powerStateListenerState = CarPowerStateListener.SHUTDOWN_PREPARE;
880                     break;
881                 case SUSPEND:
882                     powerStateListenerState = CarPowerStateListener.SUSPEND_ENTER;
883                     break;
884                 case WAIT_FOR_VHAL:
885                 case WAIT_FOR_FINISH:
886                 default:
887                     // Illegal state for this constructor.  Throw an exception?
888                     break;
889             }
890             return powerStateListenerState;
891         }
892 
893         @Override
equals(Object o)894         public boolean equals(Object o) {
895             if (this == o) {
896                 return true;
897             }
898             if (!(o instanceof CpmsState)) {
899                 return false;
900             }
901             CpmsState that = (CpmsState) o;
902             return this.mState == that.mState
903                     && this.mCanSleep == that.mCanSleep
904                     && this.mCanPostpone == that.mCanPostpone
905                     && this.mCarPowerStateListenerState == that.mCarPowerStateListenerState;
906         }
907 
908         @Override
toString()909         public String toString() {
910             return "CpmsState canSleep:" + mCanSleep + ", canPostpone=" + mCanPostpone
911                     + ", carPowerStateListenerState=" + mCarPowerStateListenerState
912                     + ", CpmsState=" + this.name();
913         }
914     }
915 
916     /**
917      * Resume after a manually-invoked suspend.
918      * Invoked using "adb shell dumpsys activity service com.android.car resume".
919      */
forceSimulatedResume()920     public void forceSimulatedResume() {
921         PowerHandler handler;
922         synchronized (this) {
923             // Cancel Garage Mode in case it's running
924             mPendingPowerStates.addFirst(new CpmsState(CpmsState.WAIT_FOR_VHAL,
925                                                        CarPowerStateListener.SHUTDOWN_CANCELLED));
926             handler = mHandler;
927         }
928         handler.handlePowerStateChange();
929 
930         synchronized (mSimulationSleepObject) {
931             mWakeFromSimulatedSleep = true;
932             mSimulationSleepObject.notify();
933         }
934     }
935 
936     /**
937      * Manually enter simulated suspend (Deep Sleep) mode
938      * Invoked using "adb shell dumpsys activity service com.android.car suspend".
939      * This is similar to 'onApPowerStateChange()' except that it needs to create a CpmsState
940      * that is not directly derived from a VehicleApPowerStateReq.
941      */
forceSimulatedSuspend()942     public void forceSimulatedSuspend() {
943         synchronized (mSimulationSleepObject) {
944             mInSimulatedDeepSleepMode = true;
945             mWakeFromSimulatedSleep = false;
946         }
947         PowerHandler handler;
948         synchronized (this) {
949             mPendingPowerStates.addFirst(new CpmsState(CpmsState.SIMULATE_SLEEP,
950                                                        CarPowerStateListener.SHUTDOWN_PREPARE));
951             handler = mHandler;
952         }
953         handler.handlePowerStateChange();
954     }
955 
956     // In a real Deep Sleep, the hardware removes power from the CPU (but retains power
957     // on the RAM). This puts the processor to sleep. Upon some external signal, power
958     // is re-applied to the CPU, and processing resumes right where it left off.
959     // We simulate this behavior by simply going into a loop.
960     // We exit the loop when forceResume() is called.
simulateSleepByLooping()961     private void simulateSleepByLooping() {
962         Log.i(CarLog.TAG_POWER, "Starting to simulate Deep Sleep by looping");
963         synchronized (mSimulationSleepObject) {
964             while (!mWakeFromSimulatedSleep) {
965                 try {
966                     mSimulationSleepObject.wait();
967                 } catch (InterruptedException ignored) {
968                 }
969             }
970             mInSimulatedDeepSleepMode = false;
971         }
972         Log.i(CarLog.TAG_POWER, "Exit Deep Sleep simulation loop");
973     }
974 }
975