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 19 import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AP_POWER_STATE_REPORT; 20 import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AP_POWER_STATE_REQ; 21 import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.DISPLAY_BRIGHTNESS; 22 23 import android.annotation.Nullable; 24 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateConfigFlag; 25 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateReport; 26 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateReq; 27 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateReqIndex; 28 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateShutdownParam; 29 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig; 30 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 31 import android.hardware.automotive.vehicle.V2_0.VehicleProperty; 32 import android.util.Log; 33 34 import com.android.car.CarLog; 35 import com.android.internal.annotations.VisibleForTesting; 36 37 import java.io.PrintWriter; 38 import java.util.Collection; 39 import java.util.HashMap; 40 import java.util.LinkedList; 41 import java.util.List; 42 43 public class PowerHalService extends HalServiceBase { 44 // Set display brightness from 0-100% 45 public static final int MAX_BRIGHTNESS = 100; 46 47 @VisibleForTesting 48 public static final int SET_WAIT_FOR_VHAL = VehicleApPowerStateReport.WAIT_FOR_VHAL; 49 @VisibleForTesting 50 public static final int SET_DEEP_SLEEP_ENTRY = VehicleApPowerStateReport.DEEP_SLEEP_ENTRY; 51 @VisibleForTesting 52 public static final int SET_DEEP_SLEEP_EXIT = VehicleApPowerStateReport.DEEP_SLEEP_EXIT; 53 @VisibleForTesting 54 public static final int SET_SHUTDOWN_POSTPONE = VehicleApPowerStateReport.SHUTDOWN_POSTPONE; 55 @VisibleForTesting 56 public static final int SET_SHUTDOWN_START = VehicleApPowerStateReport.SHUTDOWN_START; 57 @VisibleForTesting 58 public static final int SET_ON = VehicleApPowerStateReport.ON; 59 @VisibleForTesting 60 public static final int SET_SHUTDOWN_PREPARE = VehicleApPowerStateReport.SHUTDOWN_PREPARE; 61 @VisibleForTesting 62 public static final int SET_SHUTDOWN_CANCELLED = VehicleApPowerStateReport.SHUTDOWN_CANCELLED; 63 64 @VisibleForTesting 65 public static final int SHUTDOWN_CAN_SLEEP = VehicleApPowerStateShutdownParam.CAN_SLEEP; 66 @VisibleForTesting 67 public static final int SHUTDOWN_IMMEDIATELY = 68 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY; 69 @VisibleForTesting 70 public static final int SHUTDOWN_ONLY = VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY; 71 powerStateReportName(int state)72 private static String powerStateReportName(int state) { 73 String baseName; 74 switch(state) { 75 case SET_WAIT_FOR_VHAL: baseName = "WAIT_FOR_VHAL"; break; 76 case SET_DEEP_SLEEP_ENTRY: baseName = "DEEP_SLEEP_ENTRY"; break; 77 case SET_DEEP_SLEEP_EXIT: baseName = "DEEP_SLEEP_EXIT"; break; 78 case SET_SHUTDOWN_POSTPONE: baseName = "SHUTDOWN_POSTPONE"; break; 79 case SET_SHUTDOWN_START: baseName = "SHUTDOWN_START"; break; 80 case SET_ON: baseName = "ON"; break; 81 case SET_SHUTDOWN_PREPARE: baseName = "SHUTDOWN_PREPARE"; break; 82 case SET_SHUTDOWN_CANCELLED: baseName = "SHUTDOWN_CANCELLED"; break; 83 default: baseName = "<unknown>"; break; 84 } 85 return baseName + "(" + state + ")"; 86 } 87 powerStateReqName(int state)88 private static String powerStateReqName(int state) { 89 String baseName; 90 switch(state) { 91 case VehicleApPowerStateReq.ON: baseName = "ON"; break; 92 case VehicleApPowerStateReq.SHUTDOWN_PREPARE: baseName = "SHUTDOWN_PREPARE"; break; 93 case VehicleApPowerStateReq.CANCEL_SHUTDOWN: baseName = "CANCEL_SHUTDOWN"; break; 94 case VehicleApPowerStateReq.FINISHED: baseName = "FINISHED"; break; 95 default: baseName = "<unknown>"; break; 96 } 97 return baseName + "(" + state + ")"; 98 } 99 100 public interface PowerEventListener { 101 /** 102 * Received power state change event. 103 * @param state One of STATE_* 104 */ onApPowerStateChange(PowerState state)105 void onApPowerStateChange(PowerState state); 106 /** 107 * Received display brightness change event. 108 * @param brightness in percentile. 100% full. 109 */ onDisplayBrightnessChange(int brightness)110 void onDisplayBrightnessChange(int brightness); 111 } 112 113 public static final class PowerState { 114 /** 115 * One of STATE_* 116 */ 117 public final int mState; 118 public final int mParam; 119 PowerState(int state, int param)120 public PowerState(int state, int param) { 121 this.mState = state; 122 this.mParam = param; 123 } 124 125 /** 126 * Whether the current PowerState allows deep sleep or not. Calling this for 127 * power state other than STATE_SHUTDOWN_PREPARE will trigger exception. 128 * @return 129 * @throws IllegalStateException 130 */ canEnterDeepSleep()131 public boolean canEnterDeepSleep() { 132 if (mState != VehicleApPowerStateReq.SHUTDOWN_PREPARE) { 133 throw new IllegalStateException("wrong state"); 134 } 135 return (mParam == VehicleApPowerStateShutdownParam.CAN_SLEEP); 136 } 137 138 /** 139 * Whether the current PowerState allows postponing or not. Calling this for 140 * power state other than STATE_SHUTDOWN_PREPARE will trigger exception. 141 * @return 142 * @throws IllegalStateException 143 */ canPostponeShutdown()144 public boolean canPostponeShutdown() { 145 if (mState != VehicleApPowerStateReq.SHUTDOWN_PREPARE) { 146 throw new IllegalStateException("wrong state"); 147 } 148 return (mParam != VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY); 149 } 150 151 @Override equals(Object o)152 public boolean equals(Object o) { 153 if (this == o) { 154 return true; 155 } 156 if (!(o instanceof PowerState)) { 157 return false; 158 } 159 PowerState that = (PowerState) o; 160 return this.mState == that.mState && this.mParam == that.mParam; 161 } 162 163 @Override toString()164 public String toString() { 165 return "PowerState state:" + mState + ", param:" + mParam; 166 } 167 } 168 169 private final HashMap<Integer, VehiclePropConfig> mProperties = new HashMap<>(); 170 private final VehicleHal mHal; 171 private LinkedList<VehiclePropValue> mQueuedEvents; 172 private PowerEventListener mListener; 173 private int mMaxDisplayBrightness; 174 PowerHalService(VehicleHal hal)175 public PowerHalService(VehicleHal hal) { 176 mHal = hal; 177 } 178 setListener(PowerEventListener listener)179 public void setListener(PowerEventListener listener) { 180 LinkedList<VehiclePropValue> eventsToDispatch = null; 181 synchronized (this) { 182 mListener = listener; 183 if (mQueuedEvents != null && mQueuedEvents.size() > 0) { 184 eventsToDispatch = mQueuedEvents; 185 } 186 mQueuedEvents = null; 187 } 188 // do this outside lock 189 if (eventsToDispatch != null) { 190 dispatchEvents(eventsToDispatch, listener); 191 } 192 } 193 194 /** 195 * Send WaitForVhal message to VHAL 196 */ sendWaitForVhal()197 public void sendWaitForVhal() { 198 Log.i(CarLog.TAG_POWER, "send wait for vhal"); 199 setPowerState(VehicleApPowerStateReport.WAIT_FOR_VHAL, 0); 200 } 201 202 /** 203 * Send SleepEntry message to VHAL 204 * @param wakeupTimeSec Notify VHAL when system wants to be woken from sleep. 205 */ sendSleepEntry(int wakeupTimeSec)206 public void sendSleepEntry(int wakeupTimeSec) { 207 Log.i(CarLog.TAG_POWER, "send sleep entry"); 208 setPowerState(VehicleApPowerStateReport.DEEP_SLEEP_ENTRY, wakeupTimeSec); 209 } 210 211 /** 212 * Send SleepExit message to VHAL 213 * Notifies VHAL when SOC has woken. 214 */ sendSleepExit()215 public void sendSleepExit() { 216 Log.i(CarLog.TAG_POWER, "send sleep exit"); 217 setPowerState(VehicleApPowerStateReport.DEEP_SLEEP_EXIT, 0); 218 } 219 220 /** 221 * Send Shutdown Postpone message to VHAL 222 */ sendShutdownPostpone(int postponeTimeMs)223 public void sendShutdownPostpone(int postponeTimeMs) { 224 Log.i(CarLog.TAG_POWER, "send shutdown postpone, time:" + postponeTimeMs); 225 setPowerState(VehicleApPowerStateReport.SHUTDOWN_POSTPONE, postponeTimeMs); 226 } 227 228 /** 229 * Send Shutdown Start message to VHAL 230 */ sendShutdownStart(int wakeupTimeSec)231 public void sendShutdownStart(int wakeupTimeSec) { 232 Log.i(CarLog.TAG_POWER, "send shutdown start"); 233 setPowerState(VehicleApPowerStateReport.SHUTDOWN_START, wakeupTimeSec); 234 } 235 236 /** 237 * Send On message to VHAL 238 */ sendOn()239 public void sendOn() { 240 Log.i(CarLog.TAG_POWER, "send on"); 241 setPowerState(VehicleApPowerStateReport.ON, 0); 242 } 243 244 /** 245 * Send Shutdown Prepare message to VHAL 246 */ sendShutdownPrepare()247 public void sendShutdownPrepare() { 248 Log.i(CarLog.TAG_POWER, "send shutdown prepare"); 249 setPowerState(VehicleApPowerStateReport.SHUTDOWN_PREPARE, 0); 250 } 251 252 /** 253 * Send Shutdown Cancel message to VHAL 254 */ sendShutdownCancel()255 public void sendShutdownCancel() { 256 Log.i(CarLog.TAG_POWER, "send shutdown cancel"); 257 setPowerState(VehicleApPowerStateReport.SHUTDOWN_CANCELLED, 0); 258 } 259 260 /** 261 * Sets the display brightness for the vehicle. 262 * @param brightness value from 0 to 100. 263 */ sendDisplayBrightness(int brightness)264 public void sendDisplayBrightness(int brightness) { 265 if (brightness < 0) { 266 brightness = 0; 267 } else if (brightness > 100) { 268 brightness = 100; 269 } 270 VehiclePropConfig prop = mProperties.get(DISPLAY_BRIGHTNESS); 271 if (prop == null) { 272 return; 273 } 274 try { 275 mHal.set(VehicleProperty.DISPLAY_BRIGHTNESS, 0).to(brightness); 276 Log.i(CarLog.TAG_POWER, "send display brightness = " + brightness); 277 } catch (PropertyTimeoutException e) { 278 Log.e(CarLog.TAG_POWER, "cannot set DISPLAY_BRIGHTNESS", e); 279 } 280 } 281 setPowerState(int state, int additionalParam)282 private void setPowerState(int state, int additionalParam) { 283 if (isPowerStateSupported()) { 284 int[] values = { state, additionalParam }; 285 try { 286 mHal.set(VehicleProperty.AP_POWER_STATE_REPORT, 0).to(values); 287 Log.i(CarLog.TAG_POWER, "setPowerState=" + powerStateReportName(state) 288 + " param=" + additionalParam); 289 } catch (PropertyTimeoutException e) { 290 Log.e(CarLog.TAG_POWER, "cannot set to AP_POWER_STATE_REPORT", e); 291 } 292 } 293 } 294 295 @Nullable getCurrentPowerState()296 public PowerState getCurrentPowerState() { 297 int[] state; 298 try { 299 state = mHal.get(int[].class, VehicleProperty.AP_POWER_STATE_REQ); 300 } catch (PropertyTimeoutException e) { 301 Log.e(CarLog.TAG_POWER, "Cannot get AP_POWER_STATE_REQ", e); 302 return null; 303 } 304 return new PowerState(state[VehicleApPowerStateReqIndex.STATE], 305 state[VehicleApPowerStateReqIndex.ADDITIONAL]); 306 } 307 isPowerStateSupported()308 public synchronized boolean isPowerStateSupported() { 309 return (mProperties.get(VehicleProperty.AP_POWER_STATE_REQ) != null) 310 && (mProperties.get(VehicleProperty.AP_POWER_STATE_REPORT) != null); 311 } 312 isConfigFlagSet(int flag)313 private synchronized boolean isConfigFlagSet(int flag) { 314 VehiclePropConfig config = mProperties.get(VehicleProperty.AP_POWER_STATE_REQ); 315 if (config == null) { 316 return false; 317 } else if (config.configArray.size() < 1) { 318 return false; 319 } 320 return (config.configArray.get(0) & flag) != 0; 321 } 322 isDeepSleepAllowed()323 public boolean isDeepSleepAllowed() { 324 return isConfigFlagSet(VehicleApPowerStateConfigFlag.ENABLE_DEEP_SLEEP_FLAG); 325 } 326 isTimedWakeupAllowed()327 public boolean isTimedWakeupAllowed() { 328 return isConfigFlagSet(VehicleApPowerStateConfigFlag.CONFIG_SUPPORT_TIMER_POWER_ON_FLAG); 329 } 330 331 @Override init()332 public synchronized void init() { 333 for (VehiclePropConfig config : mProperties.values()) { 334 if (VehicleHal.isPropertySubscribable(config)) { 335 mHal.subscribeProperty(this, config.prop); 336 } 337 } 338 VehiclePropConfig brightnessProperty = mProperties.get(DISPLAY_BRIGHTNESS); 339 if (brightnessProperty != null) { 340 mMaxDisplayBrightness = brightnessProperty.areaConfigs.size() > 0 341 ? brightnessProperty.areaConfigs.get(0).maxInt32Value : 0; 342 if (mMaxDisplayBrightness <= 0) { 343 Log.w(CarLog.TAG_POWER, "Max display brightness from vehicle HAL is invalid:" + 344 mMaxDisplayBrightness); 345 mMaxDisplayBrightness = 1; 346 } 347 } 348 } 349 350 @Override release()351 public synchronized void release() { 352 mProperties.clear(); 353 } 354 355 @Override takeSupportedProperties( Collection<VehiclePropConfig> allProperties)356 public synchronized Collection<VehiclePropConfig> takeSupportedProperties( 357 Collection<VehiclePropConfig> allProperties) { 358 for (VehiclePropConfig config : allProperties) { 359 switch (config.prop) { 360 case AP_POWER_STATE_REQ: 361 case AP_POWER_STATE_REPORT: 362 case DISPLAY_BRIGHTNESS: 363 mProperties.put(config.prop, config); 364 break; 365 } 366 } 367 return new LinkedList<>(mProperties.values()); 368 } 369 370 @Override handleHalEvents(List<VehiclePropValue> values)371 public void handleHalEvents(List<VehiclePropValue> values) { 372 PowerEventListener listener; 373 synchronized (this) { 374 if (mListener == null) { 375 if (mQueuedEvents == null) { 376 mQueuedEvents = new LinkedList<>(); 377 } 378 mQueuedEvents.addAll(values); 379 return; 380 } 381 listener = mListener; 382 } 383 dispatchEvents(values, listener); 384 } 385 dispatchEvents(List<VehiclePropValue> values, PowerEventListener listener)386 private void dispatchEvents(List<VehiclePropValue> values, PowerEventListener listener) { 387 for (VehiclePropValue v : values) { 388 switch (v.prop) { 389 case AP_POWER_STATE_REPORT: 390 // Ignore this property. It made inside of CarService. 391 break; 392 case AP_POWER_STATE_REQ: 393 int state = v.value.int32Values.get(VehicleApPowerStateReqIndex.STATE); 394 int param = v.value.int32Values.get(VehicleApPowerStateReqIndex.ADDITIONAL); 395 Log.i(CarLog.TAG_POWER, "Received AP_POWER_STATE_REQ=" 396 + powerStateReqName(state) + " param=" + param); 397 listener.onApPowerStateChange(new PowerState(state, param)); 398 break; 399 case DISPLAY_BRIGHTNESS: 400 { 401 int maxBrightness; 402 synchronized (this) { 403 maxBrightness = mMaxDisplayBrightness; 404 } 405 int brightness = v.value.int32Values.get(0) * MAX_BRIGHTNESS / maxBrightness; 406 if (brightness < 0) { 407 Log.e(CarLog.TAG_POWER, "invalid brightness: " + brightness + ", set to 0"); 408 brightness = 0; 409 } else if (brightness > MAX_BRIGHTNESS) { 410 Log.e(CarLog.TAG_POWER, "invalid brightness: " + brightness + ", set to " 411 + MAX_BRIGHTNESS); 412 brightness = MAX_BRIGHTNESS; 413 } 414 Log.i(CarLog.TAG_POWER, "Received DISPLAY_BRIGHTNESS=" + brightness); 415 listener.onDisplayBrightnessChange(brightness); 416 } 417 break; 418 } 419 } 420 } 421 422 @Override dump(PrintWriter writer)423 public void dump(PrintWriter writer) { 424 writer.println("*Power HAL*"); 425 writer.println("isPowerStateSupported:" + isPowerStateSupported() + 426 ",isDeepSleepAllowed:" + isDeepSleepAllowed()); 427 } 428 } 429