Home | History | Annotate | Download | only in hal
      1 /*
      2  * Copyright (C) 2018 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 com.android.car.hal.CarPropertyUtils.toCarPropertyValue;
     19 import static com.android.car.hal.CarPropertyUtils.toVehiclePropValue;
     20 
     21 import static java.lang.Integer.toHexString;
     22 
     23 import android.annotation.Nullable;
     24 import android.car.hardware.CarPropertyConfig;
     25 import android.car.hardware.CarPropertyValue;
     26 import android.car.hardware.property.CarPropertyEvent;
     27 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
     28 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
     29 import android.util.Log;
     30 import android.util.SparseArray;
     31 
     32 import com.android.car.CarLog;
     33 import com.android.internal.annotations.GuardedBy;
     34 
     35 import java.io.PrintWriter;
     36 import java.util.Collection;
     37 import java.util.HashSet;
     38 import java.util.LinkedList;
     39 import java.util.List;
     40 import java.util.Map;
     41 import java.util.Set;
     42 import java.util.concurrent.ConcurrentHashMap;
     43 
     44 /**
     45  * Common interface for HAL services that send Vehicle Properties back and forth via ICarProperty.
     46  * Services that communicate by passing vehicle properties back and forth via ICarProperty should
     47  * extend this class.
     48  */
     49 public class PropertyHalService extends HalServiceBase {
     50     private final boolean mDbg = true;
     51     private final LinkedList<CarPropertyEvent> mEventsToDispatch = new LinkedList<>();
     52     private final Map<Integer, CarPropertyConfig<?>> mProps =
     53             new ConcurrentHashMap<>();
     54     private final SparseArray<Float> mRates = new SparseArray<Float>();
     55     private static final String TAG = "PropertyHalService";
     56     private final VehicleHal mVehicleHal;
     57     private final PropertyHalServiceIds mPropIds;
     58 
     59     @GuardedBy("mLock")
     60     private PropertyHalListener mListener;
     61 
     62     private Set<Integer> mSubscribedPropIds;
     63 
     64     private final Object mLock = new Object();
     65 
     66     /**
     67      * Converts manager property ID to Vehicle HAL property ID.
     68      * If property is not supported, it will return {@link #NOT_SUPPORTED_PROPERTY}.
     69      */
     70     private int managerToHalPropId(int propId) {
     71         if (mProps.containsKey(propId)) {
     72             return propId;
     73         } else {
     74             return NOT_SUPPORTED_PROPERTY;
     75         }
     76     }
     77 
     78     /**
     79      * Converts Vehicle HAL property ID to manager property ID.
     80      * If property is not supported, it will return {@link #NOT_SUPPORTED_PROPERTY}.
     81      */
     82     private int halToManagerPropId(int halPropId) {
     83         if (mProps.containsKey(halPropId)) {
     84             return halPropId;
     85         } else {
     86             return NOT_SUPPORTED_PROPERTY;
     87         }
     88     }
     89 
     90     /**
     91      * PropertyHalListener used to send events to CarPropertyService
     92      */
     93     public interface PropertyHalListener {
     94         /**
     95          * This event is sent whenever the property value is updated
     96          * @param event
     97          */
     98         void onPropertyChange(List<CarPropertyEvent> events);
     99         /**
    100          * This event is sent when the set property call fails
    101          * @param property
    102          * @param area
    103          */
    104         void onPropertySetError(int property, int area);
    105     }
    106 
    107     public PropertyHalService(VehicleHal vehicleHal) {
    108         mPropIds = new PropertyHalServiceIds();
    109         mSubscribedPropIds = new HashSet<Integer>();
    110         mVehicleHal = vehicleHal;
    111         if (mDbg) {
    112             Log.d(TAG, "started PropertyHalService");
    113         }
    114     }
    115 
    116     /**
    117      * Set the listener for the HAL service
    118      * @param listener
    119      */
    120     public void setListener(PropertyHalListener listener) {
    121         synchronized (mLock) {
    122             mListener = listener;
    123         }
    124     }
    125 
    126     /**
    127      *
    128      * @return List<CarPropertyConfig> List of configs available.
    129      */
    130     public Map<Integer, CarPropertyConfig<?>> getPropertyList() {
    131         if (mDbg) {
    132             Log.d(TAG, "getPropertyList");
    133         }
    134         return mProps;
    135     }
    136 
    137     /**
    138      * Returns property or null if property is not ready yet.
    139      * @param mgrPropId
    140      * @param areaId
    141      */
    142     @Nullable
    143     public CarPropertyValue getProperty(int mgrPropId, int areaId) {
    144         int halPropId = managerToHalPropId(mgrPropId);
    145         if (halPropId == NOT_SUPPORTED_PROPERTY) {
    146             throw new IllegalArgumentException("Invalid property Id : 0x" + toHexString(mgrPropId));
    147         }
    148 
    149         VehiclePropValue value = null;
    150         try {
    151             value = mVehicleHal.get(halPropId, areaId);
    152         } catch (PropertyTimeoutException e) {
    153             Log.e(CarLog.TAG_PROPERTY, "get, property not ready 0x" + toHexString(halPropId), e);
    154         }
    155 
    156         return value == null ? null : toCarPropertyValue(value, mgrPropId);
    157     }
    158 
    159     /**
    160      * Returns sample rate for the property
    161      * @param propId
    162      */
    163     public float getSampleRate(int propId) {
    164         return mVehicleHal.getSampleRate(propId);
    165     }
    166 
    167     /**
    168      * Get the read permission string for the property.
    169      * @param propId
    170      */
    171     @Nullable
    172     public String getReadPermission(int propId) {
    173         return mPropIds.getReadPermission(propId);
    174     }
    175 
    176     /**
    177      * Get the write permission string for the property.
    178      * @param propId
    179      */
    180     @Nullable
    181     public String getWritePermission(int propId) {
    182         return mPropIds.getWritePermission(propId);
    183     }
    184 
    185     /**
    186      * Set the property value.
    187      * @param prop
    188      */
    189     public void setProperty(CarPropertyValue prop) {
    190         int halPropId = managerToHalPropId(prop.getPropertyId());
    191         if (halPropId == NOT_SUPPORTED_PROPERTY) {
    192             throw new IllegalArgumentException("Invalid property Id : 0x"
    193                     + toHexString(prop.getPropertyId()));
    194         }
    195         VehiclePropValue halProp = toVehiclePropValue(prop, halPropId);
    196         try {
    197             mVehicleHal.set(halProp);
    198         } catch (PropertyTimeoutException e) {
    199             Log.e(CarLog.TAG_PROPERTY, "set, property not ready 0x" + toHexString(halPropId), e);
    200             throw new RuntimeException(e);
    201         }
    202     }
    203 
    204     /**
    205      * Subscribe to this property at the specified update rate.
    206      * @param propId
    207      * @param rate
    208      */
    209     public void subscribeProperty(int propId, float rate) {
    210         if (mDbg) {
    211             Log.d(TAG, "subscribeProperty propId=0x" + toHexString(propId) + ", rate=" + rate);
    212         }
    213         int halPropId = managerToHalPropId(propId);
    214         if (halPropId == NOT_SUPPORTED_PROPERTY) {
    215             throw new IllegalArgumentException("Invalid property Id : 0x"
    216                     + toHexString(propId));
    217         }
    218         // Validate the min/max rate
    219         CarPropertyConfig cfg = mProps.get(propId);
    220         if (rate > cfg.getMaxSampleRate()) {
    221             rate = cfg.getMaxSampleRate();
    222         } else if (rate < cfg.getMinSampleRate()) {
    223             rate = cfg.getMinSampleRate();
    224         }
    225         synchronized (mSubscribedPropIds) {
    226             mSubscribedPropIds.add(halPropId);
    227         }
    228         mVehicleHal.subscribeProperty(this, halPropId, rate);
    229     }
    230 
    231     /**
    232      * Unsubscribe the property and turn off update events for it.
    233      * @param propId
    234      */
    235     public void unsubscribeProperty(int propId) {
    236         if (mDbg) {
    237             Log.d(TAG, "unsubscribeProperty propId=0x" + toHexString(propId));
    238         }
    239         int halPropId = managerToHalPropId(propId);
    240         if (halPropId == NOT_SUPPORTED_PROPERTY) {
    241             throw new IllegalArgumentException("Invalid property Id : 0x"
    242                     + toHexString(propId));
    243         }
    244         synchronized (mSubscribedPropIds) {
    245             if (mSubscribedPropIds.contains(halPropId)) {
    246                 mSubscribedPropIds.remove(halPropId);
    247                 mVehicleHal.unsubscribeProperty(this, halPropId);
    248             }
    249         }
    250     }
    251 
    252     @Override
    253     public void init() {
    254         if (mDbg) {
    255             Log.d(TAG, "init()");
    256         }
    257     }
    258 
    259     @Override
    260     public void release() {
    261         if (mDbg) {
    262             Log.d(TAG, "release()");
    263         }
    264         synchronized (mSubscribedPropIds) {
    265             for (Integer prop : mSubscribedPropIds) {
    266                 mVehicleHal.unsubscribeProperty(this, prop);
    267             }
    268             mSubscribedPropIds.clear();
    269         }
    270         mProps.clear();
    271 
    272         synchronized (mLock) {
    273             mListener = null;
    274         }
    275     }
    276 
    277     @Override
    278     public Collection<VehiclePropConfig> takeSupportedProperties(
    279             Collection<VehiclePropConfig> allProperties) {
    280         List<VehiclePropConfig> taken = new LinkedList<>();
    281 
    282         for (VehiclePropConfig p : allProperties) {
    283             if (mPropIds.isSupportedProperty(p.prop)) {
    284                 CarPropertyConfig config = CarPropertyUtils.toCarPropertyConfig(p, p.prop);
    285                 taken.add(p);
    286                 mProps.put(p.prop, config);
    287                 if (mDbg) {
    288                     Log.d(TAG, "takeSupportedProperties: " + toHexString(p.prop));
    289                 }
    290             }
    291         }
    292         if (mDbg) {
    293             Log.d(TAG, "takeSupportedProperties() took " + taken.size() + " properties");
    294         }
    295         return taken;
    296     }
    297 
    298     @Override
    299     public void handleHalEvents(List<VehiclePropValue> values) {
    300         PropertyHalListener listener;
    301         synchronized (mLock) {
    302             listener = mListener;
    303         }
    304         if (listener != null) {
    305             for (VehiclePropValue v : values) {
    306                 int mgrPropId = halToManagerPropId(v.prop);
    307                 if (mgrPropId == NOT_SUPPORTED_PROPERTY) {
    308                     Log.e(TAG, "Property is not supported: 0x" + toHexString(v.prop));
    309                     continue;
    310                 }
    311                 CarPropertyValue<?> propVal = toCarPropertyValue(v, mgrPropId);
    312                 CarPropertyEvent event = new CarPropertyEvent(
    313                         CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, propVal);
    314                 if (event != null) {
    315                     mEventsToDispatch.add(event);
    316                 }
    317             }
    318             listener.onPropertyChange(mEventsToDispatch);
    319             mEventsToDispatch.clear();
    320         }
    321     }
    322 
    323     @Override
    324     public void handlePropertySetError(int property, int area) {
    325         PropertyHalListener listener;
    326         synchronized (mLock) {
    327             listener = mListener;
    328         }
    329         if (listener != null) {
    330             listener.onPropertySetError(property, area);
    331         }
    332     }
    333 
    334     @Override
    335     public void dump(PrintWriter writer) {
    336         writer.println(TAG);
    337         writer.println("  Properties available:");
    338         for (CarPropertyConfig prop : mProps.values()) {
    339             writer.println("    " + prop.toString());
    340         }
    341     }
    342 }
    343