• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.property;
18 
19 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.PRIVATE_CONSTRUCTOR;
20 import static com.android.car.internal.util.ConstantDebugUtils.toName;
21 import static com.android.car.internal.util.DebugUtils.flagsToOptionalString;
22 
23 import static java.lang.Integer.toHexString;
24 
25 import android.annotation.Nullable;
26 import android.hardware.automotive.vehicle.EnumForVehicleProperty;
27 import android.hardware.automotive.vehicle.UnitsForVehicleProperty;
28 import android.hardware.automotive.vehicle.VehicleArea;
29 import android.hardware.automotive.vehicle.VehicleAreaDoor;
30 import android.hardware.automotive.vehicle.VehicleAreaMirror;
31 import android.hardware.automotive.vehicle.VehicleAreaSeat;
32 import android.hardware.automotive.vehicle.VehicleAreaWheel;
33 import android.hardware.automotive.vehicle.VehicleAreaWindow;
34 import android.hardware.automotive.vehicle.VehicleProperty;
35 import android.hardware.automotive.vehicle.VehiclePropertyAccess;
36 import android.hardware.automotive.vehicle.VehiclePropertyChangeMode;
37 import android.hardware.automotive.vehicle.VehiclePropertyGroup;
38 import android.hardware.automotive.vehicle.VehiclePropertyStatus;
39 import android.hardware.automotive.vehicle.VehiclePropertyType;
40 import android.hardware.automotive.vehicle.VehicleUnit;
41 import android.util.Slog;
42 
43 import com.android.car.hal.HalPropValue;
44 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
45 import com.android.car.internal.property.CarPropertyHelper;
46 import com.android.car.internal.property.PropIdAreaId;
47 import com.android.car.internal.util.ConstantDebugUtils;
48 
49 import java.util.Arrays;
50 import java.util.StringJoiner;
51 
52 /**
53  * Utility class for converting {@link VehicleProperty} related information to human-readable names.
54  */
55 public final class HalPropertyDebugUtils {
56     private static final String TAG = HalPropertyDebugUtils.class.getSimpleName();
57     private static final int MAX_BYTE_SIZE = 20;
58     private static final String NO_VALUE = "NO_VALUE";
59 
60     /**
61      * HalPropertyDebugUtils only contains static fields and methods and must never be
62      * instantiated.
63      */
64     @ExcludeFromCodeCoverageGeneratedReport(reason = PRIVATE_CONSTRUCTOR)
HalPropertyDebugUtils()65     private HalPropertyDebugUtils() {
66         throw new UnsupportedOperationException("Must never be called");
67     }
68 
69     /**
70      * Gets a user-friendly representation string representation of a {@code propertyId}.
71      */
toPropertyIdString(int propertyId)72     public static String toPropertyIdString(int propertyId) {
73         String hexSuffix = "(0x" + toHexString(propertyId) + ")";
74         if (isSystemPropertyId(propertyId)) {
75             return VehicleProperty.$.toString(propertyId) + hexSuffix;
76         } else if (CarPropertyHelper.isVendorProperty(propertyId)) {
77             return "VENDOR_PROPERTY" + hexSuffix;
78         } else if (CarPropertyHelper.isBackportedProperty(propertyId)) {
79             return "BACKPORTED_PROPERTY" + hexSuffix;
80         }
81         return "INVALID_PROPERTY_ID" + hexSuffix;
82     }
83 
84     /**
85      * Gets the HAL property's ID based on the passed name.
86      */
87     @Nullable
toPropertyId(String propertyName)88     public static Integer toPropertyId(String propertyName) {
89         return ConstantDebugUtils.toValue(VehicleProperty.class, propertyName);
90     }
91 
92     /**
93      * Gets a user-friendly string representation of an {@code areaId} for the given
94      * {@code propertyId}.
95      */
toAreaIdString(int propertyId, int areaId)96     public static String toAreaIdString(int propertyId, int areaId) {
97         switch (propertyId & VehicleArea.MASK) {
98             case VehicleArea.GLOBAL -> {
99                 if (areaId == 0) {
100                     return "GLOBAL(0x0)";
101                 }
102                 return "INVALID_GLOBAL_AREA_ID(0x" + toHexString(areaId) + ")";
103             }
104             case VehicleArea.DOOR -> {
105                 return processOptionalFlagsString(
106                         flagsToOptionalString(VehicleAreaDoor.class, areaId),
107                         VehicleAreaDoor.class.getSimpleName(), areaId);
108             }
109             case VehicleArea.SEAT -> {
110                 return processOptionalFlagsString(
111                         flagsToOptionalString(VehicleAreaSeat.class, areaId),
112                         VehicleAreaSeat.class.getSimpleName(), areaId);
113             }
114             case VehicleArea.MIRROR -> {
115                 return processOptionalFlagsString(
116                         flagsToOptionalString(VehicleAreaMirror.class, areaId),
117                         VehicleAreaMirror.class.getSimpleName(), areaId);
118             }
119             case VehicleArea.WHEEL -> {
120                 return processOptionalFlagsString(
121                         flagsToOptionalString(VehicleAreaWheel.class, areaId),
122                         VehicleAreaWheel.class.getSimpleName(), areaId);
123             }
124             case VehicleArea.WINDOW -> {
125                 return processOptionalFlagsString(
126                         flagsToOptionalString(VehicleAreaWindow.class, areaId),
127                         VehicleAreaWindow.class.getSimpleName(), areaId);
128             }
129             default -> {
130                 return "UNKNOWN_AREA_ID(0x" + toHexString(areaId) + ")";
131             }
132         }
133     }
134 
135     /**
136      * Gets a user-friendly representation string representation of the value of a
137      * {@link HalPropValue} instance.
138      */
toValueString(HalPropValue halPropValue)139     public static String toValueString(HalPropValue halPropValue) {
140         int propertyId = halPropValue.getPropId();
141         int valueType = propertyId & VehiclePropertyType.MASK;
142         String propertyUnits = getUnitsIfSupported(propertyId);
143         StringJoiner stringJoiner = new StringJoiner(", ", "[", "]");
144         switch (valueType) {
145             case VehiclePropertyType.BOOLEAN -> {
146                 if (halPropValue.getInt32ValuesSize() != 1) {
147                     return NO_VALUE;
148                 }
149                 return halPropValue.getInt32Value(0) == 0 ? "FALSE" : "TRUE";
150             }
151             case VehiclePropertyType.INT32 -> {
152                 if (halPropValue.getInt32ValuesSize() != 1) {
153                     return NO_VALUE;
154                 }
155                 return getIntValueName(propertyId, halPropValue.getInt32Value(0), propertyUnits);
156             }
157             case VehiclePropertyType.INT32_VEC -> {
158                 for (int i = 0; i < halPropValue.getInt32ValuesSize(); i++) {
159                     stringJoiner.add(getIntValueName(propertyId, halPropValue.getInt32Value(i),
160                             propertyUnits));
161                 }
162                 return stringJoiner.toString();
163             }
164             case VehiclePropertyType.FLOAT -> {
165                 if (halPropValue.getFloatValuesSize() != 1) {
166                     return NO_VALUE;
167                 }
168                 return halPropValue.getFloatValue(0) + propertyUnits;
169             }
170             case VehiclePropertyType.FLOAT_VEC -> {
171                 for (int i = 0; i < halPropValue.getFloatValuesSize(); i++) {
172                     stringJoiner.add(halPropValue.getFloatValue(i) + propertyUnits);
173                 }
174                 return stringJoiner.toString();
175             }
176             case VehiclePropertyType.INT64 -> {
177                 if (halPropValue.getInt64ValuesSize() != 1) {
178                     return NO_VALUE;
179                 }
180                 return halPropValue.getInt64Value(0) + propertyUnits;
181             }
182             case VehiclePropertyType.INT64_VEC -> {
183                 for (int i = 0; i < halPropValue.getInt64ValuesSize(); i++) {
184                     stringJoiner.add(halPropValue.getInt64Value(i) + propertyUnits);
185                 }
186                 return stringJoiner.toString();
187             }
188             case VehiclePropertyType.STRING -> {
189                 return halPropValue.getStringValue();
190             }
191             case VehiclePropertyType.BYTES -> {
192                 String bytesString = "";
193                 byte[] byteValues = halPropValue.getByteArray();
194                 if (byteValues.length > MAX_BYTE_SIZE) {
195                     byte[] bytes = Arrays.copyOf(byteValues, MAX_BYTE_SIZE);
196                     bytesString = Arrays.toString(bytes);
197                 } else {
198                     bytesString = Arrays.toString(byteValues);
199                 }
200                 return bytesString;
201             }
202         }
203         String bytesString = "";
204         byte[] byteValues = halPropValue.getByteArray();
205         if (byteValues.length > MAX_BYTE_SIZE) {
206             byte[] bytes = Arrays.copyOf(byteValues, MAX_BYTE_SIZE);
207             bytesString = Arrays.toString(bytes);
208         } else {
209             bytesString = Arrays.toString(byteValues);
210         }
211         return "floatValues: " + halPropValue.dumpFloatValues() + ", int32Values: "
212                 + halPropValue.dumpInt32Values() + ", int64Values: "
213                 + halPropValue.dumpInt64Values() + ", bytes: " + bytesString + ", string: "
214                 + halPropValue.getStringValue();
215     }
216 
getIntValueName(int propertyId, int value, String propertyUnits)217     private static String getIntValueName(int propertyId, int value, String propertyUnits) {
218         if (EnumForVehicleProperty.values.containsKey(propertyId)) {
219             for (int i = 0; i < EnumForVehicleProperty.values.get(propertyId).size(); i++) {
220                 Class<?> enumClazz = EnumForVehicleProperty.values.get(propertyId).get(i);
221                 String valueName = ConstantDebugUtils.toName(enumClazz, value);
222                 if (valueName != null) {
223                     return valueName + "(0x" + toHexString(value) + ")";
224                 }
225             }
226             Slog.w(TAG,
227                     "Failed to find enum name for property ID: " + toPropertyIdString(propertyId)
228                             + " value: " + value);
229         }
230         return value + propertyUnits;
231     }
232 
getUnitsIfSupported(int propertyId)233     private static String getUnitsIfSupported(int propertyId) {
234         if (!UnitsForVehicleProperty.values.containsKey(propertyId)) {
235             return "";
236         }
237         Integer units = UnitsForVehicleProperty.values.get(propertyId);
238         String unitsString = ConstantDebugUtils.toName(VehicleUnit.class, units);
239         if (unitsString == null) {
240             return "";
241         }
242         return " " + unitsString;
243     }
244 
245     /**
246      * Gets a user-friendly representation string representation of {@link VehicleArea}
247      * constant for the passed {@code propertyId}.
248      */
toAreaTypeString(int propertyId)249     public static String toAreaTypeString(int propertyId) {
250         int areaType = propertyId & VehicleArea.MASK;
251         return toDebugString(VehicleArea.class, areaType);
252     }
253 
254     /**
255      * Gets a user-friendly representation string representation of {@link VehiclePropertyGroup}
256      * constant for the passed {@code propertyId}.
257      */
toGroupString(int propertyId)258     public static String toGroupString(int propertyId) {
259         int group = propertyId & VehiclePropertyGroup.MASK;
260         return toDebugString(VehiclePropertyGroup.class, group);
261     }
262 
263     /**
264      * Gets a user-friendly representation string representation of {@link VehiclePropertyType}
265      * constant for the passed {@code propertyId}.
266      */
toValueTypeString(int propertyId)267     public static String toValueTypeString(int propertyId) {
268         int valueType = propertyId & VehiclePropertyType.MASK;
269         return toDebugString(VehiclePropertyType.class, valueType);
270     }
271 
272     /**
273      * Gets a user-friendly representation string representation of
274      * {@link VehiclePropertyAccess} constant.
275      */
toAccessString(int access)276     public static String toAccessString(int access) {
277         return toDebugString(VehiclePropertyAccess.class, access);
278     }
279 
280     /**
281      * Gets a user-friendly representation string representation of
282      * {@link VehiclePropertyChangeMode} constant.
283      */
toChangeModeString(int changeMode)284     public static String toChangeModeString(int changeMode) {
285         return toDebugString(VehiclePropertyChangeMode.class, changeMode);
286     }
287 
288     /**
289      * Gets a user-friendly representation string representation of
290      * {@link VehiclePropertyStatus} constant.
291      */
toStatusString(int status)292     public static String toStatusString(int status) {
293         return toDebugString(VehiclePropertyStatus.class, status);
294     }
295 
toDebugString(Class<?> clazz, int constantValue)296     private static String toDebugString(Class<?> clazz, int constantValue) {
297         String hexSuffix = "(0x" + toHexString(constantValue) + ")";
298         if (toName(clazz, constantValue) == null) {
299             String invalidConstantValue = "INVALID_" + clazz.getSimpleName() + hexSuffix;
300             Slog.e(TAG, invalidConstantValue);
301             return invalidConstantValue;
302         }
303         return toName(clazz, constantValue) + hexSuffix;
304     }
305 
306     /**
307      * Gets human-readable representation of a {@code PropIdAreaId} structure.
308      *
309      * Note that the property ID is the VHAL property ID, not the CarPropertyManager property ID.
310      */
toHalPropIdAreaIdString(PropIdAreaId propIdAreaId)311     public static String toHalPropIdAreaIdString(PropIdAreaId propIdAreaId) {
312         return "PropIdAreaId{propId=" + toPropertyIdString(propIdAreaId.propId)
313             + ", areaId=" + toAreaIdString(propIdAreaId.propId, propIdAreaId.areaId) + "}";
314     }
315 
316     /**
317      * Gets human-readable representation of a list of {@code PropIdAreaId}.
318      *
319      * Note that the property ID is the VHAL property ID, not the CarPropertyManager property ID.
320      */
toHalPropIdAreaIdsString(Iterable<PropIdAreaId> propIdAreaIds)321     public static String toHalPropIdAreaIdsString(Iterable<PropIdAreaId> propIdAreaIds) {
322         StringBuilder sb = new StringBuilder();
323         sb.append("[");
324         boolean first = true;
325         for (PropIdAreaId propIdAreaId : propIdAreaIds) {
326             if (first) {
327                 first = false;
328             } else {
329                 sb.append(", ");
330             }
331             sb.append(toHalPropIdAreaIdString(propIdAreaId));
332         }
333         sb.append("]");
334         return sb.toString();
335     }
336 
337     /**
338      * Returns {@code true} if {@code propertyId} is defined in {@link VehicleProperty}.
339      * {@code false} otherwise.
340      */
isSystemPropertyId(int propertyId)341     private static boolean isSystemPropertyId(int propertyId) {
342         return (propertyId & VehiclePropertyGroup.MASK) == VehiclePropertyGroup.SYSTEM;
343     }
344 
processOptionalFlagsString(@ullable String flagsString, String clazzName, int areaId)345     private static String processOptionalFlagsString(@Nullable String flagsString, String clazzName,
346             int areaId) {
347         StringBuilder stringBuilder = new StringBuilder();
348         if (flagsString == null) {
349             stringBuilder.append("INVALID_").append(clazzName).append("_AREA_ID");
350         } else {
351             stringBuilder.append(flagsString);
352         }
353         return stringBuilder.append("(0x").append(toHexString(areaId)).append(")").toString();
354     }
355 }
356