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 * 1000); 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 * 1000); 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 try { 271 mHal.set(VehicleProperty.DISPLAY_BRIGHTNESS, 0).to(brightness); 272 Log.i(CarLog.TAG_POWER, "send display brightness = " + brightness); 273 } catch (PropertyTimeoutException e) { 274 Log.e(CarLog.TAG_POWER, "cannot set DISPLAY_BRIGHTNESS", e); 275 } 276 } 277 setPowerState(int state, int additionalParam)278 private void setPowerState(int state, int additionalParam) { 279 if (isPowerStateSupported()) { 280 int[] values = { state, additionalParam }; 281 try { 282 mHal.set(VehicleProperty.AP_POWER_STATE_REPORT, 0).to(values); 283 Log.i(CarLog.TAG_POWER, "setPowerState=" + powerStateReportName(state) 284 + " param=" + additionalParam); 285 } catch (PropertyTimeoutException e) { 286 Log.e(CarLog.TAG_POWER, "cannot set to AP_POWER_STATE_REPORT", e); 287 } 288 } 289 } 290 291 @Nullable getCurrentPowerState()292 public PowerState getCurrentPowerState() { 293 int[] state; 294 try { 295 state = mHal.get(int[].class, VehicleProperty.AP_POWER_STATE_REQ); 296 } catch (PropertyTimeoutException e) { 297 Log.e(CarLog.TAG_POWER, "Cannot get AP_POWER_STATE_REQ", e); 298 return null; 299 } 300 return new PowerState(state[VehicleApPowerStateReqIndex.STATE], 301 state[VehicleApPowerStateReqIndex.ADDITIONAL]); 302 } 303 isPowerStateSupported()304 public synchronized boolean isPowerStateSupported() { 305 return (mProperties.get(VehicleProperty.AP_POWER_STATE_REQ) != null) 306 && (mProperties.get(VehicleProperty.AP_POWER_STATE_REPORT) != null); 307 } 308 isConfigFlagSet(int flag)309 private synchronized boolean isConfigFlagSet(int flag) { 310 VehiclePropConfig config = mProperties.get(VehicleProperty.AP_POWER_STATE_REQ); 311 if (config == null) { 312 return false; 313 } else if (config.configArray.size() < 1) { 314 return false; 315 } 316 return (config.configArray.get(0) & flag) != 0; 317 } 318 isDeepSleepAllowed()319 public boolean isDeepSleepAllowed() { 320 return isConfigFlagSet(VehicleApPowerStateConfigFlag.ENABLE_DEEP_SLEEP_FLAG); 321 } 322 isTimedWakeupAllowed()323 public boolean isTimedWakeupAllowed() { 324 return isConfigFlagSet(VehicleApPowerStateConfigFlag.CONFIG_SUPPORT_TIMER_POWER_ON_FLAG); 325 } 326 327 @Override init()328 public synchronized void init() { 329 for (VehiclePropConfig config : mProperties.values()) { 330 if (VehicleHal.isPropertySubscribable(config)) { 331 mHal.subscribeProperty(this, config.prop); 332 } 333 } 334 VehiclePropConfig brightnessProperty = mProperties.get(DISPLAY_BRIGHTNESS); 335 if (brightnessProperty != null) { 336 mMaxDisplayBrightness = brightnessProperty.areaConfigs.size() > 0 337 ? brightnessProperty.areaConfigs.get(0).maxInt32Value : 0; 338 if (mMaxDisplayBrightness <= 0) { 339 Log.w(CarLog.TAG_POWER, "Max display brightness from vehicle HAL is invalid:" + 340 mMaxDisplayBrightness); 341 mMaxDisplayBrightness = 1; 342 } 343 } 344 } 345 346 @Override release()347 public synchronized void release() { 348 mProperties.clear(); 349 } 350 351 @Override takeSupportedProperties( Collection<VehiclePropConfig> allProperties)352 public synchronized Collection<VehiclePropConfig> takeSupportedProperties( 353 Collection<VehiclePropConfig> allProperties) { 354 for (VehiclePropConfig config : allProperties) { 355 switch (config.prop) { 356 case AP_POWER_STATE_REQ: 357 case AP_POWER_STATE_REPORT: 358 case DISPLAY_BRIGHTNESS: 359 mProperties.put(config.prop, config); 360 break; 361 } 362 } 363 return new LinkedList<>(mProperties.values()); 364 } 365 366 @Override handleHalEvents(List<VehiclePropValue> values)367 public void handleHalEvents(List<VehiclePropValue> values) { 368 PowerEventListener listener; 369 synchronized (this) { 370 if (mListener == null) { 371 if (mQueuedEvents == null) { 372 mQueuedEvents = new LinkedList<>(); 373 } 374 mQueuedEvents.addAll(values); 375 return; 376 } 377 listener = mListener; 378 } 379 dispatchEvents(values, listener); 380 } 381 dispatchEvents(List<VehiclePropValue> values, PowerEventListener listener)382 private void dispatchEvents(List<VehiclePropValue> values, PowerEventListener listener) { 383 for (VehiclePropValue v : values) { 384 switch (v.prop) { 385 case AP_POWER_STATE_REPORT: 386 // Should never see this; write-only property 387 break; 388 case AP_POWER_STATE_REQ: 389 int state = v.value.int32Values.get(VehicleApPowerStateReqIndex.STATE); 390 int param = v.value.int32Values.get(VehicleApPowerStateReqIndex.ADDITIONAL); 391 Log.i(CarLog.TAG_POWER, "Received AP_POWER_STATE_REQ=" 392 + powerStateReqName(state) + " param=" + param); 393 listener.onApPowerStateChange(new PowerState(state, param)); 394 break; 395 case DISPLAY_BRIGHTNESS: 396 { 397 int maxBrightness; 398 synchronized (this) { 399 maxBrightness = mMaxDisplayBrightness; 400 } 401 int brightness = v.value.int32Values.get(0) * MAX_BRIGHTNESS / maxBrightness; 402 if (brightness < 0) { 403 Log.e(CarLog.TAG_POWER, "invalid brightness: " + brightness + ", set to 0"); 404 brightness = 0; 405 } else if (brightness > MAX_BRIGHTNESS) { 406 Log.e(CarLog.TAG_POWER, "invalid brightness: " + brightness + ", set to " 407 + MAX_BRIGHTNESS); 408 brightness = MAX_BRIGHTNESS; 409 } 410 Log.i(CarLog.TAG_POWER, "Received DISPLAY_BRIGHTNESS=" + brightness); 411 listener.onDisplayBrightnessChange(brightness); 412 } 413 break; 414 } 415 } 416 } 417 418 @Override dump(PrintWriter writer)419 public void dump(PrintWriter writer) { 420 writer.println("*Power HAL*"); 421 writer.println("isPowerStateSupported:" + isPowerStateSupported() + 422 ",isDeepSleepAllowed:" + isDeepSleepAllowed()); 423 } 424 } 425