• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
managerToHalPropId(int propId)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      */
halToManagerPropId(int halPropId)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          */
onPropertyChange(List<CarPropertyEvent> events)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          */
onPropertySetError(int property, int area)104         void onPropertySetError(int property, int area);
105     }
106 
PropertyHalService(VehicleHal vehicleHal)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      */
setListener(PropertyHalListener listener)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      */
getPropertyList()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
getProperty(int mgrPropId, int areaId)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      */
getSampleRate(int propId)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
getReadPermission(int propId)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
getWritePermission(int propId)181     public String getWritePermission(int propId) {
182         return mPropIds.getWritePermission(propId);
183     }
184 
185     /**
186      * Set the property value.
187      * @param prop
188      */
setProperty(CarPropertyValue prop)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      */
subscribeProperty(int propId, float rate)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      */
unsubscribeProperty(int propId)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
init()253     public void init() {
254         if (mDbg) {
255             Log.d(TAG, "init()");
256         }
257     }
258 
259     @Override
release()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
takeSupportedProperties( Collection<VehiclePropConfig> allProperties)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
handleHalEvents(List<VehiclePropValue> values)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
handlePropertySetError(int property, int area)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
dump(PrintWriter writer)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