1 /* 2 * Copyright (C) 2015 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 package com.android.car.hal; 17 18 import static android.hardware.automotive.vehicle.VehicleProperty.AP_POWER_STATE_REPORT; 19 import static android.hardware.automotive.vehicle.VehicleProperty.AP_POWER_STATE_REQ; 20 import static android.hardware.automotive.vehicle.VehicleProperty.DISPLAY_BRIGHTNESS; 21 import static android.hardware.automotive.vehicle.VehicleProperty.PER_DISPLAY_BRIGHTNESS; 22 import static android.hardware.automotive.vehicle.VehicleProperty.VEHICLE_IN_USE; 23 24 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 25 26 import android.annotation.IntDef; 27 import android.annotation.Nullable; 28 import android.car.builtin.util.Slogf; 29 import android.car.builtin.view.DisplayHelper; 30 import android.content.Context; 31 import android.hardware.automotive.vehicle.VehicleApPowerStateConfigFlag; 32 import android.hardware.automotive.vehicle.VehicleApPowerStateReport; 33 import android.hardware.automotive.vehicle.VehicleApPowerStateReq; 34 import android.hardware.automotive.vehicle.VehicleApPowerStateReqIndex; 35 import android.hardware.automotive.vehicle.VehicleApPowerStateShutdownParam; 36 import android.hardware.automotive.vehicle.VehicleProperty; 37 import android.hardware.automotive.vehicle.VehiclePropertyStatus; 38 import android.hardware.display.DisplayManager; 39 import android.os.ServiceSpecificException; 40 import android.util.SparseArray; 41 import android.view.Display; 42 43 import com.android.car.CarLog; 44 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 45 import com.android.internal.annotations.GuardedBy; 46 import com.android.internal.annotations.VisibleForTesting; 47 import com.android.internal.util.Preconditions; 48 49 import java.io.PrintWriter; 50 import java.lang.annotation.Retention; 51 import java.lang.annotation.RetentionPolicy; 52 import java.util.ArrayList; 53 import java.util.Collection; 54 import java.util.List; 55 import java.util.Objects; 56 57 /** 58 * Translates HAL power events to higher-level semantic information. 59 */ 60 public class PowerHalService extends HalServiceBase { 61 // Set display brightness from 0-100% 62 public static final int MAX_BRIGHTNESS = 100; 63 64 private static final int[] SUPPORTED_PROPERTIES = new int[]{ 65 AP_POWER_STATE_REQ, 66 AP_POWER_STATE_REPORT, 67 DISPLAY_BRIGHTNESS, 68 PER_DISPLAY_BRIGHTNESS, 69 VEHICLE_IN_USE, 70 }; 71 72 @VisibleForTesting 73 public static final int SET_WAIT_FOR_VHAL = VehicleApPowerStateReport.WAIT_FOR_VHAL; 74 @VisibleForTesting 75 public static final int SET_DEEP_SLEEP_ENTRY = VehicleApPowerStateReport.DEEP_SLEEP_ENTRY; 76 @VisibleForTesting 77 public static final int SET_DEEP_SLEEP_EXIT = VehicleApPowerStateReport.DEEP_SLEEP_EXIT; 78 @VisibleForTesting 79 public static final int SET_SHUTDOWN_POSTPONE = VehicleApPowerStateReport.SHUTDOWN_POSTPONE; 80 @VisibleForTesting 81 public static final int SET_SHUTDOWN_START = VehicleApPowerStateReport.SHUTDOWN_START; 82 @VisibleForTesting 83 public static final int SET_ON = VehicleApPowerStateReport.ON; 84 @VisibleForTesting 85 public static final int SET_SHUTDOWN_PREPARE = VehicleApPowerStateReport.SHUTDOWN_PREPARE; 86 @VisibleForTesting 87 public static final int SET_SHUTDOWN_CANCELLED = VehicleApPowerStateReport.SHUTDOWN_CANCELLED; 88 89 @VisibleForTesting 90 public static final int SHUTDOWN_CAN_SLEEP = VehicleApPowerStateShutdownParam.CAN_SLEEP; 91 @VisibleForTesting 92 public static final int SHUTDOWN_IMMEDIATELY = 93 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY; 94 @VisibleForTesting 95 public static final int SHUTDOWN_ONLY = VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY; 96 @VisibleForTesting 97 public static final int SET_HIBERNATION_ENTRY = VehicleApPowerStateReport.HIBERNATION_ENTRY; 98 @VisibleForTesting 99 public static final int SET_HIBERNATION_EXIT = VehicleApPowerStateReport.HIBERNATION_EXIT; 100 101 private final Object mLock = new Object(); 102 powerStateReportName(int state)103 private static String powerStateReportName(int state) { 104 String baseName; 105 switch(state) { 106 case SET_WAIT_FOR_VHAL: baseName = "WAIT_FOR_VHAL"; break; 107 case SET_DEEP_SLEEP_ENTRY: baseName = "DEEP_SLEEP_ENTRY"; break; 108 case SET_DEEP_SLEEP_EXIT: baseName = "DEEP_SLEEP_EXIT"; break; 109 case SET_SHUTDOWN_POSTPONE: baseName = "SHUTDOWN_POSTPONE"; break; 110 case SET_SHUTDOWN_START: baseName = "SHUTDOWN_START"; break; 111 case SET_ON: baseName = "ON"; break; 112 case SET_SHUTDOWN_PREPARE: baseName = "SHUTDOWN_PREPARE"; break; 113 case SET_SHUTDOWN_CANCELLED: baseName = "SHUTDOWN_CANCELLED"; break; 114 case SET_HIBERNATION_ENTRY: baseName = "HIBERNATION_ENTRY"; break; 115 case SET_HIBERNATION_EXIT: baseName = "HIBERNATION_EXIT"; break; 116 default: baseName = "<unknown>"; break; 117 } 118 return baseName + "(" + state + ")"; 119 } 120 powerStateReqName(int state)121 private static String powerStateReqName(int state) { 122 String baseName; 123 switch(state) { 124 case VehicleApPowerStateReq.ON: baseName = "ON"; break; 125 case VehicleApPowerStateReq.SHUTDOWN_PREPARE: baseName = "SHUTDOWN_PREPARE"; break; 126 case VehicleApPowerStateReq.CANCEL_SHUTDOWN: baseName = "CANCEL_SHUTDOWN"; break; 127 case VehicleApPowerStateReq.FINISHED: baseName = "FINISHED"; break; 128 default: baseName = "<unknown>"; break; 129 } 130 return baseName + "(" + state + ")"; 131 } 132 133 /** 134 * Interface to be implemented by any object that wants to be notified by any Vehicle's power 135 * change. 136 */ 137 public interface PowerEventListener { 138 /** 139 * Received power state change event. 140 * @param state One of STATE_* 141 */ onApPowerStateChange(PowerState state)142 void onApPowerStateChange(PowerState state); 143 144 /** 145 * Received display brightness change event. 146 * @param brightness in percentile. 100% full. 147 */ onDisplayBrightnessChange(int brightness)148 void onDisplayBrightnessChange(int brightness); 149 150 /** 151 * Received display brightness change event. 152 * @param displayId the display id. 153 * @param brightness in percentile. 100% full. 154 */ onDisplayBrightnessChange(int displayId, int brightness)155 void onDisplayBrightnessChange(int displayId, int brightness); 156 } 157 158 /** 159 * Contains information about the Vehicle's power state. 160 */ 161 public static final class PowerState { 162 163 @IntDef({SHUTDOWN_TYPE_UNDEFINED, SHUTDOWN_TYPE_POWER_OFF, SHUTDOWN_TYPE_DEEP_SLEEP, 164 SHUTDOWN_TYPE_HIBERNATION}) 165 @Retention(RetentionPolicy.SOURCE) 166 public @interface ShutdownType {} 167 168 public static final int SHUTDOWN_TYPE_UNDEFINED = 0; 169 public static final int SHUTDOWN_TYPE_POWER_OFF = 1; 170 public static final int SHUTDOWN_TYPE_DEEP_SLEEP = 2; 171 public static final int SHUTDOWN_TYPE_HIBERNATION = 3; 172 /** 173 * One of STATE_* 174 */ 175 public final int mState; 176 public final int mParam; 177 PowerState(int state, int param)178 public PowerState(int state, int param) { 179 this.mState = state; 180 this.mParam = param; 181 } 182 183 /** 184 * Whether the current PowerState allows postponing or not. Calling this for 185 * power state other than STATE_SHUTDOWN_PREPARE will trigger exception. 186 * @return 187 * @throws IllegalStateException 188 */ canPostponeShutdown()189 public boolean canPostponeShutdown() { 190 if (mState != VehicleApPowerStateReq.SHUTDOWN_PREPARE) { 191 throw new IllegalStateException("wrong state"); 192 } 193 return (mParam != VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY 194 && mParam != VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY 195 && mParam != VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY); 196 } 197 198 /** 199 * Gets whether the current PowerState allows suspend or not. 200 * 201 * @throws IllegalStateException if called in state other than {@code 202 * STATE_SHUTDOWN_PREPARE} 203 */ canSuspend()204 public boolean canSuspend() { 205 Preconditions.checkArgument(mState == VehicleApPowerStateReq.SHUTDOWN_PREPARE, 206 "canSuspend was called in the wrong state! State = %d", mState); 207 208 return (mParam == VehicleApPowerStateShutdownParam.CAN_HIBERNATE 209 || mParam == VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY 210 || mParam == VehicleApPowerStateShutdownParam.CAN_SLEEP 211 || mParam == VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY); 212 } 213 214 /** 215 * Gets shutdown type 216 * 217 * @return {@code ShutdownType} - type of shutdown 218 * @throws IllegalStateException if called in state other than {@code 219 * STATE_SHUTDOWN_PREPARE} 220 */ 221 @ShutdownType getShutdownType()222 public int getShutdownType() { 223 Preconditions.checkArgument(mState == VehicleApPowerStateReq.SHUTDOWN_PREPARE, 224 "getShutdownType was called in the wrong state! State = %d", mState); 225 226 int result = SHUTDOWN_TYPE_POWER_OFF; 227 if (mParam == VehicleApPowerStateShutdownParam.CAN_SLEEP 228 || mParam == VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY) { 229 result = SHUTDOWN_TYPE_DEEP_SLEEP; 230 } else if (mParam == VehicleApPowerStateShutdownParam.CAN_HIBERNATE 231 || mParam == VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY) { 232 result = SHUTDOWN_TYPE_HIBERNATION; 233 } 234 235 return result; 236 } 237 238 @Override equals(Object o)239 public boolean equals(Object o) { 240 if (this == o) { 241 return true; 242 } 243 if (!(o instanceof PowerState)) { 244 return false; 245 } 246 PowerState that = (PowerState) o; 247 return this.mState == that.mState && this.mParam == that.mParam; 248 } 249 250 @Override hashCode()251 public int hashCode() { 252 return Objects.hash(mState, mParam); 253 } 254 255 @Override toString()256 public String toString() { 257 return "PowerState state:" + mState + ", param:" + mParam; 258 } 259 } 260 261 @GuardedBy("mLock") 262 private final SparseArray<HalPropConfig> mProperties = new SparseArray<>(); 263 private final Context mContext; 264 private final VehicleHal mHal; 265 @Nullable 266 @GuardedBy("mLock") 267 private ArrayList<HalPropValue> mQueuedEvents; 268 @GuardedBy("mLock") 269 private PowerEventListener mListener; 270 @GuardedBy("mLock") 271 private int mMaxDisplayBrightness; 272 @GuardedBy("mLock") 273 private boolean mPerDisplayBrightnessSupported; 274 PowerHalService(Context context, VehicleHal hal)275 public PowerHalService(Context context, VehicleHal hal) { 276 mContext = context; 277 mHal = hal; 278 } 279 280 /** 281 * Sets the event listener to receive Vehicle's power events. 282 */ setListener(PowerEventListener listener)283 public void setListener(PowerEventListener listener) { 284 ArrayList<HalPropValue> eventsToDispatch = null; 285 synchronized (mLock) { 286 mListener = listener; 287 if (mQueuedEvents != null && !mQueuedEvents.isEmpty()) { 288 eventsToDispatch = mQueuedEvents; 289 } 290 mQueuedEvents = null; 291 } 292 // do this outside lock 293 if (eventsToDispatch != null) { 294 dispatchEvents(eventsToDispatch, listener); 295 } 296 } 297 298 /** 299 * Send WaitForVhal message to VHAL 300 */ sendWaitForVhal()301 public void sendWaitForVhal() { 302 Slogf.i(CarLog.TAG_POWER, "send wait for vhal"); 303 setPowerState(VehicleApPowerStateReport.WAIT_FOR_VHAL, 0); 304 } 305 306 /** 307 * Send SleepEntry message to VHAL 308 * @param wakeupTimeSec Notify VHAL when system wants to be woken from sleep. 309 */ sendSleepEntry(int wakeupTimeSec)310 public void sendSleepEntry(int wakeupTimeSec) { 311 Slogf.i(CarLog.TAG_POWER, "send sleep entry"); 312 setPowerState(VehicleApPowerStateReport.DEEP_SLEEP_ENTRY, wakeupTimeSec); 313 } 314 315 /** 316 * Send SleepExit message to VHAL 317 * Notifies VHAL when SOC has woken. 318 */ sendSleepExit()319 public void sendSleepExit() { 320 Slogf.i(CarLog.TAG_POWER, "send sleep exit"); 321 setPowerState(VehicleApPowerStateReport.DEEP_SLEEP_EXIT, 0); 322 } 323 324 /** 325 * Sends HibernationEntry message to VHAL 326 * 327 * @param wakeupTimeSec Number of seconds from now to be woken from sleep. 328 */ sendHibernationEntry(int wakeupTimeSec)329 public void sendHibernationEntry(int wakeupTimeSec) { 330 Slogf.i(CarLog.TAG_POWER, "send hibernation entry - wakeupTimeSec = %d", 331 wakeupTimeSec); 332 setPowerState(VehicleApPowerStateReport.HIBERNATION_ENTRY, wakeupTimeSec); 333 } 334 335 /** 336 * Sends HibernationExit message to VHAL 337 * 338 * Notifies VHAL after SOC woke up from hibernation. 339 */ sendHibernationExit()340 public void sendHibernationExit() { 341 Slogf.i(CarLog.TAG_POWER, "send hibernation exit"); 342 setPowerState(VehicleApPowerStateReport.HIBERNATION_EXIT, 0); 343 } 344 345 /** 346 * Send Shutdown Postpone message to VHAL 347 */ sendShutdownPostpone(int postponeTimeMs)348 public void sendShutdownPostpone(int postponeTimeMs) { 349 Slogf.i(CarLog.TAG_POWER, "send shutdown postpone, time:" + postponeTimeMs); 350 setPowerState(VehicleApPowerStateReport.SHUTDOWN_POSTPONE, postponeTimeMs); 351 } 352 353 /** 354 * Send Shutdown Start message to VHAL 355 */ sendShutdownStart(int wakeupTimeSec)356 public void sendShutdownStart(int wakeupTimeSec) { 357 Slogf.i(CarLog.TAG_POWER, "send shutdown start"); 358 setPowerState(VehicleApPowerStateReport.SHUTDOWN_START, wakeupTimeSec); 359 } 360 361 /** 362 * Send On message to VHAL 363 */ sendOn()364 public void sendOn() { 365 Slogf.i(CarLog.TAG_POWER, "send on"); 366 setPowerState(VehicleApPowerStateReport.ON, 0); 367 } 368 369 /** 370 * Send Shutdown Prepare message to VHAL 371 */ sendShutdownPrepare()372 public void sendShutdownPrepare() { 373 Slogf.i(CarLog.TAG_POWER, "send shutdown prepare"); 374 setPowerState(VehicleApPowerStateReport.SHUTDOWN_PREPARE, 0); 375 } 376 377 /** 378 * Send Shutdown Cancel message to VHAL 379 */ sendShutdownCancel()380 public void sendShutdownCancel() { 381 Slogf.i(CarLog.TAG_POWER, "send shutdown cancel"); 382 setPowerState(VehicleApPowerStateReport.SHUTDOWN_CANCELLED, 0); 383 } 384 385 /** 386 * Sets the display brightness for the vehicle. 387 * @param brightness value from 0 to 100. 388 */ sendDisplayBrightness(int brightness)389 public void sendDisplayBrightness(int brightness) { 390 int brightnessToSet = adjustBrightness(brightness, /* minBrightness= */ 0, 391 /* maxBrightness= */ 100); 392 393 synchronized (mLock) { 394 if (mProperties.get(DISPLAY_BRIGHTNESS) == null) { 395 return; 396 } 397 if (mPerDisplayBrightnessSupported) { 398 Slogf.w(CarLog.TAG_POWER, "PER_DISPLAY_BRIGHTNESS is supported and " 399 + "sendDisplayBrightness(int displayId, int brightness) should be used " 400 + "instead of DISPLAY_BRIGHTNESS"); 401 return; 402 } 403 } 404 try { 405 mHal.set(VehicleProperty.DISPLAY_BRIGHTNESS, 0).to(brightnessToSet); 406 Slogf.i(CarLog.TAG_POWER, "send display brightness = " + brightnessToSet); 407 } catch (ServiceSpecificException | IllegalArgumentException e) { 408 Slogf.e(CarLog.TAG_POWER, "cannot set DISPLAY_BRIGHTNESS", e); 409 } 410 } 411 412 /** 413 * Received display brightness change event. 414 * @param displayId the display id. 415 * @param brightness in percentile. 100% full. 416 */ sendDisplayBrightness(int displayId, int brightness)417 public void sendDisplayBrightness(int displayId, int brightness) { 418 int brightnessToSet = adjustBrightness(brightness, /* minBrightness= */ 0, 419 /* maxBrightness= */ 100); 420 421 synchronized (mLock) { 422 if (!mPerDisplayBrightnessSupported) { 423 Slogf.w(CarLog.TAG_POWER, "PER_DISPLAY_BRIGHTNESS is not supported"); 424 return; 425 } 426 } 427 int displayPort = getDisplayPort(displayId); 428 if (displayPort == DisplayHelper.INVALID_PORT) { 429 return; 430 } 431 try { 432 HalPropValue value = mHal.getHalPropValueBuilder() 433 .build(VehicleProperty.PER_DISPLAY_BRIGHTNESS, /* areaId= */ 0, 434 new int[]{displayPort, brightnessToSet}); 435 mHal.set(value); 436 Slogf.i(CarLog.TAG_POWER, "send display brightness = %d, port = %d", 437 brightnessToSet, displayPort); 438 } catch (ServiceSpecificException e) { 439 Slogf.e(CarLog.TAG_POWER, e, "cannot set PER_DISPLAY_BRIGHTNESS port = %d", 440 displayPort); 441 } 442 } 443 444 /** 445 * Sends {@code SHUTDOWN_REQUEST} to the VHAL. 446 */ requestShutdownAp(@owerState.ShutdownType int powerState, boolean runGarageMode)447 public void requestShutdownAp(@PowerState.ShutdownType int powerState, boolean runGarageMode) { 448 int shutdownParam = VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY; 449 switch (powerState) { 450 case PowerState.SHUTDOWN_TYPE_POWER_OFF: 451 shutdownParam = runGarageMode ? VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY 452 : VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY; 453 break; 454 case PowerState.SHUTDOWN_TYPE_DEEP_SLEEP: 455 shutdownParam = runGarageMode ? VehicleApPowerStateShutdownParam.CAN_SLEEP 456 : VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY; 457 break; 458 case PowerState.SHUTDOWN_TYPE_HIBERNATION: 459 shutdownParam = runGarageMode ? VehicleApPowerStateShutdownParam.CAN_HIBERNATE 460 : VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY; 461 break; 462 case PowerState.SHUTDOWN_TYPE_UNDEFINED: 463 default: 464 Slogf.w(CarLog.TAG_POWER, "Unknown power state(%d) for requestShutdownAp", 465 powerState); 466 return; 467 } 468 469 try { 470 mHal.set(VehicleProperty.SHUTDOWN_REQUEST, /* areaId= */ 0).to(shutdownParam); 471 } catch (ServiceSpecificException | IllegalArgumentException e) { 472 Slogf.e(CarLog.TAG_POWER, "cannot send SHUTDOWN_REQUEST to VHAL", e); 473 } 474 } 475 setPowerState(int state, int additionalParam)476 private void setPowerState(int state, int additionalParam) { 477 if (isPowerStateSupported()) { 478 int[] values = { state, additionalParam }; 479 try { 480 mHal.set(VehicleProperty.AP_POWER_STATE_REPORT, 0).to(values); 481 Slogf.i(CarLog.TAG_POWER, "setPowerState=" + powerStateReportName(state) 482 + " param=" + additionalParam); 483 } catch (ServiceSpecificException e) { 484 Slogf.e(CarLog.TAG_POWER, "cannot set to AP_POWER_STATE_REPORT", e); 485 } 486 } 487 } 488 489 /** 490 * Returns a {@link PowerState} representing the current power state for the vehicle. 491 */ 492 @Nullable getCurrentPowerState()493 public PowerState getCurrentPowerState() { 494 HalPropValue value; 495 try { 496 value = mHal.get(VehicleProperty.AP_POWER_STATE_REQ); 497 } catch (ServiceSpecificException e) { 498 Slogf.e(CarLog.TAG_POWER, "Cannot get AP_POWER_STATE_REQ", e); 499 return null; 500 } 501 return new PowerState(value.getInt32Value(VehicleApPowerStateReqIndex.STATE), 502 value.getInt32Value(VehicleApPowerStateReqIndex.ADDITIONAL)); 503 } 504 505 /** 506 * Determines if the current properties describe a valid power state 507 * @return true if both the power state request and power state report are valid 508 */ isPowerStateSupported()509 public boolean isPowerStateSupported() { 510 synchronized (mLock) { 511 return (mProperties.get(VehicleProperty.AP_POWER_STATE_REQ) != null) 512 && (mProperties.get(VehicleProperty.AP_POWER_STATE_REPORT) != null); 513 } 514 } 515 516 /** 517 * Returns if the vehicle is currently in use. 518 * 519 * In use means a human user is present in the vehicle and is currently using the vehicle or 520 * will use the vehicle soon. 521 */ isVehicleInUse()522 public boolean isVehicleInUse() { 523 try { 524 HalPropValue value = mHal.get(VEHICLE_IN_USE); 525 return (value.getStatus() == VehiclePropertyStatus.AVAILABLE 526 && value.getInt32ValuesSize() >= 1 && value.getInt32Value(0) != 0); 527 } catch (ServiceSpecificException | IllegalArgumentException e) { 528 Slogf.w(CarLog.TAG_POWER, "Failed to get VEHICLE_IN_USE value", e); 529 return false; 530 } 531 } 532 isConfigFlagSet(int flag)533 private boolean isConfigFlagSet(int flag) { 534 HalPropConfig config; 535 synchronized (mLock) { 536 config = mProperties.get(VehicleProperty.AP_POWER_STATE_REQ); 537 } 538 if (config == null) { 539 return false; 540 } 541 int[] configArray = config.getConfigArray(); 542 if (configArray.length < 1) { 543 return false; 544 } 545 return (configArray[0] & flag) != 0; 546 } 547 isDeepSleepAllowed()548 public boolean isDeepSleepAllowed() { 549 return isConfigFlagSet(VehicleApPowerStateConfigFlag.ENABLE_DEEP_SLEEP_FLAG); 550 } 551 isHibernationAllowed()552 public boolean isHibernationAllowed() { 553 return isConfigFlagSet(VehicleApPowerStateConfigFlag.ENABLE_HIBERNATION_FLAG); 554 } 555 isTimedWakeupAllowed()556 public boolean isTimedWakeupAllowed() { 557 return isConfigFlagSet(VehicleApPowerStateConfigFlag.CONFIG_SUPPORT_TIMER_POWER_ON_FLAG); 558 } 559 560 @Override init()561 public void init() { 562 synchronized (mLock) { 563 for (int i = 0; i < mProperties.size(); i++) { 564 HalPropConfig config = mProperties.valueAt(i); 565 if (VehicleHal.isPropertySubscribable(config)) { 566 mHal.subscribeProperty(this, config.getPropId()); 567 } 568 } 569 HalPropConfig brightnessProperty = mProperties.get(PER_DISPLAY_BRIGHTNESS); 570 mPerDisplayBrightnessSupported = brightnessProperty != null; 571 if (brightnessProperty == null) { 572 brightnessProperty = mProperties.get(DISPLAY_BRIGHTNESS); 573 } 574 if (brightnessProperty != null) { 575 HalAreaConfig[] areaConfigs = brightnessProperty.getAreaConfigs(); 576 mMaxDisplayBrightness = areaConfigs.length > 0 577 ? areaConfigs[0].getMaxInt32Value() : 0; 578 if (mMaxDisplayBrightness <= 0) { 579 Slogf.w(CarLog.TAG_POWER, "Max display brightness from vehicle HAL is invalid:" 580 + mMaxDisplayBrightness); 581 mMaxDisplayBrightness = 1; 582 } 583 } 584 } 585 } 586 587 @Override release()588 public void release() { 589 synchronized (mLock) { 590 mProperties.clear(); 591 } 592 } 593 594 @Override getAllSupportedProperties()595 public int[] getAllSupportedProperties() { 596 return SUPPORTED_PROPERTIES; 597 } 598 599 @Override takeProperties(Collection<HalPropConfig> properties)600 public void takeProperties(Collection<HalPropConfig> properties) { 601 if (properties.isEmpty()) { 602 return; 603 } 604 synchronized (mLock) { 605 for (HalPropConfig config : properties) { 606 mProperties.put(config.getPropId(), config); 607 } 608 } 609 } 610 611 @Override onHalEvents(List<HalPropValue> values)612 public void onHalEvents(List<HalPropValue> values) { 613 PowerEventListener listener; 614 synchronized (mLock) { 615 if (mListener == null) { 616 if (mQueuedEvents == null) { 617 mQueuedEvents = new ArrayList<>(values.size()); 618 } 619 mQueuedEvents.addAll(values); 620 return; 621 } 622 listener = mListener; 623 } 624 dispatchEvents(values, listener); 625 } 626 dispatchEvents(List<HalPropValue> values, PowerEventListener listener)627 private void dispatchEvents(List<HalPropValue> values, PowerEventListener listener) { 628 for (int i = 0; i < values.size(); i++) { 629 HalPropValue v = values.get(i); 630 switch (v.getPropId()) { 631 case AP_POWER_STATE_REPORT: 632 // Ignore this property event. It was generated inside of CarService. 633 break; 634 case AP_POWER_STATE_REQ: 635 int state; 636 int param; 637 try { 638 state = v.getInt32Value(VehicleApPowerStateReqIndex.STATE); 639 param = v.getInt32Value(VehicleApPowerStateReqIndex.ADDITIONAL); 640 } catch (IndexOutOfBoundsException e) { 641 Slogf.e(CarLog.TAG_POWER, "Received invalid event, ignore, int32Values: " 642 + v.dumpInt32Values(), e); 643 break; 644 } 645 Slogf.i(CarLog.TAG_POWER, "Received AP_POWER_STATE_REQ=" 646 + powerStateReqName(state) + " param=" + param); 647 listener.onApPowerStateChange(new PowerState(state, param)); 648 break; 649 case DISPLAY_BRIGHTNESS: 650 { 651 int maxBrightness; 652 synchronized (mLock) { 653 if (mPerDisplayBrightnessSupported) { 654 Slogf.w(CarLog.TAG_POWER, "Received DISPLAY_BRIGHTNESS " 655 + "while PER_DISPLAY_BRIGHTNESS is supported, ignore"); 656 return; 657 } 658 maxBrightness = mMaxDisplayBrightness; 659 } 660 int brightness; 661 try { 662 brightness = v.getInt32Value(0) * MAX_BRIGHTNESS / maxBrightness; 663 } catch (IndexOutOfBoundsException e) { 664 Slogf.e(CarLog.TAG_POWER, "Received invalid event, ignore, int32Values: " 665 + v.dumpInt32Values(), e); 666 break; 667 } 668 if (brightness < 0) { 669 Slogf.e(CarLog.TAG_POWER, "invalid brightness: " + brightness 670 + ", set to 0"); 671 brightness = 0; 672 } else if (brightness > MAX_BRIGHTNESS) { 673 Slogf.e(CarLog.TAG_POWER, "invalid brightness: " + brightness + ", set to " 674 + MAX_BRIGHTNESS); 675 brightness = MAX_BRIGHTNESS; 676 } 677 Slogf.i(CarLog.TAG_POWER, "Received DISPLAY_BRIGHTNESS=" + brightness); 678 listener.onDisplayBrightnessChange(brightness); 679 break; 680 } 681 case PER_DISPLAY_BRIGHTNESS: 682 { 683 int maxBrightness; 684 synchronized (mLock) { 685 maxBrightness = mMaxDisplayBrightness; 686 } 687 int displayPort; 688 int brightness; 689 try { 690 displayPort = v.getInt32Value(0); 691 brightness = v.getInt32Value(1) * MAX_BRIGHTNESS / maxBrightness; 692 } catch (IndexOutOfBoundsException e) { 693 Slogf.e(CarLog.TAG_POWER, "Received invalid event, ignore, int32Values: " 694 + v.dumpInt32Values(), e); 695 break; 696 } 697 brightness = adjustBrightness(brightness, /* minBrightness= */ 0, 698 MAX_BRIGHTNESS); 699 Slogf.i(CarLog.TAG_POWER, "Received PER_DISPLAY_BRIGHTNESS=" + brightness 700 + ", displayPort=" + displayPort); 701 int displayId = getDisplayId(displayPort); 702 listener.onDisplayBrightnessChange(displayId, brightness); 703 break; 704 } 705 default: 706 Slogf.w(CarLog.TAG_POWER, "Received event with invalid property id: %d", 707 v.getPropId()); 708 break; 709 } 710 } 711 } 712 getDisplayId(int displayPort)713 private int getDisplayId(int displayPort) { 714 DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); 715 int displayId = Display.DEFAULT_DISPLAY; 716 for (Display display : displayManager.getDisplays()) { 717 if (displayPort == DisplayHelper.getPhysicalPort(display)) { 718 displayId = display.getDisplayId(); 719 break; 720 } 721 } 722 return displayId; 723 } 724 getDisplayPort(int displayId)725 private int getDisplayPort(int displayId) { 726 DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); 727 Display display = displayManager.getDisplay(displayId); 728 if (display != null) { 729 int displayPort = DisplayHelper.getPhysicalPort(display); 730 if (displayPort != DisplayHelper.INVALID_PORT) { 731 return displayPort; 732 } 733 } 734 Slogf.w(CarLog.TAG_POWER, "cannot get display port from displayId = %d", 735 displayId); 736 return DisplayHelper.INVALID_PORT; 737 } 738 adjustBrightness(int brightness, int minBrightness, int maxBrightness)739 private int adjustBrightness(int brightness, int minBrightness, int maxBrightness) { 740 if (brightness < minBrightness) { 741 Slogf.w(CarLog.TAG_POWER, "invalid brightness: %d, brightness is set to %d", brightness, 742 minBrightness); 743 brightness = minBrightness; 744 } else if (brightness > maxBrightness) { 745 Slogf.w(CarLog.TAG_POWER, "invalid brightness: %d, brightness is set to %d", brightness, 746 maxBrightness); 747 brightness = maxBrightness; 748 } 749 return brightness; 750 } 751 752 @Override 753 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(PrintWriter writer)754 public void dump(PrintWriter writer) { 755 writer.println("*Power HAL*"); 756 writer.printf("isPowerStateSupported:%b, isDeepSleepAllowed:%b, isHibernationAllowed:%b\n", 757 isPowerStateSupported(), isDeepSleepAllowed(), isHibernationAllowed()); 758 759 } 760 } 761