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 android.car.hardware.CarPropertyValue; 20 import android.hardware.automotive.vehicle.VehiclePropertyType; 21 import android.util.Log; 22 23 import java.util.ArrayList; 24 import java.util.Arrays; 25 import java.util.List; 26 27 /** 28 * HalPropValue represents a vehicle property value. 29 * 30 * It could be used to convert between AIDL or HIDL VehiclePropValue used in vehicle HAL and 31 * {@link CarPropertyValue} used in CarPropertyManager. 32 */ 33 public abstract class HalPropValue { 34 private static final String TAG = HalPropValue.class.getSimpleName(); 35 36 /** 37 * Gets the timestamp. 38 * 39 * @return The timestamp. 40 */ getTimestamp()41 public abstract long getTimestamp(); 42 43 /** 44 * Gets the area ID. 45 * 46 * @return The area ID. 47 */ getAreaId()48 public abstract int getAreaId(); 49 50 /** 51 * Gets the property ID. 52 * 53 * @return The property ID. 54 */ getPropId()55 public abstract int getPropId(); 56 57 /** 58 * Gets the property status. 59 * 60 * @return The property status. 61 */ getStatus()62 public abstract int getStatus(); 63 64 /** 65 * Get stored int32 values size. 66 * 67 * @return The size for the stored int32 values. 68 */ getInt32ValuesSize()69 public abstract int getInt32ValuesSize(); 70 71 /** 72 * Gets the int32 value at index. 73 * 74 * @param index The index. 75 * @return The int32 value at index. 76 */ getInt32Value(int index)77 public abstract int getInt32Value(int index); 78 79 /** 80 * Dump all int32 values as a string. Used for debugging. 81 * 82 * @return A String representation of all int32 values. 83 */ dumpInt32Values()84 public abstract String dumpInt32Values(); 85 86 /** 87 * Get stored float values size. 88 * 89 * @return The size for the stored float values. 90 */ getFloatValuesSize()91 public abstract int getFloatValuesSize(); 92 93 /** 94 * Gets the float value at index. 95 * 96 * @param index The index. 97 * @return The float value at index. 98 */ getFloatValue(int index)99 public abstract float getFloatValue(int index); 100 101 /** 102 * Dump all float values as a string. Used for debugging. 103 * 104 * @return A String representation of all float values. 105 */ dumpFloatValues()106 public abstract String dumpFloatValues(); 107 108 /** 109 * Get stored inn64 values size. 110 * 111 * @return The size for the stored inn64 values. 112 */ getInt64ValuesSize()113 public abstract int getInt64ValuesSize(); 114 115 /** 116 * Gets the int64 value at index. 117 * 118 * @param index The index. 119 * @return The int64 value at index. 120 */ getInt64Value(int index)121 public abstract long getInt64Value(int index); 122 123 /** 124 * Dump all int64 values as a string. Used for debugging. 125 * 126 * @return A String representation of all int64 values. 127 */ dumpInt64Values()128 public abstract String dumpInt64Values(); 129 130 /** 131 * Get stored byte values size. 132 * 133 * @return The size for the stored byte values. 134 */ getByteValuesSize()135 public abstract int getByteValuesSize(); 136 137 /** 138 * Gets the byte value at index. 139 * 140 * @param index The index. 141 * @return The byte value at index. 142 */ getByteValue(int index)143 public abstract byte getByteValue(int index); 144 145 /** 146 * Gets the byte values. 147 * 148 * @return The byte values. 149 */ getByteArray()150 public abstract byte[] getByteArray(); 151 152 /** 153 * Gets the string value. 154 * 155 * @return The stored string value. 156 */ getStringValue()157 public abstract String getStringValue(); 158 159 /** 160 * Converts to an AIDL/HIDL VehiclePropValue that could be used to sent to vehicle HAL. 161 * 162 * @return An AIDL or HIDL VehiclePropValue. 163 */ toVehiclePropValue()164 public abstract Object toVehiclePropValue(); 165 166 /** 167 * Turns this class to a {@link CarPropertyValue}. 168 * 169 * @param mgrPropId The property ID used in {@link android.car.VehiclePropertyIds}. 170 * @param config The config for the property. 171 * @return A CarPropertyValue that could be passed to upper layer. 172 */ toCarPropertyValue(int mgrPropId, HalPropConfig config)173 public CarPropertyValue toCarPropertyValue(int mgrPropId, HalPropConfig config) { 174 if (isMixedTypeProperty(getPropId())) { 175 int[] configArray = config.getConfigArray(); 176 boolean containStringType = configArray[0] == 1; 177 boolean containBooleanType = configArray[1] == 1; 178 return toMixedCarPropertyValue(mgrPropId, containBooleanType, containStringType); 179 } 180 return toCarPropertyValue(mgrPropId); 181 } 182 183 /** 184 * Check whether this property is equal to another property. 185 * 186 * @param argument The property to compare. 187 * @return true if equal, false if not. 188 */ 189 @Override equals(Object argument)190 public boolean equals(Object argument) { 191 if (!(argument instanceof HalPropValue)) { 192 return false; 193 } 194 195 HalPropValue other = (HalPropValue) argument; 196 197 if (other.getPropId() != getPropId()) { 198 Log.i(TAG, "Property ID mismatch, got " + other.getPropId() + " want " 199 + getPropId()); 200 return false; 201 } 202 if (other.getAreaId() != getAreaId()) { 203 Log.i(TAG, "Area ID mismatch, got " + other.getAreaId() + " want " + getAreaId()); 204 return false; 205 } 206 if (other.getStatus() != getStatus()) { 207 Log.i(TAG, "Status mismatch, got " + other.getStatus() + " want " + getStatus()); 208 return false; 209 } 210 if (other.getTimestamp() != getTimestamp()) { 211 Log.i(TAG, "Timestamp mismatch, got " + other.getTimestamp() + " want " 212 + getTimestamp()); 213 return false; 214 } 215 if (!equalInt32Values(other)) { 216 Log.i(TAG, "Int32Values mismatch, got " + other.dumpInt32Values() + " want " 217 + dumpInt32Values()); 218 return false; 219 } 220 if (!equalFloatValues(other)) { 221 Log.i(TAG, "FloatValues mismatch, got " + other.dumpFloatValues() + " want " 222 + dumpFloatValues()); 223 return false; 224 } 225 if (!equalInt64Values(other)) { 226 Log.i(TAG, "Int64Values mismatch, got " + other.dumpInt64Values() + " want " 227 + dumpInt64Values()); 228 return false; 229 } 230 if (!Arrays.equals(other.getByteArray(), getByteArray())) { 231 Log.i(TAG, "ByteValues mismatch, got " + Arrays.toString(other.getByteArray()) 232 + " want " + Arrays.toString(getByteArray())); 233 return false; 234 } 235 if (!other.getStringValue().equals(getStringValue())) { 236 Log.i(TAG, "StringValue mismatch, got " + other.getStringValue() + " want " 237 + getStringValue()); 238 return false; 239 } 240 return true; 241 } 242 243 /** 244 * Get the hashCode for this value. 245 */ 246 @Override hashCode()247 public abstract int hashCode(); 248 isMixedTypeProperty(int prop)249 protected static boolean isMixedTypeProperty(int prop) { 250 return (prop & VehiclePropertyType.MASK) == VehiclePropertyType.MIXED; 251 } 252 getFloatContainerArray()253 protected abstract Float[] getFloatContainerArray(); 254 getInt32ContainerArray()255 protected abstract Integer[] getInt32ContainerArray(); 256 getInt64ContainerArray()257 protected abstract Long[] getInt64ContainerArray(); 258 toCarPropertyValue(int propertyId)259 private CarPropertyValue<?> toCarPropertyValue(int propertyId) { 260 Class<?> clazz = CarPropertyUtils.getJavaClass(getPropId() & VehiclePropertyType.MASK); 261 int areaId = getAreaId(); 262 int status = getStatus(); 263 long timestamp = getTimestamp(); 264 265 // Handles each return value from {@link getJavaClass}. 266 if (Boolean.class == clazz) { 267 return new CarPropertyValue<>( 268 propertyId, areaId, status, timestamp, getInt32Value(0) == 1); 269 } else if (Float.class == clazz) { 270 return new CarPropertyValue<>(propertyId, areaId, status, timestamp, getFloatValue(0)); 271 } else if (Integer.class == clazz) { 272 return new CarPropertyValue<>(propertyId, areaId, status, timestamp, getInt32Value(0)); 273 } else if (Long.class == clazz) { 274 return new CarPropertyValue<>(propertyId, areaId, status, timestamp, getInt64Value(0)); 275 } else if (Float[].class == clazz) { 276 return new CarPropertyValue<>( 277 propertyId, areaId, status, timestamp, getFloatContainerArray()); 278 } else if (Integer[].class == clazz) { 279 return new CarPropertyValue<>( 280 propertyId, areaId, status, timestamp, getInt32ContainerArray()); 281 } else if (Long[].class == clazz) { 282 return new CarPropertyValue<>( 283 propertyId, areaId, status, timestamp, getInt64ContainerArray()); 284 } else if (String.class == clazz) { 285 return new CarPropertyValue<>(propertyId, areaId, status, timestamp, getStringValue()); 286 } else if (byte[].class == clazz) { 287 return new CarPropertyValue<>(propertyId, areaId, status, timestamp, getByteArray()); 288 } else { 289 throw new IllegalArgumentException("Unexpected type in: " + propertyId); 290 } 291 } 292 toMixedCarPropertyValue( int propertyId, boolean containBoolean, boolean containString)293 private CarPropertyValue<?> toMixedCarPropertyValue( 294 int propertyId, boolean containBoolean, boolean containString) { 295 int areaId = getAreaId(); 296 int status = getStatus(); 297 long timestamp = getTimestamp(); 298 299 List<Object> valuesList = new ArrayList<>(); 300 if (containString) { 301 valuesList.add(getStringValue()); 302 } 303 if (containBoolean) { 304 boolean boolValue = getInt32Value(0) == 1; 305 valuesList.add(boolValue); 306 for (int i = 1; i < getInt32ValuesSize(); i++) { 307 valuesList.add(getInt32Value(i)); 308 } 309 } else { 310 for (int i = 0; i < getInt32ValuesSize(); i++) { 311 valuesList.add(getInt32Value(i)); 312 } 313 } 314 for (int i = 0; i < getInt64ValuesSize(); i++) { 315 valuesList.add(getInt64Value(i)); 316 } 317 for (int i = 0; i < getFloatValuesSize(); i++) { 318 valuesList.add(getFloatValue(i)); 319 } 320 for (int i = 0; i < getByteValuesSize(); i++) { 321 valuesList.add(getByteValue(i)); 322 } 323 return new CarPropertyValue<>(propertyId, areaId, status, timestamp, valuesList.toArray()); 324 } 325 equalInt32Values(HalPropValue argument)326 private boolean equalInt32Values(HalPropValue argument) { 327 if (getInt32ValuesSize() != argument.getInt32ValuesSize()) { 328 return false; 329 } 330 for (int i = 0; i < getInt32ValuesSize(); i++) { 331 if (getInt32Value(i) != argument.getInt32Value(i)) { 332 return false; 333 } 334 } 335 return true; 336 } 337 equalFloatValues(HalPropValue argument)338 private boolean equalFloatValues(HalPropValue argument) { 339 if (getFloatValuesSize() != argument.getFloatValuesSize()) { 340 return false; 341 } 342 for (int i = 0; i < getFloatValuesSize(); i++) { 343 if (getFloatValue(i) != argument.getFloatValue(i)) { 344 return false; 345 } 346 } 347 return true; 348 } 349 equalInt64Values(HalPropValue argument)350 private boolean equalInt64Values(HalPropValue argument) { 351 if (getInt64ValuesSize() != argument.getInt64ValuesSize()) { 352 return false; 353 } 354 for (int i = 0; i < getInt64ValuesSize(); i++) { 355 if (getInt64Value(i) != argument.getInt64Value(i)) { 356 return false; 357 } 358 } 359 return true; 360 } 361 } 362