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