CarVendorExtensionManagerTest.java revision 52d7da59a5445b9e139527a75b795625c174a948
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.vehiclenetwork.VehicleNetworkConsts.VehiclePermissionModel.VEHICLE_PERMISSION_NO_RESTRICTION;
20import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
21import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE;
22import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_BYTES;
23import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_INT32;
24import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_STRING;
25import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_FLOAT;
26import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleZone.VEHICLE_ZONE_ROW_1_LEFT;
27import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleZone.VEHICLE_ZONE_ROW_1_RIGHT;
28import static com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue.newBuilder;
29import static java.util.Collections.singletonList;
30
31import android.car.Car;
32import android.car.hardware.CarPropertyConfig;
33import android.car.hardware.CarVendorExtensionManager;
34import android.car.test.CarTestManager;
35import android.car.test.CarTestManagerBinderWrapper;
36import android.os.SystemClock;
37import android.util.Log;
38import android.util.SparseArray;
39
40import com.google.android.collect.Lists;
41import com.google.protobuf.ByteString;
42
43import com.android.car.vehiclenetwork.VehicleNetwork.VehicleNetworkHalMock;
44import com.android.car.vehiclenetwork.VehicleNetworkConsts;
45import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig;
46import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfigs;
47import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
48import com.android.car.vehiclenetwork.VehiclePropValueUtil;
49
50import org.junit.Assert;
51
52import java.util.Arrays;
53import java.util.List;
54import java.util.Random;
55
56/**
57 * Tests for {@link CarVendorExtensionManager}
58 */
59public class CarVendorExtensionManagerTest extends MockedCarTestBase {
60
61    private static final String TAG = CarVendorExtensionManager.class.getSimpleName();
62
63    private static final int CUSTOM_GLOBAL_INT_PROP_ID =
64            VehicleNetworkConsts.VEHICLE_PROPERTY_CUSTOM_START;
65    private static final int CUSTOM_ZONED_FLOAT_PROP_ID =
66            VehicleNetworkConsts.VEHICLE_PROPERTY_CUSTOM_START + 1;
67    private static final int CUSTOM_BYTES_PROP_ID_1 =
68            VehicleNetworkConsts.VEHICLE_PROPERTY_CUSTOM_START + 2;
69    private static final int CUSTOM_BYTES_PROP_ID_2 =
70            VehicleNetworkConsts.VEHICLE_PROPERTY_CUSTOM_START + 3;
71    private static final int CUSTOM_STRING_PROP_ID =
72            VehicleNetworkConsts.VEHICLE_PROPERTY_CUSTOM_START + 4;
73
74    private static final float EPS = 1e-9f;
75    private static final int MILLION = 1000 * 1000;
76
77    private static final int MIN_PROP_INT32 = 0x0000005;
78    private static final int MAX_PROP_INT32 = 0xDeadBee;
79
80    private static final float MIN_PROP_FLOAT = 10.42f;
81    private static final float MAX_PROP_FLOAT = 42.10f;
82
83    private static final MockedVehicleHal mVehicleHal = new MockedVehicleHal();
84
85    private static final VehiclePropConfigs VEHICLE_HAL_CONFIGS = VehiclePropConfigs.newBuilder()
86            .addConfigs(VehiclePropConfig.newBuilder()
87                    .setProp(CUSTOM_GLOBAL_INT_PROP_ID)
88                    .setAccess(VEHICLE_PROP_ACCESS_READ_WRITE)
89                    .setChangeMode(VEHICLE_PROP_CHANGE_MODE_ON_CHANGE)
90                    .setValueType(VEHICLE_VALUE_TYPE_INT32)
91                    .setPermissionModel(VEHICLE_PERMISSION_NO_RESTRICTION)
92                    .addConfigArray(0)
93                    .setSampleRateMin(0f)
94                    .setSampleRateMax(0f)
95                    .addAllInt32Mins(singletonList(MIN_PROP_INT32))
96                    .addAllInt32Maxs(singletonList(MAX_PROP_INT32))
97                    .build())
98            .addConfigs(VehiclePropConfig.newBuilder()
99                    .setProp(CUSTOM_ZONED_FLOAT_PROP_ID)
100                    .setAccess(VEHICLE_PROP_ACCESS_READ_WRITE)
101                    .setChangeMode(VEHICLE_PROP_CHANGE_MODE_ON_CHANGE)
102                    .setValueType(VEHICLE_VALUE_TYPE_ZONED_FLOAT)
103                    .setPermissionModel(VEHICLE_PERMISSION_NO_RESTRICTION)
104                    .setZones(VEHICLE_ZONE_ROW_1_LEFT | VEHICLE_ZONE_ROW_1_RIGHT)
105                    .addConfigArray(0)
106                    .setSampleRateMin(0f)
107                    .setSampleRateMax(0f)
108                    .addAllFloatMins(Lists.newArrayList(MIN_PROP_FLOAT, MIN_PROP_FLOAT))
109                    .addAllFloatMaxs(Lists.newArrayList(MAX_PROP_FLOAT, MAX_PROP_FLOAT))
110                    .build())
111            .addConfigs(VehiclePropConfig.newBuilder()
112                    .setProp(CUSTOM_BYTES_PROP_ID_1)
113                    .setAccess(VEHICLE_PROP_ACCESS_READ_WRITE)
114                    .setChangeMode(VEHICLE_PROP_CHANGE_MODE_ON_CHANGE)
115                    .setValueType(VEHICLE_VALUE_TYPE_BYTES)
116                    .setPermissionModel(VEHICLE_PERMISSION_NO_RESTRICTION)
117                    .setZones(VEHICLE_ZONE_ROW_1_LEFT | VEHICLE_ZONE_ROW_1_RIGHT)
118                    .addConfigArray(0)
119                    .setSampleRateMin(0f)
120                    .setSampleRateMax(0f)
121                    .build())
122            .addConfigs(VehiclePropConfig.newBuilder()
123                    .setProp(CUSTOM_BYTES_PROP_ID_2)
124                    .setAccess(VEHICLE_PROP_ACCESS_READ_WRITE)
125                    .setChangeMode(VEHICLE_PROP_CHANGE_MODE_ON_CHANGE)
126                    .setValueType(VEHICLE_VALUE_TYPE_BYTES)
127                    .setPermissionModel(VEHICLE_PERMISSION_NO_RESTRICTION)
128                    .addConfigArray(0)
129                    .setSampleRateMin(0f)
130                    .setSampleRateMax(0f)
131                    .build())
132            .addConfigs(VehiclePropConfig.newBuilder()
133                    .setProp(CUSTOM_STRING_PROP_ID)
134                    .setAccess(VEHICLE_PROP_ACCESS_READ_WRITE)
135                    .setChangeMode(VEHICLE_PROP_CHANGE_MODE_ON_CHANGE)
136                    .setValueType(VEHICLE_VALUE_TYPE_STRING)
137                    .setPermissionModel(VEHICLE_PERMISSION_NO_RESTRICTION)
138                    .addConfigArray(0)
139                    .setSampleRateMin(0f)
140                    .setSampleRateMax(0f)
141                    .build())
142            .build();
143
144    private CarVendorExtensionManager mManager;
145    private CarTestManager mCarTestManager;
146
147    @Override
148    protected void setUp() throws Exception {
149        super.setUp();
150
151        CarTestManagerBinderWrapper testManagerWrapper =
152                (CarTestManagerBinderWrapper) getCar().getCarManager(Car.TEST_SERVICE);
153
154        mCarTestManager = new CarTestManager(testManagerWrapper);
155        mCarTestManager.startMocking(mVehicleHal, 0);
156
157        mManager = (CarVendorExtensionManager) getCar().getCarManager(Car.VENDOR_EXTENSION_SERVICE);
158        assertNotNull(mManager);
159    }
160
161    @Override
162    protected void tearDown() throws Exception {
163        super.tearDown();
164        mCarTestManager.stopMocking();
165    }
166
167    public void testPropertyList() throws Exception {
168        List<CarPropertyConfig> configs = mManager.getProperties();
169        assertEquals(VEHICLE_HAL_CONFIGS.getConfigsCount(), configs.size());
170
171        SparseArray<CarPropertyConfig> configById = new SparseArray<>(configs.size());
172        for (CarPropertyConfig config : configs) {
173            configById.put(config.getPropertyId(), config);
174        }
175
176        CarPropertyConfig prop1 = configById.get(CUSTOM_GLOBAL_INT_PROP_ID);
177        assertNotNull(prop1);
178        assertEquals(Integer.class, prop1.getPropertyType());
179        assertEquals(MIN_PROP_INT32, prop1.getMinValue());
180        assertEquals(MAX_PROP_INT32, prop1.getMaxValue());
181    }
182
183    public void testIntGlobalProperty() throws Exception {
184        final int value = 0xbeef;
185        mManager.setGlobalProperty(Integer.class, CUSTOM_GLOBAL_INT_PROP_ID, value);
186        int actualValue = mManager.getGlobalProperty(Integer.class, CUSTOM_GLOBAL_INT_PROP_ID);
187        assertEquals(value, actualValue);
188    }
189
190    public void testFloatZonedProperty() throws Exception {
191        final float value = MIN_PROP_FLOAT + 1;
192        mManager.setProperty(
193                Float.class,
194                CUSTOM_ZONED_FLOAT_PROP_ID,
195                VEHICLE_ZONE_ROW_1_RIGHT,
196                value);
197
198        float actualValue = mManager.getProperty(
199                Float.class, CUSTOM_ZONED_FLOAT_PROP_ID, VEHICLE_ZONE_ROW_1_RIGHT);
200        assertEquals(value, actualValue, EPS);
201    }
202
203    public void testByteArrayProperty() throws Exception {
204        final byte[] expectedData = new byte[] { 1, 2, 3, 4, -1, 127, -127, 0 };
205
206        // Write to CUSTOM_BYTES_PROP_ID_1 and read this value from CUSTOM_BYTES_PROP_ID_2
207        mManager.setGlobalProperty(
208                byte[].class,
209                CUSTOM_BYTES_PROP_ID_1,
210                expectedData);
211
212        byte[] actualData = mManager.getGlobalProperty(
213                byte[].class,
214                CUSTOM_BYTES_PROP_ID_2);
215
216        assertEquals(Arrays.toString(expectedData), Arrays.toString(actualData));
217    }
218
219    public void testLargeByteArrayProperty() throws Exception {
220        // Allocate array of byte which is greater than binder transaction buffer limitation.
221        byte[] expectedData = new byte[3 * MILLION];
222
223        new Random(SystemClock.elapsedRealtimeNanos())
224            .nextBytes(expectedData);
225
226        // Write to CUSTOM_BYTES_PROP_ID_1 and read this value from CUSTOM_BYTES_PROP_ID_2
227        mManager.setGlobalProperty(
228                byte[].class,
229                CUSTOM_BYTES_PROP_ID_1,
230                expectedData);
231
232        byte[] actualData = mManager.getGlobalProperty(
233                byte[].class,
234                CUSTOM_BYTES_PROP_ID_2);
235
236        Assert.assertArrayEquals(expectedData, actualData);
237    }
238
239    public void testLargeStringProperty() throws Exception {
240        // Allocate string which is greater than binder transaction buffer limitation.
241        String expectedString = generateRandomString(2 * MILLION,
242                "abcdefghijKLMNεὕρηκα!@#$%^&*()[]{}:\"\t\n\r!'");
243
244        mManager.setGlobalProperty(
245                String.class,
246                CUSTOM_STRING_PROP_ID,
247                expectedString);
248
249        String actualString = mManager.getGlobalProperty(
250                String.class,
251                CUSTOM_STRING_PROP_ID);
252
253        assertEquals(expectedString, actualString);
254    }
255
256    public void testStringProperty() throws Exception {
257        final String expectedString = "εὕρηκα!";  // Test some utf as well.
258
259        mManager.setGlobalProperty(
260                String.class,
261                CUSTOM_STRING_PROP_ID,
262                expectedString);
263
264        String actualString = mManager.getGlobalProperty(
265                String.class,
266                CUSTOM_STRING_PROP_ID);
267
268        assertEquals(expectedString, actualString);
269    }
270
271    private static String generateRandomString(int length, String allowedSymbols) {
272        Random r = new Random(SystemClock.elapsedRealtimeNanos());
273        StringBuilder sb = new StringBuilder(length);
274        char[] chars = allowedSymbols.toCharArray();
275        for (int i = 0; i < length; i++) {
276            sb.append(chars[r.nextInt(chars.length)]);
277        }
278        return sb.toString();
279    }
280
281    private static class MockedVehicleHal implements VehicleNetworkHalMock {
282        private final SparseArray<VehiclePropValue> mValues = new SparseArray<>();
283
284        private byte[] mBytes = null;
285
286        @Override
287        public VehiclePropConfigs onListProperties() {
288            return VEHICLE_HAL_CONFIGS;
289        }
290
291        @Override
292        public void onPropertySet(VehiclePropValue value) {
293            if (value.getProp() == CUSTOM_BYTES_PROP_ID_1) {
294                mBytes = value.getBytesValue().toByteArray();
295            }
296
297            mValues.put(value.getProp(), newBuilder(value).build());
298        }
299
300        @Override
301        public VehiclePropValue onPropertyGet(VehiclePropValue value) {
302            Log.d(TAG, "onPropertyGet: 0x" + Integer.toHexString(value.getProp()) + ", "
303                    + VehiclePropValueUtil.toString(value));
304
305            if (value.getProp() == CUSTOM_BYTES_PROP_ID_2 && mBytes != null) {
306                Log.d(TAG, "Returning byte array property, value: " + Arrays.toString(mBytes));
307                return VehiclePropValue
308                        .newBuilder(value)
309                        .setBytesValue(ByteString.copyFrom(mBytes))
310                        .build();
311            }
312
313            VehiclePropValue existingValue = mValues.get(value.getProp());
314            if (existingValue != null) {
315                return existingValue;
316            }
317
318            int type = value.getValueType();
319
320            // VehicleNetwork will fail if we do not set empty data for these properties.
321            if (type == VEHICLE_VALUE_TYPE_BYTES && !value.hasBytesValue()) {
322                return VehiclePropValue.newBuilder(value).setBytesValue(ByteString.EMPTY).build();
323            } else if (type == VEHICLE_VALUE_TYPE_STRING && !value.hasStringValue()) {
324                return VehiclePropValue.newBuilder(value).setStringValue("").build();
325            } else {
326                return value;
327            }
328        }
329
330        @Override
331        public void onPropertySubscribe(int property, float sampleRate, int zones) { }
332
333        @Override
334        public void onPropertyUnsubscribe(int property) { }
335    }
336}
337