1 /* 2 * Copyright (C) 2016 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; 18 19 import static com.android.car.CarServiceUtils.toByteArray; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertNotNull; 23 24 import android.car.Car; 25 import android.car.hardware.CarPropertyConfig; 26 import android.car.hardware.CarVendorExtensionManager; 27 import android.hardware.automotive.vehicle.V2_0.StatusCode; 28 import android.hardware.automotive.vehicle.V2_0.VehicleArea; 29 import android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat; 30 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig; 31 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 32 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup; 33 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType; 34 import android.os.SystemClock; 35 import android.support.test.filters.MediumTest; 36 import android.support.test.runner.AndroidJUnit4; 37 import android.util.Log; 38 import android.util.SparseArray; 39 40 import com.android.car.vehiclehal.test.MockedVehicleHal; 41 import com.android.car.vehiclehal.test.VehiclePropConfigBuilder; 42 43 import org.junit.Assert; 44 import org.junit.Test; 45 import org.junit.runner.RunWith; 46 47 import java.util.Arrays; 48 import java.util.List; 49 import java.util.Random; 50 51 /** 52 * Tests for {@link CarVendorExtensionManager} 53 */ 54 @RunWith(AndroidJUnit4.class) 55 @MediumTest 56 public class CarVendorExtensionManagerTest extends MockedCarTestBase { 57 58 private static final String TAG = CarVendorExtensionManager.class.getSimpleName(); 59 60 private static final int CUSTOM_GLOBAL_INT_PROP_ID = 61 0x1 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 62 63 private static final int CUSTOM_ZONED_FLOAT_PROP_ID = 64 0x2 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.FLOAT | VehicleArea.SEAT; 65 66 private static final int CUSTOM_BYTES_PROP_ID_1 = 67 0x3 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.BYTES | VehicleArea.SEAT; 68 69 private static final int CUSTOM_BYTES_PROP_ID_2 = 70 0x4 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.BYTES | VehicleArea.GLOBAL; 71 72 private static final int CUSTOM_STRING_PROP_ID = 73 0x5 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.STRING | VehicleArea.GLOBAL; 74 75 private static final float EPS = 1e-9f; 76 private static final int MILLION = 1000 * 1000; 77 78 private static final int MIN_PROP_INT32 = 0x0000005; 79 private static final int MAX_PROP_INT32 = 0xDeadBee; 80 81 private static final float MIN_PROP_FLOAT = 10.42f; 82 private static final float MAX_PROP_FLOAT = 42.10f; 83 84 // private static final MockedVehicleHal mVehicleHal = new MockedVehicleHal(); 85 86 private static final VehiclePropConfig mConfigs[] = new VehiclePropConfig[] { 87 VehiclePropConfigBuilder.newBuilder(CUSTOM_GLOBAL_INT_PROP_ID) 88 .addAreaConfig(0, MIN_PROP_INT32, MAX_PROP_INT32) 89 .build(), 90 VehiclePropConfigBuilder.newBuilder(CUSTOM_ZONED_FLOAT_PROP_ID) 91 .addAreaConfig(VehicleAreaSeat.ROW_1_LEFT | VehicleAreaSeat.ROW_1_RIGHT, 0, 0) 92 .addAreaConfig(VehicleAreaSeat.ROW_1_LEFT, MIN_PROP_FLOAT, MAX_PROP_FLOAT) 93 .addAreaConfig(VehicleAreaSeat.ROW_2_RIGHT, MIN_PROP_FLOAT, MAX_PROP_FLOAT) 94 .build(), 95 VehiclePropConfigBuilder.newBuilder(CUSTOM_BYTES_PROP_ID_1) 96 .addAreaConfig(VehicleAreaSeat.ROW_1_LEFT | VehicleAreaSeat.ROW_1_RIGHT, 0, 0) 97 .build(), 98 VehiclePropConfigBuilder.newBuilder(CUSTOM_BYTES_PROP_ID_2).build(), 99 VehiclePropConfigBuilder.newBuilder(CUSTOM_STRING_PROP_ID).build(), 100 }; 101 102 private CarVendorExtensionManager mManager; 103 104 @Override 105 public void setUp() throws Exception { 106 super.setUp(); 107 108 mManager = (CarVendorExtensionManager) getCar().getCarManager(Car.VENDOR_EXTENSION_SERVICE); 109 assertNotNull(mManager); 110 } 111 112 @Test 113 public void testPropertyList() throws Exception { 114 List<CarPropertyConfig> configs = mManager.getProperties(); 115 assertEquals(mConfigs.length, configs.size()); 116 117 SparseArray<CarPropertyConfig> configById = new SparseArray<>(configs.size()); 118 for (CarPropertyConfig config : configs) { 119 configById.put(config.getPropertyId(), config); 120 } 121 122 CarPropertyConfig prop1 = configById.get(CUSTOM_GLOBAL_INT_PROP_ID); 123 assertNotNull(prop1); 124 assertEquals(Integer.class, prop1.getPropertyType()); 125 assertEquals(MIN_PROP_INT32, prop1.getMinValue()); 126 assertEquals(MAX_PROP_INT32, prop1.getMaxValue()); 127 } 128 129 @Test 130 public void testIntGlobalProperty() throws Exception { 131 final int value = 0xbeef; 132 mManager.setGlobalProperty(Integer.class, CUSTOM_GLOBAL_INT_PROP_ID, value); 133 int actualValue = mManager.getGlobalProperty(Integer.class, CUSTOM_GLOBAL_INT_PROP_ID); 134 assertEquals(value, actualValue); 135 } 136 137 @Test 138 public void testFloatZonedProperty() throws Exception { 139 final float value = MIN_PROP_FLOAT + 1; 140 mManager.setProperty( 141 Float.class, 142 CUSTOM_ZONED_FLOAT_PROP_ID, 143 VehicleAreaSeat.ROW_1_RIGHT, 144 value); 145 146 float actualValue = mManager.getProperty( 147 Float.class, CUSTOM_ZONED_FLOAT_PROP_ID, VehicleAreaSeat.ROW_1_RIGHT); 148 assertEquals(value, actualValue, EPS); 149 } 150 151 @Test 152 public void testByteArrayProperty() throws Exception { 153 final byte[] expectedData = new byte[] { 1, 2, 3, 4, -1, 127, -127, 0 }; 154 155 // Write to CUSTOM_BYTES_PROP_ID_1 and read this value from CUSTOM_BYTES_PROP_ID_2 156 mManager.setGlobalProperty( 157 byte[].class, 158 CUSTOM_BYTES_PROP_ID_1, 159 expectedData); 160 161 byte[] actualData = mManager.getGlobalProperty( 162 byte[].class, 163 CUSTOM_BYTES_PROP_ID_2); 164 165 assertEquals(Arrays.toString(expectedData), Arrays.toString(actualData)); 166 } 167 168 @Test 169 public void testLargeByteArrayProperty() throws Exception { 170 // Allocate array of byte which is greater than binder transaction buffer limitation. 171 byte[] expectedData = new byte[2 * MILLION]; 172 173 new Random(SystemClock.elapsedRealtimeNanos()) 174 .nextBytes(expectedData); 175 176 // Write to CUSTOM_BYTES_PROP_ID_1 and read this value from CUSTOM_BYTES_PROP_ID_2 177 mManager.setGlobalProperty( 178 byte[].class, 179 CUSTOM_BYTES_PROP_ID_1, 180 expectedData); 181 182 byte[] actualData = mManager.getGlobalProperty( 183 byte[].class, 184 CUSTOM_BYTES_PROP_ID_2); 185 186 Assert.assertArrayEquals(expectedData, actualData); 187 } 188 189 @Test 190 public void testLargeStringProperty() throws Exception { 191 // Allocate string which is greater than binder transaction buffer limitation. 192 String expectedString = generateRandomString(2 * MILLION, 193 "abcdefghijKLMN!@#$%^&*()[]{}:\"\t\n\r!'"); 194 195 mManager.setGlobalProperty( 196 String.class, 197 CUSTOM_STRING_PROP_ID, 198 expectedString); 199 200 String actualString = mManager.getGlobalProperty( 201 String.class, 202 CUSTOM_STRING_PROP_ID); 203 204 assertEquals(expectedString, actualString); 205 } 206 207 @Test 208 public void testStringProperty() throws Exception { 209 final String expectedString = "!"; // Test some utf as well. 210 211 mManager.setGlobalProperty( 212 String.class, 213 CUSTOM_STRING_PROP_ID, 214 expectedString); 215 216 String actualString = mManager.getGlobalProperty( 217 String.class, 218 CUSTOM_STRING_PROP_ID); 219 220 assertEquals(expectedString, actualString); 221 } 222 223 private static String generateRandomString(int length, String allowedSymbols) { 224 Random r = new Random(SystemClock.elapsedRealtimeNanos()); 225 StringBuilder sb = new StringBuilder(length); 226 char[] chars = allowedSymbols.toCharArray(); 227 for (int i = 0; i < length; i++) { 228 sb.append(chars[r.nextInt(chars.length)]); 229 } 230 return sb.toString(); 231 } 232 233 @Override 234 protected synchronized MockedVehicleHal createMockedVehicleHal() { 235 MockedVehicleHal hal = new VendorExtMockedVehicleHal(); 236 hal.addProperties(mConfigs); 237 return hal; 238 } 239 240 private static class VendorExtMockedVehicleHal extends MockedVehicleHal { 241 private final SparseArray<VehiclePropValue> mValues = new SparseArray<>(); 242 243 private byte[] mBytes = null; 244 245 @Override 246 public synchronized int set(VehiclePropValue propValue) { 247 if (propValue.prop == CUSTOM_BYTES_PROP_ID_1) { 248 mBytes = toByteArray(propValue.value.bytes); 249 } 250 251 mValues.put(propValue.prop, propValue); 252 return StatusCode.OK; 253 } 254 255 @Override 256 public synchronized void get(VehiclePropValue requestedPropValue, getCallback cb) { 257 if (!isVendorProperty(requestedPropValue.prop)) { 258 super.get(requestedPropValue, cb); 259 return; 260 } 261 VehiclePropValue result = new VehiclePropValue(); 262 result.prop = requestedPropValue.prop; 263 result.areaId = requestedPropValue.areaId; 264 265 if (requestedPropValue.prop == CUSTOM_BYTES_PROP_ID_2 && mBytes != null) { 266 Log.d(TAG, "Returning byte array property, value size " + mBytes.length); 267 result.value.bytes.ensureCapacity(mBytes.length); 268 for (byte b : mBytes) { 269 result.value.bytes.add(b); 270 } 271 } else { 272 VehiclePropValue existingValue = mValues.get(requestedPropValue.prop); 273 if (existingValue != null) { 274 result = existingValue; 275 } else { 276 result = requestedPropValue; 277 } 278 } 279 cb.onValues(StatusCode.OK, result); 280 } 281 282 private boolean isVendorProperty(int prop) { 283 return VehiclePropertyGroup.VENDOR == (prop & VehiclePropertyGroup.VENDOR); 284 } 285 } 286 } 287