• 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 import static android.hardware.automotive.vehicle.VehicleProperty.AP_POWER_STATE_REPORT;
19 import static android.hardware.automotive.vehicle.VehicleProperty.AP_POWER_STATE_REQ;
20 import static android.hardware.automotive.vehicle.VehicleProperty.DISPLAY_BRIGHTNESS;
21 import static android.hardware.automotive.vehicle.VehicleProperty.PER_DISPLAY_BRIGHTNESS;
22 import static android.hardware.automotive.vehicle.VehicleProperty.VEHICLE_IN_USE;
23 
24 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
25 
26 import android.annotation.IntDef;
27 import android.annotation.Nullable;
28 import android.car.builtin.util.Slogf;
29 import android.car.builtin.view.DisplayHelper;
30 import android.content.Context;
31 import android.hardware.automotive.vehicle.VehicleApPowerStateConfigFlag;
32 import android.hardware.automotive.vehicle.VehicleApPowerStateReport;
33 import android.hardware.automotive.vehicle.VehicleApPowerStateReq;
34 import android.hardware.automotive.vehicle.VehicleApPowerStateReqIndex;
35 import android.hardware.automotive.vehicle.VehicleApPowerStateShutdownParam;
36 import android.hardware.automotive.vehicle.VehicleProperty;
37 import android.hardware.automotive.vehicle.VehiclePropertyStatus;
38 import android.hardware.display.DisplayManager;
39 import android.os.ServiceSpecificException;
40 import android.util.SparseArray;
41 import android.view.Display;
42 
43 import com.android.car.CarLog;
44 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
45 import com.android.internal.annotations.GuardedBy;
46 import com.android.internal.annotations.VisibleForTesting;
47 import com.android.internal.util.Preconditions;
48 
49 import java.io.PrintWriter;
50 import java.lang.annotation.Retention;
51 import java.lang.annotation.RetentionPolicy;
52 import java.util.ArrayList;
53 import java.util.Collection;
54 import java.util.List;
55 import java.util.Objects;
56 
57 /**
58  * Translates HAL power events to higher-level semantic information.
59  */
60 public class PowerHalService extends HalServiceBase {
61     // Set display brightness from 0-100%
62     public static final int MAX_BRIGHTNESS = 100;
63 
64     private static final int[] SUPPORTED_PROPERTIES = new int[]{
65             AP_POWER_STATE_REQ,
66             AP_POWER_STATE_REPORT,
67             DISPLAY_BRIGHTNESS,
68             PER_DISPLAY_BRIGHTNESS,
69             VEHICLE_IN_USE,
70     };
71 
72     @VisibleForTesting
73     public static final int SET_WAIT_FOR_VHAL = VehicleApPowerStateReport.WAIT_FOR_VHAL;
74     @VisibleForTesting
75     public static final int SET_DEEP_SLEEP_ENTRY = VehicleApPowerStateReport.DEEP_SLEEP_ENTRY;
76     @VisibleForTesting
77     public static final int SET_DEEP_SLEEP_EXIT = VehicleApPowerStateReport.DEEP_SLEEP_EXIT;
78     @VisibleForTesting
79     public static final int SET_SHUTDOWN_POSTPONE = VehicleApPowerStateReport.SHUTDOWN_POSTPONE;
80     @VisibleForTesting
81     public static final int SET_SHUTDOWN_START = VehicleApPowerStateReport.SHUTDOWN_START;
82     @VisibleForTesting
83     public static final int SET_ON = VehicleApPowerStateReport.ON;
84     @VisibleForTesting
85     public static final int SET_SHUTDOWN_PREPARE = VehicleApPowerStateReport.SHUTDOWN_PREPARE;
86     @VisibleForTesting
87     public static final int SET_SHUTDOWN_CANCELLED = VehicleApPowerStateReport.SHUTDOWN_CANCELLED;
88 
89     @VisibleForTesting
90     public static final int SHUTDOWN_CAN_SLEEP = VehicleApPowerStateShutdownParam.CAN_SLEEP;
91     @VisibleForTesting
92     public static final int SHUTDOWN_IMMEDIATELY =
93             VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY;
94     @VisibleForTesting
95     public static final int SHUTDOWN_ONLY = VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY;
96     @VisibleForTesting
97     public static final int SET_HIBERNATION_ENTRY = VehicleApPowerStateReport.HIBERNATION_ENTRY;
98     @VisibleForTesting
99     public static final int SET_HIBERNATION_EXIT = VehicleApPowerStateReport.HIBERNATION_EXIT;
100 
101     private final Object mLock = new Object();
102 
powerStateReportName(int state)103     private static String powerStateReportName(int state) {
104         String baseName;
105         switch(state) {
106             case SET_WAIT_FOR_VHAL:      baseName = "WAIT_FOR_VHAL";      break;
107             case SET_DEEP_SLEEP_ENTRY:   baseName = "DEEP_SLEEP_ENTRY";   break;
108             case SET_DEEP_SLEEP_EXIT:    baseName = "DEEP_SLEEP_EXIT";    break;
109             case SET_SHUTDOWN_POSTPONE:  baseName = "SHUTDOWN_POSTPONE";  break;
110             case SET_SHUTDOWN_START:     baseName = "SHUTDOWN_START";     break;
111             case SET_ON:                 baseName = "ON";                 break;
112             case SET_SHUTDOWN_PREPARE:   baseName = "SHUTDOWN_PREPARE";   break;
113             case SET_SHUTDOWN_CANCELLED: baseName = "SHUTDOWN_CANCELLED"; break;
114             case SET_HIBERNATION_ENTRY:  baseName = "HIBERNATION_ENTRY";  break;
115             case SET_HIBERNATION_EXIT:   baseName = "HIBERNATION_EXIT";   break;
116             default:                     baseName = "<unknown>";          break;
117         }
118         return baseName + "(" + state + ")";
119     }
120 
powerStateReqName(int state)121     private static String powerStateReqName(int state) {
122         String baseName;
123         switch(state) {
124             case VehicleApPowerStateReq.ON:               baseName = "ON";               break;
125             case VehicleApPowerStateReq.SHUTDOWN_PREPARE: baseName = "SHUTDOWN_PREPARE"; break;
126             case VehicleApPowerStateReq.CANCEL_SHUTDOWN:  baseName = "CANCEL_SHUTDOWN";  break;
127             case VehicleApPowerStateReq.FINISHED:         baseName = "FINISHED";         break;
128             default:                                      baseName = "<unknown>";        break;
129         }
130         return baseName + "(" + state + ")";
131     }
132 
133     /**
134      * Interface to be implemented by any object that wants to be notified by any Vehicle's power
135      * change.
136      */
137     public interface PowerEventListener {
138         /**
139          * Received power state change event.
140          * @param state One of STATE_*
141          */
onApPowerStateChange(PowerState state)142         void onApPowerStateChange(PowerState state);
143 
144         /**
145          * Received display brightness change event.
146          * @param brightness in percentile. 100% full.
147          */
onDisplayBrightnessChange(int brightness)148         void onDisplayBrightnessChange(int brightness);
149 
150         /**
151          * Received display brightness change event.
152          * @param displayId the display id.
153          * @param brightness in percentile. 100% full.
154          */
onDisplayBrightnessChange(int displayId, int brightness)155         void onDisplayBrightnessChange(int displayId, int brightness);
156     }
157 
158     /**
159      * Contains information about the Vehicle's power state.
160      */
161     public static final class PowerState {
162 
163         @IntDef({SHUTDOWN_TYPE_UNDEFINED, SHUTDOWN_TYPE_POWER_OFF, SHUTDOWN_TYPE_DEEP_SLEEP,
164                 SHUTDOWN_TYPE_HIBERNATION})
165         @Retention(RetentionPolicy.SOURCE)
166         public @interface ShutdownType {}
167 
168         public static final int SHUTDOWN_TYPE_UNDEFINED = 0;
169         public static final int SHUTDOWN_TYPE_POWER_OFF = 1;
170         public static final int SHUTDOWN_TYPE_DEEP_SLEEP = 2;
171         public static final int SHUTDOWN_TYPE_HIBERNATION = 3;
172         /**
173          * One of STATE_*
174          */
175         public final int mState;
176         public final int mParam;
177 
PowerState(int state, int param)178         public PowerState(int state, int param) {
179             this.mState = state;
180             this.mParam = param;
181         }
182 
183         /**
184          * Whether the current PowerState allows postponing or not. Calling this for
185          * power state other than STATE_SHUTDOWN_PREPARE will trigger exception.
186          * @return
187          * @throws IllegalStateException
188          */
canPostponeShutdown()189         public boolean canPostponeShutdown() {
190             if (mState != VehicleApPowerStateReq.SHUTDOWN_PREPARE) {
191                 throw new IllegalStateException("wrong state");
192             }
193             return (mParam != VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY
194                     && mParam != VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY
195                     && mParam != VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY);
196         }
197 
198         /**
199          * Gets whether the current PowerState allows suspend or not.
200          *
201          * @throws IllegalStateException if called in state other than {@code
202          * STATE_SHUTDOWN_PREPARE}
203          */
canSuspend()204         public boolean canSuspend() {
205             Preconditions.checkArgument(mState == VehicleApPowerStateReq.SHUTDOWN_PREPARE,
206                     "canSuspend was called in the wrong state! State = %d", mState);
207 
208             return (mParam == VehicleApPowerStateShutdownParam.CAN_HIBERNATE
209                     || mParam == VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY
210                     || mParam == VehicleApPowerStateShutdownParam.CAN_SLEEP
211                     || mParam == VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY);
212         }
213 
214         /**
215          * Gets shutdown type
216          *
217          * @return {@code ShutdownType} - type of shutdown
218          * @throws IllegalStateException if called in state other than {@code
219          * STATE_SHUTDOWN_PREPARE}
220          */
221         @ShutdownType
getShutdownType()222         public int getShutdownType() {
223             Preconditions.checkArgument(mState == VehicleApPowerStateReq.SHUTDOWN_PREPARE,
224                     "getShutdownType was called in the wrong state! State = %d", mState);
225 
226             int result = SHUTDOWN_TYPE_POWER_OFF;
227             if (mParam == VehicleApPowerStateShutdownParam.CAN_SLEEP
228                     || mParam == VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY) {
229                 result = SHUTDOWN_TYPE_DEEP_SLEEP;
230             } else if (mParam == VehicleApPowerStateShutdownParam.CAN_HIBERNATE
231                     || mParam == VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY) {
232                 result = SHUTDOWN_TYPE_HIBERNATION;
233             }
234 
235             return result;
236         }
237 
238         @Override
equals(Object o)239         public boolean equals(Object o) {
240             if (this == o) {
241                 return true;
242             }
243             if (!(o instanceof PowerState)) {
244                 return false;
245             }
246             PowerState that = (PowerState) o;
247             return this.mState == that.mState && this.mParam == that.mParam;
248         }
249 
250         @Override
hashCode()251         public int hashCode() {
252             return Objects.hash(mState, mParam);
253         }
254 
255         @Override
toString()256         public String toString() {
257             return "PowerState state:" + mState + ", param:" + mParam;
258         }
259     }
260 
261     @GuardedBy("mLock")
262     private final SparseArray<HalPropConfig> mProperties = new SparseArray<>();
263     private final Context mContext;
264     private final VehicleHal mHal;
265     @Nullable
266     @GuardedBy("mLock")
267     private ArrayList<HalPropValue> mQueuedEvents;
268     @GuardedBy("mLock")
269     private PowerEventListener mListener;
270     @GuardedBy("mLock")
271     private int mMaxDisplayBrightness;
272     @GuardedBy("mLock")
273     private boolean mPerDisplayBrightnessSupported;
274 
PowerHalService(Context context, VehicleHal hal)275     public PowerHalService(Context context, VehicleHal hal) {
276         mContext = context;
277         mHal = hal;
278     }
279 
280     /**
281      * Sets the event listener to receive Vehicle's power events.
282      */
setListener(PowerEventListener listener)283     public void setListener(PowerEventListener listener) {
284         ArrayList<HalPropValue> eventsToDispatch = null;
285         synchronized (mLock) {
286             mListener = listener;
287             if (mQueuedEvents != null && !mQueuedEvents.isEmpty()) {
288                 eventsToDispatch = mQueuedEvents;
289             }
290             mQueuedEvents = null;
291         }
292         // do this outside lock
293         if (eventsToDispatch != null) {
294             dispatchEvents(eventsToDispatch, listener);
295         }
296     }
297 
298     /**
299      * Send WaitForVhal message to VHAL
300      */
sendWaitForVhal()301     public void sendWaitForVhal() {
302         Slogf.i(CarLog.TAG_POWER, "send wait for vhal");
303         setPowerState(VehicleApPowerStateReport.WAIT_FOR_VHAL, 0);
304     }
305 
306     /**
307      * Send SleepEntry message to VHAL
308      * @param wakeupTimeSec Notify VHAL when system wants to be woken from sleep.
309      */
sendSleepEntry(int wakeupTimeSec)310     public void sendSleepEntry(int wakeupTimeSec) {
311         Slogf.i(CarLog.TAG_POWER, "send sleep entry");
312         setPowerState(VehicleApPowerStateReport.DEEP_SLEEP_ENTRY, wakeupTimeSec);
313     }
314 
315     /**
316      * Send SleepExit message to VHAL
317      * Notifies VHAL when SOC has woken.
318      */
sendSleepExit()319     public void sendSleepExit() {
320         Slogf.i(CarLog.TAG_POWER, "send sleep exit");
321         setPowerState(VehicleApPowerStateReport.DEEP_SLEEP_EXIT, 0);
322     }
323 
324     /**
325      * Sends HibernationEntry message to VHAL
326      *
327      * @param wakeupTimeSec Number of seconds from now to be woken from sleep.
328      */
sendHibernationEntry(int wakeupTimeSec)329     public void sendHibernationEntry(int wakeupTimeSec) {
330         Slogf.i(CarLog.TAG_POWER, "send hibernation entry - wakeupTimeSec = %d",
331                 wakeupTimeSec);
332         setPowerState(VehicleApPowerStateReport.HIBERNATION_ENTRY, wakeupTimeSec);
333     }
334 
335     /**
336      * Sends HibernationExit message to VHAL
337      *
338      * Notifies VHAL after SOC woke up from hibernation.
339      */
sendHibernationExit()340     public void sendHibernationExit() {
341         Slogf.i(CarLog.TAG_POWER, "send hibernation exit");
342         setPowerState(VehicleApPowerStateReport.HIBERNATION_EXIT, 0);
343     }
344 
345     /**
346      * Send Shutdown Postpone message to VHAL
347      */
sendShutdownPostpone(int postponeTimeMs)348     public void sendShutdownPostpone(int postponeTimeMs) {
349         Slogf.i(CarLog.TAG_POWER, "send shutdown postpone, time:" + postponeTimeMs);
350         setPowerState(VehicleApPowerStateReport.SHUTDOWN_POSTPONE, postponeTimeMs);
351     }
352 
353     /**
354      * Send Shutdown Start message to VHAL
355      */
sendShutdownStart(int wakeupTimeSec)356     public void sendShutdownStart(int wakeupTimeSec) {
357         Slogf.i(CarLog.TAG_POWER, "send shutdown start");
358         setPowerState(VehicleApPowerStateReport.SHUTDOWN_START, wakeupTimeSec);
359     }
360 
361     /**
362      * Send On message to VHAL
363      */
sendOn()364     public void sendOn() {
365         Slogf.i(CarLog.TAG_POWER, "send on");
366         setPowerState(VehicleApPowerStateReport.ON, 0);
367     }
368 
369     /**
370      * Send Shutdown Prepare message to VHAL
371      */
sendShutdownPrepare()372     public void sendShutdownPrepare() {
373         Slogf.i(CarLog.TAG_POWER, "send shutdown prepare");
374         setPowerState(VehicleApPowerStateReport.SHUTDOWN_PREPARE, 0);
375     }
376 
377     /**
378      * Send Shutdown Cancel message to VHAL
379      */
sendShutdownCancel()380     public void sendShutdownCancel() {
381         Slogf.i(CarLog.TAG_POWER, "send shutdown cancel");
382         setPowerState(VehicleApPowerStateReport.SHUTDOWN_CANCELLED, 0);
383     }
384 
385     /**
386      * Sets the display brightness for the vehicle.
387      * @param brightness value from 0 to 100.
388      */
sendDisplayBrightness(int brightness)389     public void sendDisplayBrightness(int brightness) {
390         int brightnessToSet = adjustBrightness(brightness, /* minBrightness= */ 0,
391                 /* maxBrightness= */ 100);
392 
393         synchronized (mLock) {
394             if (mProperties.get(DISPLAY_BRIGHTNESS) == null) {
395                 return;
396             }
397             if (mPerDisplayBrightnessSupported) {
398                 Slogf.w(CarLog.TAG_POWER, "PER_DISPLAY_BRIGHTNESS is supported and "
399                         + "sendDisplayBrightness(int displayId, int brightness) should be used "
400                         + "instead of DISPLAY_BRIGHTNESS");
401                 return;
402             }
403         }
404         try {
405             mHal.set(VehicleProperty.DISPLAY_BRIGHTNESS, 0).to(brightnessToSet);
406             Slogf.i(CarLog.TAG_POWER, "send display brightness = " + brightnessToSet);
407         } catch (ServiceSpecificException | IllegalArgumentException e) {
408             Slogf.e(CarLog.TAG_POWER, "cannot set DISPLAY_BRIGHTNESS", e);
409         }
410     }
411 
412     /**
413      * Received display brightness change event.
414      * @param displayId the display id.
415      * @param brightness in percentile. 100% full.
416      */
sendDisplayBrightness(int displayId, int brightness)417     public void sendDisplayBrightness(int displayId, int brightness) {
418         int brightnessToSet = adjustBrightness(brightness, /* minBrightness= */ 0,
419                 /* maxBrightness= */ 100);
420 
421         synchronized (mLock) {
422             if (!mPerDisplayBrightnessSupported) {
423                 Slogf.w(CarLog.TAG_POWER, "PER_DISPLAY_BRIGHTNESS is not supported");
424                 return;
425             }
426         }
427         int displayPort = getDisplayPort(displayId);
428         if (displayPort == DisplayHelper.INVALID_PORT) {
429             return;
430         }
431         try {
432             HalPropValue value = mHal.getHalPropValueBuilder()
433                     .build(VehicleProperty.PER_DISPLAY_BRIGHTNESS, /* areaId= */ 0,
434                             new int[]{displayPort, brightnessToSet});
435             mHal.set(value);
436             Slogf.i(CarLog.TAG_POWER, "send display brightness = %d, port = %d",
437                     brightnessToSet, displayPort);
438         } catch (ServiceSpecificException e) {
439             Slogf.e(CarLog.TAG_POWER, e, "cannot set PER_DISPLAY_BRIGHTNESS port = %d",
440                     displayPort);
441         }
442     }
443 
444     /**
445      * Sends {@code SHUTDOWN_REQUEST} to the VHAL.
446      */
requestShutdownAp(@owerState.ShutdownType int powerState, boolean runGarageMode)447     public void requestShutdownAp(@PowerState.ShutdownType int powerState, boolean runGarageMode) {
448         int shutdownParam = VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY;
449         switch (powerState) {
450             case PowerState.SHUTDOWN_TYPE_POWER_OFF:
451                 shutdownParam = runGarageMode ? VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY
452                         : VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY;
453                 break;
454             case PowerState.SHUTDOWN_TYPE_DEEP_SLEEP:
455                 shutdownParam = runGarageMode ? VehicleApPowerStateShutdownParam.CAN_SLEEP
456                         : VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY;
457                 break;
458             case PowerState.SHUTDOWN_TYPE_HIBERNATION:
459                 shutdownParam = runGarageMode ? VehicleApPowerStateShutdownParam.CAN_HIBERNATE
460                         : VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY;
461                 break;
462             case PowerState.SHUTDOWN_TYPE_UNDEFINED:
463             default:
464                 Slogf.w(CarLog.TAG_POWER, "Unknown power state(%d) for requestShutdownAp",
465                         powerState);
466                 return;
467         }
468 
469         try {
470             mHal.set(VehicleProperty.SHUTDOWN_REQUEST, /* areaId= */ 0).to(shutdownParam);
471         } catch (ServiceSpecificException | IllegalArgumentException e) {
472             Slogf.e(CarLog.TAG_POWER, "cannot send SHUTDOWN_REQUEST to VHAL", e);
473         }
474     }
475 
setPowerState(int state, int additionalParam)476     private void setPowerState(int state, int additionalParam) {
477         if (isPowerStateSupported()) {
478             int[] values = { state, additionalParam };
479             try {
480                 mHal.set(VehicleProperty.AP_POWER_STATE_REPORT, 0).to(values);
481                 Slogf.i(CarLog.TAG_POWER, "setPowerState=" + powerStateReportName(state)
482                         + " param=" + additionalParam);
483             } catch (ServiceSpecificException e) {
484                 Slogf.e(CarLog.TAG_POWER, "cannot set to AP_POWER_STATE_REPORT", e);
485             }
486         }
487     }
488 
489     /**
490      * Returns a {@link PowerState} representing the current power state for the vehicle.
491      */
492     @Nullable
getCurrentPowerState()493     public PowerState getCurrentPowerState() {
494         HalPropValue value;
495         try {
496             value = mHal.get(VehicleProperty.AP_POWER_STATE_REQ);
497         } catch (ServiceSpecificException e) {
498             Slogf.e(CarLog.TAG_POWER, "Cannot get AP_POWER_STATE_REQ", e);
499             return null;
500         }
501         return new PowerState(value.getInt32Value(VehicleApPowerStateReqIndex.STATE),
502                 value.getInt32Value(VehicleApPowerStateReqIndex.ADDITIONAL));
503     }
504 
505     /**
506      * Determines if the current properties describe a valid power state
507      * @return true if both the power state request and power state report are valid
508      */
isPowerStateSupported()509     public boolean isPowerStateSupported() {
510         synchronized (mLock) {
511             return (mProperties.get(VehicleProperty.AP_POWER_STATE_REQ) != null)
512                     && (mProperties.get(VehicleProperty.AP_POWER_STATE_REPORT) != null);
513         }
514     }
515 
516     /**
517      * Returns if the vehicle is currently in use.
518      *
519      * In use means a human user is present in the vehicle and is currently using the vehicle or
520      * will use the vehicle soon.
521      */
isVehicleInUse()522     public boolean isVehicleInUse() {
523         try {
524             HalPropValue value = mHal.get(VEHICLE_IN_USE);
525             return (value.getStatus() == VehiclePropertyStatus.AVAILABLE
526                     && value.getInt32ValuesSize() >= 1 && value.getInt32Value(0) != 0);
527         } catch (ServiceSpecificException | IllegalArgumentException e) {
528             Slogf.w(CarLog.TAG_POWER, "Failed to get VEHICLE_IN_USE value", e);
529             return false;
530         }
531     }
532 
isConfigFlagSet(int flag)533     private boolean isConfigFlagSet(int flag) {
534         HalPropConfig config;
535         synchronized (mLock) {
536             config = mProperties.get(VehicleProperty.AP_POWER_STATE_REQ);
537         }
538         if (config == null) {
539             return false;
540         }
541         int[] configArray = config.getConfigArray();
542         if (configArray.length < 1) {
543             return false;
544         }
545         return (configArray[0] & flag) != 0;
546     }
547 
isDeepSleepAllowed()548     public boolean isDeepSleepAllowed() {
549         return isConfigFlagSet(VehicleApPowerStateConfigFlag.ENABLE_DEEP_SLEEP_FLAG);
550     }
551 
isHibernationAllowed()552     public boolean isHibernationAllowed() {
553         return isConfigFlagSet(VehicleApPowerStateConfigFlag.ENABLE_HIBERNATION_FLAG);
554     }
555 
isTimedWakeupAllowed()556     public boolean isTimedWakeupAllowed() {
557         return isConfigFlagSet(VehicleApPowerStateConfigFlag.CONFIG_SUPPORT_TIMER_POWER_ON_FLAG);
558     }
559 
560     @Override
init()561     public void init() {
562         synchronized (mLock) {
563             for (int i = 0; i < mProperties.size(); i++) {
564                 HalPropConfig config = mProperties.valueAt(i);
565                 if (VehicleHal.isPropertySubscribable(config)) {
566                     mHal.subscribeProperty(this, config.getPropId());
567                 }
568             }
569             HalPropConfig brightnessProperty = mProperties.get(PER_DISPLAY_BRIGHTNESS);
570             mPerDisplayBrightnessSupported = brightnessProperty != null;
571             if (brightnessProperty == null) {
572                 brightnessProperty = mProperties.get(DISPLAY_BRIGHTNESS);
573             }
574             if (brightnessProperty != null) {
575                 HalAreaConfig[] areaConfigs = brightnessProperty.getAreaConfigs();
576                 mMaxDisplayBrightness = areaConfigs.length > 0
577                         ? areaConfigs[0].getMaxInt32Value() : 0;
578                 if (mMaxDisplayBrightness <= 0) {
579                     Slogf.w(CarLog.TAG_POWER, "Max display brightness from vehicle HAL is invalid:"
580                             + mMaxDisplayBrightness);
581                     mMaxDisplayBrightness = 1;
582                 }
583             }
584         }
585     }
586 
587     @Override
release()588     public void release() {
589         synchronized (mLock) {
590             mProperties.clear();
591         }
592     }
593 
594     @Override
getAllSupportedProperties()595     public int[] getAllSupportedProperties() {
596         return SUPPORTED_PROPERTIES;
597     }
598 
599     @Override
takeProperties(Collection<HalPropConfig> properties)600     public void takeProperties(Collection<HalPropConfig> properties) {
601         if (properties.isEmpty()) {
602             return;
603         }
604         synchronized (mLock) {
605             for (HalPropConfig config : properties) {
606                 mProperties.put(config.getPropId(), config);
607             }
608         }
609     }
610 
611     @Override
onHalEvents(List<HalPropValue> values)612     public void onHalEvents(List<HalPropValue> values) {
613         PowerEventListener listener;
614         synchronized (mLock) {
615             if (mListener == null) {
616                 if (mQueuedEvents == null) {
617                     mQueuedEvents = new ArrayList<>(values.size());
618                 }
619                 mQueuedEvents.addAll(values);
620                 return;
621             }
622             listener = mListener;
623         }
624         dispatchEvents(values, listener);
625     }
626 
dispatchEvents(List<HalPropValue> values, PowerEventListener listener)627     private void dispatchEvents(List<HalPropValue> values, PowerEventListener listener) {
628         for (int i = 0; i < values.size(); i++) {
629             HalPropValue v = values.get(i);
630             switch (v.getPropId()) {
631                 case AP_POWER_STATE_REPORT:
632                     // Ignore this property event. It was generated inside of CarService.
633                     break;
634                 case AP_POWER_STATE_REQ:
635                     int state;
636                     int param;
637                     try {
638                         state = v.getInt32Value(VehicleApPowerStateReqIndex.STATE);
639                         param = v.getInt32Value(VehicleApPowerStateReqIndex.ADDITIONAL);
640                     } catch (IndexOutOfBoundsException e) {
641                         Slogf.e(CarLog.TAG_POWER, "Received invalid event, ignore, int32Values: "
642                                 + v.dumpInt32Values(), e);
643                         break;
644                     }
645                     Slogf.i(CarLog.TAG_POWER, "Received AP_POWER_STATE_REQ="
646                             + powerStateReqName(state) + " param=" + param);
647                     listener.onApPowerStateChange(new PowerState(state, param));
648                     break;
649                 case DISPLAY_BRIGHTNESS:
650                 {
651                     int maxBrightness;
652                     synchronized (mLock) {
653                         if (mPerDisplayBrightnessSupported) {
654                             Slogf.w(CarLog.TAG_POWER, "Received DISPLAY_BRIGHTNESS "
655                                     + "while PER_DISPLAY_BRIGHTNESS is supported, ignore");
656                             return;
657                         }
658                         maxBrightness = mMaxDisplayBrightness;
659                     }
660                     int brightness;
661                     try {
662                         brightness = v.getInt32Value(0) * MAX_BRIGHTNESS / maxBrightness;
663                     } catch (IndexOutOfBoundsException e) {
664                         Slogf.e(CarLog.TAG_POWER, "Received invalid event, ignore, int32Values: "
665                                 + v.dumpInt32Values(), e);
666                         break;
667                     }
668                     if (brightness < 0) {
669                         Slogf.e(CarLog.TAG_POWER, "invalid brightness: " + brightness
670                                 + ", set to 0");
671                         brightness = 0;
672                     } else if (brightness > MAX_BRIGHTNESS) {
673                         Slogf.e(CarLog.TAG_POWER, "invalid brightness: " + brightness + ", set to "
674                                 + MAX_BRIGHTNESS);
675                         brightness = MAX_BRIGHTNESS;
676                     }
677                     Slogf.i(CarLog.TAG_POWER, "Received DISPLAY_BRIGHTNESS=" + brightness);
678                     listener.onDisplayBrightnessChange(brightness);
679                     break;
680                 }
681                 case PER_DISPLAY_BRIGHTNESS:
682                 {
683                     int maxBrightness;
684                     synchronized (mLock) {
685                         maxBrightness = mMaxDisplayBrightness;
686                     }
687                     int displayPort;
688                     int brightness;
689                     try {
690                         displayPort = v.getInt32Value(0);
691                         brightness = v.getInt32Value(1) * MAX_BRIGHTNESS / maxBrightness;
692                     } catch (IndexOutOfBoundsException e) {
693                         Slogf.e(CarLog.TAG_POWER, "Received invalid event, ignore, int32Values: "
694                                 + v.dumpInt32Values(), e);
695                         break;
696                     }
697                     brightness = adjustBrightness(brightness, /* minBrightness= */ 0,
698                             MAX_BRIGHTNESS);
699                     Slogf.i(CarLog.TAG_POWER, "Received PER_DISPLAY_BRIGHTNESS=" + brightness
700                             + ", displayPort=" + displayPort);
701                     int displayId = getDisplayId(displayPort);
702                     listener.onDisplayBrightnessChange(displayId, brightness);
703                     break;
704                 }
705                 default:
706                     Slogf.w(CarLog.TAG_POWER, "Received event with invalid property id: %d",
707                             v.getPropId());
708                     break;
709             }
710         }
711     }
712 
getDisplayId(int displayPort)713     private int getDisplayId(int displayPort) {
714         DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
715         int displayId = Display.DEFAULT_DISPLAY;
716         for (Display display : displayManager.getDisplays()) {
717             if (displayPort == DisplayHelper.getPhysicalPort(display)) {
718                 displayId = display.getDisplayId();
719                 break;
720             }
721         }
722         return displayId;
723     }
724 
getDisplayPort(int displayId)725     private int getDisplayPort(int displayId) {
726         DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
727         Display display = displayManager.getDisplay(displayId);
728         if (display != null) {
729             int displayPort = DisplayHelper.getPhysicalPort(display);
730             if (displayPort != DisplayHelper.INVALID_PORT) {
731                 return displayPort;
732             }
733         }
734         Slogf.w(CarLog.TAG_POWER, "cannot get display port from displayId = %d",
735                 displayId);
736         return DisplayHelper.INVALID_PORT;
737     }
738 
adjustBrightness(int brightness, int minBrightness, int maxBrightness)739     private int adjustBrightness(int brightness, int minBrightness, int maxBrightness) {
740         if (brightness < minBrightness) {
741             Slogf.w(CarLog.TAG_POWER, "invalid brightness: %d, brightness is set to %d", brightness,
742                     minBrightness);
743             brightness = minBrightness;
744         } else if (brightness > maxBrightness) {
745             Slogf.w(CarLog.TAG_POWER, "invalid brightness: %d, brightness is set to %d", brightness,
746                     maxBrightness);
747             brightness = maxBrightness;
748         }
749         return brightness;
750     }
751 
752     @Override
753     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(PrintWriter writer)754     public void dump(PrintWriter writer) {
755         writer.println("*Power HAL*");
756         writer.printf("isPowerStateSupported:%b, isDeepSleepAllowed:%b, isHibernationAllowed:%b\n",
757                 isPowerStateSupported(), isDeepSleepAllowed(), isHibernationAllowed());
758 
759     }
760 }
761