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