blob: ff43cfcae74d91a044bda0a5806cb5c98c3484cd [file] [log] [blame]
keunyoung4b0212c2015-10-29 17:11:57 -07001/*
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 */
16package com.android.car.hal;
17
Pavel Maltsev0d07c762016-11-03 16:40:15 -070018import static android.hardware.vehicle.V2_0.VehicleProperty.AP_POWER_STATE;
19import static android.hardware.vehicle.V2_0.VehicleProperty.DISPLAY_BRIGHTNESS;
20
21import android.annotation.Nullable;
22import android.hardware.vehicle.V2_0.VehicleApPowerSetState;
23import android.hardware.vehicle.V2_0.VehicleApPowerState;
24import android.hardware.vehicle.V2_0.VehicleApPowerStateConfigFlag;
25import android.hardware.vehicle.V2_0.VehicleApPowerStateIndex;
26import android.hardware.vehicle.V2_0.VehicleApPowerStateShutdownParam;
27import android.hardware.vehicle.V2_0.VehiclePropConfig;
28import android.hardware.vehicle.V2_0.VehiclePropValue;
29import android.hardware.vehicle.V2_0.VehicleProperty;
keunyoung4b0212c2015-10-29 17:11:57 -070030import android.util.Log;
31
32import com.android.car.CarLog;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080033import com.android.internal.annotations.VisibleForTesting;
keunyoung4b0212c2015-10-29 17:11:57 -070034
35import java.io.PrintWriter;
Pavel Maltsev0d07c762016-11-03 16:40:15 -070036import java.util.Collection;
keunyoung4b0212c2015-10-29 17:11:57 -070037import java.util.HashMap;
38import java.util.LinkedList;
39import java.util.List;
40
41public class PowerHalService extends HalServiceBase {
42
Pavel Maltsev0d07c762016-11-03 16:40:15 -070043 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;
keunyoung4b0212c2015-10-29 17:11:57 -070048
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080049 @VisibleForTesting
Pavel Maltsev0d07c762016-11-03 16:40:15 -070050 public static final int SET_BOOT_COMPLETE = VehicleApPowerSetState.BOOT_COMPLETE;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080051 @VisibleForTesting
Pavel Maltsev0d07c762016-11-03 16:40:15 -070052 public static final int SET_DEEP_SLEEP_ENTRY = VehicleApPowerSetState.DEEP_SLEEP_ENTRY;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080053 @VisibleForTesting
Pavel Maltsev0d07c762016-11-03 16:40:15 -070054 public static final int SET_DEEP_SLEEP_EXIT = VehicleApPowerSetState.DEEP_SLEEP_EXIT;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080055 @VisibleForTesting
Pavel Maltsev0d07c762016-11-03 16:40:15 -070056 public static final int SET_SHUTDOWN_POSTPONE = VehicleApPowerSetState.SHUTDOWN_POSTPONE;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080057 @VisibleForTesting
Pavel Maltsev0d07c762016-11-03 16:40:15 -070058 public static final int SET_SHUTDOWN_START = VehicleApPowerSetState.SHUTDOWN_START;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080059 @VisibleForTesting
Pavel Maltsev0d07c762016-11-03 16:40:15 -070060 public static final int SET_DISPLAY_ON = VehicleApPowerSetState.DISPLAY_ON;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080061 @VisibleForTesting
62 public static final int SET_DISPLAY_OFF =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070063 VehicleApPowerSetState.DISPLAY_OFF;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080064
65 @VisibleForTesting
66 public static final int FLAG_SHUTDOWN_PARAM_CAN_SLEEP =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070067 VehicleApPowerStateShutdownParam.CAN_SLEEP;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080068 @VisibleForTesting
69 public static final int FLAG_SHUTDOWN_IMMEDIATELY =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070070 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080071
keunyoung4b0212c2015-10-29 17:11:57 -070072 public interface PowerEventListener {
73 /**
74 * Received power state change event.
75 * @param state One of STATE_*
keunyoung4b0212c2015-10-29 17:11:57 -070076 */
77 void onApPowerStateChange(PowerState state);
78 /**
79 * Received display brightness change event.
80 * @param brightness in percentile. 100% full.
81 */
82 void onDisplayBrightnessChange(int brightness);
83 }
84
85 public static final class PowerState {
86 /**
87 * One of STATE_*
88 */
Pavel Maltsev0d07c762016-11-03 16:40:15 -070089 public final int mState;
90 public final int mParam;
keunyoung4b0212c2015-10-29 17:11:57 -070091
92 public PowerState(int state, int param) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -070093 this.mState = state;
94 this.mParam = param;
keunyoung4b0212c2015-10-29 17:11:57 -070095 }
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 */
103 public boolean canEnterDeepSleep() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700104 if (mState != STATE_SHUTDOWN_PREPARE) {
keunyoung4b0212c2015-10-29 17:11:57 -0700105 throw new IllegalStateException("wrong state");
106 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700107 return (mParam & VehicleApPowerStateShutdownParam.CAN_SLEEP) != 0;
keunyoung4b0212c2015-10-29 17:11:57 -0700108 }
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 */
116 public boolean canPostponeShutdown() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700117 if (mState != STATE_SHUTDOWN_PREPARE) {
keunyoung4b0212c2015-10-29 17:11:57 -0700118 throw new IllegalStateException("wrong state");
119 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700120 return (mParam & VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY) == 0;
keunyoung4b0212c2015-10-29 17:11:57 -0700121 }
122
123 @Override
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;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700132 return this.mState == that.mState && this.mParam == that.mParam;
keunyoung4b0212c2015-10-29 17:11:57 -0700133 }
134
135 @Override
136 public String toString() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700137 return "PowerState state:" + mState + ", param:" + mParam;
keunyoung4b0212c2015-10-29 17:11:57 -0700138 }
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
147 public PowerHalService(VehicleHal hal) {
148 mHal = hal;
149 }
150
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
166 public void sendBootComplete() {
167 Log.i(CarLog.TAG_POWER, "send boot complete");
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700168 setPowerState(VehicleApPowerSetState.BOOT_COMPLETE, 0);
keunyoung4b0212c2015-10-29 17:11:57 -0700169 }
170
171 public void sendSleepEntry() {
172 Log.i(CarLog.TAG_POWER, "send sleep entry");
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700173 setPowerState(VehicleApPowerSetState.DEEP_SLEEP_ENTRY, 0);
keunyoung4b0212c2015-10-29 17:11:57 -0700174 }
175
176 public void sendSleepExit() {
177 Log.i(CarLog.TAG_POWER, "send sleep exit");
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700178 setPowerState(VehicleApPowerSetState.DEEP_SLEEP_EXIT, 0);
keunyoung4b0212c2015-10-29 17:11:57 -0700179 }
180
181 public void sendShutdownPostpone(int postponeTimeMs) {
182 Log.i(CarLog.TAG_POWER, "send shutdown postpone, time:" + postponeTimeMs);
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700183 setPowerState(VehicleApPowerSetState.SHUTDOWN_POSTPONE,
Keun-young Parke78bf532016-04-25 18:59:22 -0700184 postponeTimeMs);
keunyoung4b0212c2015-10-29 17:11:57 -0700185 }
186
187 public void sendShutdownStart(int wakeupTimeSec) {
188 Log.i(CarLog.TAG_POWER, "send shutdown start");
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700189 setPowerState(VehicleApPowerSetState.SHUTDOWN_START, 0);
keunyoung4b0212c2015-10-29 17:11:57 -0700190 }
191
192 public void sendDisplayOn() {
193 Log.i(CarLog.TAG_POWER, "send display on");
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700194 setPowerState(VehicleApPowerSetState.DISPLAY_ON, 0);
keunyoung4b0212c2015-10-29 17:11:57 -0700195 }
196
197 public void sendDisplayOff() {
198 Log.i(CarLog.TAG_POWER, "send display off");
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700199 setPowerState(VehicleApPowerSetState.DISPLAY_OFF, 0);
Keun-young Parke78bf532016-04-25 18:59:22 -0700200 }
201
202 private void setPowerState(int state, int additionalParam) {
203 int[] values = { state, additionalParam };
204 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700205 mHal.set(VehicleProperty.AP_POWER_STATE).to(values);
206 } catch (PropertyTimeoutException e) {
Keun-young Parke78bf532016-04-25 18:59:22 -0700207 Log.e(CarLog.TAG_POWER, "cannot set to AP_POWER_STATE", e);
208 }
keunyoung4b0212c2015-10-29 17:11:57 -0700209 }
210
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700211 @Nullable
keunyoung4b0212c2015-10-29 17:11:57 -0700212 public PowerState getCurrentPowerState() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700213 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]);
keunyoung4b0212c2015-10-29 17:11:57 -0700222 }
223
224 public synchronized boolean isPowerStateSupported() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700225 VehiclePropConfig config = mProperties.get(VehicleProperty.AP_POWER_STATE);
keunyoung4b0212c2015-10-29 17:11:57 -0700226 return config != null;
227 }
228
229 public synchronized boolean isDeepSleepAllowed() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700230 VehiclePropConfig config = mProperties.get(VehicleProperty.AP_POWER_STATE);
keunyoung4b0212c2015-10-29 17:11:57 -0700231 if (config == null) {
232 return false;
233 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700234 return (config.configArray.get(0)
235 & VehicleApPowerStateConfigFlag.ENABLE_DEEP_SLEEP_FLAG) != 0;
keunyoung4b0212c2015-10-29 17:11:57 -0700236 }
237
238 public synchronized boolean isTimedWakeupAllowed() {
239 VehiclePropConfig config = mProperties.get(
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700240 AP_POWER_STATE);
keunyoung4b0212c2015-10-29 17:11:57 -0700241 if (config == null) {
242 return false;
243 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700244 return (config.configArray.get(0)
245 & VehicleApPowerStateConfigFlag.CONFIG_SUPPORT_TIMER_POWER_ON_FLAG) != 0;
keunyoung4b0212c2015-10-29 17:11:57 -0700246 }
247
248 @Override
249 public synchronized void init() {
250 for (VehiclePropConfig config : mProperties.values()) {
251 if (VehicleHal.isPropertySubscribable(config)) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700252 mHal.subscribeProperty(this, config.prop, 0);
keunyoung4b0212c2015-10-29 17:11:57 -0700253 }
254 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700255 VehiclePropConfig brightnessProperty = mProperties.get(DISPLAY_BRIGHTNESS);
keunyoung4b0212c2015-10-29 17:11:57 -0700256 if (brightnessProperty != null) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700257 mMaxDisplayBrightness = brightnessProperty.areaConfigs.size() > 0
258 ? brightnessProperty.areaConfigs.get(0).maxInt32Value : 0;
keunyoung4b0212c2015-10-29 17:11:57 -0700259 if (mMaxDisplayBrightness <= 0) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700260 Log.w(CarLog.TAG_POWER, "Max display brightness from vehicle HAL is invalid:" +
keunyoung4b0212c2015-10-29 17:11:57 -0700261 mMaxDisplayBrightness);
262 mMaxDisplayBrightness = 1;
263 }
264 }
265 }
266
267 @Override
268 public synchronized void release() {
269 mProperties.clear();
270 }
271
272 @Override
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700273 public synchronized Collection<VehiclePropConfig> takeSupportedProperties(
274 Collection<VehiclePropConfig> allProperties) {
keunyoung4b0212c2015-10-29 17:11:57 -0700275 for (VehiclePropConfig config : allProperties) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700276 switch (config.prop) {
277 case AP_POWER_STATE:
278 case DISPLAY_BRIGHTNESS:
279 mProperties.put(config.prop, config);
keunyoung4b0212c2015-10-29 17:11:57 -0700280 break;
281 }
282 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700283 return new LinkedList<>(mProperties.values());
keunyoung4b0212c2015-10-29 17:11:57 -0700284 }
285
286 @Override
287 public void handleHalEvents(List<VehiclePropValue> values) {
288 PowerEventListener listener;
289 synchronized (this) {
290 if (mListener == null) {
291 if (mQueuedEvents == null) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700292 mQueuedEvents = new LinkedList<>();
keunyoung4b0212c2015-10-29 17:11:57 -0700293 }
294 mQueuedEvents.addAll(values);
295 return;
296 }
297 listener = mListener;
298 }
299 dispatchEvents(values, listener);
300 }
301
302 private void dispatchEvents(List<VehiclePropValue> values, PowerEventListener listener) {
303 for (VehiclePropValue v : values) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700304 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));
keunyoung4b0212c2015-10-29 17:11:57 -0700309 break;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700310 case DISPLAY_BRIGHTNESS:
keunyoung4b0212c2015-10-29 17:11:57 -0700311 int maxBrightness;
312 synchronized (this) {
313 maxBrightness = mMaxDisplayBrightness;
314 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700315 listener.onDisplayBrightnessChange(
316 (v.value.int32Values.get(0) * 100) / maxBrightness);
keunyoung4b0212c2015-10-29 17:11:57 -0700317 break;
318 }
319 }
320 }
321
322 @Override
323 public void dump(PrintWriter writer) {
Keun-young Parka28d7b22016-02-29 16:54:29 -0800324 writer.println("*Power HAL*");
325 writer.println("isPowerStateSupported:" + isPowerStateSupported() +
326 ",isDeepSleepAllowed:" + isDeepSleepAllowed());
keunyoung4b0212c2015-10-29 17:11:57 -0700327 }
328}