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