1 /*
2  * Copyright (C) 2018 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 
17 package android.car.hardware.power;
18 
19 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
20 
21 
22 import android.annotation.CallbackExecutor;
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.RequiresPermission;
27 import android.annotation.SystemApi;
28 import android.annotation.TestApi;
29 import android.car.Car;
30 import android.car.CarManagerBase;
31 import android.car.builtin.util.Slogf;
32 import android.os.Binder;
33 import android.os.IBinder;
34 import android.os.RemoteException;
35 import android.util.ArrayMap;
36 import android.util.Pair;
37 import android.util.SparseIntArray;
38 
39 import com.android.internal.annotations.GuardedBy;
40 
41 import java.lang.annotation.ElementType;
42 import java.lang.annotation.Retention;
43 import java.lang.annotation.RetentionPolicy;
44 import java.lang.annotation.Target;
45 import java.util.ArrayList;
46 import java.util.Objects;
47 import java.util.concurrent.Executor;
48 
49 /**
50  * API to receive power policy change notifications.
51  */
52 public class CarPowerManager extends CarManagerBase {
53 
54     /** @hide */
55     public static final String TAG = CarPowerManager.class.getSimpleName();
56 
57     private final Object mLock = new Object();
58     private final ICarPower mService;
59     @GuardedBy("mLock")
60     private final ArrayMap<CarPowerPolicyListener, Pair<Executor, CarPowerPolicyFilter>>
61             mPolicyListenerMap = new ArrayMap<>();
62     // key: power component, value: number of listeners to have interest in the component
63     @GuardedBy("mLock")
64     private final SparseIntArray mInterestedComponentMap = new SparseIntArray();
65     private final ICarPowerPolicyListener mPolicyChangeBinderCallback =
66             new ICarPowerPolicyListener.Stub() {
67         @Override
68         public void onPolicyChanged(CarPowerPolicy appliedPolicy,
69                 CarPowerPolicy accumulatedPolicy) {
70             long identityToken = Binder.clearCallingIdentity();
71             notifyPowerPolicyListeners(appliedPolicy, accumulatedPolicy);
72             Binder.restoreCallingIdentity(identityToken);
73         }
74     };
75 
76     @GuardedBy("mLock")
77     private CarPowerStateListener mListener;
78     @GuardedBy("mLock")
79     private CarPowerStateListenerWithCompletion mListenerWithCompletion;
80     @GuardedBy("mLock")
81     private CompletablePowerStateChangeFutureImpl mFuture;
82     @GuardedBy("mLock")
83     private ICarPowerStateListener mListenerToService;
84     @GuardedBy("mLock")
85     private Executor mExecutor;
86 
87     // The following power state definitions must match the ones located in the native
88     // CarPowerManager: packages/services/Car/car-lib/native/include/CarPowerManager.h
89     /**
90      * Power state to represent the current one is unavailable, unknown, or invalid.
91      *
92      * @hide
93      */
94     @SystemApi
95     public static final int STATE_INVALID = 0;
96 
97     /**
98      * Power state to represent Android is up, but waits for the vendor to give a signal to start
99      * main functionality.
100      *
101      * @hide
102      */
103     @SystemApi
104     public static final int STATE_WAIT_FOR_VHAL = 1;
105 
106     /**
107      * Power state to represent the system enters deep sleep (suspend to RAM).
108      *
109      * <p>In case of using {@link CarPowerStateListenerWithCompletion}, the timeout for suspend
110      * enter is 5 seconds by default and can be configured by setting
111      * {@code config_shutdownEnterTimeout} in the car service resource.
112      *
113      * @hide
114      */
115     @SystemApi
116     public static final int STATE_SUSPEND_ENTER = 2;
117 
118     /**
119      * Power state to represent the system wakes up from suspend.
120      *
121      * @hide
122      */
123     @SystemApi
124     public static final int STATE_SUSPEND_EXIT = 3;
125 
126     /**
127      * Power state to represent the system enters shutdown state.
128      *
129      * <p>In case of using {@link CarPowerStateListenerWithCompletion}, the timeout for shutdown
130      * enter is 5 seconds by default and can be configured by setting
131      * {@code config_shutdownEnterTimeout} in the car service resource.
132      *
133      * @hide
134      */
135     @SystemApi
136     public static final int STATE_SHUTDOWN_ENTER = 5;
137 
138     /**
139      * Power state to represent the system is at on state.
140      *
141      * @hide
142      */
143     @SystemApi
144     public static final int STATE_ON = 6;
145 
146     /**
147      * Power state to represent the system is getting ready for shutdown or suspend. Application is
148      * expected to cleanup and be ready to suspend.
149      *
150      * <p>The maximum duration of shutdown preprare is 15 minutes by default, and can be increased
151      * by setting {@code maxGarageModeRunningDurationInSecs} in the car service resource.
152      *
153      * @hide
154      */
155     @SystemApi
156     public static final int STATE_SHUTDOWN_PREPARE = 7;
157 
158     /**
159      * Power state to represent shutdown is cancelled, returning to normal state.
160      *
161      * @hide
162      */
163     @SystemApi
164     public static final int STATE_SHUTDOWN_CANCELLED = 8;
165 
166     /**
167      * Power state to represent the system enters hibernation (suspend to disk) state.
168      *
169      * <p>In case of using {@link CarPowerStateListenerWithCompletion}, the timeout for hibernation
170      * enter is 5 seconds by default and can be configured by setting
171      * {@code config_shutdownEnterTimeout} in the car service resource.
172      *
173      * @hide
174      */
175     @SystemApi
176     public static final int STATE_HIBERNATION_ENTER = 9;
177 
178     /**
179      * Power state to represent the system wakes up from hibernation.
180      *
181      * @hide
182      */
183     @SystemApi
184     public static final int STATE_HIBERNATION_EXIT = 10;
185 
186     /**
187      * Power state to represent system shutdown is initiated, but output components such as display
188      * is still on. UI to show a device is about to shutdown can be presented at this state.
189      *
190      * <p>In case of using {@link CarPowerStateListenerWithCompletion}, the timeout for pre shutdown
191      * prepare is 5 seconds by default and can be configured by setting
192      * {@code config_preShutdownPrepareTimeout} in the car service resource.
193      *
194      * @hide
195      */
196     @SystemApi
197     public static final int STATE_PRE_SHUTDOWN_PREPARE = 11;
198 
199     /**
200      * Power state to represent car power management service and VHAL finish processing to enter
201      * deep sleep and the device is about to sleep.
202      *
203      * <p>In case of using {@link CarPowerStateListenerWithCompletion}, the timeout for post suspend
204      * enter is 5 seconds by default and can be configured by setting
205      * {@code config_postShutdownEnterTimeout} in the car service resource.
206      *
207      * @hide
208      */
209     @SystemApi
210     public static final int STATE_POST_SUSPEND_ENTER = 12;
211 
212     /**
213      * Power state to represent car power management service and VHAL finish processing to shutdown
214      * and the device is about to power off.
215      *
216      * <p>In case of using {@link CarPowerStateListenerWithCompletion}, the timeout for post
217      * shutdown enter is 5 seconds by default and can be configured by setting
218      * {@code config_postShutdownEnterTimeout} in the car service resource.
219      *
220      * @hide
221      */
222     @SystemApi
223     public static final int STATE_POST_SHUTDOWN_ENTER = 13;
224 
225     /**
226      * Power state to represent car power management service and VHAL finish processing to enter
227      * hibernation and the device is about to hibernate.
228      *
229      * <p>In case of using {@link CarPowerStateListenerWithCompletion}, the timeout for post
230      * hibernation enter is 5 seconds by default and can be configured by setting
231      * {@code config_postShutdownEnterTimeout} in the car service resource.
232      *
233      * @hide
234      */
235     @SystemApi
236     public static final int STATE_POST_HIBERNATION_ENTER = 14;
237 
238     /** @hide */
239     @Retention(RetentionPolicy.SOURCE)
240     @IntDef(prefix = "STATE_", value = {
241             STATE_INVALID,
242             STATE_WAIT_FOR_VHAL,
243             STATE_SUSPEND_ENTER,
244             STATE_SUSPEND_EXIT,
245             STATE_SHUTDOWN_ENTER,
246             STATE_ON,
247             STATE_SHUTDOWN_PREPARE,
248             STATE_SHUTDOWN_CANCELLED,
249             STATE_HIBERNATION_ENTER,
250             STATE_HIBERNATION_EXIT,
251             STATE_PRE_SHUTDOWN_PREPARE,
252             STATE_POST_SUSPEND_ENTER,
253             STATE_POST_SHUTDOWN_ENTER,
254             STATE_POST_HIBERNATION_ENTER,
255     })
256     @Target({ElementType.TYPE_USE})
257     public @interface CarPowerState {}
258 
259     /**
260      * An interface passed from {@link CarPowerStateListenerWithCompletion}.
261      *
262      * <p>The listener uses this interface to tell {@link CarPowerManager} that it completed the
263      * task relevant to the power state change.
264      *
265      * @hide
266      */
267     @SystemApi
268     public interface CompletablePowerStateChangeFuture {
269         /**
270          * Tells {@link CarPowerManager} that the listener completed the task to handle the power
271          * state change.
272          */
complete()273         void complete();
274 
275         /**
276          * Gets the timestamp when the timeout happens.
277          *
278          * <p>The timestamp is system elapsed time in milliseconds.
279          */
getExpirationTime()280         long getExpirationTime();
281     }
282 
283     /**
284      * Applications set a {@link CarPowerStateListener} for power state event updates.
285      *
286      * @hide
287      */
288     @SystemApi
289     public interface CarPowerStateListener {
290         /**
291          * Called when power state changes.
292          *
293          * @param state New power state of the system.
294          */
onStateChanged(@arPowerState int state)295         void onStateChanged(@CarPowerState int state);
296     }
297 
298     /**
299      * Applications set a {@link CarPowerStateListenerWithCompletion} for power state
300      * event updates where a {@link CompletablePowerStateChangeFuture} is used.
301      *
302      * @hide
303      */
304     @SystemApi
305     public interface CarPowerStateListenerWithCompletion {
306         /**
307          * Called when power state changes.
308          *
309          * <p>Some {@code state}s allow for completion and the listeners are supposed to tell the
310          * completion of handling the power state change. Those states include:
311          * <ul>
312          * <li>{@link STATE_PRE_SHUTDOWN_PREPARE}</li>
313          * <li>{@link STATE_SHUTDOWN_ENTER}</li>
314          * <li>{@link STATE_SUSPEND_ENTER}</li>
315          * <li>{@link STATE_HIBERNATION_ENTER}</li>
316          * <li>{@link STATE_POST_SHUTDOWN_ENTER}</li>
317          * <li>{@link STATE_POST_SUSPEND_ENTER}</li>
318          * <li>{@link STATE_POST_HIBERNATION_ENTER}</li>
319          * </ul>
320          * If the listeners don't complete before the timeout expires, car power management service
321          * moves to the next step, anyway. The timeout given to the listener can be queried by
322          * {@link CompletablePowerStateChangeFuture#getExpirationTime()}.
323          *
324          * @param state New power state of the system.
325          * @param future CompletablePowerStateChangeFuture used by listeners to notify
326          *               CarPowerManager that they are ready to move to the next step. Car power
327          *               management service waits until the listeners call
328          *               {@code CompletablePowerStateChangeFuture#complete()} or timeout happens.
329          *               In the case {@code state} doesn't allow for completion, {@code future} is
330          *               {@code null}.
331          */
onStateChanged(@arPowerState int state, @Nullable CompletablePowerStateChangeFuture future)332         void onStateChanged(@CarPowerState int state,
333                 @Nullable CompletablePowerStateChangeFuture future);
334     }
335 
336     /**
337      * Listeners to receive power policy change.
338      *
339      * <p>Applications interested in power policy change register
340      * {@code CarPowerPolicyListener} and will be notified when power policy changes.
341      */
342     public interface CarPowerPolicyListener {
343         /**
344          * Called with {@link CarPowerPolicy} when power policy changes.
345          *
346          * @param policy The current power policy.
347          */
onPolicyChanged(@onNull CarPowerPolicy policy)348         void onPolicyChanged(@NonNull CarPowerPolicy policy);
349     }
350 
351     /**
352      * Gets an instance of the CarPowerManager.
353      *
354      * <p>Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
355      *
356      * @hide
357      */
CarPowerManager(Car car, IBinder service)358     public CarPowerManager(Car car, IBinder service) {
359         super(car);
360         mService = ICarPower.Stub.asInterface(service);
361     }
362 
363     /**
364      * Requests power manager to shutdown in lieu of suspend at the next opportunity.
365      *
366      * @hide
367      */
368     @RequiresPermission(Car.PERMISSION_CAR_POWER)
requestShutdownOnNextSuspend()369     public void requestShutdownOnNextSuspend() {
370         try {
371             mService.requestShutdownOnNextSuspend();
372         } catch (RemoteException e) {
373             handleRemoteExceptionFromCarService(e);
374         }
375     }
376 
377     /**
378      * Schedules next wake up time in CarPowerManagementService.
379      *
380      * @hide
381      */
382     @RequiresPermission(Car.PERMISSION_CAR_POWER)
scheduleNextWakeupTime(int seconds)383     public void scheduleNextWakeupTime(int seconds) {
384         try {
385             mService.scheduleNextWakeupTime(seconds);
386         } catch (RemoteException e) {
387             handleRemoteExceptionFromCarService(e);
388         }
389     }
390 
391     /**
392      * Returns the current power state.
393      *
394      * @return One of the values defined in {@link CarPowerStateListener}.
395      *
396      * @hide
397      */
398     @SystemApi
399     @RequiresPermission(Car.PERMISSION_CAR_POWER)
getPowerState()400     public @CarPowerState int getPowerState() {
401         try {
402             return mService.getPowerState();
403         } catch (RemoteException e) {
404             return handleRemoteExceptionFromCarService(e, STATE_INVALID);
405         }
406     }
407 
408     /**
409      * Sets a listener to receive power state changes. Only one listener may be set at a
410      * time for an instance of CarPowerManager.
411      *
412      * <p>The listener is assumed to completely handle the {@code onStateChanged} before returning.
413      *
414      * @param listener The listener which will receive the power state change.
415      * @throws IllegalStateException When a listener is already set for the power state change.
416      * @throws IllegalArgumentException When the given listener is null.
417      *
418      * @hide
419      */
420     @SystemApi
421     @RequiresPermission(Car.PERMISSION_CAR_POWER)
setListener(@onNull @allbackExecutor Executor executor, @NonNull CarPowerStateListener listener)422     public void setListener(@NonNull @CallbackExecutor Executor executor,
423             @NonNull CarPowerStateListener listener) {
424         checkArgument(executor != null, "excutor cannot be null");
425         checkArgument(listener != null, "listener cannot be null");
426         synchronized (mLock) {
427             if (mListener != null || mListenerWithCompletion != null) {
428                 throw new IllegalStateException("Listener must be cleared first");
429             }
430             // Updates listener
431             mListener = listener;
432             mExecutor = executor;
433             setServiceForListenerLocked(/* useCompletion= */ false);
434         }
435     }
436 
437     /**
438      * Sets a listener to receive power state changes. Only one listener may be set at a time for an
439      * instance of CarPowerManager.
440      *
441      * <p>For calls that require completion before continue, we attach a
442      * {@link CompletablePowerStateChangeFuture} which is being used as a signal that caller is
443      * finished and ready to proceed.
444      * Once the future is completed, car power management service knows that the application has
445      * handled the power state transition and moves to the next state.
446      *
447      * @param listener The listener which will receive the power state change.
448      * @throws IllegalStateException When a listener is already set for the power state change.
449      * @throws IllegalArgumentException When the given listener is null.
450      *
451      * @hide
452      */
453     @SystemApi
454     @RequiresPermission(Car.PERMISSION_CONTROL_SHUTDOWN_PROCESS)
setListenerWithCompletion(@onNull @allbackExecutor Executor executor, @NonNull CarPowerStateListenerWithCompletion listener)455     public void setListenerWithCompletion(@NonNull @CallbackExecutor Executor executor,
456             @NonNull CarPowerStateListenerWithCompletion listener) {
457         checkArgument(executor != null, "executor cannot be null");
458         checkArgument(listener != null, "listener cannot be null");
459         synchronized (mLock) {
460             if (mListener != null || mListenerWithCompletion != null) {
461                 throw new IllegalStateException("Listener must be cleared first");
462             }
463             // Updates listener
464             mListenerWithCompletion = listener;
465             mExecutor = executor;
466             setServiceForListenerLocked(/* useCompletion= */ true);
467         }
468     }
469 
470     /**
471      * Removes the power state listener.
472      *
473      * @hide
474      */
475     @SystemApi
476     @RequiresPermission(Car.PERMISSION_CAR_POWER)
clearListener()477     public void clearListener() {
478         ICarPowerStateListener listenerToService;
479         synchronized (mLock) {
480             listenerToService = mListenerToService;
481             mListenerToService = null;
482             mListener = null;
483             mListenerWithCompletion = null;
484             mExecutor = null;
485             cleanupFutureLocked();
486         }
487 
488         if (listenerToService == null) {
489             Slogf.w(TAG, "clearListener: listener was not registered");
490             return;
491         }
492 
493         try {
494             mService.unregisterListener(listenerToService);
495         } catch (RemoteException e) {
496             handleRemoteExceptionFromCarService(e);
497         }
498     }
499 
500     /**
501      * Gets the current power policy.
502      *
503      * <p>The returned power policy has ID of the power policy applied most recently. If no power
504      * policy has been applied, the ID is an empty string. Note that enabled components and disabled
505      * components might be different from those of the latest power policy applied. This is because
506      * the returned power policy contains the current state of all power components determined by
507      * applying power policies in an accumulative way.
508      *
509      * @return The power policy containing the latest state of all power components.
510      */
511     @RequiresPermission(Car.PERMISSION_READ_CAR_POWER_POLICY)
512     @Nullable
getCurrentPowerPolicy()513     public CarPowerPolicy getCurrentPowerPolicy() {
514         try {
515             return mService.getCurrentPowerPolicy();
516         } catch (RemoteException e) {
517             return handleRemoteExceptionFromCarService(e, null);
518         }
519     }
520 
521     /**
522      * Applies the given power policy.
523      *
524      * <p>Power components are turned on or off as specified in the given power policy. Power
525      * policies are defined at {@code /vendor/etc/automotive/power_policy.xml}.
526      * If the given power policy doesn't exist, this method throws
527      * {@link java.lang.IllegalArgumentException}.
528      *
529      * @param policyId ID of power policy.
530      * @throws IllegalArgumentException if {@code policyId} is null.
531      *
532      * @hide
533      */
534     @SystemApi
535     @RequiresPermission(Car.PERMISSION_CONTROL_CAR_POWER_POLICY)
applyPowerPolicy(@onNull String policyId)536     public void applyPowerPolicy(@NonNull String policyId) {
537         checkArgument(policyId != null, "Null policyId");
538         try {
539             mService.applyPowerPolicy(policyId);
540         } catch (RemoteException e) {
541             handleRemoteExceptionFromCarService(e);
542         }
543     }
544 
545     /**
546      * Sets the current power policy group.
547      *
548      * <p>Power policy group defines a rule to apply a certain power policy according to the power
549      * state transition. For example, a power policy named "default_for_on" is supposed to be
550      * applied when the power state becomes ON. This rule is specified in the power policy group.
551      * Many power policy groups can be pre-defined, and one of them is set for the current one using
552      * {@code setPowerPolicyGroup}.
553      *
554      * @param policyGroupId ID of power policy group.
555      * @throws IllegalArgumentException if {@code policyGroupId} is null.
556      *
557      * @hide
558      */
559     @SystemApi
560     @RequiresPermission(Car.PERMISSION_CONTROL_CAR_POWER_POLICY)
setPowerPolicyGroup(@onNull String policyGroupId)561     public void setPowerPolicyGroup(@NonNull String policyGroupId) {
562         checkArgument(policyGroupId != null, "Null policyGroupId");
563         try {
564             mService.setPowerPolicyGroup(policyGroupId);
565         } catch (RemoteException e) {
566             handleRemoteExceptionFromCarService(e);
567         }
568     }
569 
570     /**
571      * Subscribes to power policy change.
572      *
573      * <p>If the same listener is added with different filters, the listener is notified based on
574      * the last added filter.
575      *
576      * @param executor Executor where the listener method is called.
577      * @param listener Listener to be notified.
578      * @param filter Filter specifying power components of interest.
579      * @throws IllegalArgumentException if {@code executor}, {@code listener}, or {@code filter} is
580      *                                  null.
581      */
582     @RequiresPermission(Car.PERMISSION_READ_CAR_POWER_POLICY)
addPowerPolicyListener(@onNull @allbackExecutor Executor executor, @NonNull CarPowerPolicyFilter filter, @NonNull CarPowerPolicyListener listener)583     public void addPowerPolicyListener(@NonNull @CallbackExecutor Executor executor,
584             @NonNull CarPowerPolicyFilter filter, @NonNull CarPowerPolicyListener listener) {
585         assertPermission(Car.PERMISSION_READ_CAR_POWER_POLICY);
586         checkArgument(executor != null, "Null executor");
587         checkArgument(filter != null, "Null filter");
588         checkArgument(listener != null, "Null listener");
589         boolean updateCallbackNeeded = false;
590         CarPowerPolicyFilter newFilter = null;
591         synchronized (mLock) {
592             mPolicyListenerMap.remove(listener);
593             int[] filterComponents = filter.getComponents().clone();
594             Pair<Executor, CarPowerPolicyFilter> pair =
595                     new Pair<>(executor, new CarPowerPolicyFilter(filterComponents));
596             mPolicyListenerMap.put(listener, pair);
597             for (int i = 0; i < filterComponents.length; i++) {
598                 int key = filterComponents[i];
599                 int currentCount = mInterestedComponentMap.get(key);
600                 if (currentCount == 0) {
601                     updateCallbackNeeded = true;
602                     mInterestedComponentMap.put(key, 1);
603                 } else {
604                     mInterestedComponentMap.put(key, currentCount + 1);
605                 }
606             }
607             if (updateCallbackNeeded) {
608                 newFilter = createFilterFromInterestedComponentsLocked();
609             }
610         }
611         if (updateCallbackNeeded) {
612             updatePowerPolicyChangeCallback(newFilter);
613         }
614     }
615 
616     /**
617      * Unsubscribes from power policy change.
618      *
619      * @param listener Listener that will not be notified any more.
620      * @throws IllegalArgumentException if {@code listener} is null.
621      */
622     @RequiresPermission(Car.PERMISSION_READ_CAR_POWER_POLICY)
removePowerPolicyListener(@onNull CarPowerPolicyListener listener)623     public void removePowerPolicyListener(@NonNull CarPowerPolicyListener listener) {
624         assertPermission(Car.PERMISSION_READ_CAR_POWER_POLICY);
625         checkArgument(listener != null, "Null listener");
626         boolean updateCallbackNeeded = false;
627         CarPowerPolicyFilter filter = null;
628         synchronized (mLock) {
629             Pair<Executor, CarPowerPolicyFilter> pair = mPolicyListenerMap.remove(listener);
630             if (pair == null) {
631                 return;
632             }
633             int[] filterComponents = pair.second.getComponents();
634             for (int i = 0; i < filterComponents.length; i++) {
635                 int key = filterComponents[i];
636                 int currentCount = mInterestedComponentMap.get(key);
637                 if (currentCount == 0 || currentCount == 1) {
638                     mInterestedComponentMap.delete(key);
639                     updateCallbackNeeded = true;
640                 } else {
641                     mInterestedComponentMap.put(key, currentCount - 1);
642                 }
643             }
644             if (updateCallbackNeeded) {
645                 filter = createFilterFromInterestedComponentsLocked();
646             }
647         }
648         if (updateCallbackNeeded) {
649             updatePowerPolicyChangeCallback(filter);
650         }
651     }
652 
653     /**
654      * Turns on or off the individual display.
655      *
656      * <p>Changing the driver display is not allowed.
657      *
658      * @param displayId ID of the display
659      * @param enable Display power state to set
660      * @throws UnsupportedOperationException When trying to change the driver display power state.
661      *
662      * @hide
663      */
664     @SystemApi
665     @RequiresPermission(Car.PERMISSION_CAR_POWER)
setDisplayPowerState(int displayId, boolean enable)666     public void setDisplayPowerState(int displayId, boolean enable) {
667         try {
668             mService.setDisplayPowerState(displayId, enable);
669         } catch (RemoteException e) {
670             handleRemoteExceptionFromCarService(e);
671         }
672     }
673 
674     /**
675      * Notifies that user activity has happened in the given display.
676      *
677      * @param displayId ID of the display
678      * @hide
679      */
680     @RequiresPermission(Car.PERMISSION_CAR_POWER)
notifyUserActivity(int displayId)681     public void notifyUserActivity(int displayId) {
682         try {
683             mService.notifyUserActivity(displayId);
684         } catch (RemoteException e) {
685             handleRemoteExceptionFromCarService(e);
686         }
687     }
688 
689     /**
690      * Returns whether listen completion is allowed for {@code state}.
691      *
692      * @hide
693      */
694     @TestApi
isCompletionAllowed(@arPowerState int state)695     public static boolean isCompletionAllowed(@CarPowerState int state) {
696         switch (state) {
697             case CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE:
698             case CarPowerManager.STATE_SHUTDOWN_PREPARE:
699             case CarPowerManager.STATE_SHUTDOWN_ENTER:
700             case CarPowerManager.STATE_SUSPEND_ENTER:
701             case CarPowerManager.STATE_HIBERNATION_ENTER:
702             case CarPowerManager.STATE_POST_SHUTDOWN_ENTER:
703             case CarPowerManager.STATE_POST_SUSPEND_ENTER:
704             case CarPowerManager.STATE_POST_HIBERNATION_ENTER:
705                 return true;
706             default:
707                 return false;
708         }
709     }
710 
711     @GuardedBy("mLock")
setServiceForListenerLocked(boolean useCompletion)712     private void setServiceForListenerLocked(boolean useCompletion) {
713         if (mListenerToService == null) {
714             ICarPowerStateListener listenerToService = new ICarPowerStateListener.Stub() {
715                 @Override
716                 public void onStateChanged(int state, long expirationTimeMs)
717                         throws RemoteException {
718                     if (useCompletion) {
719                         CarPowerStateListenerWithCompletion listenerWithCompletion;
720                         CompletablePowerStateChangeFuture future;
721                         Executor executor;
722                         synchronized (mLock) {
723                             // Updates CompletablePowerStateChangeFuture. This will recreate it or
724                             // just clean it up.
725                             updateFutureLocked(state, expirationTimeMs);
726                             listenerWithCompletion = mListenerWithCompletion;
727                             future = mFuture;
728                             executor = mExecutor;
729                         }
730                         // Notifies the user that the state has changed and supply a future.
731                         if (listenerWithCompletion != null && executor != null) {
732                             long identityToken = Binder.clearCallingIdentity();
733                             try {
734                                 executor.execute(
735                                         () -> listenerWithCompletion.onStateChanged(state, future));
736                             } finally {
737                                 Binder.restoreCallingIdentity(identityToken);
738                             }
739                         }
740                     } else {
741                         CarPowerStateListener listener;
742                         Executor executor;
743                         synchronized (mLock) {
744                             listener = mListener;
745                             executor = mExecutor;
746                         }
747                         // Notifies the user without supplying a future.
748                         if (listener != null && executor != null) {
749                             long identityToken = Binder.clearCallingIdentity();
750                             try {
751                                 executor.execute(() -> listener.onStateChanged(state));
752                             } finally {
753                                 Binder.restoreCallingIdentity(identityToken);
754                             }
755                         }
756                     }
757                 }
758             };
759             try {
760                 if (useCompletion) {
761                     mService.registerListenerWithCompletion(listenerToService);
762                 } else {
763                     mService.registerListener(listenerToService);
764                 }
765                 mListenerToService = listenerToService;
766             } catch (RemoteException e) {
767                 handleRemoteExceptionFromCarService(e);
768             }
769         }
770     }
771 
772     @GuardedBy("mLock")
updateFutureLocked(@arPowerState int state, long expirationTimeMs)773     private void updateFutureLocked(@CarPowerState int state, long expirationTimeMs) {
774         cleanupFutureLocked();
775         if (isCompletionAllowed(state)) {
776             // Creates a CompletablePowerStateChangeFuture and passes it to the listener.
777             // When the listener completes, tells CarPowerManagementService that this action is
778             // finished.
779             mFuture = new CompletablePowerStateChangeFutureImpl(() -> {
780                 ICarPowerStateListener listenerToService;
781                 synchronized (mLock) {
782                     listenerToService = mListenerToService;
783                 }
784                 try {
785                     mService.finished(state, listenerToService);
786                 } catch (RemoteException e) {
787                     handleRemoteExceptionFromCarService(e);
788                 }
789             }, expirationTimeMs);
790         }
791     }
792 
793     @GuardedBy("mLock")
cleanupFutureLocked()794     private void cleanupFutureLocked() {
795         if (mFuture != null) {
796             mFuture.invalidate();
797             Slogf.w(TAG, "The current future becomes invalid");
798             mFuture = null;
799         }
800     }
801 
802     @GuardedBy("mLock")
createFilterFromInterestedComponentsLocked()803     private CarPowerPolicyFilter createFilterFromInterestedComponentsLocked() {
804         CarPowerPolicyFilter newFilter = null;
805         int componentCount = mInterestedComponentMap.size();
806         if (componentCount != 0) {
807             int[] components = new int[componentCount];
808             for (int i = 0; i < componentCount; i++) {
809                 components[i] = mInterestedComponentMap.keyAt(i);
810             }
811             newFilter = new CarPowerPolicyFilter(components);
812         }
813         return newFilter;
814     }
815 
updatePowerPolicyChangeCallback(CarPowerPolicyFilter filter)816     private void updatePowerPolicyChangeCallback(CarPowerPolicyFilter filter) {
817         try {
818             if (filter == null) {
819                 mService.removePowerPolicyListener(mPolicyChangeBinderCallback);
820             } else {
821                 mService.addPowerPolicyListener(filter, mPolicyChangeBinderCallback);
822             }
823         } catch (RemoteException e) {
824             handleRemoteExceptionFromCarService(e);
825         }
826     }
827 
notifyPowerPolicyListeners(CarPowerPolicy appliedPolicy, CarPowerPolicy accumulatedPolicy)828     private void notifyPowerPolicyListeners(CarPowerPolicy appliedPolicy,
829             CarPowerPolicy accumulatedPolicy) {
830         ArrayList<Pair<CarPowerPolicyListener, Executor>> listeners = new ArrayList<>();
831         synchronized (mLock) {
832             for (int i = 0; i < mPolicyListenerMap.size(); i++) {
833                 CarPowerPolicyListener listener = mPolicyListenerMap.keyAt(i);
834                 Pair<Executor, CarPowerPolicyFilter> pair = mPolicyListenerMap.valueAt(i);
835                 if (PowerComponentUtil.hasComponents(appliedPolicy, pair.second)) {
836                     listeners.add(
837                             new Pair<CarPowerPolicyListener, Executor>(listener, pair.first));
838                 }
839             }
840         }
841         for (int i = 0; i < listeners.size(); i++) {
842             Pair<CarPowerPolicyListener, Executor> pair = listeners.get(i);
843             pair.second.execute(() -> pair.first.onPolicyChanged(accumulatedPolicy));
844         }
845     }
846 
assertPermission(String permission)847     private void assertPermission(String permission) {
848         if (getContext().checkCallingOrSelfPermission(permission) != PERMISSION_GRANTED) {
849             throw new SecurityException("requires " + permission);
850         }
851     }
852 
checkArgument(boolean test, String message)853     private void checkArgument(boolean test, String message) {
854         if (!test) {
855             throw new IllegalArgumentException(message);
856         }
857     }
858 
859     /** @hide */
860     @Override
onCarDisconnected()861     public void onCarDisconnected() {
862         synchronized (mLock) {
863             mListener = null;
864             mListenerWithCompletion = null;
865         }
866     }
867 
868     private static final class CompletablePowerStateChangeFutureImpl
869             implements CompletablePowerStateChangeFuture {
870 
871         private final Runnable mRunnableForCompletion;
872         private final long mExpirationTimeMs;
873         private final Object mCompletionLock = new Object();
874 
875         @GuardedBy("mCompletionLock")
876         private boolean mCanBeCompleted = true;
877 
CompletablePowerStateChangeFutureImpl(Runnable runnable, long expirationTimeMs)878         private CompletablePowerStateChangeFutureImpl(Runnable runnable, long expirationTimeMs) {
879             mRunnableForCompletion = Objects.requireNonNull(runnable);
880             mExpirationTimeMs = expirationTimeMs;
881         }
882 
883         @Override
complete()884         public void complete() {
885             synchronized (mCompletionLock) {
886                 if (!mCanBeCompleted) {
887                     Slogf.w(TAG, "Cannot complete: already completed or invalid state");
888                     return;
889                 }
890                 // Once completed, this instance cannot be completed again.
891                 mCanBeCompleted = false;
892             }
893             mRunnableForCompletion.run();
894         }
895 
896         @Override
getExpirationTime()897         public long getExpirationTime() {
898             return mExpirationTimeMs;
899         }
900 
invalidate()901         private void invalidate() {
902             synchronized (mCompletionLock) {
903                 mCanBeCompleted = false;
904             }
905         }
906     }
907 }
908