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