Home | History | Annotate | Download | only in hal
      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_BOOTUP_REASON;
     20 import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AP_POWER_STATE_REPORT;
     21 import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AP_POWER_STATE_REQ;
     22 import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.DISPLAY_BRIGHTNESS;
     23 
     24 import android.annotation.Nullable;
     25 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerBootupReason;
     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.util.Log;
     35 
     36 import com.android.car.CarLog;
     37 import com.android.internal.annotations.VisibleForTesting;
     38 
     39 import java.io.PrintWriter;
     40 import java.util.Collection;
     41 import java.util.HashMap;
     42 import java.util.LinkedList;
     43 import java.util.List;
     44 
     45 public class PowerHalService extends HalServiceBase {
     46     // AP Power State constants set by HAL implementation
     47     public static final int STATE_OFF = VehicleApPowerStateReq.OFF;
     48     public static final int STATE_DEEP_SLEEP = VehicleApPowerStateReq.DEEP_SLEEP;
     49     public static final int STATE_ON_DISP_OFF = VehicleApPowerStateReq.ON_DISP_OFF;
     50     public static final int STATE_ON_FULL = VehicleApPowerStateReq.ON_FULL;
     51     public static final int STATE_SHUTDOWN_PREPARE = VehicleApPowerStateReq.SHUTDOWN_PREPARE;
     52 
     53     // Boot reason set by VMCU
     54     public static final int BOOT_REASON_USER_POWER_ON = VehicleApPowerBootupReason.USER_POWER_ON;
     55     public static final int BOOT_REASON_USER_UNLOCK = VehicleApPowerBootupReason.USER_UNLOCK;
     56     public static final int BOOT_REASON_TIMER = VehicleApPowerBootupReason.TIMER;
     57 
     58     // Set display brightness from 0-100%
     59     public static final int MAX_BRIGHTNESS = 100;
     60 
     61     @VisibleForTesting
     62     public static final int SET_BOOT_COMPLETE = VehicleApPowerStateReport.BOOT_COMPLETE;
     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_DISPLAY_ON = VehicleApPowerStateReport.DISPLAY_ON;
     73     @VisibleForTesting
     74     public static final int SET_DISPLAY_OFF = VehicleApPowerStateReport.DISPLAY_OFF;
     75 
     76     @VisibleForTesting
     77     public static final int SHUTDOWN_CAN_SLEEP = VehicleApPowerStateShutdownParam.CAN_SLEEP;
     78     @VisibleForTesting
     79     public static final int SHUTDOWN_IMMEDIATELY =
     80             VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY;
     81     @VisibleForTesting
     82     public static final int SHUTDOWN_ONLY = VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY;
     83 
     84     public interface PowerEventListener {
     85         /**
     86          * Received power state change event.
     87          * @param state One of STATE_*
     88          */
     89         void onApPowerStateChange(PowerState state);
     90         /**
     91          * Received display brightness change event.
     92          * @param brightness in percentile. 100% full.
     93          */
     94         void onDisplayBrightnessChange(int brightness);
     95         /**
     96          * Received boot reason.
     97          * @param boot reason.
     98          */
     99         void onBootReasonReceived(int bootReason);
    100     }
    101 
    102     public static final class PowerState {
    103         /**
    104          * One of STATE_*
    105          */
    106         public final int mState;
    107         public final int mParam;
    108 
    109         public PowerState(int state, int param) {
    110             this.mState = state;
    111             this.mParam = param;
    112         }
    113 
    114         /**
    115          * Whether the current PowerState allows deep sleep or not. Calling this for
    116          * power state other than STATE_SHUTDOWN_PREPARE will trigger exception.
    117          * @return
    118          * @throws IllegalStateException
    119          */
    120         public boolean canEnterDeepSleep() {
    121             if (mState != STATE_SHUTDOWN_PREPARE) {
    122                 throw new IllegalStateException("wrong state");
    123             }
    124             return (mParam == VehicleApPowerStateShutdownParam.CAN_SLEEP);
    125         }
    126 
    127         /**
    128          * Whether the current PowerState allows postponing or not. Calling this for
    129          * power state other than STATE_SHUTDOWN_PREPARE will trigger exception.
    130          * @return
    131          * @throws IllegalStateException
    132          */
    133         public boolean canPostponeShutdown() {
    134             if (mState != STATE_SHUTDOWN_PREPARE) {
    135                 throw new IllegalStateException("wrong state");
    136             }
    137             return (mParam != VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
    138         }
    139 
    140         @Override
    141         public boolean equals(Object o) {
    142             if (this == o) {
    143                 return true;
    144             }
    145             if (!(o instanceof PowerState)) {
    146                 return false;
    147             }
    148             PowerState that = (PowerState) o;
    149             return this.mState == that.mState && this.mParam == that.mParam;
    150         }
    151 
    152         @Override
    153         public String toString() {
    154             return "PowerState state:" + mState + ", param:" + mParam;
    155         }
    156     }
    157 
    158     private final HashMap<Integer, VehiclePropConfig> mProperties = new HashMap<>();
    159     private final VehicleHal mHal;
    160     private LinkedList<VehiclePropValue> mQueuedEvents;
    161     private PowerEventListener mListener;
    162     private int mMaxDisplayBrightness;
    163 
    164     public PowerHalService(VehicleHal hal) {
    165         mHal = hal;
    166     }
    167 
    168     public void setListener(PowerEventListener listener) {
    169         LinkedList<VehiclePropValue> eventsToDispatch = null;
    170         synchronized (this) {
    171             mListener = listener;
    172             if (mQueuedEvents != null && mQueuedEvents.size() > 0) {
    173                 eventsToDispatch = mQueuedEvents;
    174             }
    175             mQueuedEvents = null;
    176         }
    177         // do this outside lock
    178         if (eventsToDispatch != null) {
    179             dispatchEvents(eventsToDispatch, listener);
    180         }
    181     }
    182 
    183     public void sendBootComplete() {
    184         Log.i(CarLog.TAG_POWER, "send boot complete");
    185         setPowerState(VehicleApPowerStateReport.BOOT_COMPLETE, 0);
    186     }
    187 
    188     public void sendSleepEntry() {
    189         Log.i(CarLog.TAG_POWER, "send sleep entry");
    190         setPowerState(VehicleApPowerStateReport.DEEP_SLEEP_ENTRY, 0);
    191     }
    192 
    193     public void sendSleepExit() {
    194         Log.i(CarLog.TAG_POWER, "send sleep exit");
    195         setPowerState(VehicleApPowerStateReport.DEEP_SLEEP_EXIT, 0);
    196     }
    197 
    198     public void sendShutdownPostpone(int postponeTimeMs) {
    199         Log.i(CarLog.TAG_POWER, "send shutdown postpone, time:" + postponeTimeMs);
    200         setPowerState(VehicleApPowerStateReport.SHUTDOWN_POSTPONE, postponeTimeMs);
    201     }
    202 
    203     public void sendShutdownStart(int wakeupTimeSec) {
    204         Log.i(CarLog.TAG_POWER, "send shutdown start");
    205         setPowerState(VehicleApPowerStateReport.SHUTDOWN_START, wakeupTimeSec);
    206     }
    207 
    208     /**
    209      * Sets the display brightness for the vehicle.
    210      * @param brightness value from 0 to 100.
    211      */
    212     public void sendDisplayBrightness(int brightness) {
    213         if (brightness < 0) {
    214             brightness = 0;
    215         } else if (brightness > 100) {
    216             brightness = 100;
    217         }
    218         try {
    219             mHal.set(VehicleProperty.DISPLAY_BRIGHTNESS, 0).to(brightness);
    220             Log.i(CarLog.TAG_POWER, "send display brightness = " + brightness);
    221         } catch (PropertyTimeoutException e) {
    222             Log.e(CarLog.TAG_POWER, "cannot set DISPLAY_BRIGHTNESS", e);
    223         }
    224     }
    225 
    226     public void sendDisplayOn() {
    227         Log.i(CarLog.TAG_POWER, "send display on");
    228         setPowerState(VehicleApPowerStateReport.DISPLAY_ON, 0);
    229     }
    230 
    231     public void sendDisplayOff() {
    232         Log.i(CarLog.TAG_POWER, "send display off");
    233         setPowerState(VehicleApPowerStateReport.DISPLAY_OFF, 0);
    234     }
    235 
    236     private void setPowerState(int state, int additionalParam) {
    237         int[] values = { state, additionalParam };
    238         try {
    239             mHal.set(VehicleProperty.AP_POWER_STATE_REPORT, 0).to(values);
    240             Log.i(CarLog.TAG_POWER, "setPowerState=" + state + " param=" + additionalParam);
    241         } catch (PropertyTimeoutException e) {
    242             Log.e(CarLog.TAG_POWER, "cannot set to AP_POWER_STATE_REPORT", e);
    243         }
    244     }
    245 
    246     @Nullable
    247     public PowerState getCurrentPowerState() {
    248         int[] state;
    249         try {
    250             state = mHal.get(int[].class, VehicleProperty.AP_POWER_STATE_REQ);
    251         } catch (PropertyTimeoutException e) {
    252             Log.e(CarLog.TAG_POWER, "Cannot get AP_POWER_STATE_REQ", e);
    253             return null;
    254         }
    255         return new PowerState(state[VehicleApPowerStateReqIndex.STATE],
    256                 state[VehicleApPowerStateReqIndex.ADDITIONAL]);
    257     }
    258 
    259     public synchronized boolean isPowerStateSupported() {
    260         VehiclePropConfig config = mProperties.get(VehicleProperty.AP_POWER_STATE_REQ);
    261         return config != null;
    262     }
    263 
    264     private synchronized boolean isConfigFlagSet(int flag) {
    265         VehiclePropConfig config = mProperties.get(VehicleProperty.AP_POWER_STATE_REQ);
    266         if (config == null) {
    267             return false;
    268         } else if (config.configArray.size() < 1) {
    269             return false;
    270         }
    271         return (config.configArray.get(0) & flag) != 0;
    272     }
    273 
    274     public boolean isDeepSleepAllowed() {
    275         return isConfigFlagSet(VehicleApPowerStateConfigFlag.ENABLE_DEEP_SLEEP_FLAG);
    276     }
    277 
    278     public boolean isTimedWakeupAllowed() {
    279         return isConfigFlagSet(VehicleApPowerStateConfigFlag.CONFIG_SUPPORT_TIMER_POWER_ON_FLAG);
    280     }
    281 
    282     @Override
    283     public synchronized void init() {
    284         for (VehiclePropConfig config : mProperties.values()) {
    285             if (VehicleHal.isPropertySubscribable(config)) {
    286                 mHal.subscribeProperty(this, config.prop);
    287             }
    288         }
    289         VehiclePropConfig brightnessProperty = mProperties.get(DISPLAY_BRIGHTNESS);
    290         if (brightnessProperty != null) {
    291             mMaxDisplayBrightness = brightnessProperty.areaConfigs.size() > 0
    292                     ? brightnessProperty.areaConfigs.get(0).maxInt32Value : 0;
    293             if (mMaxDisplayBrightness <= 0) {
    294                 Log.w(CarLog.TAG_POWER, "Max display brightness from vehicle HAL is invalid:" +
    295                         mMaxDisplayBrightness);
    296                 mMaxDisplayBrightness = 1;
    297             }
    298         }
    299     }
    300 
    301     @Override
    302     public synchronized void release() {
    303         mProperties.clear();
    304     }
    305 
    306     @Override
    307     public synchronized Collection<VehiclePropConfig> takeSupportedProperties(
    308             Collection<VehiclePropConfig> allProperties) {
    309         for (VehiclePropConfig config : allProperties) {
    310             switch (config.prop) {
    311                 case AP_POWER_BOOTUP_REASON:
    312                 case AP_POWER_STATE_REQ:
    313                 case AP_POWER_STATE_REPORT:
    314                 case DISPLAY_BRIGHTNESS:
    315                     mProperties.put(config.prop, config);
    316                     break;
    317             }
    318         }
    319         return new LinkedList<>(mProperties.values());
    320     }
    321 
    322     @Override
    323     public void handleHalEvents(List<VehiclePropValue> values) {
    324         PowerEventListener listener;
    325         synchronized (this) {
    326             if (mListener == null) {
    327                 if (mQueuedEvents == null) {
    328                     mQueuedEvents = new LinkedList<>();
    329                 }
    330                 mQueuedEvents.addAll(values);
    331                 return;
    332             }
    333             listener = mListener;
    334         }
    335         dispatchEvents(values, listener);
    336     }
    337 
    338     private void dispatchEvents(List<VehiclePropValue> values, PowerEventListener listener) {
    339         for (VehiclePropValue v : values) {
    340             switch (v.prop) {
    341                 case AP_POWER_BOOTUP_REASON:
    342                     int reason = v.value.int32Values.get(0);
    343                     Log.i(CarLog.TAG_POWER, "Received AP_POWER_BOOTUP_REASON=" + reason);
    344                     listener.onBootReasonReceived(reason);
    345                     break;
    346                 case AP_POWER_STATE_REQ:
    347                     int state = v.value.int32Values.get(VehicleApPowerStateReqIndex.STATE);
    348                     int param = v.value.int32Values.get(VehicleApPowerStateReqIndex.ADDITIONAL);
    349                     Log.i(CarLog.TAG_POWER, "Received AP_POWER_STATE_REQ=" + state
    350                             + " param=" + param);
    351                     listener.onApPowerStateChange(new PowerState(state, param));
    352                     break;
    353                 case DISPLAY_BRIGHTNESS:
    354                 {
    355                     int maxBrightness;
    356                     synchronized (this) {
    357                         maxBrightness = mMaxDisplayBrightness;
    358                     }
    359                     int brightness = v.value.int32Values.get(0) * MAX_BRIGHTNESS / maxBrightness;
    360                     if (brightness < 0) {
    361                         Log.e(CarLog.TAG_POWER, "invalid brightness: " + brightness + ", set to 0");
    362                         brightness = 0;
    363                     } else if (brightness > MAX_BRIGHTNESS) {
    364                         Log.e(CarLog.TAG_POWER, "invalid brightness: " + brightness + ", set to "
    365                                 + MAX_BRIGHTNESS);
    366                         brightness = MAX_BRIGHTNESS;
    367                     }
    368                     Log.i(CarLog.TAG_POWER, "Received DISPLAY_BRIGHTNESS=" + brightness);
    369                     listener.onDisplayBrightnessChange(brightness);
    370                 }
    371                     break;
    372             }
    373         }
    374     }
    375 
    376     @Override
    377     public void dump(PrintWriter writer) {
    378         writer.println("*Power HAL*");
    379         writer.println("isPowerStateSupported:" + isPowerStateSupported() +
    380                 ",isDeepSleepAllowed:" + isDeepSleepAllowed());
    381     }
    382 }
    383