• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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