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