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