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