• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.internal.property;
18 
19 import android.annotation.SuppressLint;
20 import android.car.VehiclePropertyIds;
21 import android.car.hardware.CarPropertyValue;
22 import android.car.hardware.property.VehicleHalStatusCode;
23 import android.car.hardware.property.VehicleHalStatusCode.VehicleHalStatusCodeInt;
24 import android.util.Log;
25 import android.util.SparseArray;
26 
27 import java.lang.reflect.Field;
28 import java.lang.reflect.Modifier;
29 import java.util.Collection;
30 import java.util.concurrent.atomic.AtomicReference;
31 
32 /**
33  * Helper class for CarPropertyService/CarPropertyManager.
34  *
35  * @hide
36  */
37 public final class CarPropertyHelper {
38     private static final String TAG = CarPropertyHelper.class.getSimpleName();
39 
40     /**
41      * Status indicating no error.
42      *
43      * <p>This is not exposed to the client as this will be used only for deciding
44      * {@link GetPropertyCallback#onSuccess} or {@link GetPropertyCallback#onFailure} is called.
45      */
46     public static final int STATUS_OK = 0;
47 
48     /**
49      * Error indicating that too many sync operation is ongoing, caller should try again after
50      * some time.
51      */
52     public static final int SYNC_OP_LIMIT_TRY_AGAIN = -1;
53 
54     // These are the same values as defined in VHAL interface.
55     private static final int VEHICLE_PROPERTY_GROUP_MASK = 0xf0000000;
56     private static final int VEHICLE_PROPERTY_GROUP_VENDOR = 0x20000000;
57 
58     private static final int SYSTEM_ERROR_CODE_MASK = 0xffff;
59     private static final int VENDOR_ERROR_CODE_SHIFT = 16;
60 
61     /*
62      * Used to cache the mapping of property Id integer values into property name strings. This
63      * will be initialized during the first usage.
64      */
65     private static final AtomicReference<SparseArray<String>> sPropertyIdToPropertyNameHolder =
66             new AtomicReference<>();
67 
68     /**
69      * CarPropertyHelper only contains static fields and methods and must never be instantiated.
70      */
CarPropertyHelper()71     private CarPropertyHelper() {
72         throw new IllegalArgumentException("Must never be called");
73     }
74 
75     /**
76      * Returns whether the property ID is supported by the current Car Service version.
77      */
isSupported(int propertyId)78     public static boolean isSupported(int propertyId) {
79         return isSystemProperty(propertyId) || isVendorProperty(propertyId);
80     }
81 
82     /**
83      * Gets a user-friendly representation of a property.
84      */
toString(int propertyId)85     public static String toString(int propertyId) {
86         String name = cachePropertyIdsToNameMapping().get(propertyId);
87         return name != null ? name : "0x" + Integer.toHexString(propertyId);
88     }
89 
90     /**
91      * Gets a user-friendly representation of a list of properties.
92      */
propertyIdsToString(Collection<Integer> propertyIds)93     public static String propertyIdsToString(Collection<Integer> propertyIds) {
94         String names = "[";
95         boolean first = true;
96         for (int propertyId : propertyIds) {
97             if (first) {
98                 first = false;
99             } else {
100                 names += ", ";
101             }
102             names += toString(propertyId);
103         }
104         return names + "]";
105     }
106 
107     /**
108      * Returns the system error code contained in the error code returned from VHAL.
109      */
110     @SuppressLint("WrongConstant")
getVhalSystemErrorCode(int vhalErrorCode)111     public static @VehicleHalStatusCodeInt int getVhalSystemErrorCode(int vhalErrorCode) {
112         return vhalErrorCode & SYSTEM_ERROR_CODE_MASK;
113     }
114 
115     /**
116      * Returns the vendor error code contained in the error code returned from VHAL.
117      */
getVhalVendorErrorCode(int vhalErrorCode)118     public static int getVhalVendorErrorCode(int vhalErrorCode) {
119         return vhalErrorCode >>> VENDOR_ERROR_CODE_SHIFT;
120     }
121 
122     /**
123      * Returns {@code true} if {@code vehicleHalStatusCode} is one of the not available
124      * {@link VehicleHalStatusCode} values}. Otherwise returns {@code false}.
125      */
isNotAvailableVehicleHalStatusCode( @ehicleHalStatusCodeInt int vehicleHalStatusCode)126     public static boolean isNotAvailableVehicleHalStatusCode(
127             @VehicleHalStatusCodeInt int vehicleHalStatusCode) {
128         switch (vehicleHalStatusCode) {
129             case VehicleHalStatusCode.STATUS_NOT_AVAILABLE:
130             case VehicleHalStatusCode.STATUS_NOT_AVAILABLE_DISABLED:
131             case VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_LOW:
132             case VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_HIGH:
133             case VehicleHalStatusCode.STATUS_NOT_AVAILABLE_POOR_VISIBILITY:
134             case VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SAFETY:
135                 return true;
136             default:
137                 return false;
138         }
139     }
140 
cachePropertyIdsToNameMapping()141     private static SparseArray<String> cachePropertyIdsToNameMapping() {
142         SparseArray<String> propertyIdsToNameMapping = sPropertyIdToPropertyNameHolder.get();
143         if (propertyIdsToNameMapping == null) {
144             propertyIdsToNameMapping = getPropertyIdsToNameMapping();
145             sPropertyIdToPropertyNameHolder.compareAndSet(null, propertyIdsToNameMapping);
146         }
147         return propertyIdsToNameMapping;
148     }
149 
150     /**
151      * Creates a SparseArray mapping property Ids to their String representations
152      * directly from this class.
153      */
getPropertyIdsToNameMapping()154     private static SparseArray<String> getPropertyIdsToNameMapping() {
155         Field[] classFields = VehiclePropertyIds.class.getDeclaredFields();
156         SparseArray<String> propertyIdsToNameMapping = new SparseArray<>(classFields.length);
157         for (int i = 0; i < classFields.length; i++) {
158             Field candidateField = classFields[i];
159             try {
160                 if (isPropertyId(candidateField)) {
161                     propertyIdsToNameMapping
162                             .put(candidateField.getInt(null), candidateField.getName());
163                 }
164             } catch (IllegalAccessException e) {
165                 Log.wtf(TAG, "Failed trying to find value for " + candidateField.getName(), e);
166             }
167         }
168         return propertyIdsToNameMapping;
169     }
170 
isPropertyId(Field field)171     private static boolean isPropertyId(Field field) {
172         // We only want public static final int values
173         return field.getType() == int.class
174             && field.getModifiers() == (Modifier.STATIC | Modifier.FINAL | Modifier.PUBLIC);
175     }
176 
177     /**
178      * Returns whether the property ID is defined as a system property.
179      */
isSystemProperty(int propertyId)180     private static boolean isSystemProperty(int propertyId) {
181         return propertyId != VehiclePropertyIds.INVALID
182                 && cachePropertyIdsToNameMapping().contains(propertyId);
183     }
184 
185     /**
186      * Returns whether the property ID is defined as a vendor property.
187      */
isVendorProperty(int propertyId)188     private static boolean isVendorProperty(int propertyId) {
189         return (propertyId & VEHICLE_PROPERTY_GROUP_MASK) == VEHICLE_PROPERTY_GROUP_VENDOR;
190     }
191 
192 
193     /**
194      * Gets the default value for a {@link CarPropertyValue} class type.
195      */
getDefaultValue(Class<T> clazz)196     public static <T> T getDefaultValue(Class<T> clazz) {
197         if (clazz.equals(Boolean.class)) {
198             return (T) Boolean.FALSE;
199         }
200         if (clazz.equals(Integer.class)) {
201             return (T) Integer.valueOf(0);
202         }
203         if (clazz.equals(Long.class)) {
204             return (T) Long.valueOf(0);
205         }
206         if (clazz.equals(Float.class)) {
207             return (T) Float.valueOf(0f);
208         }
209         if (clazz.equals(Integer[].class)) {
210             return (T) new Integer[0];
211         }
212         if (clazz.equals(Long[].class)) {
213             return (T) new Long[0];
214         }
215         if (clazz.equals(Float[].class)) {
216             return (T) new Float[0];
217         }
218         if (clazz.equals(byte[].class)) {
219             return (T) new byte[0];
220         }
221         if (clazz.equals(Object[].class)) {
222             return (T) new Object[0];
223         }
224         if (clazz.equals(String.class)) {
225             return (T) new String("");
226         }
227         throw new IllegalArgumentException("Unexpected class: " + clazz);
228     }
229 }
230