• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_PREPARE}</li>
314          * <li>{@link STATE_SHUTDOWN_ENTER}</li>
315          * <li>{@link STATE_SUSPEND_ENTER}</li>
316          * <li>{@link STATE_HIBERNATION_ENTER}</li>
317          * <li>{@link STATE_POST_SHUTDOWN_ENTER}</li>
318          * <li>{@link STATE_POST_SUSPEND_ENTER}</li>
319          * <li>{@link STATE_POST_HIBERNATION_ENTER}</li>
320          * </ul>
321          * If the listeners don't complete before the timeout expires, car power management service
322          * moves to the next step, anyway. The timeout given to the listener can be queried by
323          * {@link CompletablePowerStateChangeFuture#getExpirationTime()}.
324          *
325          * @param state New power state of the system.
326          * @param future CompletablePowerStateChangeFuture used by listeners to notify
327          *               CarPowerManager that they are ready to move to the next step. Car power
328          *               management service waits until the listeners call
329          *               {@code CompletablePowerStateChangeFuture#complete()} or timeout happens.
330          *               In the case {@code state} doesn't allow for completion, {@code future} is
331          *               {@code null}.
332          */
onStateChanged(@arPowerState int state, @Nullable CompletablePowerStateChangeFuture future)333         void onStateChanged(@CarPowerState int state,
334                 @Nullable CompletablePowerStateChangeFuture future);
335     }
336 
337     /**
338      * Listeners to receive power policy change.
339      *
340      * <p>Applications interested in power policy change register
341      * {@code CarPowerPolicyListener} and will be notified when power policy changes.
342      */
343     public interface CarPowerPolicyListener {
344         /**
345          * Called with {@link CarPowerPolicy} when power policy changes.
346          *
347          * @param policy The current power policy.
348          */
onPolicyChanged(@onNull CarPowerPolicy policy)349         void onPolicyChanged(@NonNull CarPowerPolicy policy);
350     }
351 
352     /**
353      * Gets an instance of the CarPowerManager.
354      *
355      * <p>Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
356      *
357      * @hide
358      */
CarPowerManager(Car car, IBinder service)359     public CarPowerManager(Car car, IBinder service) {
360         super(car);
361         mService = ICarPower.Stub.asInterface(service);
362     }
363 
364     /**
365      * Requests power manager to shutdown in lieu of suspend at the next opportunity.
366      *
367      * @hide
368      */
369     @RequiresPermission(Car.PERMISSION_CAR_POWER)
requestShutdownOnNextSuspend()370     public void requestShutdownOnNextSuspend() {
371         try {
372             mService.requestShutdownOnNextSuspend();
373         } catch (RemoteException e) {
374             handleRemoteExceptionFromCarService(e);
375         }
376     }
377 
378     /**
379      * Schedules next wake up time in CarPowerManagementService.
380      *
381      * @hide
382      */
383     @RequiresPermission(Car.PERMISSION_CAR_POWER)
scheduleNextWakeupTime(int seconds)384     public void scheduleNextWakeupTime(int seconds) {
385         try {
386             mService.scheduleNextWakeupTime(seconds);
387         } catch (RemoteException e) {
388             handleRemoteExceptionFromCarService(e);
389         }
390     }
391 
392     /**
393      * Returns the current power state.
394      *
395      * @return One of the values defined in {@link CarPowerStateListener}.
396      *
397      * @hide
398      */
399     @SystemApi
400     @RequiresPermission(Car.PERMISSION_CAR_POWER)
getPowerState()401     public @CarPowerState int getPowerState() {
402         try {
403             return mService.getPowerState();
404         } catch (RemoteException e) {
405             return handleRemoteExceptionFromCarService(e, STATE_INVALID);
406         }
407     }
408 
409     /**
410      * Sets a listener to receive power state changes. Only one listener may be set at a
411      * time for an instance of CarPowerManager.
412      *
413      * <p>The listener is assumed to completely handle the {@code onStateChanged} before returning.
414      *
415      * @param listener The listener which will receive the power state change.
416      * @throws IllegalStateException When a listener is already set for the power state change.
417      * @throws IllegalArgumentException When the given listener is null.
418      *
419      * @hide
420      */
421     @SystemApi
422     @RequiresPermission(Car.PERMISSION_CAR_POWER)
setListener(@onNull @allbackExecutor Executor executor, @NonNull CarPowerStateListener listener)423     public void setListener(@NonNull @CallbackExecutor Executor executor,
424             @NonNull CarPowerStateListener listener) {
425         checkArgument(executor != null, "excutor cannot be null");
426         checkArgument(listener != null, "listener cannot be null");
427         synchronized (mLock) {
428             if (mListener != null || mListenerWithCompletion != null) {
429                 throw new IllegalStateException("Listener must be cleared first");
430             }
431             // Updates listener
432             mListener = listener;
433             mExecutor = executor;
434             setServiceForListenerLocked(/* useCompletion= */ false);
435         }
436     }
437 
438     /**
439      * Sets a listener to receive power state changes. Only one listener may be set at a time for an
440      * instance of CarPowerManager.
441      *
442      * <p>For calls that require completion before continue, we attach a
443      * {@link CompletablePowerStateChangeFuture} which is being used as a signal that caller is
444      * finished and ready to proceed.
445      * Once the future is completed, car power management service knows that the application has
446      * handled the power state transition and moves to the next state.
447      *
448      * @param listener The listener which will receive the power state change.
449      * @throws IllegalStateException When a listener is already set for the power state change.
450      * @throws IllegalArgumentException When the given listener is null.
451      *
452      * @hide
453      */
454     @SystemApi
455     @RequiresPermission(Car.PERMISSION_CONTROL_SHUTDOWN_PROCESS)
setListenerWithCompletion(@onNull @allbackExecutor Executor executor, @NonNull CarPowerStateListenerWithCompletion listener)456     public void setListenerWithCompletion(@NonNull @CallbackExecutor Executor executor,
457             @NonNull CarPowerStateListenerWithCompletion listener) {
458         checkArgument(executor != null, "executor cannot be null");
459         checkArgument(listener != null, "listener cannot be null");
460         synchronized (mLock) {
461             if (mListener != null || mListenerWithCompletion != null) {
462                 throw new IllegalStateException("Listener must be cleared first");
463             }
464             // Updates listener
465             mListenerWithCompletion = listener;
466             mExecutor = executor;
467             setServiceForListenerLocked(/* useCompletion= */ true);
468         }
469     }
470 
471     /**
472      * Removes the power state listener.
473      *
474      * @hide
475      */
476     @SystemApi
477     @RequiresPermission(Car.PERMISSION_CAR_POWER)
clearListener()478     public void clearListener() {
479         ICarPowerStateListener listenerToService;
480         synchronized (mLock) {
481             listenerToService = mListenerToService;
482             mListenerToService = null;
483             mListener = null;
484             mListenerWithCompletion = null;
485             mExecutor = null;
486             cleanupFutureLocked();
487         }
488 
489         if (listenerToService == null) {
490             Slogf.w(TAG, "clearListener: listener was not registered");
491             return;
492         }
493 
494         try {
495             mService.unregisterListener(listenerToService);
496         } catch (RemoteException e) {
497             handleRemoteExceptionFromCarService(e);
498         }
499     }
500 
501     /**
502      * Gets the current power policy.
503      *
504      * <p>The returned power policy has ID of the power policy applied most recently. If no power
505      * policy has been applied, the ID is an empty string. Note that enabled components and disabled
506      * components might be different from those of the latest power policy applied. This is because
507      * the returned power policy contains the current state of all power components determined by
508      * applying power policies in an accumulative way.
509      *
510      * @return The power policy containing the latest state of all power components.
511      */
512     @RequiresPermission(Car.PERMISSION_READ_CAR_POWER_POLICY)
513     @Nullable
getCurrentPowerPolicy()514     public CarPowerPolicy getCurrentPowerPolicy() {
515         try {
516             return mService.getCurrentPowerPolicy();
517         } catch (RemoteException e) {
518             return handleRemoteExceptionFromCarService(e, null);
519         }
520     }
521 
522     /**
523      * Applies the given power policy.
524      *
525      * <p>Power components are turned on or off as specified in the given power policy. Power
526      * policies are defined at {@code /vendor/etc/automotive/power_policy.xml}.
527      * If the given power policy doesn't exist, this method throws
528      * {@link java.lang.IllegalArgumentException}.
529      *
530      * <p>When this API returns, it doesn't mean the given power policy is applied. The application
531      * of a power policy can be checked with {@link CarPowerPolicyListener}.
532      *
533      * @param policyId ID of power policy.
534      * @throws IllegalArgumentException if {@code policyId} is {@code null}.
535      *
536      * @hide
537      */
538     @SystemApi
539     @RequiresPermission(Car.PERMISSION_CONTROL_CAR_POWER_POLICY)
applyPowerPolicy(@onNull String policyId)540     public void applyPowerPolicy(@NonNull String policyId) {
541         checkArgument(policyId != null, "Null policyId");
542         try {
543             mService.applyPowerPolicy(policyId);
544         } catch (RemoteException e) {
545             handleRemoteExceptionFromCarService(e);
546         }
547     }
548 
549     /**
550      * Sets the current power policy group.
551      *
552      * <p>Power policy group defines a rule to apply a certain power policy according to the power
553      * state transition. For example, a power policy named "default_for_on" is supposed to be
554      * applied when the power state becomes ON. This rule is specified in the power policy group.
555      * Many power policy groups can be pre-defined, and one of them is set for the current one using
556      * {@code setPowerPolicyGroup}.
557      *
558      * @param policyGroupId ID of power policy group.
559      * @throws IllegalArgumentException if {@code policyGroupId} is null.
560      *
561      * @hide
562      */
563     @SystemApi
564     @RequiresPermission(Car.PERMISSION_CONTROL_CAR_POWER_POLICY)
setPowerPolicyGroup(@onNull String policyGroupId)565     public void setPowerPolicyGroup(@NonNull String policyGroupId) {
566         checkArgument(policyGroupId != null, "Null policyGroupId");
567         try {
568             mService.setPowerPolicyGroup(policyGroupId);
569         } catch (RemoteException e) {
570             handleRemoteExceptionFromCarService(e);
571         }
572     }
573 
574     /**
575      * Subscribes to power policy change.
576      *
577      * <p>If the same listener is added with different filters, the listener is notified based on
578      * the last added filter.
579      *
580      * @param executor Executor where the listener method is called.
581      * @param listener Listener to be notified.
582      * @param filter Filter specifying power components of interest.
583      * @throws IllegalArgumentException if {@code executor}, {@code listener}, or {@code filter} is
584      *                                  null.
585      */
586     @RequiresPermission(Car.PERMISSION_READ_CAR_POWER_POLICY)
addPowerPolicyListener(@onNull @allbackExecutor Executor executor, @NonNull CarPowerPolicyFilter filter, @NonNull CarPowerPolicyListener listener)587     public void addPowerPolicyListener(@NonNull @CallbackExecutor Executor executor,
588             @NonNull CarPowerPolicyFilter filter, @NonNull CarPowerPolicyListener listener) {
589         assertPermission(Car.PERMISSION_READ_CAR_POWER_POLICY);
590         checkArgument(executor != null, "Null executor");
591         checkArgument(filter != null, "Null filter");
592         checkArgument(listener != null, "Null listener");
593         boolean updateCallbackNeeded = false;
594         CarPowerPolicyFilter newFilter = null;
595         synchronized (mLock) {
596             mPolicyListenerMap.remove(listener);
597             int[] filterComponents = filter.getComponents().clone();
598             Pair<Executor, CarPowerPolicyFilter> pair =
599                     new Pair<>(executor, new CarPowerPolicyFilter(filterComponents));
600             mPolicyListenerMap.put(listener, pair);
601             for (int i = 0; i < filterComponents.length; i++) {
602                 int key = filterComponents[i];
603                 int currentCount = mInterestedComponentMap.get(key);
604                 if (currentCount == 0) {
605                     updateCallbackNeeded = true;
606                     mInterestedComponentMap.put(key, 1);
607                 } else {
608                     mInterestedComponentMap.put(key, currentCount + 1);
609                 }
610             }
611             if (updateCallbackNeeded) {
612                 newFilter = createFilterFromInterestedComponentsLocked();
613             }
614         }
615         if (updateCallbackNeeded) {
616             updatePowerPolicyChangeCallback(newFilter);
617         }
618     }
619 
620     /**
621      * Unsubscribes from power policy change.
622      *
623      * @param listener Listener that will not be notified any more.
624      * @throws IllegalArgumentException if {@code listener} is null.
625      */
626     @RequiresPermission(Car.PERMISSION_READ_CAR_POWER_POLICY)
removePowerPolicyListener(@onNull CarPowerPolicyListener listener)627     public void removePowerPolicyListener(@NonNull CarPowerPolicyListener listener) {
628         assertPermission(Car.PERMISSION_READ_CAR_POWER_POLICY);
629         checkArgument(listener != null, "Null listener");
630         boolean updateCallbackNeeded = false;
631         CarPowerPolicyFilter filter = null;
632         synchronized (mLock) {
633             Pair<Executor, CarPowerPolicyFilter> pair = mPolicyListenerMap.remove(listener);
634             if (pair == null) {
635                 return;
636             }
637             int[] filterComponents = pair.second.getComponents();
638             for (int i = 0; i < filterComponents.length; i++) {
639                 int key = filterComponents[i];
640                 int currentCount = mInterestedComponentMap.get(key);
641                 if (currentCount == 0 || currentCount == 1) {
642                     mInterestedComponentMap.delete(key);
643                     updateCallbackNeeded = true;
644                 } else {
645                     mInterestedComponentMap.put(key, currentCount - 1);
646                 }
647             }
648             if (updateCallbackNeeded) {
649                 filter = createFilterFromInterestedComponentsLocked();
650             }
651         }
652         if (updateCallbackNeeded) {
653             updatePowerPolicyChangeCallback(filter);
654         }
655     }
656 
657     /**
658      * Turns on or off the individual display.
659      *
660      * <p>Changing the driver display is not allowed.
661      *
662      * @param displayId ID of the display
663      * @param enable Display power state to set
664      * @throws UnsupportedOperationException When trying to change the driver display power state.
665      *
666      * @hide
667      */
668     @SystemApi
669     @RequiresPermission(Car.PERMISSION_CAR_POWER)
setDisplayPowerState(int displayId, boolean enable)670     public void setDisplayPowerState(int displayId, boolean enable) {
671         try {
672             mService.setDisplayPowerState(displayId, enable);
673         } catch (RemoteException e) {
674             handleRemoteExceptionFromCarService(e);
675         }
676     }
677 
678     /**
679      * Notifies that user activity has happened in the given display.
680      *
681      * @param displayId ID of the display
682      * @hide
683      */
684     @RequiresPermission(Car.PERMISSION_CAR_POWER)
notifyUserActivity(int displayId)685     public void notifyUserActivity(int displayId) {
686         try {
687             mService.notifyUserActivity(displayId);
688         } catch (RemoteException e) {
689             handleRemoteExceptionFromCarService(e);
690         }
691     }
692 
693     /**
694      * Returns whether listen completion is allowed for {@code state}.
695      *
696      * @hide
697      */
698     @TestApi
isCompletionAllowed(@arPowerState int state)699     public static boolean isCompletionAllowed(@CarPowerState int state) {
700         switch (state) {
701             case CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE:
702             case CarPowerManager.STATE_SHUTDOWN_PREPARE:
703             case CarPowerManager.STATE_SHUTDOWN_ENTER:
704             case CarPowerManager.STATE_SUSPEND_ENTER:
705             case CarPowerManager.STATE_HIBERNATION_ENTER:
706             case CarPowerManager.STATE_POST_SHUTDOWN_ENTER:
707             case CarPowerManager.STATE_POST_SUSPEND_ENTER:
708             case CarPowerManager.STATE_POST_HIBERNATION_ENTER:
709                 return true;
710             default:
711                 return false;
712         }
713     }
714 
715     @GuardedBy("mLock")
setServiceForListenerLocked(boolean useCompletion)716     private void setServiceForListenerLocked(boolean useCompletion) {
717         if (mListenerToService == null) {
718             ICarPowerStateListener listenerToService = new ICarPowerStateListener.Stub() {
719                 @Override
720                 public void onStateChanged(int state, long expirationTimeMs)
721                         throws RemoteException {
722                     if (useCompletion) {
723                         CarPowerStateListenerWithCompletion listenerWithCompletion;
724                         CompletablePowerStateChangeFuture future;
725                         Executor executor;
726                         synchronized (mLock) {
727                             // Updates CompletablePowerStateChangeFuture. This will recreate it or
728                             // just clean it up.
729                             updateFutureLocked(state, expirationTimeMs);
730                             listenerWithCompletion = mListenerWithCompletion;
731                             future = mFuture;
732                             executor = mExecutor;
733                         }
734                         // Notifies the user that the state has changed and supply a future.
735                         if (listenerWithCompletion != null && executor != null) {
736                             long identityToken = Binder.clearCallingIdentity();
737                             try {
738                                 executor.execute(
739                                         () -> listenerWithCompletion.onStateChanged(state, future));
740                             } finally {
741                                 Binder.restoreCallingIdentity(identityToken);
742                             }
743                         }
744                     } else {
745                         CarPowerStateListener listener;
746                         Executor executor;
747                         synchronized (mLock) {
748                             listener = mListener;
749                             executor = mExecutor;
750                         }
751                         // Notifies the user without supplying a future.
752                         if (listener != null && executor != null) {
753                             long identityToken = Binder.clearCallingIdentity();
754                             try {
755                                 executor.execute(() -> listener.onStateChanged(state));
756                             } finally {
757                                 Binder.restoreCallingIdentity(identityToken);
758                             }
759                         }
760                     }
761                 }
762             };
763             try {
764                 if (useCompletion) {
765                     mService.registerListenerWithCompletion(listenerToService);
766                 } else {
767                     mService.registerListener(listenerToService);
768                 }
769                 mListenerToService = listenerToService;
770             } catch (RemoteException e) {
771                 handleRemoteExceptionFromCarService(e);
772             }
773         }
774     }
775 
776     @GuardedBy("mLock")
updateFutureLocked(@arPowerState int state, long expirationTimeMs)777     private void updateFutureLocked(@CarPowerState int state, long expirationTimeMs) {
778         cleanupFutureLocked();
779         if (isCompletionAllowed(state)) {
780             // Creates a CompletablePowerStateChangeFuture and passes it to the listener.
781             // When the listener completes, tells CarPowerManagementService that this action is
782             // finished.
783             mFuture = new CompletablePowerStateChangeFutureImpl(() -> {
784                 ICarPowerStateListener listenerToService;
785                 synchronized (mLock) {
786                     listenerToService = mListenerToService;
787                 }
788                 try {
789                     mService.finished(state, listenerToService);
790                 } catch (RemoteException e) {
791                     handleRemoteExceptionFromCarService(e);
792                 }
793             }, expirationTimeMs);
794         }
795     }
796 
797     @GuardedBy("mLock")
cleanupFutureLocked()798     private void cleanupFutureLocked() {
799         if (mFuture != null) {
800             mFuture.invalidate();
801             Slogf.w(TAG, "The current future becomes invalid");
802             mFuture = null;
803         }
804     }
805 
806     @GuardedBy("mLock")
createFilterFromInterestedComponentsLocked()807     private CarPowerPolicyFilter createFilterFromInterestedComponentsLocked() {
808         CarPowerPolicyFilter newFilter = null;
809         int componentCount = mInterestedComponentMap.size();
810         if (componentCount != 0) {
811             int[] components = new int[componentCount];
812             for (int i = 0; i < componentCount; i++) {
813                 components[i] = mInterestedComponentMap.keyAt(i);
814             }
815             newFilter = new CarPowerPolicyFilter(components);
816         }
817         return newFilter;
818     }
819 
updatePowerPolicyChangeCallback(CarPowerPolicyFilter filter)820     private void updatePowerPolicyChangeCallback(CarPowerPolicyFilter filter) {
821         try {
822             if (filter == null) {
823                 mService.removePowerPolicyListener(mPolicyChangeBinderCallback);
824             } else {
825                 mService.addPowerPolicyListener(filter, mPolicyChangeBinderCallback);
826             }
827         } catch (RemoteException e) {
828             handleRemoteExceptionFromCarService(e);
829         }
830     }
831 
notifyPowerPolicyListeners(CarPowerPolicy appliedPolicy, CarPowerPolicy accumulatedPolicy)832     private void notifyPowerPolicyListeners(CarPowerPolicy appliedPolicy,
833             CarPowerPolicy accumulatedPolicy) {
834         ArrayList<Pair<CarPowerPolicyListener, Executor>> listeners = new ArrayList<>();
835         synchronized (mLock) {
836             for (int i = 0; i < mPolicyListenerMap.size(); i++) {
837                 CarPowerPolicyListener listener = mPolicyListenerMap.keyAt(i);
838                 Pair<Executor, CarPowerPolicyFilter> pair = mPolicyListenerMap.valueAt(i);
839                 if (PowerComponentUtil.hasComponents(appliedPolicy, pair.second)) {
840                     listeners.add(
841                             new Pair<CarPowerPolicyListener, Executor>(listener, pair.first));
842                 }
843             }
844         }
845         for (int i = 0; i < listeners.size(); i++) {
846             Pair<CarPowerPolicyListener, Executor> pair = listeners.get(i);
847             pair.second.execute(() -> pair.first.onPolicyChanged(accumulatedPolicy));
848         }
849     }
850 
assertPermission(String permission)851     private void assertPermission(String permission) {
852         if (getContext().checkCallingOrSelfPermission(permission) != PERMISSION_GRANTED) {
853             throw new SecurityException("requires " + permission);
854         }
855     }
856 
checkArgument(boolean test, String message)857     private void checkArgument(boolean test, String message) {
858         if (!test) {
859             throw new IllegalArgumentException(message);
860         }
861     }
862 
863     /** @hide */
864     @Override
onCarDisconnected()865     public void onCarDisconnected() {
866         synchronized (mLock) {
867             mListener = null;
868             mListenerWithCompletion = null;
869         }
870     }
871 
872     private static final class CompletablePowerStateChangeFutureImpl
873             implements CompletablePowerStateChangeFuture {
874 
875         private final Runnable mRunnableForCompletion;
876         private final long mExpirationTimeMs;
877         private final Object mCompletionLock = new Object();
878 
879         @GuardedBy("mCompletionLock")
880         private boolean mCanBeCompleted = true;
881 
CompletablePowerStateChangeFutureImpl(Runnable runnable, long expirationTimeMs)882         private CompletablePowerStateChangeFutureImpl(Runnable runnable, long expirationTimeMs) {
883             mRunnableForCompletion = Objects.requireNonNull(runnable);
884             mExpirationTimeMs = expirationTimeMs;
885         }
886 
887         @Override
complete()888         public void complete() {
889             synchronized (mCompletionLock) {
890                 if (!mCanBeCompleted) {
891                     Slogf.w(TAG, "Cannot complete: already completed or invalid state");
892                     return;
893                 }
894                 // Once completed, this instance cannot be completed again.
895                 mCanBeCompleted = false;
896             }
897             mRunnableForCompletion.run();
898         }
899 
900         @Override
getExpirationTime()901         public long getExpirationTime() {
902             return mExpirationTimeMs;
903         }
904 
invalidate()905         private void invalidate() {
906             synchronized (mCompletionLock) {
907                 mCanBeCompleted = false;
908             }
909         }
910     }
911 }
912