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_ENTER}</li> 314 * <li>{@link STATE_SUSPEND_ENTER}</li> 315 * <li>{@link STATE_HIBERNATION_ENTER}</li> 316 * <li>{@link STATE_POST_SHUTDOWN_ENTER}</li> 317 * <li>{@link STATE_POST_SUSPEND_ENTER}</li> 318 * <li>{@link STATE_POST_HIBERNATION_ENTER}</li> 319 * </ul> 320 * If the listeners don't complete before the timeout expires, car power management service 321 * moves to the next step, anyway. The timeout given to the listener can be queried by 322 * {@link CompletablePowerStateChangeFuture#getExpirationTime()}. 323 * 324 * @param state New power state of the system. 325 * @param future CompletablePowerStateChangeFuture used by listeners to notify 326 * CarPowerManager that they are ready to move to the next step. Car power 327 * management service waits until the listeners call 328 * {@code CompletablePowerStateChangeFuture#complete()} or timeout happens. 329 * In the case {@code state} doesn't allow for completion, {@code future} is 330 * {@code null}. 331 */ onStateChanged(@arPowerState int state, @Nullable CompletablePowerStateChangeFuture future)332 void onStateChanged(@CarPowerState int state, 333 @Nullable CompletablePowerStateChangeFuture future); 334 } 335 336 /** 337 * Listeners to receive power policy change. 338 * 339 * <p>Applications interested in power policy change register 340 * {@code CarPowerPolicyListener} and will be notified when power policy changes. 341 */ 342 public interface CarPowerPolicyListener { 343 /** 344 * Called with {@link CarPowerPolicy} when power policy changes. 345 * 346 * @param policy The current power policy. 347 */ onPolicyChanged(@onNull CarPowerPolicy policy)348 void onPolicyChanged(@NonNull CarPowerPolicy policy); 349 } 350 351 /** 352 * Gets an instance of the CarPowerManager. 353 * 354 * <p>Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead. 355 * 356 * @hide 357 */ CarPowerManager(Car car, IBinder service)358 public CarPowerManager(Car car, IBinder service) { 359 super(car); 360 mService = ICarPower.Stub.asInterface(service); 361 } 362 363 /** 364 * Requests power manager to shutdown in lieu of suspend at the next opportunity. 365 * 366 * @hide 367 */ 368 @RequiresPermission(Car.PERMISSION_CAR_POWER) requestShutdownOnNextSuspend()369 public void requestShutdownOnNextSuspend() { 370 try { 371 mService.requestShutdownOnNextSuspend(); 372 } catch (RemoteException e) { 373 handleRemoteExceptionFromCarService(e); 374 } 375 } 376 377 /** 378 * Schedules next wake up time in CarPowerManagementService. 379 * 380 * @hide 381 */ 382 @RequiresPermission(Car.PERMISSION_CAR_POWER) scheduleNextWakeupTime(int seconds)383 public void scheduleNextWakeupTime(int seconds) { 384 try { 385 mService.scheduleNextWakeupTime(seconds); 386 } catch (RemoteException e) { 387 handleRemoteExceptionFromCarService(e); 388 } 389 } 390 391 /** 392 * Returns the current power state. 393 * 394 * @return One of the values defined in {@link CarPowerStateListener}. 395 * 396 * @hide 397 */ 398 @SystemApi 399 @RequiresPermission(Car.PERMISSION_CAR_POWER) getPowerState()400 public @CarPowerState int getPowerState() { 401 try { 402 return mService.getPowerState(); 403 } catch (RemoteException e) { 404 return handleRemoteExceptionFromCarService(e, STATE_INVALID); 405 } 406 } 407 408 /** 409 * Sets a listener to receive power state changes. Only one listener may be set at a 410 * time for an instance of CarPowerManager. 411 * 412 * <p>The listener is assumed to completely handle the {@code onStateChanged} before returning. 413 * 414 * @param listener The listener which will receive the power state change. 415 * @throws IllegalStateException When a listener is already set for the power state change. 416 * @throws IllegalArgumentException When the given listener is null. 417 * 418 * @hide 419 */ 420 @SystemApi 421 @RequiresPermission(Car.PERMISSION_CAR_POWER) setListener(@onNull @allbackExecutor Executor executor, @NonNull CarPowerStateListener listener)422 public void setListener(@NonNull @CallbackExecutor Executor executor, 423 @NonNull CarPowerStateListener listener) { 424 checkArgument(executor != null, "excutor cannot be null"); 425 checkArgument(listener != null, "listener cannot be null"); 426 synchronized (mLock) { 427 if (mListener != null || mListenerWithCompletion != null) { 428 throw new IllegalStateException("Listener must be cleared first"); 429 } 430 // Updates listener 431 mListener = listener; 432 mExecutor = executor; 433 setServiceForListenerLocked(/* useCompletion= */ false); 434 } 435 } 436 437 /** 438 * Sets a listener to receive power state changes. Only one listener may be set at a time for an 439 * instance of CarPowerManager. 440 * 441 * <p>For calls that require completion before continue, we attach a 442 * {@link CompletablePowerStateChangeFuture} which is being used as a signal that caller is 443 * finished and ready to proceed. 444 * Once the future is completed, car power management service knows that the application has 445 * handled the power state transition and moves to the next state. 446 * 447 * @param listener The listener which will receive the power state change. 448 * @throws IllegalStateException When a listener is already set for the power state change. 449 * @throws IllegalArgumentException When the given listener is null. 450 * 451 * @hide 452 */ 453 @SystemApi 454 @RequiresPermission(Car.PERMISSION_CONTROL_SHUTDOWN_PROCESS) setListenerWithCompletion(@onNull @allbackExecutor Executor executor, @NonNull CarPowerStateListenerWithCompletion listener)455 public void setListenerWithCompletion(@NonNull @CallbackExecutor Executor executor, 456 @NonNull CarPowerStateListenerWithCompletion listener) { 457 checkArgument(executor != null, "executor cannot be null"); 458 checkArgument(listener != null, "listener cannot be null"); 459 synchronized (mLock) { 460 if (mListener != null || mListenerWithCompletion != null) { 461 throw new IllegalStateException("Listener must be cleared first"); 462 } 463 // Updates listener 464 mListenerWithCompletion = listener; 465 mExecutor = executor; 466 setServiceForListenerLocked(/* useCompletion= */ true); 467 } 468 } 469 470 /** 471 * Removes the power state listener. 472 * 473 * @hide 474 */ 475 @SystemApi 476 @RequiresPermission(Car.PERMISSION_CAR_POWER) clearListener()477 public void clearListener() { 478 ICarPowerStateListener listenerToService; 479 synchronized (mLock) { 480 listenerToService = mListenerToService; 481 mListenerToService = null; 482 mListener = null; 483 mListenerWithCompletion = null; 484 mExecutor = null; 485 cleanupFutureLocked(); 486 } 487 488 if (listenerToService == null) { 489 Slogf.w(TAG, "clearListener: listener was not registered"); 490 return; 491 } 492 493 try { 494 mService.unregisterListener(listenerToService); 495 } catch (RemoteException e) { 496 handleRemoteExceptionFromCarService(e); 497 } 498 } 499 500 /** 501 * Gets the current power policy. 502 * 503 * <p>The returned power policy has ID of the power policy applied most recently. If no power 504 * policy has been applied, the ID is an empty string. Note that enabled components and disabled 505 * components might be different from those of the latest power policy applied. This is because 506 * the returned power policy contains the current state of all power components determined by 507 * applying power policies in an accumulative way. 508 * 509 * @return The power policy containing the latest state of all power components. 510 */ 511 @RequiresPermission(Car.PERMISSION_READ_CAR_POWER_POLICY) 512 @Nullable getCurrentPowerPolicy()513 public CarPowerPolicy getCurrentPowerPolicy() { 514 try { 515 return mService.getCurrentPowerPolicy(); 516 } catch (RemoteException e) { 517 return handleRemoteExceptionFromCarService(e, null); 518 } 519 } 520 521 /** 522 * Applies the given power policy. 523 * 524 * <p>Power components are turned on or off as specified in the given power policy. Power 525 * policies are defined at {@code /vendor/etc/automotive/power_policy.xml}. 526 * If the given power policy doesn't exist, this method throws 527 * {@link java.lang.IllegalArgumentException}. 528 * 529 * @param policyId ID of power policy. 530 * @throws IllegalArgumentException if {@code policyId} is null. 531 * 532 * @hide 533 */ 534 @SystemApi 535 @RequiresPermission(Car.PERMISSION_CONTROL_CAR_POWER_POLICY) applyPowerPolicy(@onNull String policyId)536 public void applyPowerPolicy(@NonNull String policyId) { 537 checkArgument(policyId != null, "Null policyId"); 538 try { 539 mService.applyPowerPolicy(policyId); 540 } catch (RemoteException e) { 541 handleRemoteExceptionFromCarService(e); 542 } 543 } 544 545 /** 546 * Sets the current power policy group. 547 * 548 * <p>Power policy group defines a rule to apply a certain power policy according to the power 549 * state transition. For example, a power policy named "default_for_on" is supposed to be 550 * applied when the power state becomes ON. This rule is specified in the power policy group. 551 * Many power policy groups can be pre-defined, and one of them is set for the current one using 552 * {@code setPowerPolicyGroup}. 553 * 554 * @param policyGroupId ID of power policy group. 555 * @throws IllegalArgumentException if {@code policyGroupId} is null. 556 * 557 * @hide 558 */ 559 @SystemApi 560 @RequiresPermission(Car.PERMISSION_CONTROL_CAR_POWER_POLICY) setPowerPolicyGroup(@onNull String policyGroupId)561 public void setPowerPolicyGroup(@NonNull String policyGroupId) { 562 checkArgument(policyGroupId != null, "Null policyGroupId"); 563 try { 564 mService.setPowerPolicyGroup(policyGroupId); 565 } catch (RemoteException e) { 566 handleRemoteExceptionFromCarService(e); 567 } 568 } 569 570 /** 571 * Subscribes to power policy change. 572 * 573 * <p>If the same listener is added with different filters, the listener is notified based on 574 * the last added filter. 575 * 576 * @param executor Executor where the listener method is called. 577 * @param listener Listener to be notified. 578 * @param filter Filter specifying power components of interest. 579 * @throws IllegalArgumentException if {@code executor}, {@code listener}, or {@code filter} is 580 * null. 581 */ 582 @RequiresPermission(Car.PERMISSION_READ_CAR_POWER_POLICY) addPowerPolicyListener(@onNull @allbackExecutor Executor executor, @NonNull CarPowerPolicyFilter filter, @NonNull CarPowerPolicyListener listener)583 public void addPowerPolicyListener(@NonNull @CallbackExecutor Executor executor, 584 @NonNull CarPowerPolicyFilter filter, @NonNull CarPowerPolicyListener listener) { 585 assertPermission(Car.PERMISSION_READ_CAR_POWER_POLICY); 586 checkArgument(executor != null, "Null executor"); 587 checkArgument(filter != null, "Null filter"); 588 checkArgument(listener != null, "Null listener"); 589 boolean updateCallbackNeeded = false; 590 CarPowerPolicyFilter newFilter = null; 591 synchronized (mLock) { 592 mPolicyListenerMap.remove(listener); 593 int[] filterComponents = filter.getComponents().clone(); 594 Pair<Executor, CarPowerPolicyFilter> pair = 595 new Pair<>(executor, new CarPowerPolicyFilter(filterComponents)); 596 mPolicyListenerMap.put(listener, pair); 597 for (int i = 0; i < filterComponents.length; i++) { 598 int key = filterComponents[i]; 599 int currentCount = mInterestedComponentMap.get(key); 600 if (currentCount == 0) { 601 updateCallbackNeeded = true; 602 mInterestedComponentMap.put(key, 1); 603 } else { 604 mInterestedComponentMap.put(key, currentCount + 1); 605 } 606 } 607 if (updateCallbackNeeded) { 608 newFilter = createFilterFromInterestedComponentsLocked(); 609 } 610 } 611 if (updateCallbackNeeded) { 612 updatePowerPolicyChangeCallback(newFilter); 613 } 614 } 615 616 /** 617 * Unsubscribes from power policy change. 618 * 619 * @param listener Listener that will not be notified any more. 620 * @throws IllegalArgumentException if {@code listener} is null. 621 */ 622 @RequiresPermission(Car.PERMISSION_READ_CAR_POWER_POLICY) removePowerPolicyListener(@onNull CarPowerPolicyListener listener)623 public void removePowerPolicyListener(@NonNull CarPowerPolicyListener listener) { 624 assertPermission(Car.PERMISSION_READ_CAR_POWER_POLICY); 625 checkArgument(listener != null, "Null listener"); 626 boolean updateCallbackNeeded = false; 627 CarPowerPolicyFilter filter = null; 628 synchronized (mLock) { 629 Pair<Executor, CarPowerPolicyFilter> pair = mPolicyListenerMap.remove(listener); 630 if (pair == null) { 631 return; 632 } 633 int[] filterComponents = pair.second.getComponents(); 634 for (int i = 0; i < filterComponents.length; i++) { 635 int key = filterComponents[i]; 636 int currentCount = mInterestedComponentMap.get(key); 637 if (currentCount == 0 || currentCount == 1) { 638 mInterestedComponentMap.delete(key); 639 updateCallbackNeeded = true; 640 } else { 641 mInterestedComponentMap.put(key, currentCount - 1); 642 } 643 } 644 if (updateCallbackNeeded) { 645 filter = createFilterFromInterestedComponentsLocked(); 646 } 647 } 648 if (updateCallbackNeeded) { 649 updatePowerPolicyChangeCallback(filter); 650 } 651 } 652 653 /** 654 * Turns on or off the individual display. 655 * 656 * <p>Changing the driver display is not allowed. 657 * 658 * @param displayId ID of the display 659 * @param enable Display power state to set 660 * @throws UnsupportedOperationException When trying to change the driver display power state. 661 * 662 * @hide 663 */ 664 @SystemApi 665 @RequiresPermission(Car.PERMISSION_CAR_POWER) setDisplayPowerState(int displayId, boolean enable)666 public void setDisplayPowerState(int displayId, boolean enable) { 667 try { 668 mService.setDisplayPowerState(displayId, enable); 669 } catch (RemoteException e) { 670 handleRemoteExceptionFromCarService(e); 671 } 672 } 673 674 /** 675 * Notifies that user activity has happened in the given display. 676 * 677 * @param displayId ID of the display 678 * @hide 679 */ 680 @RequiresPermission(Car.PERMISSION_CAR_POWER) notifyUserActivity(int displayId)681 public void notifyUserActivity(int displayId) { 682 try { 683 mService.notifyUserActivity(displayId); 684 } catch (RemoteException e) { 685 handleRemoteExceptionFromCarService(e); 686 } 687 } 688 689 /** 690 * Returns whether listen completion is allowed for {@code state}. 691 * 692 * @hide 693 */ 694 @TestApi isCompletionAllowed(@arPowerState int state)695 public static boolean isCompletionAllowed(@CarPowerState int state) { 696 switch (state) { 697 case CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE: 698 case CarPowerManager.STATE_SHUTDOWN_PREPARE: 699 case CarPowerManager.STATE_SHUTDOWN_ENTER: 700 case CarPowerManager.STATE_SUSPEND_ENTER: 701 case CarPowerManager.STATE_HIBERNATION_ENTER: 702 case CarPowerManager.STATE_POST_SHUTDOWN_ENTER: 703 case CarPowerManager.STATE_POST_SUSPEND_ENTER: 704 case CarPowerManager.STATE_POST_HIBERNATION_ENTER: 705 return true; 706 default: 707 return false; 708 } 709 } 710 711 @GuardedBy("mLock") setServiceForListenerLocked(boolean useCompletion)712 private void setServiceForListenerLocked(boolean useCompletion) { 713 if (mListenerToService == null) { 714 ICarPowerStateListener listenerToService = new ICarPowerStateListener.Stub() { 715 @Override 716 public void onStateChanged(int state, long expirationTimeMs) 717 throws RemoteException { 718 if (useCompletion) { 719 CarPowerStateListenerWithCompletion listenerWithCompletion; 720 CompletablePowerStateChangeFuture future; 721 Executor executor; 722 synchronized (mLock) { 723 // Updates CompletablePowerStateChangeFuture. This will recreate it or 724 // just clean it up. 725 updateFutureLocked(state, expirationTimeMs); 726 listenerWithCompletion = mListenerWithCompletion; 727 future = mFuture; 728 executor = mExecutor; 729 } 730 // Notifies the user that the state has changed and supply a future. 731 if (listenerWithCompletion != null && executor != null) { 732 long identityToken = Binder.clearCallingIdentity(); 733 try { 734 executor.execute( 735 () -> listenerWithCompletion.onStateChanged(state, future)); 736 } finally { 737 Binder.restoreCallingIdentity(identityToken); 738 } 739 } 740 } else { 741 CarPowerStateListener listener; 742 Executor executor; 743 synchronized (mLock) { 744 listener = mListener; 745 executor = mExecutor; 746 } 747 // Notifies the user without supplying a future. 748 if (listener != null && executor != null) { 749 long identityToken = Binder.clearCallingIdentity(); 750 try { 751 executor.execute(() -> listener.onStateChanged(state)); 752 } finally { 753 Binder.restoreCallingIdentity(identityToken); 754 } 755 } 756 } 757 } 758 }; 759 try { 760 if (useCompletion) { 761 mService.registerListenerWithCompletion(listenerToService); 762 } else { 763 mService.registerListener(listenerToService); 764 } 765 mListenerToService = listenerToService; 766 } catch (RemoteException e) { 767 handleRemoteExceptionFromCarService(e); 768 } 769 } 770 } 771 772 @GuardedBy("mLock") updateFutureLocked(@arPowerState int state, long expirationTimeMs)773 private void updateFutureLocked(@CarPowerState int state, long expirationTimeMs) { 774 cleanupFutureLocked(); 775 if (isCompletionAllowed(state)) { 776 // Creates a CompletablePowerStateChangeFuture and passes it to the listener. 777 // When the listener completes, tells CarPowerManagementService that this action is 778 // finished. 779 mFuture = new CompletablePowerStateChangeFutureImpl(() -> { 780 ICarPowerStateListener listenerToService; 781 synchronized (mLock) { 782 listenerToService = mListenerToService; 783 } 784 try { 785 mService.finished(state, listenerToService); 786 } catch (RemoteException e) { 787 handleRemoteExceptionFromCarService(e); 788 } 789 }, expirationTimeMs); 790 } 791 } 792 793 @GuardedBy("mLock") cleanupFutureLocked()794 private void cleanupFutureLocked() { 795 if (mFuture != null) { 796 mFuture.invalidate(); 797 Slogf.w(TAG, "The current future becomes invalid"); 798 mFuture = null; 799 } 800 } 801 802 @GuardedBy("mLock") createFilterFromInterestedComponentsLocked()803 private CarPowerPolicyFilter createFilterFromInterestedComponentsLocked() { 804 CarPowerPolicyFilter newFilter = null; 805 int componentCount = mInterestedComponentMap.size(); 806 if (componentCount != 0) { 807 int[] components = new int[componentCount]; 808 for (int i = 0; i < componentCount; i++) { 809 components[i] = mInterestedComponentMap.keyAt(i); 810 } 811 newFilter = new CarPowerPolicyFilter(components); 812 } 813 return newFilter; 814 } 815 updatePowerPolicyChangeCallback(CarPowerPolicyFilter filter)816 private void updatePowerPolicyChangeCallback(CarPowerPolicyFilter filter) { 817 try { 818 if (filter == null) { 819 mService.removePowerPolicyListener(mPolicyChangeBinderCallback); 820 } else { 821 mService.addPowerPolicyListener(filter, mPolicyChangeBinderCallback); 822 } 823 } catch (RemoteException e) { 824 handleRemoteExceptionFromCarService(e); 825 } 826 } 827 notifyPowerPolicyListeners(CarPowerPolicy appliedPolicy, CarPowerPolicy accumulatedPolicy)828 private void notifyPowerPolicyListeners(CarPowerPolicy appliedPolicy, 829 CarPowerPolicy accumulatedPolicy) { 830 ArrayList<Pair<CarPowerPolicyListener, Executor>> listeners = new ArrayList<>(); 831 synchronized (mLock) { 832 for (int i = 0; i < mPolicyListenerMap.size(); i++) { 833 CarPowerPolicyListener listener = mPolicyListenerMap.keyAt(i); 834 Pair<Executor, CarPowerPolicyFilter> pair = mPolicyListenerMap.valueAt(i); 835 if (PowerComponentUtil.hasComponents(appliedPolicy, pair.second)) { 836 listeners.add( 837 new Pair<CarPowerPolicyListener, Executor>(listener, pair.first)); 838 } 839 } 840 } 841 for (int i = 0; i < listeners.size(); i++) { 842 Pair<CarPowerPolicyListener, Executor> pair = listeners.get(i); 843 pair.second.execute(() -> pair.first.onPolicyChanged(accumulatedPolicy)); 844 } 845 } 846 assertPermission(String permission)847 private void assertPermission(String permission) { 848 if (getContext().checkCallingOrSelfPermission(permission) != PERMISSION_GRANTED) { 849 throw new SecurityException("requires " + permission); 850 } 851 } 852 checkArgument(boolean test, String message)853 private void checkArgument(boolean test, String message) { 854 if (!test) { 855 throw new IllegalArgumentException(message); 856 } 857 } 858 859 /** @hide */ 860 @Override onCarDisconnected()861 public void onCarDisconnected() { 862 synchronized (mLock) { 863 mListener = null; 864 mListenerWithCompletion = null; 865 } 866 } 867 868 private static final class CompletablePowerStateChangeFutureImpl 869 implements CompletablePowerStateChangeFuture { 870 871 private final Runnable mRunnableForCompletion; 872 private final long mExpirationTimeMs; 873 private final Object mCompletionLock = new Object(); 874 875 @GuardedBy("mCompletionLock") 876 private boolean mCanBeCompleted = true; 877 CompletablePowerStateChangeFutureImpl(Runnable runnable, long expirationTimeMs)878 private CompletablePowerStateChangeFutureImpl(Runnable runnable, long expirationTimeMs) { 879 mRunnableForCompletion = Objects.requireNonNull(runnable); 880 mExpirationTimeMs = expirationTimeMs; 881 } 882 883 @Override complete()884 public void complete() { 885 synchronized (mCompletionLock) { 886 if (!mCanBeCompleted) { 887 Slogf.w(TAG, "Cannot complete: already completed or invalid state"); 888 return; 889 } 890 // Once completed, this instance cannot be completed again. 891 mCanBeCompleted = false; 892 } 893 mRunnableForCompletion.run(); 894 } 895 896 @Override getExpirationTime()897 public long getExpirationTime() { 898 return mExpirationTimeMs; 899 } 900 invalidate()901 private void invalidate() { 902 synchronized (mCompletionLock) { 903 mCanBeCompleted = false; 904 } 905 } 906 } 907 } 908