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_BOOTUP_REASON; 19 import static android.hardware.automotive.vehicle.VehicleProperty.AP_POWER_STATE_REPORT; 20 import static android.hardware.automotive.vehicle.VehicleProperty.AP_POWER_STATE_REQ; 21 import static android.hardware.automotive.vehicle.VehicleProperty.DISPLAY_BRIGHTNESS; 22 import static android.hardware.automotive.vehicle.VehicleProperty.PER_DISPLAY_BRIGHTNESS; 23 import static android.hardware.automotive.vehicle.VehicleProperty.PER_DISPLAY_MAX_BRIGHTNESS; 24 import static android.hardware.automotive.vehicle.VehicleProperty.SHUTDOWN_REQUEST; 25 import static android.hardware.automotive.vehicle.VehicleProperty.VEHICLE_IN_USE; 26 27 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 28 29 import android.annotation.IntDef; 30 import android.annotation.Nullable; 31 import android.car.builtin.util.Slogf; 32 import android.car.builtin.view.DisplayHelper; 33 import android.car.feature.FeatureFlags; 34 import android.content.Context; 35 import android.hardware.automotive.vehicle.VehicleApPowerBootupReason; 36 import android.hardware.automotive.vehicle.VehicleApPowerStateConfigFlag; 37 import android.hardware.automotive.vehicle.VehicleApPowerStateReport; 38 import android.hardware.automotive.vehicle.VehicleApPowerStateReq; 39 import android.hardware.automotive.vehicle.VehicleApPowerStateReqIndex; 40 import android.hardware.automotive.vehicle.VehicleApPowerStateShutdownParam; 41 import android.hardware.automotive.vehicle.VehicleProperty; 42 import android.hardware.automotive.vehicle.VehiclePropertyStatus; 43 import android.hardware.display.DisplayManager; 44 import android.os.Handler; 45 import android.os.HandlerThread; 46 import android.os.ServiceSpecificException; 47 import android.util.SparseArray; 48 import android.util.SparseIntArray; 49 import android.view.Display; 50 51 import com.android.car.CarLog; 52 import com.android.car.CarServiceUtils; 53 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 54 import com.android.car.systeminterface.DisplayHelperInterface; 55 import com.android.internal.annotations.GuardedBy; 56 import com.android.internal.annotations.VisibleForTesting; 57 import com.android.internal.util.Preconditions; 58 59 import java.io.PrintWriter; 60 import java.lang.annotation.Retention; 61 import java.lang.annotation.RetentionPolicy; 62 import java.util.ArrayList; 63 import java.util.Collection; 64 import java.util.LinkedList; 65 import java.util.List; 66 import java.util.Objects; 67 68 /** 69 * Translates HAL power events to higher-level semantic information. 70 */ 71 public class PowerHalService extends HalServiceBase { 72 // Set display brightness from 0-100% 73 public static final int MAX_BRIGHTNESS = 100; 74 75 // In order to prevent flickering caused by 76 // set_vhal_brightness_1 -> set_vhal_brightness_2 -> vhal_report_1 -> set_vhal_brightness_1 77 // -> vhal_report_2 -> set_vhal_brightness_2 -> ... 78 // We set a time window to ignore the value update event for the requests we have sent. 79 private static final int PREVENT_LOOP_REQUEST_TIME_WINDOW_MS = 1000; 80 private static final int GLOBAL_PORT = -1; 81 PropertyInfo(boolean needSubscription)82 private record PropertyInfo(boolean needSubscription) {} 83 getSupportedProperties()84 private static SparseArray<PropertyInfo> getSupportedProperties() { 85 SparseArray<PropertyInfo> propertyInfo = new SparseArray<>(); 86 propertyInfo.put(AP_POWER_STATE_REQ, new PropertyInfo(/*needSubscription=*/ true)); 87 // This is issued from PowerHalService so we do not need to subscribe to it. 88 propertyInfo.put(AP_POWER_STATE_REPORT, new PropertyInfo(/*needSubscription=*/ false)); 89 propertyInfo.put(DISPLAY_BRIGHTNESS, new PropertyInfo(/*needSubscription=*/ true)); 90 propertyInfo.put(PER_DISPLAY_BRIGHTNESS, new PropertyInfo(/*needSubscription=*/ true)); 91 propertyInfo.put(VEHICLE_IN_USE, new PropertyInfo(/*needSubscription=*/ false)); 92 propertyInfo.put(AP_POWER_BOOTUP_REASON, new PropertyInfo(/*needSubscription=*/ false)); 93 propertyInfo.put(PER_DISPLAY_MAX_BRIGHTNESS, new PropertyInfo(/*needSubscription=*/ false)); 94 return propertyInfo; 95 } 96 97 private static final SparseArray<PropertyInfo> SUPPORTED_PROPERTIES = getSupportedProperties(); 98 99 /** 100 * Unknown bootup reason. 101 */ 102 public static final int BOOTUP_REASON_UNKNOWN = -1; 103 104 /** 105 * Power on due to user's pressing of power key or rotating of ignition switch. 106 */ 107 public static final int BOOTUP_REASON_USER_POWER_ON = 0; 108 109 /** 110 * Automatic power on triggered by door unlock or any other kind of automatic user detection. 111 */ 112 public static final int BOOTUP_REASON_SYSTEM_USER_DETECTION = 1; 113 114 /** 115 * Automatic power on to execute a remote task. This is triggered by receiving a wakeup message 116 * from an external system in the vehicle. 117 */ 118 public static final int BOOTUP_REASON_SYSTEM_REMOTE_ACCESS = 2; 119 120 /** 121 * Automatic power on to enter garage mode. This is triggered by receiving a wakeup message from 122 * an external system in the vehicle. 123 */ 124 public static final int BOOTUP_REASON_SYSTEM_ENTER_GARAGE_MODE = 3; 125 126 /** @hide */ 127 @IntDef(prefix = {"BOOTUP_REASON_"}, value = { 128 BOOTUP_REASON_UNKNOWN, 129 BOOTUP_REASON_USER_POWER_ON, 130 BOOTUP_REASON_SYSTEM_USER_DETECTION, 131 BOOTUP_REASON_SYSTEM_REMOTE_ACCESS, 132 BOOTUP_REASON_SYSTEM_ENTER_GARAGE_MODE, 133 }) 134 @Retention(RetentionPolicy.SOURCE) 135 public @interface BootupReason {} 136 137 @VisibleForTesting 138 public static final int SET_WAIT_FOR_VHAL = VehicleApPowerStateReport.WAIT_FOR_VHAL; 139 @VisibleForTesting 140 public static final int SET_DEEP_SLEEP_ENTRY = VehicleApPowerStateReport.DEEP_SLEEP_ENTRY; 141 @VisibleForTesting 142 public static final int SET_DEEP_SLEEP_EXIT = VehicleApPowerStateReport.DEEP_SLEEP_EXIT; 143 @VisibleForTesting 144 public static final int SET_SHUTDOWN_POSTPONE = VehicleApPowerStateReport.SHUTDOWN_POSTPONE; 145 @VisibleForTesting 146 public static final int SET_SHUTDOWN_START = VehicleApPowerStateReport.SHUTDOWN_START; 147 @VisibleForTesting 148 public static final int SET_ON = VehicleApPowerStateReport.ON; 149 @VisibleForTesting 150 public static final int SET_SHUTDOWN_PREPARE = VehicleApPowerStateReport.SHUTDOWN_PREPARE; 151 @VisibleForTesting 152 public static final int SET_SHUTDOWN_CANCELLED = VehicleApPowerStateReport.SHUTDOWN_CANCELLED; 153 154 @VisibleForTesting 155 public static final int SHUTDOWN_CAN_SLEEP = VehicleApPowerStateShutdownParam.CAN_SLEEP; 156 @VisibleForTesting 157 public static final int SHUTDOWN_IMMEDIATELY = 158 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY; 159 @VisibleForTesting 160 public static final int SHUTDOWN_ONLY = VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY; 161 @VisibleForTesting 162 public static final int SET_HIBERNATION_ENTRY = VehicleApPowerStateReport.HIBERNATION_ENTRY; 163 @VisibleForTesting 164 public static final int SET_HIBERNATION_EXIT = VehicleApPowerStateReport.HIBERNATION_EXIT; 165 166 private final Object mLock = new Object(); 167 powerStateReportName(int state)168 private static String powerStateReportName(int state) { 169 String baseName; 170 switch(state) { 171 case SET_WAIT_FOR_VHAL: baseName = "WAIT_FOR_VHAL"; break; 172 case SET_DEEP_SLEEP_ENTRY: baseName = "DEEP_SLEEP_ENTRY"; break; 173 case SET_DEEP_SLEEP_EXIT: baseName = "DEEP_SLEEP_EXIT"; break; 174 case SET_SHUTDOWN_POSTPONE: baseName = "SHUTDOWN_POSTPONE"; break; 175 case SET_SHUTDOWN_START: baseName = "SHUTDOWN_START"; break; 176 case SET_ON: baseName = "ON"; break; 177 case SET_SHUTDOWN_PREPARE: baseName = "SHUTDOWN_PREPARE"; break; 178 case SET_SHUTDOWN_CANCELLED: baseName = "SHUTDOWN_CANCELLED"; break; 179 case SET_HIBERNATION_ENTRY: baseName = "HIBERNATION_ENTRY"; break; 180 case SET_HIBERNATION_EXIT: baseName = "HIBERNATION_EXIT"; break; 181 default: baseName = "<unknown>"; break; 182 } 183 return baseName + "(" + state + ")"; 184 } 185 powerStateReqName(int state)186 private static String powerStateReqName(int state) { 187 String baseName; 188 switch(state) { 189 case VehicleApPowerStateReq.ON: baseName = "ON"; break; 190 case VehicleApPowerStateReq.SHUTDOWN_PREPARE: baseName = "SHUTDOWN_PREPARE"; break; 191 case VehicleApPowerStateReq.CANCEL_SHUTDOWN: baseName = "CANCEL_SHUTDOWN"; break; 192 case VehicleApPowerStateReq.FINISHED: baseName = "FINISHED"; break; 193 default: baseName = "<unknown>"; break; 194 } 195 return baseName + "(" + state + ")"; 196 } 197 198 /** 199 * Interface to be implemented by any object that wants to be notified by any Vehicle's power 200 * change. 201 */ 202 public interface PowerEventListener { 203 /** 204 * Received power state change event. 205 * @param state One of STATE_* 206 */ onApPowerStateChange(PowerState state)207 void onApPowerStateChange(PowerState state); 208 209 /** 210 * Received display brightness change event. 211 * @param brightness in percentile. 100% full. 212 */ onDisplayBrightnessChange(int brightness)213 void onDisplayBrightnessChange(int brightness); 214 215 /** 216 * Received display brightness change event. 217 * @param displayId the display id. 218 * @param brightness in percentile. 100% full. 219 */ onDisplayBrightnessChange(int displayId, int brightness)220 void onDisplayBrightnessChange(int displayId, int brightness); 221 } 222 223 /** 224 * Contains information about the Vehicle's power state. 225 */ 226 public static final class PowerState { 227 228 @IntDef({SHUTDOWN_TYPE_UNDEFINED, SHUTDOWN_TYPE_POWER_OFF, SHUTDOWN_TYPE_DEEP_SLEEP, 229 SHUTDOWN_TYPE_HIBERNATION, SHUTDOWN_TYPE_EMERGENCY}) 230 @Retention(RetentionPolicy.SOURCE) 231 public @interface ShutdownType {} 232 233 public static final int SHUTDOWN_TYPE_UNDEFINED = 0; 234 public static final int SHUTDOWN_TYPE_POWER_OFF = 1; 235 public static final int SHUTDOWN_TYPE_DEEP_SLEEP = 2; 236 public static final int SHUTDOWN_TYPE_HIBERNATION = 3; 237 public static final int SHUTDOWN_TYPE_EMERGENCY = 4; 238 /** 239 * One of STATE_* 240 */ 241 public final int mState; 242 public final int mParam; 243 PowerState(int state, int param)244 public PowerState(int state, int param) { 245 this.mState = state; 246 this.mParam = param; 247 } 248 249 /** 250 * Whether the current PowerState allows postponing or not. Calling this for 251 * power state other than STATE_SHUTDOWN_PREPARE will trigger exception. 252 * @return 253 * @throws IllegalStateException 254 */ canPostponeShutdown()255 public boolean canPostponeShutdown() { 256 if (mState != VehicleApPowerStateReq.SHUTDOWN_PREPARE) { 257 throw new IllegalStateException("wrong state"); 258 } 259 return (mParam != VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY 260 && mParam != VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY 261 && mParam != VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY 262 && mParam != VehicleApPowerStateShutdownParam.EMERGENCY_SHUTDOWN); 263 } 264 265 /** 266 * Gets whether the current PowerState allows suspend or not. 267 * 268 * @throws IllegalStateException if called in state other than {@code 269 * STATE_SHUTDOWN_PREPARE} 270 */ canSuspend()271 public boolean canSuspend() { 272 Preconditions.checkArgument(mState == VehicleApPowerStateReq.SHUTDOWN_PREPARE, 273 "canSuspend was called in the wrong state! State = %d", mState); 274 275 return (mParam == VehicleApPowerStateShutdownParam.CAN_HIBERNATE 276 || mParam == VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY 277 || mParam == VehicleApPowerStateShutdownParam.CAN_SLEEP 278 || mParam == VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY); 279 } 280 281 /** 282 * Gets shutdown type 283 * 284 * @return {@code ShutdownType} - type of shutdown 285 * @throws IllegalStateException if called in state other than {@code 286 * STATE_SHUTDOWN_PREPARE} 287 */ 288 @ShutdownType getShutdownType()289 public int getShutdownType() { 290 Preconditions.checkArgument(mState == VehicleApPowerStateReq.SHUTDOWN_PREPARE, 291 "getShutdownType was called in the wrong state! State = %d", mState); 292 293 int result = SHUTDOWN_TYPE_POWER_OFF; 294 if (mParam == VehicleApPowerStateShutdownParam.CAN_SLEEP 295 || mParam == VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY) { 296 result = SHUTDOWN_TYPE_DEEP_SLEEP; 297 } else if (mParam == VehicleApPowerStateShutdownParam.CAN_HIBERNATE 298 || mParam == VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY) { 299 result = SHUTDOWN_TYPE_HIBERNATION; 300 } else if (mParam == VehicleApPowerStateShutdownParam.EMERGENCY_SHUTDOWN) { 301 result = SHUTDOWN_TYPE_EMERGENCY; 302 } 303 304 return result; 305 } 306 307 @Override equals(Object o)308 public boolean equals(Object o) { 309 if (this == o) { 310 return true; 311 } 312 if (!(o instanceof PowerState)) { 313 return false; 314 } 315 PowerState that = (PowerState) o; 316 return this.mState == that.mState && this.mParam == that.mParam; 317 } 318 319 @Override hashCode()320 public int hashCode() { 321 return Objects.hash(mState, mParam); 322 } 323 324 @Override toString()325 public String toString() { 326 return "PowerState state:" + mState + ", param:" + mParam; 327 } 328 } 329 BrightnessForDisplayPort(int brightness, int displayPort)330 private record BrightnessForDisplayPort(int brightness, int displayPort) {} 331 332 @GuardedBy("mLock") 333 private final SparseArray<HalPropConfig> mProperties = new SparseArray<>(); 334 private final Context mContext; 335 private final VehicleHal mHal; 336 private final FeatureFlags mFeatureFlags; 337 private final HandlerThread mHandlerThread; 338 private final Handler mHandler; 339 // A FIFO queue that stores the brightness value we previously set to VHAL in a short time 340 // window. 341 @GuardedBy("mLock") 342 private final LinkedList<BrightnessForDisplayPort> mRecentlySetBrightness = new LinkedList<>(); 343 private final DisplayHelperInterface mDisplayHelper; 344 @Nullable 345 @GuardedBy("mLock") 346 private ArrayList<HalPropValue> mQueuedEvents; 347 @GuardedBy("mLock") 348 private PowerEventListener mListener; 349 @GuardedBy("mLock") 350 private int mMaxDisplayBrightness; 351 @GuardedBy("mLock") 352 private SparseIntArray mMaxPerDisplayBrightness = new SparseIntArray(); 353 @GuardedBy("mLock") 354 private boolean mPerDisplayBrightnessSupported; 355 PowerHalService(Context context, FeatureFlags featureFlags, VehicleHal hal, DisplayHelperInterface displayHelper)356 public PowerHalService(Context context, FeatureFlags featureFlags, VehicleHal hal, 357 DisplayHelperInterface displayHelper) { 358 mContext = context; 359 mFeatureFlags = featureFlags; 360 mHal = hal; 361 mHandlerThread = CarServiceUtils.getHandlerThread(getClass().getSimpleName()); 362 mHandler = new Handler(mHandlerThread.getLooper()); 363 mDisplayHelper = displayHelper; 364 } 365 366 /** 367 * Sets the event listener to receive Vehicle's power events. 368 */ setListener(PowerEventListener listener)369 public void setListener(PowerEventListener listener) { 370 ArrayList<HalPropValue> eventsToDispatch = null; 371 synchronized (mLock) { 372 mListener = listener; 373 if (mQueuedEvents != null && !mQueuedEvents.isEmpty()) { 374 eventsToDispatch = mQueuedEvents; 375 } 376 mQueuedEvents = null; 377 } 378 // do this outside lock 379 if (eventsToDispatch != null) { 380 dispatchEvents(eventsToDispatch, listener); 381 } 382 } 383 384 /** 385 * Send WaitForVhal message to VHAL 386 */ sendWaitForVhal()387 public void sendWaitForVhal() { 388 Slogf.i(CarLog.TAG_POWER, "send wait for vhal"); 389 setPowerState(VehicleApPowerStateReport.WAIT_FOR_VHAL, 0); 390 } 391 392 /** 393 * Send SleepEntry message to VHAL 394 * @param wakeupTimeSec Notify VHAL when system wants to be woken from sleep. 395 */ sendSleepEntry(int wakeupTimeSec)396 public void sendSleepEntry(int wakeupTimeSec) { 397 Slogf.i(CarLog.TAG_POWER, "send sleep entry"); 398 setPowerState(VehicleApPowerStateReport.DEEP_SLEEP_ENTRY, wakeupTimeSec); 399 } 400 401 /** 402 * Send SleepExit message to VHAL 403 * Notifies VHAL when SOC has woken. 404 */ sendSleepExit()405 public void sendSleepExit() { 406 Slogf.i(CarLog.TAG_POWER, "send sleep exit"); 407 setPowerState(VehicleApPowerStateReport.DEEP_SLEEP_EXIT, 0); 408 } 409 410 /** 411 * Sends HibernationEntry message to VHAL 412 * 413 * @param wakeupTimeSec Number of seconds from now to be woken from sleep. 414 */ sendHibernationEntry(int wakeupTimeSec)415 public void sendHibernationEntry(int wakeupTimeSec) { 416 Slogf.i(CarLog.TAG_POWER, "send hibernation entry - wakeupTimeSec = %d", 417 wakeupTimeSec); 418 setPowerState(VehicleApPowerStateReport.HIBERNATION_ENTRY, wakeupTimeSec); 419 } 420 421 /** 422 * Sends HibernationExit message to VHAL 423 * 424 * Notifies VHAL after SOC woke up from hibernation. 425 */ sendHibernationExit()426 public void sendHibernationExit() { 427 Slogf.i(CarLog.TAG_POWER, "send hibernation exit"); 428 setPowerState(VehicleApPowerStateReport.HIBERNATION_EXIT, 0); 429 } 430 431 /** 432 * Send Shutdown Postpone message to VHAL 433 */ sendShutdownPostpone(int postponeTimeMs)434 public void sendShutdownPostpone(int postponeTimeMs) { 435 Slogf.i(CarLog.TAG_POWER, "send shutdown postpone, time:" + postponeTimeMs); 436 setPowerState(VehicleApPowerStateReport.SHUTDOWN_POSTPONE, postponeTimeMs); 437 } 438 439 /** 440 * Send Shutdown Start message to VHAL 441 */ sendShutdownStart(int wakeupTimeSec)442 public void sendShutdownStart(int wakeupTimeSec) { 443 Slogf.i(CarLog.TAG_POWER, "send shutdown start"); 444 setPowerState(VehicleApPowerStateReport.SHUTDOWN_START, wakeupTimeSec); 445 } 446 447 /** 448 * Send On message to VHAL 449 */ sendOn()450 public void sendOn() { 451 Slogf.i(CarLog.TAG_POWER, "send on"); 452 setPowerState(VehicleApPowerStateReport.ON, 0); 453 } 454 455 /** 456 * Send Shutdown Prepare message to VHAL 457 */ sendShutdownPrepare()458 public void sendShutdownPrepare() { 459 Slogf.i(CarLog.TAG_POWER, "send shutdown prepare"); 460 setPowerState(VehicleApPowerStateReport.SHUTDOWN_PREPARE, 0); 461 } 462 463 /** 464 * Send Shutdown Cancel message to VHAL 465 */ sendShutdownCancel()466 public void sendShutdownCancel() { 467 Slogf.i(CarLog.TAG_POWER, "send shutdown cancel"); 468 setPowerState(VehicleApPowerStateReport.SHUTDOWN_CANCELLED, 0); 469 } 470 471 /** 472 * Sets the display brightness for the vehicle. 473 * @param brightness value from 0 to 100. 474 */ sendDisplayBrightnessLegacy(int brightness)475 public void sendDisplayBrightnessLegacy(int brightness) { 476 // This method should not be called if multiDisplayBrightnessControl is enabled. 477 Slogf.i(CarLog.TAG_POWER, "brightness from system: " + brightness); 478 479 int brightnessToSet = adjustBrightness(brightness, /* minBrightness= */ 0, 480 /* maxBrightness= */ MAX_BRIGHTNESS); 481 482 synchronized (mLock) { 483 if (mProperties.get(DISPLAY_BRIGHTNESS) == null) { 484 return; 485 } 486 if (mPerDisplayBrightnessSupported) { 487 Slogf.e(CarLog.TAG_POWER, "PER_DISPLAY_BRIGHTNESS is supported and " 488 + "sendDisplayBrightness(int displayId, int brightness) should be used " 489 + "instead of sendDisplayBrightnessLegacy"); 490 return; 491 } 492 } 493 494 setGlobalBrightness(Display.DEFAULT_DISPLAY, brightnessToSet); 495 } 496 497 /** 498 * Received display brightness change event. 499 * @param displayId the display id. 500 * @param brightness in percentile. 100% full. 501 */ sendDisplayBrightness(int displayId, int brightness)502 public void sendDisplayBrightness(int displayId, int brightness) { 503 Slogf.i(CarLog.TAG_POWER, "brightness from system: " + brightness 504 + ", displayId: " + displayId); 505 int brightnessToSet = adjustBrightness(brightness, /* minBrightness= */ 0, 506 /* maxBrightness= */ 100); 507 boolean perDisplayBrightnessSupported; 508 synchronized (mLock) { 509 perDisplayBrightnessSupported = mPerDisplayBrightnessSupported; 510 } 511 512 if (!perDisplayBrightnessSupported) { 513 if (!mFeatureFlags.multiDisplayBrightnessControl()) { 514 Slogf.w(CarLog.TAG_POWER, "PER_DISPLAY_BRIGHTNESS is not supported, trying to set" 515 + " individual display's brightness does nothing in legacy mode"); 516 return; 517 } 518 Slogf.w(CarLog.TAG_POWER, "PER_DISPLAY_BRIGHTNESS is not supported, always set the" 519 + " default display brightness"); 520 setGlobalBrightness(displayId, brightnessToSet); 521 return; 522 } 523 524 setBrightnessForDisplayId(displayId, brightnessToSet); 525 } 526 setBrightnessForDisplayId(int displayId, int brightness)527 private void setBrightnessForDisplayId(int displayId, int brightness) { 528 int displayPort = getDisplayPort(displayId); 529 if (displayPort == DisplayHelper.INVALID_PORT) { 530 return; 531 } 532 533 synchronized (mLock) { 534 // Adjust brightness back from 0-100 back to 0-maxDisplayBrightness scale. 535 int maxDisplayBrightnessForPort = getMaxPerDisplayBrightnessLocked(displayPort); 536 brightness = brightness * maxDisplayBrightnessForPort / MAX_BRIGHTNESS; 537 addRecentlySetBrightnessChangeLocked(brightness, displayPort); 538 } 539 540 Slogf.i(CarLog.TAG_POWER, "brightness to VHAL: " + brightness 541 + ", displayPort: " + displayPort); 542 try { 543 HalPropValue value = mHal.getHalPropValueBuilder() 544 .build(PER_DISPLAY_BRIGHTNESS, /* areaId= */ 0, 545 new int[]{displayPort, brightness}); 546 mHal.set(value); 547 Slogf.i(CarLog.TAG_POWER, "sent display brightness = %d, port = %d", 548 brightness, displayPort); 549 } catch (ServiceSpecificException | IllegalArgumentException e) { 550 Slogf.e(CarLog.TAG_POWER, e, "cannot set PER_DISPLAY_BRIGHTNESS port = %d", 551 displayPort); 552 } 553 } 554 555 // The brightness is in 0-100 scale. 556 // fromDisplayId represents which display this request is sent from, even though in reality, 557 // because VHAL only supports global brightness. setGlobalBrightness(int fromDisplayId, int brightness)558 private void setGlobalBrightness(int fromDisplayId, int brightness) { 559 // Adjust brightness back from 0-100 back to 0-maxDisplayBrightness scale. 560 synchronized (mLock) { 561 brightness = brightness * mMaxDisplayBrightness / MAX_BRIGHTNESS; 562 } 563 564 int displayPort = getDisplayPort(fromDisplayId); 565 if (displayPort == DisplayHelper.INVALID_PORT) { 566 return; 567 } 568 569 Slogf.i(CarLog.TAG_POWER, "brightness to VHAL: " + brightness); 570 synchronized (mLock) { 571 addRecentlySetBrightnessChangeLocked(brightness, displayPort); 572 } 573 574 try { 575 mHal.set(VehicleProperty.DISPLAY_BRIGHTNESS, /* areaId= */ 0).to(brightness); 576 Slogf.i(CarLog.TAG_POWER, "sent global display brightness = %d", brightness); 577 } catch (ServiceSpecificException | IllegalArgumentException e) { 578 Slogf.e(CarLog.TAG_POWER, e, "cannot set DISPLAY_BRIGHTNESS"); 579 } 580 } 581 582 /** 583 * Sends {@code SHUTDOWN_REQUEST} to the VHAL. 584 */ requestShutdownAp(@owerState.ShutdownType int powerState, boolean runGarageMode)585 public void requestShutdownAp(@PowerState.ShutdownType int powerState, boolean runGarageMode) { 586 int shutdownParam = VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY; 587 switch (powerState) { 588 case PowerState.SHUTDOWN_TYPE_POWER_OFF: 589 shutdownParam = runGarageMode ? VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY 590 : VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY; 591 break; 592 case PowerState.SHUTDOWN_TYPE_DEEP_SLEEP: 593 shutdownParam = runGarageMode ? VehicleApPowerStateShutdownParam.CAN_SLEEP 594 : VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY; 595 break; 596 case PowerState.SHUTDOWN_TYPE_HIBERNATION: 597 shutdownParam = runGarageMode ? VehicleApPowerStateShutdownParam.CAN_HIBERNATE 598 : VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY; 599 break; 600 case PowerState.SHUTDOWN_TYPE_UNDEFINED: 601 default: 602 Slogf.w(CarLog.TAG_POWER, "Unknown power state(%d) for requestShutdownAp", 603 powerState); 604 return; 605 } 606 607 try { 608 mHal.set(SHUTDOWN_REQUEST, /* areaId= */ 0).to(shutdownParam); 609 } catch (ServiceSpecificException | IllegalArgumentException e) { 610 Slogf.e(CarLog.TAG_POWER, "cannot send SHUTDOWN_REQUEST to VHAL", e); 611 } 612 } 613 setPowerState(int state, int additionalParam)614 private void setPowerState(int state, int additionalParam) { 615 if (isPowerStateSupported()) { 616 int[] values = { state, additionalParam }; 617 try { 618 mHal.set(VehicleProperty.AP_POWER_STATE_REPORT, 0).to(values); 619 Slogf.i(CarLog.TAG_POWER, "setPowerState=" + powerStateReportName(state) 620 + " param=" + additionalParam); 621 } catch (ServiceSpecificException e) { 622 Slogf.e(CarLog.TAG_POWER, "cannot set to AP_POWER_STATE_REPORT", e); 623 } 624 } 625 } 626 627 /** 628 * Returns a {@link PowerState} representing the current power state for the vehicle. 629 */ 630 @Nullable getCurrentPowerState()631 public PowerState getCurrentPowerState() { 632 HalPropValue value; 633 try { 634 value = mHal.get(VehicleProperty.AP_POWER_STATE_REQ); 635 } catch (ServiceSpecificException e) { 636 Slogf.e(CarLog.TAG_POWER, "Cannot get AP_POWER_STATE_REQ", e); 637 return null; 638 } 639 return new PowerState(value.getInt32Value(VehicleApPowerStateReqIndex.STATE), 640 value.getInt32Value(VehicleApPowerStateReqIndex.ADDITIONAL)); 641 } 642 643 /** 644 * Determines if the current properties describe a valid power state 645 * @return true if both the power state request and power state report are valid 646 */ isPowerStateSupported()647 public boolean isPowerStateSupported() { 648 synchronized (mLock) { 649 return (mProperties.get(VehicleProperty.AP_POWER_STATE_REQ) != null) 650 && (mProperties.get(VehicleProperty.AP_POWER_STATE_REPORT) != null); 651 } 652 } 653 654 /** 655 * Returns if the vehicle is currently in use. 656 * 657 * In use means a human user is present in the vehicle and is currently using the vehicle or 658 * will use the vehicle soon. 659 */ isVehicleInUse()660 public boolean isVehicleInUse() { 661 try { 662 HalPropValue value = mHal.get(VEHICLE_IN_USE); 663 return (value.getStatus() == VehiclePropertyStatus.AVAILABLE 664 && value.getInt32ValuesSize() >= 1 && value.getInt32Value(0) != 0); 665 } catch (ServiceSpecificException | IllegalArgumentException e) { 666 Slogf.w(CarLog.TAG_POWER, 667 "Failed to get VEHICLE_IN_USE value, assume vehicle is in use", e); 668 return true; 669 } 670 } 671 672 /** 673 * Returns whether {@code VEHICLE_IN_USE} is supported and getting it returns a valid value. 674 */ isVehicleInUseSupported()675 public boolean isVehicleInUseSupported() { 676 try { 677 HalPropValue value = mHal.get(VEHICLE_IN_USE); 678 if (value.getStatus() != VehiclePropertyStatus.AVAILABLE) { 679 Slogf.w(CarLog.TAG_POWER, 680 "VEHICLE_IN_USE is supported in config but getting it returns a property " 681 + "value: " + value + " which does not contain AVAILABLE status"); 682 return false; 683 } 684 return true; 685 } catch (ServiceSpecificException | IllegalArgumentException e) { 686 Slogf.w(CarLog.TAG_POWER, "VEHICLE_IN_USE is not supported", e); 687 return false; 688 } 689 } 690 691 /** 692 * Returns whether {@code SHUTDOWN_REQUEST} is supported 693 */ isShutdownRequestSupported()694 public boolean isShutdownRequestSupported() { 695 return mHal.getPropConfig(SHUTDOWN_REQUEST) != null; 696 } 697 698 /** 699 * Gets the head unit's bootup reason. 700 * 701 * This reason is only set once during bootup and will not change if, say user enters the 702 * vehicle after the vehicle was booted up for remote access. 703 */ getVehicleApBootupReason()704 public @BootupReason int getVehicleApBootupReason() { 705 try { 706 HalPropValue value = mHal.get(AP_POWER_BOOTUP_REASON); 707 if (value.getStatus() != VehiclePropertyStatus.AVAILABLE) { 708 Slogf.w(CarLog.TAG_POWER, "AP_POWER_BOOTUP_REASON is not available"); 709 return BOOTUP_REASON_UNKNOWN; 710 } 711 if (value.getInt32ValuesSize() < 1) { 712 Slogf.w(CarLog.TAG_POWER, "Invalid AP_POWER_BOOTUP_REASON, no value"); 713 return BOOTUP_REASON_UNKNOWN; 714 } 715 switch (value.getInt32Value(0)) { 716 case VehicleApPowerBootupReason.USER_POWER_ON: 717 return BOOTUP_REASON_USER_POWER_ON; 718 case VehicleApPowerBootupReason.SYSTEM_USER_DETECTION: 719 return BOOTUP_REASON_SYSTEM_USER_DETECTION; 720 case VehicleApPowerBootupReason.SYSTEM_REMOTE_ACCESS: 721 return BOOTUP_REASON_SYSTEM_REMOTE_ACCESS; 722 case VehicleApPowerBootupReason.SYSTEM_ENTER_GARAGE_MODE: 723 return BOOTUP_REASON_SYSTEM_ENTER_GARAGE_MODE; 724 default: 725 return BOOTUP_REASON_UNKNOWN; 726 } 727 } catch (ServiceSpecificException | IllegalArgumentException e) { 728 Slogf.w(CarLog.TAG_POWER, "Failed to get AP_POWER_BOOTUP_REASON value", e); 729 } 730 return BOOTUP_REASON_UNKNOWN; 731 } 732 isConfigFlagSet(int flag)733 private boolean isConfigFlagSet(int flag) { 734 HalPropConfig config; 735 synchronized (mLock) { 736 config = mProperties.get(VehicleProperty.AP_POWER_STATE_REQ); 737 } 738 if (config == null) { 739 return false; 740 } 741 int[] configArray = config.getConfigArray(); 742 if (configArray.length < 1) { 743 return false; 744 } 745 return (configArray[0] & flag) != 0; 746 } 747 isDeepSleepAllowed()748 public boolean isDeepSleepAllowed() { 749 return isConfigFlagSet(VehicleApPowerStateConfigFlag.ENABLE_DEEP_SLEEP_FLAG); 750 } 751 isHibernationAllowed()752 public boolean isHibernationAllowed() { 753 return isConfigFlagSet(VehicleApPowerStateConfigFlag.ENABLE_HIBERNATION_FLAG); 754 } 755 isTimedWakeupAllowed()756 public boolean isTimedWakeupAllowed() { 757 return isConfigFlagSet(VehicleApPowerStateConfigFlag.CONFIG_SUPPORT_TIMER_POWER_ON_FLAG); 758 } 759 760 @Override init()761 public void init() { 762 synchronized (mLock) { 763 for (int i = 0; i < mProperties.size(); i++) { 764 int propId = mProperties.valueAt(i).getPropId(); 765 if (mProperties.contains(propId) 766 && SUPPORTED_PROPERTIES.get(propId).needSubscription) { 767 mHal.subscribeProperty(this, propId); 768 } 769 } 770 HalPropConfig brightnessProperty = mProperties.get(PER_DISPLAY_BRIGHTNESS); 771 mPerDisplayBrightnessSupported = brightnessProperty != null; 772 if (brightnessProperty == null) { 773 brightnessProperty = mProperties.get(DISPLAY_BRIGHTNESS); 774 } 775 if (brightnessProperty != null) { 776 HalAreaConfig[] areaConfigs = brightnessProperty.getAreaConfigs(); 777 mMaxDisplayBrightness = areaConfigs.length > 0 778 ? areaConfigs[0].getMaxInt32Value() : 0; 779 if (mMaxDisplayBrightness <= 0) { 780 Slogf.w(CarLog.TAG_POWER, "Max display brightness from vehicle HAL is invalid:" 781 + mMaxDisplayBrightness); 782 mMaxDisplayBrightness = 1; 783 } 784 785 if (mFeatureFlags.perDisplayMaxBrightness()) { 786 getMaxPerDisplayBrightnessFromVhalLocked(); 787 } 788 } 789 } 790 } 791 792 @GuardedBy("mLock") getMaxPerDisplayBrightnessFromVhalLocked()793 private void getMaxPerDisplayBrightnessFromVhalLocked() { 794 if (!mPerDisplayBrightnessSupported 795 || !mProperties.contains(PER_DISPLAY_MAX_BRIGHTNESS)) { 796 return; 797 } 798 799 try { 800 HalPropValue value = mHal.get(PER_DISPLAY_MAX_BRIGHTNESS); 801 for (int i = 0; i + 1 < value.getInt32ValuesSize(); i += 2) { 802 int displayPort = value.getInt32Value(i); 803 int maxDisplayBrightness = value.getInt32Value(i + 1); 804 if (maxDisplayBrightness <= 0) { 805 Slogf.w(CarLog.TAG_POWER, 806 "Max display brightness from vehicle HAL for display port: %d is " 807 + "invalid: %d", displayPort, maxDisplayBrightness); 808 maxDisplayBrightness = 1; 809 } 810 mMaxPerDisplayBrightness.put(displayPort, maxDisplayBrightness); 811 } 812 } catch (ServiceSpecificException e) { 813 Slogf.e(CarLog.TAG_POWER, "Cannot get PER_DISPLAY_MAX_BRIGHTNESS", e); 814 } 815 816 } 817 818 @Override release()819 public void release() { 820 synchronized (mLock) { 821 for (int i = 0; i < mProperties.size(); i++) { 822 int propId = mProperties.valueAt(i).getPropId(); 823 if (SUPPORTED_PROPERTIES.get(propId).needSubscription) { 824 mHal.unsubscribePropertySafe(this, propId); 825 } 826 } 827 mProperties.clear(); 828 } 829 mHandlerThread.quitSafely(); 830 } 831 832 @Override getAllSupportedProperties()833 public int[] getAllSupportedProperties() { 834 int[] propertyIds = new int[SUPPORTED_PROPERTIES.size()]; 835 for (int i = 0; i < SUPPORTED_PROPERTIES.size(); i++) { 836 propertyIds[i] = SUPPORTED_PROPERTIES.keyAt(i); 837 } 838 return propertyIds; 839 } 840 841 @Override takeProperties(Collection<HalPropConfig> properties)842 public void takeProperties(Collection<HalPropConfig> properties) { 843 if (properties.isEmpty()) { 844 return; 845 } 846 synchronized (mLock) { 847 for (HalPropConfig config : properties) { 848 mProperties.put(config.getPropId(), config); 849 } 850 } 851 } 852 853 @Override onHalEvents(List<HalPropValue> values)854 public void onHalEvents(List<HalPropValue> values) { 855 PowerEventListener listener; 856 synchronized (mLock) { 857 if (mListener == null) { 858 if (mQueuedEvents == null) { 859 mQueuedEvents = new ArrayList<>(values.size()); 860 } 861 mQueuedEvents.addAll(values); 862 return; 863 } 864 listener = mListener; 865 } 866 dispatchEvents(values, listener); 867 } 868 dispatchEvents(List<HalPropValue> values, PowerEventListener listener)869 private void dispatchEvents(List<HalPropValue> values, PowerEventListener listener) { 870 for (int i = 0; i < values.size(); i++) { 871 HalPropValue v = values.get(i); 872 switch (v.getPropId()) { 873 case AP_POWER_STATE_REPORT: 874 // Ignore this property event. It was generated inside of CarService. 875 break; 876 case AP_POWER_STATE_REQ: 877 int state; 878 int param; 879 try { 880 state = v.getInt32Value(VehicleApPowerStateReqIndex.STATE); 881 param = v.getInt32Value(VehicleApPowerStateReqIndex.ADDITIONAL); 882 } catch (IndexOutOfBoundsException e) { 883 Slogf.e(CarLog.TAG_POWER, "Received invalid event, ignore, int32Values: " 884 + v.dumpInt32Values(), e); 885 break; 886 } 887 Slogf.i(CarLog.TAG_POWER, "Received AP_POWER_STATE_REQ=" 888 + powerStateReqName(state) + " param=" + param); 889 listener.onApPowerStateChange(new PowerState(state, param)); 890 break; 891 case DISPLAY_BRIGHTNESS: 892 { 893 int maxBrightness; 894 synchronized (mLock) { 895 if (mPerDisplayBrightnessSupported) { 896 Slogf.w(CarLog.TAG_POWER, "Received DISPLAY_BRIGHTNESS " 897 + "while PER_DISPLAY_BRIGHTNESS is supported, ignore"); 898 return; 899 } 900 maxBrightness = mMaxDisplayBrightness; 901 } 902 int brightness; 903 try { 904 brightness = v.getInt32Value(0) * MAX_BRIGHTNESS / maxBrightness; 905 } catch (IndexOutOfBoundsException e) { 906 Slogf.e(CarLog.TAG_POWER, "Received invalid event, ignore, int32Values: " 907 + v.dumpInt32Values(), e); 908 break; 909 } 910 Slogf.i(CarLog.TAG_POWER, "Received DISPLAY_BRIGHTNESS=" + brightness); 911 912 brightness = adjustBrightness(brightness, /* minBrightness= */ 0, 913 MAX_BRIGHTNESS); 914 Slogf.i(CarLog.TAG_POWER, "brightness to system: " + brightness); 915 if (mFeatureFlags.multiDisplayBrightnessControl()) { 916 // DISPLAY_BRIGHNTESS represents the brightness for all displays. 917 onDisplayBrightnessChangeForAllDisplays(listener, brightness); 918 } else { 919 // If we have recently sent the same brightness to VHAL. This request is 920 // likely caused by that change and is duplicate. Ignore to prevent loop. 921 synchronized (mLock) { 922 if (hasRecentlySetBrightnessChangeLocked(brightness, 923 getDisplayPort(Display.DEFAULT_DISPLAY))) { 924 return; 925 } 926 } 927 928 // In legacy mode without per display brightness control, DISPLAY_BRIGHTNESS 929 // is assumed to control the default display's brightness. 930 listener.onDisplayBrightnessChange(brightness); 931 } 932 break; 933 } 934 case PER_DISPLAY_BRIGHTNESS: 935 { 936 int displayPort; 937 int brightness; 938 try { 939 displayPort = v.getInt32Value(0); 940 brightness = v.getInt32Value(1); 941 } catch (IndexOutOfBoundsException e) { 942 Slogf.e(CarLog.TAG_POWER, "Received invalid event, ignore, int32Values: " 943 + v.dumpInt32Values(), e); 944 break; 945 } 946 Slogf.i(CarLog.TAG_POWER, "Received PER_DISPLAY_BRIGHTNESS=" + brightness 947 + ", displayPort=" + displayPort); 948 949 // If we have recently sent the same brightness to VHAL. This request is likely 950 // caused by that change and is duplicate. Ignore to prevent loop. 951 synchronized (mLock) { 952 if (hasRecentlySetBrightnessChangeLocked(brightness, displayPort)) { 953 return; 954 } 955 } 956 957 int maxBrightness = getMaxPerDisplayBrightness(displayPort); 958 brightness = brightness * MAX_BRIGHTNESS / maxBrightness; 959 brightness = adjustBrightness(brightness, /* minBrightness= */ 0, 960 MAX_BRIGHTNESS); 961 int displayId = getDisplayId(displayPort); 962 Slogf.i(CarLog.TAG_POWER, "brightness to system: " + brightness 963 + ", displayId=" + displayId); 964 listener.onDisplayBrightnessChange(displayId, brightness); 965 break; 966 } 967 default: 968 Slogf.w(CarLog.TAG_POWER, "Received event with invalid property id: %d", 969 v.getPropId()); 970 break; 971 } 972 } 973 } 974 975 @GuardedBy("mLock") hasRecentlySetBrightnessChangeLocked(int brightness, int displayPort)976 private boolean hasRecentlySetBrightnessChangeLocked(int brightness, int displayPort) { 977 for (int i = 0; i < mRecentlySetBrightness.size(); i++) { 978 if (isSameBrightnessForDisplayPort(mRecentlySetBrightness.get(i), brightness, 979 displayPort)) { 980 Slogf.v(CarLog.TAG_POWER, "Ignore brightness change from VHAL, brightness=" 981 + brightness + ", displayPort=" + displayPort 982 + ", same as recently sent brightness to VHAL"); 983 return true; 984 } 985 } 986 return false; 987 } 988 989 @GuardedBy("mLock") addRecentlySetBrightnessChangeLocked(int brightness, int displayPort)990 private void addRecentlySetBrightnessChangeLocked(int brightness, int displayPort) { 991 mRecentlySetBrightness.add(new BrightnessForDisplayPort(brightness, displayPort)); 992 mHandler.postDelayed(() -> { 993 synchronized (mLock) { 994 mRecentlySetBrightness.removeFirst(); 995 } 996 }, PREVENT_LOOP_REQUEST_TIME_WINDOW_MS); 997 } 998 isSameBrightnessForDisplayPort(BrightnessForDisplayPort toCheck, int brightness, int displayPort)999 private boolean isSameBrightnessForDisplayPort(BrightnessForDisplayPort toCheck, 1000 int brightness, int displayPort) { 1001 return toCheck.brightness() == brightness && toCheck.displayPort() == displayPort; 1002 } 1003 getMaxPerDisplayBrightness(int displayPort)1004 private int getMaxPerDisplayBrightness(int displayPort) { 1005 synchronized (mLock) { 1006 return getMaxPerDisplayBrightnessLocked(displayPort); 1007 } 1008 } 1009 1010 @GuardedBy("mLock") getMaxPerDisplayBrightnessLocked(int displayPort)1011 private int getMaxPerDisplayBrightnessLocked(int displayPort) { 1012 int maxBrightness; 1013 if (!mFeatureFlags.perDisplayMaxBrightness() 1014 || mMaxPerDisplayBrightness.size() == 0) { 1015 maxBrightness = mMaxDisplayBrightness; 1016 } else { 1017 maxBrightness = mMaxPerDisplayBrightness.get(displayPort, 1018 /* valueIfKeyNotFound= */ 1); 1019 } 1020 return maxBrightness; 1021 } 1022 onDisplayBrightnessChangeForAllDisplays(PowerEventListener listener, int brightness)1023 private void onDisplayBrightnessChangeForAllDisplays(PowerEventListener listener, 1024 int brightness) { 1025 DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); 1026 for (Display display : displayManager.getDisplays()) { 1027 int displayId = display.getDisplayId(); 1028 int displayType = mDisplayHelper.getType(display); 1029 if (displayType == DisplayHelper.TYPE_VIRTUAL 1030 || displayType == DisplayHelper.TYPE_OVERLAY) { 1031 continue; 1032 } 1033 // If we have recently sent the same brightness to VHAL. This request is likely 1034 // caused by that change and is duplicate. Ignore to prevent loop. 1035 synchronized (mLock) { 1036 if (hasRecentlySetBrightnessChangeLocked(brightness, 1037 mDisplayHelper.getPhysicalPort(display))) { 1038 continue; 1039 } 1040 } 1041 listener.onDisplayBrightnessChange(displayId, brightness); 1042 } 1043 } 1044 getDisplayId(int displayPort)1045 private int getDisplayId(int displayPort) { 1046 DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); 1047 int displayId = Display.DEFAULT_DISPLAY; 1048 for (Display display : displayManager.getDisplays()) { 1049 if (displayPort == mDisplayHelper.getPhysicalPort(display)) { 1050 displayId = display.getDisplayId(); 1051 break; 1052 } 1053 } 1054 return displayId; 1055 } 1056 getDisplayPort(int displayId)1057 private int getDisplayPort(int displayId) { 1058 DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); 1059 Display display = displayManager.getDisplay(displayId); 1060 if (display != null) { 1061 int displayPort = mDisplayHelper.getPhysicalPort(display); 1062 if (displayPort != DisplayHelper.INVALID_PORT) { 1063 return displayPort; 1064 } 1065 } 1066 Slogf.w(CarLog.TAG_POWER, "cannot get display port from displayId = %d", 1067 displayId); 1068 return DisplayHelper.INVALID_PORT; 1069 } 1070 adjustBrightness(int brightness, int minBrightness, int maxBrightness)1071 private int adjustBrightness(int brightness, int minBrightness, int maxBrightness) { 1072 if (brightness < minBrightness) { 1073 Slogf.w(CarLog.TAG_POWER, "invalid brightness: %d, brightness is set to %d", brightness, 1074 minBrightness); 1075 brightness = minBrightness; 1076 } else if (brightness > maxBrightness) { 1077 Slogf.w(CarLog.TAG_POWER, "invalid brightness: %d, brightness is set to %d", brightness, 1078 maxBrightness); 1079 brightness = maxBrightness; 1080 } 1081 return brightness; 1082 } 1083 1084 @Override 1085 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(PrintWriter writer)1086 public void dump(PrintWriter writer) { 1087 writer.println("*Power HAL*"); 1088 writer.printf("isPowerStateSupported:%b, isDeepSleepAllowed:%b, isHibernationAllowed:%b\n", 1089 isPowerStateSupported(), isDeepSleepAllowed(), isHibernationAllowed()); 1090 1091 } 1092 } 1093