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