• 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 static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
24 
25 import android.annotation.Nullable;
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.os.ServiceSpecificException;
35 import android.util.Slog;
36 
37 import com.android.car.CarLog;
38 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
39 import com.android.internal.annotations.GuardedBy;
40 import com.android.internal.annotations.VisibleForTesting;
41 
42 import java.io.PrintWriter;
43 import java.util.Collection;
44 import java.util.HashMap;
45 import java.util.LinkedList;
46 import java.util.List;
47 
48 /**
49  * Translates HAL power events to higher-level semantic information.
50  */
51 public class PowerHalService extends HalServiceBase {
52     // Set display brightness from 0-100%
53     public static final int MAX_BRIGHTNESS = 100;
54 
55     private static final int[] SUPPORTED_PROPERTIES = new int[]{
56             AP_POWER_STATE_REQ,
57             AP_POWER_STATE_REPORT,
58             DISPLAY_BRIGHTNESS
59     };
60 
61     @VisibleForTesting
62     public static final int SET_WAIT_FOR_VHAL = VehicleApPowerStateReport.WAIT_FOR_VHAL;
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_ON = VehicleApPowerStateReport.ON;
73     @VisibleForTesting
74     public static final int SET_SHUTDOWN_PREPARE = VehicleApPowerStateReport.SHUTDOWN_PREPARE;
75     @VisibleForTesting
76     public static final int SET_SHUTDOWN_CANCELLED = VehicleApPowerStateReport.SHUTDOWN_CANCELLED;
77 
78     @VisibleForTesting
79     public static final int SHUTDOWN_CAN_SLEEP = VehicleApPowerStateShutdownParam.CAN_SLEEP;
80     @VisibleForTesting
81     public static final int SHUTDOWN_IMMEDIATELY =
82             VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY;
83     @VisibleForTesting
84     public static final int SHUTDOWN_ONLY = VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY;
85 
86     private final Object mLock = new Object();
87 
powerStateReportName(int state)88     private static String powerStateReportName(int state) {
89         String baseName;
90         switch(state) {
91             case SET_WAIT_FOR_VHAL:      baseName = "WAIT_FOR_VHAL";      break;
92             case SET_DEEP_SLEEP_ENTRY:   baseName = "DEEP_SLEEP_ENTRY";   break;
93             case SET_DEEP_SLEEP_EXIT:    baseName = "DEEP_SLEEP_EXIT";    break;
94             case SET_SHUTDOWN_POSTPONE:  baseName = "SHUTDOWN_POSTPONE";  break;
95             case SET_SHUTDOWN_START:     baseName = "SHUTDOWN_START";     break;
96             case SET_ON:                 baseName = "ON";                 break;
97             case SET_SHUTDOWN_PREPARE:   baseName = "SHUTDOWN_PREPARE";   break;
98             case SET_SHUTDOWN_CANCELLED: baseName = "SHUTDOWN_CANCELLED"; break;
99             default:                     baseName = "<unknown>";          break;
100         }
101         return baseName + "(" + state + ")";
102     }
103 
powerStateReqName(int state)104     private static String powerStateReqName(int state) {
105         String baseName;
106         switch(state) {
107             case VehicleApPowerStateReq.ON:               baseName = "ON";               break;
108             case VehicleApPowerStateReq.SHUTDOWN_PREPARE: baseName = "SHUTDOWN_PREPARE"; break;
109             case VehicleApPowerStateReq.CANCEL_SHUTDOWN:  baseName = "CANCEL_SHUTDOWN";  break;
110             case VehicleApPowerStateReq.FINISHED:         baseName = "FINISHED";         break;
111             default:                                      baseName = "<unknown>";        break;
112         }
113         return baseName + "(" + state + ")";
114     }
115 
116     /**
117      * Interface to be implemented by any object that wants to be notified by any Vehicle's power
118      * change.
119      */
120     public interface PowerEventListener {
121         /**
122          * Received power state change event.
123          * @param state One of STATE_*
124          */
onApPowerStateChange(PowerState state)125         void onApPowerStateChange(PowerState state);
126 
127         /**
128          * Received display brightness change event.
129          * @param brightness in percentile. 100% full.
130          */
onDisplayBrightnessChange(int brightness)131         void onDisplayBrightnessChange(int brightness);
132     }
133 
134     /**
135      * Contains information about the Vehicle's power state.
136      */
137     public static final class PowerState {
138         /**
139          * One of STATE_*
140          */
141         public final int mState;
142         public final int mParam;
143 
PowerState(int state, int param)144         public PowerState(int state, int param) {
145             this.mState = state;
146             this.mParam = param;
147         }
148 
149         /**
150          * Whether the current PowerState allows deep sleep or not. Calling this for
151          * power state other than STATE_SHUTDOWN_PREPARE will trigger exception.
152          * @return
153          * @throws IllegalStateException
154          */
canEnterDeepSleep()155         public boolean canEnterDeepSleep() {
156             if (mState != VehicleApPowerStateReq.SHUTDOWN_PREPARE) {
157                 throw new IllegalStateException("wrong state");
158             }
159             return (mParam == VehicleApPowerStateShutdownParam.CAN_SLEEP
160                     || mParam == VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY);
161         }
162 
163         /**
164          * Whether the current PowerState allows postponing or not. Calling this for
165          * power state other than STATE_SHUTDOWN_PREPARE will trigger exception.
166          * @return
167          * @throws IllegalStateException
168          */
canPostponeShutdown()169         public boolean canPostponeShutdown() {
170             if (mState != VehicleApPowerStateReq.SHUTDOWN_PREPARE) {
171                 throw new IllegalStateException("wrong state");
172             }
173             return (mParam != VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY
174                     && mParam != VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY);
175         }
176 
177         @Override
equals(Object o)178         public boolean equals(Object o) {
179             if (this == o) {
180                 return true;
181             }
182             if (!(o instanceof PowerState)) {
183                 return false;
184             }
185             PowerState that = (PowerState) o;
186             return this.mState == that.mState && this.mParam == that.mParam;
187         }
188 
189         @Override
toString()190         public String toString() {
191             return "PowerState state:" + mState + ", param:" + mParam;
192         }
193     }
194 
195     @GuardedBy("mLock")
196     private final HashMap<Integer, VehiclePropConfig> mProperties = new HashMap<>();
197     private final VehicleHal mHal;
198     @GuardedBy("mLock")
199     private LinkedList<VehiclePropValue> mQueuedEvents;
200     @GuardedBy("mLock")
201     private PowerEventListener mListener;
202     @GuardedBy("mLock")
203     private int mMaxDisplayBrightness;
204 
PowerHalService(VehicleHal hal)205     public PowerHalService(VehicleHal hal) {
206         mHal = hal;
207     }
208 
209     /**
210      * Sets the event listener to receive Vehicle's power events.
211      */
setListener(PowerEventListener listener)212     public void setListener(PowerEventListener listener) {
213         LinkedList<VehiclePropValue> eventsToDispatch = null;
214         synchronized (mLock) {
215             mListener = listener;
216             if (mQueuedEvents != null && mQueuedEvents.size() > 0) {
217                 eventsToDispatch = mQueuedEvents;
218             }
219             mQueuedEvents = null;
220         }
221         // do this outside lock
222         if (eventsToDispatch != null) {
223             dispatchEvents(eventsToDispatch, listener);
224         }
225     }
226 
227     /**
228      * Send WaitForVhal message to VHAL
229      */
sendWaitForVhal()230     public void sendWaitForVhal() {
231         Slog.i(CarLog.TAG_POWER, "send wait for vhal");
232         setPowerState(VehicleApPowerStateReport.WAIT_FOR_VHAL, 0);
233     }
234 
235     /**
236      * Send SleepEntry message to VHAL
237      * @param wakeupTimeSec Notify VHAL when system wants to be woken from sleep.
238      */
sendSleepEntry(int wakeupTimeSec)239     public void sendSleepEntry(int wakeupTimeSec) {
240         Slog.i(CarLog.TAG_POWER, "send sleep entry");
241         setPowerState(VehicleApPowerStateReport.DEEP_SLEEP_ENTRY, wakeupTimeSec);
242     }
243 
244     /**
245      * Send SleepExit message to VHAL
246      * Notifies VHAL when SOC has woken.
247      */
sendSleepExit()248     public void sendSleepExit() {
249         Slog.i(CarLog.TAG_POWER, "send sleep exit");
250         setPowerState(VehicleApPowerStateReport.DEEP_SLEEP_EXIT, 0);
251     }
252 
253     /**
254      * Send Shutdown Postpone message to VHAL
255      */
sendShutdownPostpone(int postponeTimeMs)256     public void sendShutdownPostpone(int postponeTimeMs) {
257         Slog.i(CarLog.TAG_POWER, "send shutdown postpone, time:" + postponeTimeMs);
258         setPowerState(VehicleApPowerStateReport.SHUTDOWN_POSTPONE, postponeTimeMs);
259     }
260 
261     /**
262      * Send Shutdown Start message to VHAL
263      */
sendShutdownStart(int wakeupTimeSec)264     public void sendShutdownStart(int wakeupTimeSec) {
265         Slog.i(CarLog.TAG_POWER, "send shutdown start");
266         setPowerState(VehicleApPowerStateReport.SHUTDOWN_START, wakeupTimeSec);
267     }
268 
269     /**
270      * Send On message to VHAL
271      */
sendOn()272     public void sendOn() {
273         Slog.i(CarLog.TAG_POWER, "send on");
274         setPowerState(VehicleApPowerStateReport.ON, 0);
275     }
276 
277     /**
278      * Send Shutdown Prepare message to VHAL
279      */
sendShutdownPrepare()280     public void sendShutdownPrepare() {
281         Slog.i(CarLog.TAG_POWER, "send shutdown prepare");
282         setPowerState(VehicleApPowerStateReport.SHUTDOWN_PREPARE, 0);
283     }
284 
285     /**
286      * Send Shutdown Cancel message to VHAL
287      */
sendShutdownCancel()288     public void sendShutdownCancel() {
289         Slog.i(CarLog.TAG_POWER, "send shutdown cancel");
290         setPowerState(VehicleApPowerStateReport.SHUTDOWN_CANCELLED, 0);
291     }
292 
293     /**
294      * Sets the display brightness for the vehicle.
295      * @param brightness value from 0 to 100.
296      */
sendDisplayBrightness(int brightness)297     public void sendDisplayBrightness(int brightness) {
298         if (brightness < 0) {
299             brightness = 0;
300         } else if (brightness > 100) {
301             brightness = 100;
302         }
303         VehiclePropConfig prop = mProperties.get(DISPLAY_BRIGHTNESS);
304         if (prop == null) {
305             return;
306         }
307         try {
308             mHal.set(VehicleProperty.DISPLAY_BRIGHTNESS, 0).to(brightness);
309             Slog.i(CarLog.TAG_POWER, "send display brightness = " + brightness);
310         } catch (ServiceSpecificException | IllegalArgumentException e) {
311             Slog.e(CarLog.TAG_POWER, "cannot set DISPLAY_BRIGHTNESS", e);
312         }
313     }
314 
setPowerState(int state, int additionalParam)315     private void setPowerState(int state, int additionalParam) {
316         if (isPowerStateSupported()) {
317             int[] values = { state, additionalParam };
318             try {
319                 mHal.set(VehicleProperty.AP_POWER_STATE_REPORT, 0).to(values);
320                 Slog.i(CarLog.TAG_POWER, "setPowerState=" + powerStateReportName(state)
321                         + " param=" + additionalParam);
322             } catch (ServiceSpecificException e) {
323                 Slog.e(CarLog.TAG_POWER, "cannot set to AP_POWER_STATE_REPORT", e);
324             }
325         }
326     }
327 
328     /**
329      * Returns a {@link PowerState} representing the current power state for the vehicle.
330      */
331     @Nullable
getCurrentPowerState()332     public PowerState getCurrentPowerState() {
333         int[] state;
334         try {
335             state = mHal.get(int[].class, VehicleProperty.AP_POWER_STATE_REQ);
336         } catch (ServiceSpecificException e) {
337             Slog.e(CarLog.TAG_POWER, "Cannot get AP_POWER_STATE_REQ", e);
338             return null;
339         }
340         return new PowerState(state[VehicleApPowerStateReqIndex.STATE],
341                 state[VehicleApPowerStateReqIndex.ADDITIONAL]);
342     }
343 
344     /**
345      * Determines if the current properties describe a valid power state
346      * @return true if both the power state request and power state report are valid
347      */
isPowerStateSupported()348     public boolean isPowerStateSupported() {
349         synchronized (mLock) {
350             return (mProperties.get(VehicleProperty.AP_POWER_STATE_REQ) != null)
351                     && (mProperties.get(VehicleProperty.AP_POWER_STATE_REPORT) != null);
352         }
353     }
354 
isConfigFlagSet(int flag)355     private boolean isConfigFlagSet(int flag) {
356         VehiclePropConfig config;
357         synchronized (mLock) {
358             config = mProperties.get(VehicleProperty.AP_POWER_STATE_REQ);
359         }
360         if (config == null || config.configArray.size() < 1) {
361             return false;
362         }
363         return (config.configArray.get(0) & flag) != 0;
364     }
365 
isDeepSleepAllowed()366     public boolean isDeepSleepAllowed() {
367         return isConfigFlagSet(VehicleApPowerStateConfigFlag.ENABLE_DEEP_SLEEP_FLAG);
368     }
369 
isTimedWakeupAllowed()370     public boolean isTimedWakeupAllowed() {
371         return isConfigFlagSet(VehicleApPowerStateConfigFlag.CONFIG_SUPPORT_TIMER_POWER_ON_FLAG);
372     }
373 
374     @Override
init()375     public void init() {
376         synchronized (mLock) {
377             for (VehiclePropConfig config : mProperties.values()) {
378                 if (VehicleHal.isPropertySubscribable(config)) {
379                     mHal.subscribeProperty(this, config.prop);
380                 }
381             }
382             VehiclePropConfig brightnessProperty = mProperties.get(DISPLAY_BRIGHTNESS);
383             if (brightnessProperty != null) {
384                 mMaxDisplayBrightness = brightnessProperty.areaConfigs.size() > 0
385                         ? brightnessProperty.areaConfigs.get(0).maxInt32Value : 0;
386                 if (mMaxDisplayBrightness <= 0) {
387                     Slog.w(CarLog.TAG_POWER, "Max display brightness from vehicle HAL is invalid:"
388                             + mMaxDisplayBrightness);
389                     mMaxDisplayBrightness = 1;
390                 }
391             }
392         }
393     }
394 
395     @Override
release()396     public void release() {
397         synchronized (mLock) {
398             mProperties.clear();
399         }
400     }
401 
402     @Override
getAllSupportedProperties()403     public int[] getAllSupportedProperties() {
404         return SUPPORTED_PROPERTIES;
405     }
406 
407     @Override
takeProperties(Collection<VehiclePropConfig> properties)408     public void takeProperties(Collection<VehiclePropConfig> properties) {
409         if (properties.isEmpty()) {
410             return;
411         }
412         synchronized (mLock) {
413             for (VehiclePropConfig config : properties) {
414                 mProperties.put(config.prop, config);
415             }
416         }
417     }
418 
419     @Override
onHalEvents(List<VehiclePropValue> values)420     public void onHalEvents(List<VehiclePropValue> values) {
421         PowerEventListener listener;
422         synchronized (mLock) {
423             if (mListener == null) {
424                 if (mQueuedEvents == null) {
425                     mQueuedEvents = new LinkedList<>();
426                 }
427                 mQueuedEvents.addAll(values);
428                 return;
429             }
430             listener = mListener;
431         }
432         dispatchEvents(values, listener);
433     }
434 
dispatchEvents(List<VehiclePropValue> values, PowerEventListener listener)435     private void dispatchEvents(List<VehiclePropValue> values, PowerEventListener listener) {
436         for (VehiclePropValue v : values) {
437             switch (v.prop) {
438                 case AP_POWER_STATE_REPORT:
439                     // Ignore this property event. It was generated inside of CarService.
440                     break;
441                 case AP_POWER_STATE_REQ:
442                     int state = v.value.int32Values.get(VehicleApPowerStateReqIndex.STATE);
443                     int param = v.value.int32Values.get(VehicleApPowerStateReqIndex.ADDITIONAL);
444                     Slog.i(CarLog.TAG_POWER, "Received AP_POWER_STATE_REQ="
445                             + powerStateReqName(state) + " param=" + param);
446                     listener.onApPowerStateChange(new PowerState(state, param));
447                     break;
448                 case DISPLAY_BRIGHTNESS:
449                 {
450                     int maxBrightness;
451                     synchronized (mLock) {
452                         maxBrightness = mMaxDisplayBrightness;
453                     }
454                     int brightness = v.value.int32Values.get(0) * MAX_BRIGHTNESS / maxBrightness;
455                     if (brightness < 0) {
456                         Slog.e(CarLog.TAG_POWER, "invalid brightness: " + brightness
457                                 + ", set to 0");
458                         brightness = 0;
459                     } else if (brightness > MAX_BRIGHTNESS) {
460                         Slog.e(CarLog.TAG_POWER, "invalid brightness: " + brightness + ", set to "
461                                 + MAX_BRIGHTNESS);
462                         brightness = MAX_BRIGHTNESS;
463                     }
464                     Slog.i(CarLog.TAG_POWER, "Received DISPLAY_BRIGHTNESS=" + brightness);
465                     listener.onDisplayBrightnessChange(brightness);
466                 }
467                     break;
468             }
469         }
470     }
471 
472     @Override
473     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(PrintWriter writer)474     public void dump(PrintWriter writer) {
475         writer.println("*Power HAL*");
476         writer.printf("isPowerStateSupported:%b, isDeepSleepAllowed:%b\n",
477                 isPowerStateSupported(), isDeepSleepAllowed());
478     }
479 }
480