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