diff options
author | Pavel Maltsev <pavelm@google.com> | 2017-04-11 12:38:17 -0700 |
---|---|---|
committer | Pavel Maltsev <pavelm@google.com> | 2017-04-14 10:36:04 -0700 |
commit | 82c20cdd99601923df556b99114ad5d186821977 (patch) | |
tree | 690e5a1ace0df9e96232e569c2a84cfd592f51fa /tests/vehiclehal_test | |
parent | aacfcd53c320a5297971ce609fad920e611e95ac (diff) | |
download | Car-82c20cdd99601923df556b99114ad5d186821977.tar.gz |
Initial e2e Vehicle s/w stack infrastructure
Also, fixed some sensor mapping between CarSensorManager and VHAL
Bug: b/36510399
Test: runtest -x packages/services/Car/tests/vehiclehal_test/
Change-Id: I556e03402c16a3b2c8cb25d7a048f8c9a072e23b
Diffstat (limited to 'tests/vehiclehal_test')
4 files changed, 278 insertions, 108 deletions
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2ePerformanceTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2ePerformanceTest.java new file mode 100644 index 0000000000..c76cc4ae81 --- /dev/null +++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2ePerformanceTest.java @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.car.vehiclehal.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import android.car.Car; +import android.car.hardware.CarSensorManager; +import android.car.hardware.CarSensorManager.OnSensorChangedListener; +import android.content.ComponentName; +import android.content.Context; +import android.content.ServiceConnection; +import android.hardware.automotive.vehicle.V2_0.IVehicle; +import android.hardware.automotive.vehicle.V2_0.StatusCode; +import android.hardware.automotive.vehicle.V2_0.VehicleArea; +import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; +import android.hardware.automotive.vehicle.V2_0.VehicleProperty; +import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup; +import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.RemoteException; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.LargeTest; + +import com.google.android.collect.Lists; + +import com.android.car.vehiclehal.VehiclePropValueBuilder; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +/** + * This test suite will make e2e test and measure some performance characteristics. The main idea + * is to send command to Vehicle HAL to generate some events with certain time interval and capture + * these events through car public API, e.g. CarSensorManager. + */ +@LargeTest +@RunWith(AndroidJUnit4.class) +public class E2ePerformanceTest { + private static String TAG = Utils.concatTag(E2ePerformanceTest.class); + + private IVehicle mVehicle; + private final CarConnectionListener mConnectionListener = new CarConnectionListener(); + private Context mContext; + private Car mCar; + + private static Handler sEventHandler; + private static final HandlerThread sHandlerThread = new HandlerThread(TAG); + + private static final int DEFAULT_WAIT_TIMEOUT_MS = 1000; + + private static final int GENERATE_FAKE_DATA_CONTROLLING_PROPERTY = 0x0666 + | VehiclePropertyGroup.VENDOR + | VehicleArea.GLOBAL + | VehiclePropertyType.COMPLEX; + + private static final int CMD_START = 1; + private static final int CMD_STOP = 0; + + private HalEventsGenerator mEventsGenerator; + + @BeforeClass + public static void setupEventHandler() { + sHandlerThread.start(); + sEventHandler = new Handler(sHandlerThread.getLooper()); + } + + @Before + public void connectToVehicleHal() throws Exception { + mVehicle = Utils.getVehicle(); + + mVehicle.getPropConfigs(Lists.newArrayList(GENERATE_FAKE_DATA_CONTROLLING_PROPERTY), + (status, propConfigs) -> assumeTrue(status == StatusCode.OK)); + + mEventsGenerator = new HalEventsGenerator(mVehicle); + } + + @Before + public void connectToCarService() throws Exception { + mContext = InstrumentationRegistry.getContext(); + mCar = Car.createCar(mContext, mConnectionListener, sEventHandler); + assertNotNull(mCar); + mCar.connect(); + mConnectionListener.waitForConnection(DEFAULT_WAIT_TIMEOUT_MS); + } + + @After + public void disconnect() throws Exception { + if (mVehicle != null) { + mEventsGenerator.stop(); + mVehicle = null; + mEventsGenerator = null; + } + if (mCar != null) { + mCar.disconnect(); + mCar = null; + } + } + + @Test + public void singleOnChangeProperty() throws Exception { + final int PROP = CarSensorManager.SENSOR_TYPE_ODOMETER; + // Expecting to receive at least 10 events within 150ms. + final int EXPECTED_EVENTS = 10; + final int EXPECTED_TIME_DURATION_MS = 150; + final float INITIAL_VALUE = 1000; + final float INCREMENT = 1.0f; + + CarSensorManager mgr = (CarSensorManager) mCar.getCarManager(Car.SENSOR_SERVICE); + assertNotNull(mgr); + assertTrue(mgr.isSensorSupported(CarSensorManager.SENSOR_TYPE_ODOMETER)); + + mEventsGenerator + .setIntervalMs(10) + .setInitialValue(INITIAL_VALUE) + .setIncrement(INCREMENT) + .setDispersion(100) + .start(VehicleProperty.PERF_ODOMETER); + + CountDownLatch latch = new CountDownLatch(EXPECTED_EVENTS); + OnSensorChangedListener listener = event -> latch.countDown(); + + mgr.registerListener(listener, PROP, CarSensorManager.SENSOR_RATE_FASTEST); + try { + assertTrue(latch.await(EXPECTED_TIME_DURATION_MS, TimeUnit.MILLISECONDS)); + } finally { + mgr.unregisterListener(listener); + } + } + + private static class CarConnectionListener implements ServiceConnection { + private final Semaphore mConnectionWait = new Semaphore(0); + + void waitForConnection(long timeoutMs) throws InterruptedException { + mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS); + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + mConnectionWait.release(); + } + + @Override + public void onServiceDisconnected(ComponentName name) { } + } + + static class HalEventsGenerator { + private final IVehicle mVehicle; + + private long mIntervalMs; + private float mInitialValue; + private float mDispersion; + private float mIncrement; + + HalEventsGenerator(IVehicle vehicle) { + mVehicle = vehicle; + reset(); + } + + HalEventsGenerator reset() { + mIntervalMs = 1000; + mInitialValue = 1000; + mDispersion = 0; + mInitialValue = 0; + return this; + } + + HalEventsGenerator setIntervalMs(long intervalMs) { + mIntervalMs = intervalMs; + return this; + } + + HalEventsGenerator setInitialValue(float initialValue) { + mInitialValue = initialValue; + return this; + } + + HalEventsGenerator setDispersion(float dispersion) { + mDispersion = dispersion; + return this; + } + + HalEventsGenerator setIncrement(float increment) { + mIncrement = increment; + return this; + } + + void start(int propId) throws RemoteException { + VehiclePropValue request = + VehiclePropValueBuilder.newBuilder(GENERATE_FAKE_DATA_CONTROLLING_PROPERTY) + .addIntValue(CMD_START, propId) + .setInt64Value(mIntervalMs * 1000_000) + .addFloatValue(mInitialValue, mDispersion, mIncrement) + .build(); + assertEquals(StatusCode.OK, mVehicle.set(request)); + } + + void stop() throws RemoteException { + stop(0); + } + + void stop(int propId) throws RemoteException { + VehiclePropValue request = + VehiclePropValueBuilder.newBuilder(GENERATE_FAKE_DATA_CONTROLLING_PROPERTY) + .addIntValue(CMD_STOP, propId) + .build(); + assertEquals(StatusCode.OK, mVehicle.set(request)); + } + } +} diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java index 19047f2e67..23b9dbedbc 100644 --- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java +++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java @@ -16,64 +16,45 @@ package com.android.car.vehiclehal.test; -import static com.android.car.vehiclehal.test.Utils.dumpVehiclePropValue; import static com.android.car.vehiclehal.test.Utils.isVhalPropertyAvailable; import static com.android.car.vehiclehal.test.Utils.readVhalProperty; -import static com.android.car.vehiclehal.test.Utils.tryWithDeadline; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assume.assumeTrue; -import android.annotation.Nullable; +import android.hardware.automotive.vehicle.V2_0.IVehicle; import android.hardware.automotive.vehicle.V2_0.StatusCode; import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; -import android.hardware.automotive.vehicle.V2_1.IVehicle; import android.hardware.automotive.vehicle.V2_1.VehicleProperty; import android.os.RemoteException; import android.util.Log; + import com.android.car.vehiclehal.VehiclePropValueBuilder; -import java.util.Objects; + import org.junit.Before; import org.junit.Test; /** Test retrieving the OBD2_FREEZE_FRAME property from VHAL */ public class Obd2FreezeFrameTest { - private static final String TAG = Obd2FreezeFrameTest.class.getSimpleName(); - private static final long WAIT_FOR_VEHICLE_HAL_TIMEOUT_MS = 10_000; + private static final String TAG = Utils.concatTag(Obd2FreezeFrameTest.class); private IVehicle mVehicle = null; @Before public void setUp() throws Exception { - mVehicle = Objects.requireNonNull(getVehicle(WAIT_FOR_VEHICLE_HAL_TIMEOUT_MS)); - } - - @Nullable - private IVehicle getVehicle(long waitMilliseconds) { - return tryWithDeadline( - waitMilliseconds, - () -> { - try { - return IVehicle.getService(); - } catch (RemoteException e) { - Log.w(TAG, "attempt to get IVehicle service " + - " caused RemoteException: ", e); - return null; - } - }); + mVehicle = Utils.getVehicle(); + assumeTrue("Freeze frame not available, test-case ignored.", isFreezeFrameAvailable()); } @Test public void testFreezeFrame() throws RemoteException { - if (!isFreezeFrameAvailable()) { - Log.i(TAG, "freeze frame not available; returning - our job here is done"); - return; - } readVhalProperty( mVehicle, VehicleProperty.OBD2_FREEZE_FRAME_INFO, (Integer status, VehiclePropValue value) -> { assertEquals(StatusCode.OK, status.intValue()); assertNotNull("OBD2_FREEZE_FRAME_INFO is supported; should not be null", value); - Log.i(TAG, "dump of OBD2_FREEZE_FRAME_INFO:\n" + dumpVehiclePropValue(value)); + Log.i(TAG, "dump of OBD2_FREEZE_FRAME_INFO:\n" + value); for(long timestamp: value.value.int64Values) { Log.i(TAG, "timestamp: " + timestamp); readVhalProperty( @@ -83,8 +64,9 @@ public class Obd2FreezeFrameTest { .build(), (Integer frameStatus, VehiclePropValue freezeFrame) -> { if (StatusCode.OK == frameStatus.intValue()) { - assertNotNull("OBD2_FREEZE_FRAME read OK; should not be null", freezeFrame); - Log.i(TAG, "dump of OBD2_FREEZE_FRAME:\n" + dumpVehiclePropValue(freezeFrame)); + assertNotNull("OBD2_FREEZE_FRAME read OK; should not be null", + freezeFrame); + Log.i(TAG, "dump of OBD2_FREEZE_FRAME:\n" + freezeFrame); assertEquals(freezeFrame.timestamp, timestamp); } return true; diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2LiveFrameTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2LiveFrameTest.java index 1f17358610..8e14db3596 100644 --- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2LiveFrameTest.java +++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2LiveFrameTest.java @@ -16,63 +16,43 @@ package com.android.car.vehiclehal.test; -import static com.android.car.vehiclehal.test.Utils.dumpVehiclePropValue; import static com.android.car.vehiclehal.test.Utils.isVhalPropertyAvailable; import static com.android.car.vehiclehal.test.Utils.readVhalProperty; -import static com.android.car.vehiclehal.test.Utils.tryWithDeadline; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assume.assumeTrue; -import android.annotation.Nullable; +import android.hardware.automotive.vehicle.V2_0.IVehicle; import android.hardware.automotive.vehicle.V2_0.StatusCode; import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; -import android.hardware.automotive.vehicle.V2_1.IVehicle; import android.hardware.automotive.vehicle.V2_1.VehicleProperty; import android.os.RemoteException; import android.util.Log; -import java.util.Objects; + import org.junit.Before; import org.junit.Test; /** Test retrieving the OBD2_LIVE_FRAME property from VHAL */ public class Obd2LiveFrameTest { - private static final String TAG = Obd2LiveFrameTest.class.getSimpleName(); - private static final long WAIT_FOR_VEHICLE_HAL_TIMEOUT_MS = 10_000; + private static final String TAG = Utils.concatTag(Obd2LiveFrameTest.class); private IVehicle mVehicle = null; @Before public void setUp() throws Exception { - mVehicle = Objects.requireNonNull(getVehicle(WAIT_FOR_VEHICLE_HAL_TIMEOUT_MS)); - } - - @Nullable - private IVehicle getVehicle(long waitMilliseconds) { - return tryWithDeadline( - waitMilliseconds, - () -> { - try { - return IVehicle.getService(); - } catch (RemoteException e) { - Log.w(TAG, "attempt to get IVehicle service " + - " caused RemoteException: ", e); - return null; - } - }); + mVehicle = Utils.getVehicle(); + assumeTrue("Live frame not available, test-case ignored.", isLiveFrameAvailable()); } @Test public void testLiveFrame() throws RemoteException { - if (!isLiveFrameAvailable()) { - Log.i(TAG, "live frame not available; returning - our job here is done"); - return; - } readVhalProperty( mVehicle, VehicleProperty.OBD2_LIVE_FRAME, (Integer status, VehiclePropValue value) -> { assertEquals(StatusCode.OK, status.intValue()); assertNotNull("OBD2_LIVE_FRAME is supported; should not be null", value); - Log.i(TAG, "dump of OBD2_LIVE_FRAME:\n" + dumpVehiclePropValue(value)); + Log.i(TAG, "dump of OBD2_LIVE_FRAME:\n" + value); return true; }); } diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Utils.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Utils.java index 67c5c2d6e1..5221907c50 100644 --- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Utils.java +++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Utils.java @@ -16,65 +16,25 @@ package com.android.car.vehiclehal.test; -import static android.os.SystemClock.elapsedRealtime; - import android.annotation.Nullable; import android.hardware.automotive.vehicle.V2_0.IVehicle; import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig; import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; import android.os.RemoteException; import android.util.Log; + import com.android.car.vehiclehal.VehiclePropValueBuilder; + +import java.util.NoSuchElementException; import java.util.Objects; final class Utils { private Utils() {} - private static final String TAG = Utils.class.getSimpleName(); + private static final String TAG = concatTag(Utils.class); - @Nullable - static <T> T tryWithDeadline(long waitMilliseconds, java.util.function.Supplier<T> f) { - f = Objects.requireNonNull(f); - T object = f.get(); - long start = elapsedRealtime(); - while (object == null && (start + waitMilliseconds) > elapsedRealtime()) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - throw new RuntimeException("Sleep was interrupted", e); - } - - object = f.get(); - } - return object; - } - - static String dumpVehiclePropValue(VehiclePropValue vpv) { - vpv = Objects.requireNonNull(vpv); - return "prop = " - + vpv.prop - + '\n' - + "areaId = " - + vpv.areaId - + '\n' - + "timestamp = " - + vpv.timestamp - + '\n' - + "int32Values = " - + vpv.value.int32Values - + '\n' - + "floatValues = " - + vpv.value.floatValues - + '\n' - + "int64Values =" - + vpv.value.int64Values - + '\n' - + "bytes = " - + vpv.value.bytes - + '\n' - + "string = " - + vpv.value.stringValue - + '\n'; + static String concatTag(Class clazz) { + return "VehicleHalTest." + clazz.getSimpleName(); } static boolean isVhalPropertyAvailable(IVehicle vehicle, int prop) throws RemoteException { @@ -99,8 +59,7 @@ final class Utils { } }); } catch (RemoteException e) { - Log.w(TAG, "attempt to read VHAL property " + - dumpVehiclePropValue(request) + " caused RemoteException: ", e); + Log.w(TAG, "attempt to read VHAL property " + request + " caused RemoteException: ", e); } return vpv[0]; } @@ -121,4 +80,17 @@ final class Utils { VehiclePropValueBuilder.newBuilder(propertyId).setAreaId(areaId).build(); return readVhalProperty(vehicle, request, f); } + + @Nullable + static IVehicle getVehicle() throws RemoteException { + IVehicle service; + try { + service = android.hardware.automotive.vehicle.V2_0.IVehicle.getService(); + } catch (NoSuchElementException ex) { + Log.d(TAG, "Couldn't connect to vehicle@2.1, connecting to vehicle@2.0..."); + service = IVehicle.getService(); + } + Log.d(TAG, "Connected to IVehicle service: " + service); + return service; + } } |