• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 
17 package com.android.car.hal;
18 
19 import static com.android.car.hal.property.HalPropertyDebugUtils.toAreaIdString;
20 import static com.android.car.hal.property.HalPropertyDebugUtils.toPropertyIdString;
21 import static com.android.car.hal.property.HalPropertyDebugUtils.toStatusString;
22 import static com.android.car.hal.property.HalPropertyDebugUtils.toValueString;
23 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
24 
25 import android.annotation.Nullable;
26 import android.car.VehiclePropertyIds;
27 import android.car.builtin.util.Slogf;
28 import android.car.hardware.CarPropertyValue;
29 import android.hardware.automotive.vehicle.RawPropValues;
30 import android.hardware.automotive.vehicle.VehiclePropValue;
31 import android.hardware.automotive.vehicle.VehiclePropertyStatus;
32 import android.hardware.automotive.vehicle.VehiclePropertyType;
33 
34 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
35 import com.android.car.internal.property.CarPropertyHelper;
36 import com.android.car.internal.property.RawPropertyValue;
37 
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.List;
41 import java.util.StringJoiner;
42 
43 /**
44  * HalPropValue represents a vehicle property value.
45  *
46  * It could be used to convert between AIDL or HIDL VehiclePropValue used in vehicle HAL and
47  * {@link CarPropertyValue} used in CarPropertyManager.
48  */
49 public abstract class HalPropValue {
50     private static final String TAG = HalPropValue.class.getSimpleName();
51 
52     /**
53      * Gets the timestamp.
54      *
55      * @return The timestamp.
56      */
getTimestamp()57     public abstract long getTimestamp();
58 
59     /**
60      * Gets the area ID.
61      *
62      * @return The area ID.
63      */
getAreaId()64     public abstract int getAreaId();
65 
66     /**
67      * Gets the property ID.
68      *
69      * @return The property ID.
70      */
getPropId()71     public abstract int getPropId();
72 
73     /**
74      * Gets the property status.
75      *
76      * @return The property status.
77      */
getStatus()78     public abstract int getStatus();
79 
80     /**
81      * Get stored int32 values size.
82      *
83      * @return The size for the stored int32 values.
84      */
getInt32ValuesSize()85     public abstract int getInt32ValuesSize();
86 
87     /**
88      * Gets the int32 value at index.
89      *
90      * @param index The index.
91      * @return The int32 value at index.
92      */
getInt32Value(int index)93     public abstract int getInt32Value(int index);
94 
95     /**
96      * Dump all int32 values as a string. Used for debugging.
97      *
98      * @return A String representation of all int32 values.
99      */
dumpInt32Values()100     public abstract String dumpInt32Values();
101 
102     /**
103      * Get stored float values size.
104      *
105      * @return The size for the stored float values.
106      */
getFloatValuesSize()107     public abstract int getFloatValuesSize();
108 
109     /**
110      * Gets the float value at index.
111      *
112      * @param index The index.
113      * @return The float value at index.
114      */
getFloatValue(int index)115     public abstract float getFloatValue(int index);
116 
117     /**
118      * Dump all float values as a string. Used for debugging.
119      *
120      * @return A String representation of all float values.
121      */
dumpFloatValues()122     public abstract String dumpFloatValues();
123 
124     /**
125      * Get stored inn64 values size.
126      *
127      * @return The size for the stored inn64 values.
128      */
getInt64ValuesSize()129     public abstract int getInt64ValuesSize();
130 
131     /**
132      * Gets the int64 value at index.
133      *
134      * @param index The index.
135      * @return The int64 value at index.
136      */
getInt64Value(int index)137     public abstract long getInt64Value(int index);
138 
139     /**
140      * Dump all int64 values as a string. Used for debugging.
141      *
142      * @return A String representation of all int64 values.
143      */
dumpInt64Values()144     public abstract String dumpInt64Values();
145 
146     /**
147      * Get stored byte values size.
148      *
149      * @return The size for the stored byte values.
150      */
getByteValuesSize()151     public abstract int getByteValuesSize();
152 
153     /**
154      * Gets the byte value at index.
155      *
156      * @param index The index.
157      * @return The byte value at index.
158      */
getByteValue(int index)159     public abstract byte getByteValue(int index);
160 
161     /**
162      * Gets the byte values.
163      *
164      * @return The byte values.
165      */
getByteArray()166     public abstract byte[] getByteArray();
167 
168     /**
169      * Gets the string value.
170      *
171      * @return The stored string value.
172      */
getStringValue()173     public abstract String getStringValue();
174 
175     /**
176      * Converts to an AIDL/HIDL VehiclePropValue that could be used to sent to vehicle HAL.
177      *
178      * @return An AIDL or HIDL VehiclePropValue.
179      */
toVehiclePropValue()180     public abstract Object toVehiclePropValue();
181 
182     /**
183      * Converts a {@link RawPropValues} received from AIDL VHAL to a {@link RawPropertyValue}.
184      *
185      * This only works for AIDL types.
186      *
187      * This wraps the {@link RawPropValues} to a {@link HalPropValue}, converts it to a
188      * {@link CarPropertyValue} and gets the {@link RawPropertyValue} from it.
189      */
toRawPropertyValue(int propId, int areaId, int mgrPropId, RawPropValues rawPropValues, HalPropConfig config)190     public static @Nullable RawPropertyValue<?> toRawPropertyValue(int propId, int areaId,
191             int mgrPropId, RawPropValues rawPropValues, HalPropConfig config) {
192         VehiclePropValue aidlVehiclePropValue = new VehiclePropValue();
193         aidlVehiclePropValue.prop = propId;
194         aidlVehiclePropValue.areaId = areaId;
195         aidlVehiclePropValue.value = rawPropValues;
196         HalPropValue aidlHalPropValue = new HalPropValueBuilder(/* isAidl= */ true)
197                 .build(aidlVehiclePropValue);
198         RawPropertyValue<?> rawPropertyValue = aidlHalPropValue.toRawPropertyValue(
199                 mgrPropId, config);
200         if (rawPropertyValue == null) {
201             Slogf.e(TAG, "Invalid RawPropValues: " + rawPropValues
202                     + ", cannot convert to RawPropertyValue, return null");
203             return null;
204         }
205         return rawPropertyValue;
206     }
207 
208     /**
209      * Turns this class to a {@link CarPropertyValue}.
210      *
211      * @param mgrPropId The property ID used in {@link android.car.VehiclePropertyIds}.
212      * @param config The config for the property.
213      * @return A CarPropertyValue that could be passed to upper layer
214      * @throws IllegalStateException If property has unsupported type
215      */
toCarPropertyValue(int mgrPropId, HalPropConfig config)216     public CarPropertyValue toCarPropertyValue(int mgrPropId, HalPropConfig config) {
217         return toCarPropertyValue(mgrPropId, config, /* isVhalPropId= */ false);
218     }
219 
220     /**
221      * Turns this class to a {@link CarPropertyValue}.
222      *
223      * @param mgrPropId The property ID used in {@link android.car.VehiclePropertyIds}.
224      * @param config The config for the property.
225      * @return A CarPropertyValue that could be passed to upper layer
226      * @throws IllegalStateException If property has unsupported type
227      */
toCarPropertyValue(int mgrPropId, HalPropConfig config, boolean isVhalPropId)228     public CarPropertyValue toCarPropertyValue(int mgrPropId, HalPropConfig config,
229             boolean isVhalPropId) {
230         Class<?> clazz = CarPropertyUtils.getJavaClass(getPropId() & VehiclePropertyType.MASK);
231         int areaId = getAreaId();
232         int status = vehiclePropertyStatusToCarPropertyStatus(getStatus());
233         long timestampNanos = getTimestamp();
234         var rawPropertyValue = toRawPropertyValue(mgrPropId, config);
235         if (rawPropertyValue == null) {
236             // Cannot convert to a valid rawPropertyValue. If the property has available status,
237             // change it to error.
238             if (status == CarPropertyValue.STATUS_AVAILABLE) {
239                 status = CarPropertyValue.STATUS_ERROR;
240             }
241             // Fill in the default value, rawPropertyValue must not be null.
242             rawPropertyValue = new RawPropertyValue(CarPropertyHelper.getDefaultValue(clazz));
243         }
244         return new CarPropertyValue<>(mgrPropId, areaId, status, timestampNanos,
245                 rawPropertyValue, isVhalPropId);
246     }
247 
toRawPropertyValue(int mgrPropId, HalPropConfig config)248     private @Nullable RawPropertyValue<?> toRawPropertyValue(int mgrPropId, HalPropConfig config) {
249         if (isMixedTypeProperty(getPropId())) {
250             int[] configArray = config.getConfigArray();
251             boolean containStringType = configArray[0] == 1;
252             boolean containBooleanType = configArray[1] == 1;
253             return toMixedRawPropertyValue(containBooleanType, containStringType);
254         }
255         return toRegularRawPropertyValue(mgrPropId);
256     }
257 
258     /**
259      * Check whether this property is equal to another property.
260      *
261      * @param argument The property to compare.
262      * @return true if equal, false if not.
263      */
264     @Override
equals(Object argument)265     public boolean equals(Object argument) {
266         if (!(argument instanceof HalPropValue other)) {
267             return false;
268         }
269 
270         if (!equalsExceptTimestamp(other)) {
271             return false;
272         }
273 
274         if (other.getTimestamp() != getTimestamp()) {
275             Slogf.i(TAG, "Timestamp mismatch, got " + other.getTimestamp() + " want "
276                     + getTimestamp());
277             return false;
278         }
279         return true;
280     }
281 
282     /**
283      * Check whether this property is equal to another property except timestamps.
284      *
285      * @param other The property to compare.
286      * @return true if equal, false if not.
287      */
equalsExceptTimestamp(HalPropValue other)288     public boolean equalsExceptTimestamp(HalPropValue other) {
289         if (other.getPropId() != getPropId()) {
290             Slogf.i(TAG, "Property ID mismatch, got " + other.getPropId() + " want "
291                     + getPropId());
292             return false;
293         }
294         if (other.getAreaId() != getAreaId()) {
295             Slogf.i(TAG, "Area ID mismatch, got " + other.getAreaId() + " want " + getAreaId());
296             return false;
297         }
298         if (other.getStatus() != getStatus()) {
299             Slogf.i(TAG, "Status mismatch, got " + other.getStatus() + " want " + getStatus());
300             return false;
301         }
302         if (!equalInt32Values(other)) {
303             Slogf.i(TAG, "Int32Values mismatch, got " + other.dumpInt32Values() + " want "
304                     + dumpInt32Values());
305             return false;
306         }
307         if (!equalFloatValues(other)) {
308             Slogf.i(TAG, "FloatValues mismatch, got " + other.dumpFloatValues() + " want "
309                     + dumpFloatValues());
310             return false;
311         }
312         if (!equalInt64Values(other)) {
313             Slogf.i(TAG, "Int64Values mismatch, got " + other.dumpInt64Values() + " want "
314                     + dumpInt64Values());
315             return false;
316         }
317         if (!Arrays.equals(other.getByteArray(), getByteArray())) {
318             Slogf.i(TAG, "ByteValues mismatch, got " + Arrays.toString(other.getByteArray())
319                     + " want " + Arrays.toString(getByteArray()));
320             return false;
321         }
322         if (!other.getStringValue().equals(getStringValue())) {
323             Slogf.i(TAG, "StringValue mismatch, got " + other.getStringValue() + " want "
324                     + getStringValue());
325             return false;
326         }
327         return true;
328     }
329 
330     @Override
331     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
toString()332     public String toString() {
333         StringJoiner debugStringJoiner = new StringJoiner(", ", "{", "}");
334         debugStringJoiner.add("Property ID: " + toPropertyIdString(getPropId()));
335         debugStringJoiner.add("Area ID: " + toAreaIdString(getPropId(), getAreaId()));
336         debugStringJoiner.add("ElapsedRealtimeNanos: " + getTimestamp());
337         debugStringJoiner.add("Status: " + toStatusString(getStatus()));
338         debugStringJoiner.add("Value: " + toValueString(this));
339         return "HalPropValue" + debugStringJoiner;
340     }
341 
342     /**
343      * Get the hashCode for this value.
344      */
345     @Override
hashCode()346     public abstract int hashCode();
347 
isMixedTypeProperty(int prop)348     protected static boolean isMixedTypeProperty(int prop) {
349         return (prop & VehiclePropertyType.MASK) == VehiclePropertyType.MIXED;
350     }
351 
getFloatContainerArray()352     protected abstract Float[] getFloatContainerArray();
353 
getInt32ContainerArray()354     protected abstract Integer[] getInt32ContainerArray();
355 
getInt64ContainerArray()356     protected abstract Long[] getInt64ContainerArray();
357 
toRegularRawPropertyValue(int mgrPropId)358     private @Nullable RawPropertyValue<?> toRegularRawPropertyValue(int mgrPropId) {
359         Class<?> clazz = CarPropertyUtils.getJavaClass(getPropId() & VehiclePropertyType.MASK);
360         Object value = null;
361 
362         if (Boolean.class == clazz) {
363             if (getInt32ValuesSize() == 0) {
364                 return null;
365             }
366             value = Boolean.valueOf(getInt32Value(0) == 1);
367         } else if (Float.class == clazz) {
368             if (getFloatValuesSize() == 0) {
369                 return null;
370             }
371             value = Float.valueOf(getFloatValue(0));
372         } else if (Integer.class == clazz) {
373             if (getInt32ValuesSize() == 0) {
374                 return null;
375             }
376             value = Integer.valueOf(getInt32Value(0));
377         } else if (Long.class == clazz) {
378             if (getInt64ValuesSize() == 0) {
379                 return null;
380             }
381             value = Long.valueOf(getInt64Value(0));
382         } else if (Float[].class == clazz) {
383             value = getFloatContainerArray();
384         } else if (Integer[].class == clazz) {
385             value = getInt32ContainerArray();
386         } else if (Long[].class == clazz) {
387             value = getInt64ContainerArray();
388         } else if (String.class == clazz) {
389             value = getStringValue();
390         } else if (byte[].class == clazz) {
391             value = getByteArray();
392         } else {
393             throw new IllegalStateException(
394                     "Unexpected type " + clazz + " - propertyId: " + VehiclePropertyIds.toString(
395                             mgrPropId));
396         }
397         return new RawPropertyValue(value);
398     }
399 
toMixedRawPropertyValue( boolean containBoolean, boolean containString)400     private @Nullable RawPropertyValue<?> toMixedRawPropertyValue(
401             boolean containBoolean, boolean containString) {
402         List<Object> valuesList = new ArrayList<>();
403         if (containString) {
404             valuesList.add(getStringValue());
405         }
406         if (containBoolean) {
407             if (getInt32ValuesSize() == 0) {
408                 return null;
409             }
410             boolean boolValue = getInt32Value(0) == 1;
411             valuesList.add(boolValue);
412             for (int i = 1; i < getInt32ValuesSize(); i++) {
413                 valuesList.add(getInt32Value(i));
414             }
415         } else {
416             for (int i = 0; i < getInt32ValuesSize(); i++) {
417                 valuesList.add(getInt32Value(i));
418             }
419         }
420         for (int i = 0; i < getInt64ValuesSize(); i++) {
421             valuesList.add(getInt64Value(i));
422         }
423         for (int i = 0; i < getFloatValuesSize(); i++) {
424             valuesList.add(getFloatValue(i));
425         }
426         for (int i = 0; i < getByteValuesSize(); i++) {
427             valuesList.add(getByteValue(i));
428         }
429         return new RawPropertyValue(valuesList.toArray());
430     }
431 
equalInt32Values(HalPropValue argument)432     private boolean equalInt32Values(HalPropValue argument) {
433         if (getInt32ValuesSize() != argument.getInt32ValuesSize()) {
434             return false;
435         }
436         for (int i = 0; i < getInt32ValuesSize(); i++) {
437             if (getInt32Value(i) != argument.getInt32Value(i)) {
438                 return false;
439             }
440         }
441         return true;
442     }
443 
equalFloatValues(HalPropValue argument)444     private boolean equalFloatValues(HalPropValue argument) {
445         if (getFloatValuesSize() != argument.getFloatValuesSize()) {
446             return false;
447         }
448         for (int i = 0; i < getFloatValuesSize(); i++) {
449             if (getFloatValue(i) != argument.getFloatValue(i)) {
450                 return false;
451             }
452         }
453         return true;
454     }
455 
equalInt64Values(HalPropValue argument)456     private boolean equalInt64Values(HalPropValue argument) {
457         if (getInt64ValuesSize() != argument.getInt64ValuesSize()) {
458             return false;
459         }
460         for (int i = 0; i < getInt64ValuesSize(); i++) {
461             if (getInt64Value(i) != argument.getInt64Value(i)) {
462                 return false;
463             }
464         }
465         return true;
466     }
467 
vehiclePropertyStatusToCarPropertyStatus( @ehiclePropertyStatus int status)468     private static @CarPropertyValue.PropertyStatus int vehiclePropertyStatusToCarPropertyStatus(
469             @VehiclePropertyStatus int status) {
470         switch (status) {
471             case VehiclePropertyStatus.AVAILABLE:
472                 return CarPropertyValue.STATUS_AVAILABLE;
473             case VehiclePropertyStatus.ERROR:
474                 return CarPropertyValue.STATUS_ERROR;
475             case VehiclePropertyStatus.NOT_AVAILABLE_GENERAL:
476                 return CarPropertyValue.STATUS_UNAVAILABLE;
477             // TODO(b/381298607): Map these to individual CarPropertyValue status.
478             case VehiclePropertyStatus.NOT_AVAILABLE_DISABLED:  // Fallthrough
479             case VehiclePropertyStatus.NOT_AVAILABLE_SPEED_LOW:  // Fallthrough
480             case VehiclePropertyStatus.NOT_AVAILABLE_SPEED_HIGH:  // Fallthrough
481             case VehiclePropertyStatus.NOT_AVAILABLE_POOR_VISIBILITY:  // Fallthrough
482             case VehiclePropertyStatus.NOT_AVAILABLE_SAFETY:  // Fallthrough
483             case VehiclePropertyStatus.NOT_AVAILABLE_SUBSYSTEM_NOT_CONNECTED:
484                 return CarPropertyValue.STATUS_UNAVAILABLE;
485         }
486         return CarPropertyValue.STATUS_ERROR;
487     }
488 }