Add vehicle HAL mocking with carsystem and carsystemtest API
- System API and system test API for testing only added. Client
should link only one of them.
- vehicle HAL mocking allows mocking vehicle HAL completely.
- Once mocking is started, for now, all previous states are forgotton,
so stopping mocking does not return to original state. It is
better to simply restart framework after test.
- Added skeleton code for audio focus handling. Detailed implementaiton
will be added later.
bug: 24874617
Change-Id: I6e60daab3dc96769a94acc09a695f8f49dbb8536
(cherry picked from commit a32e24f50d5895a94d3a13d6ec2233af6e43dac5)
diff --git a/service/Android.mk b/service/Android.mk
index 1967112..05734f2 100644
--- a/service/Android.mk
+++ b/service/Android.mk
@@ -31,7 +31,7 @@
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_STATIC_JAVA_LIBRARIES += libcarsupport libvehiclenetwork-java
+LOCAL_STATIC_JAVA_LIBRARIES += libvehiclenetwork-java libcarsystemtest
include $(BUILD_PACKAGE)
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index c2ad04c..ff25866 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -53,6 +53,12 @@
android:label="@string/car_permission_label_vendor_extension"
android:description="@string/car_permission_desc_vendor_extension" />
+ <permission
+ android:name="android.support.car.permission.CAR_MOCK_VEHICLE_HAL"
+ android:protectionLevel="system|signature"
+ android:label="@string/car_permission_label_mock_vehicle_hal"
+ android:description="@string/car_permission_desc_mock_vehicle_hal" />
+
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
diff --git a/service/res/values/strings.xml b/service/res/values/strings.xml
index 17f5fb2..e5ba396 100644
--- a/service/res/values/strings.xml
+++ b/service/res/values/strings.xml
@@ -20,20 +20,24 @@
<!-- Permission text: can access your car's information [CHAR LIMIT=NONE] -->
<string name="car_permission_desc">Access your car\'s information.</string>
<!-- Permission text: can access your car's fuel level [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_fuel">car fuel level</string>
+ <string name="car_permission_label_fuel">Car fuel level</string>
<!-- Permission text: can access your car's fuel level [CHAR LIMIT=NONE] -->
<string name="car_permission_desc_fuel">Access your car\'s fuel level information.</string>
<!-- Permission text: can access your car's mileage information [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_mileage">car mileage</string>
+ <string name="car_permission_label_mileage">Car mileage</string>
<!-- Permission text: can access your car's mileage information [CHAR LIMIT=NONE] -->
<string name="car_permission_desc_mileage">Access your car\'s mileage information.</string>
<!-- Permission text: can access your car's speed [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_speed">car speed</string>
+ <string name="car_permission_label_speed">Car speed</string>
<!-- Permission text: can access your car's speed [CHAR LIMIT=NONE] -->
<string name="car_permission_desc_speed">Access your car\'s speed.</string>
<!-- Permission text: apps can access car-manufacturer specific data [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_vendor_extension">car vendor channel</string>
+ <string name="car_permission_label_vendor_extension">Car vendor channel</string>
<!-- Permission text: apps can access car-manufacturer specific data [CHAR LIMIT=NONE] -->
<string name="car_permission_desc_vendor_extension">Access your car\'s vendor channel to
exchange car-specific information.</string>
-</resources>
\ No newline at end of file
+ <string name="car_permission_label_mock_vehicle_hal">Emulate vehicle HAL</string>
+ <!-- Permission text: can emulate information from your car [CHAR LIMIT=NONE] -->
+ <string name="car_permission_desc_mock_vehicle_hal">Emulate your car\'s vehicle HAL for internal
+ testing purpose.</string>
+</resources>
diff --git a/service/src/com/android/car/CarAudioService.java b/service/src/com/android/car/CarAudioService.java
index e730ee8..881b2c5 100644
--- a/service/src/com/android/car/CarAudioService.java
+++ b/service/src/com/android/car/CarAudioService.java
@@ -177,6 +177,7 @@
}
private void doHandleSystemAudioFocusGrant(AudioFocusInfo afi, int requestResult) {
+ //TODO distinguish car service's own focus request from others
if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
mFocusInfos[0] = afi;
sendCarAudioFocusRequestIfNecessary();
@@ -229,6 +230,16 @@
}
}
+ /**
+ * Focus listener to take focus away from android apps.
+ */
+ private class AndroidFocusListener implements AudioManager.OnAudioFocusChangeListener {
+ @Override
+ public void onAudioFocusChange(int focusChange) {
+ // nothing to do as system focus listener will get all necessary information.
+ }
+ }
+
private class CarAudioChangeHandler extends Handler {
private static final int MSG_FOCUS_CHANGE = 0;
private static final int MSG_STREAM_STATE_CHANGE = 1;
diff --git a/service/src/com/android/car/CarLog.java b/service/src/com/android/car/CarLog.java
index fe24354..e6ddc9e 100644
--- a/service/src/com/android/car/CarLog.java
+++ b/service/src/com/android/car/CarLog.java
@@ -23,4 +23,5 @@
public static final String TAG_HAL = "CAR.HAL";
public static final String TAG_INFO = "CAR.INFO";
public static final String TAG_AUDIO = "CAR.AUDIO";
+ public static final String TAG_TEST = "CAR.TEST";
}
diff --git a/service/src/com/android/car/CarSensorService.java b/service/src/com/android/car/CarSensorService.java
index e230f25..cffb37e 100644
--- a/service/src/com/android/car/CarSensorService.java
+++ b/service/src/com/android/car/CarSensorService.java
@@ -71,14 +71,6 @@
/** Sensor service is ready and all vehicle sensors are available. */
public abstract void onSensorServiceReady();
-
- /**
- * Provide default sensor value. This value should be always provided after {@link #init()}
- * call. Default value for safety related sensor should be giving safe state.
- * @param sensorType
- * @return
- */
- public abstract CarSensorEvent getDefaultValue(int sensorType);
}
/**
@@ -144,19 +136,20 @@
mSupportedSensors = refreshSupportedSensorsLocked();
if (mUseDefaultDrivingPolicy) {
mDrivingStatePolicy.init();
- addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS,
- mDrivingStatePolicy.getDefaultValue(
- CarSensorManager.SENSOR_TYPE_DRIVING_STATUS));
mDrivingStatePolicy.registerSensorListener(this);
}
+ // always populate default value
+ addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS,
+ DrivingStatePolicy.getDefaultValue(
+ CarSensorManager.SENSOR_TYPE_DRIVING_STATUS));
if (mUseDefaultDayNightModePolicy) {
mDayNightModePolicy.init();
- addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_NIGHT,
- mDrivingStatePolicy.getDefaultValue(
- CarSensorManager.SENSOR_TYPE_NIGHT));
mDayNightModePolicy.registerSensorListener(this);
}
-
+ // always populate default value
+ addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_NIGHT,
+ DayNightModePolicy.getDefaultValue(
+ CarSensorManager.SENSOR_TYPE_NIGHT));
} finally {
mSensorLock.unlock();
}
@@ -171,7 +164,9 @@
@Override
public void release() {
- mHandlerThread.quit();
+ if (mHandlerThread != null) {
+ mHandlerThread.quit();
+ }
tryHoldSensorLock();
try {
if (mUseDefaultDrivingPolicy) {
diff --git a/service/src/com/android/car/CarTestService.java b/service/src/com/android/car/CarTestService.java
new file mode 100644
index 0000000..26a1b7d
--- /dev/null
+++ b/service/src/com/android/car/CarTestService.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 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;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.car.hal.VehicleHal;
+import com.android.car.vehiclenetwork.IVehicleNetworkHalMock;
+import com.android.car.vehiclenetwork.VehicleNetwork;
+import com.android.car.vehiclenetwork.VehiclePropValueParcelable;
+
+import java.io.PrintWriter;
+
+/**
+ * Service to allow testing / mocking vehicle HAL.
+ * This service uses Vehicle HAL APIs directly (one exception) as vehicle HAL mocking anyway
+ * requires accessing that level directly.
+ */
+public class CarTestService extends ICarTest.Stub implements CarServiceBase {
+ private static final int VERSION = 1;
+
+ private final Context mContext;
+ private final VehicleNetwork mVehicleNetwork;
+ private final ICarImpl mICarImpl;
+
+ public CarTestService(Context context, ICarImpl carImpl) {
+ mContext = context;
+ mICarImpl = carImpl;
+ mVehicleNetwork = VehicleHal.getInstance().getVehicleNetwork();
+ }
+
+ @Override
+ public void init() {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void release() {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void dump(PrintWriter writer) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public int getVersion() {
+ return VERSION;
+ }
+
+ @Override
+ public void injectEvent(VehiclePropValueParcelable value) {
+ ICarImpl.assertVehicleHalMockPermission(mContext);
+ mVehicleNetwork.injectEvent(value.value);
+ }
+
+ @Override
+ public void startMocking(IVehicleNetworkHalMock mock) {
+ ICarImpl.assertVehicleHalMockPermission(mContext);
+ mVehicleNetwork.startMocking(mock);
+ VehicleHal.getInstance().startMocking();
+ mICarImpl.startMocking();
+ }
+
+ @Override
+ public void stopMocking(IVehicleNetworkHalMock mock) {
+ ICarImpl.assertVehicleHalMockPermission(mContext);
+ mVehicleNetwork.stopMocking(mock);
+ VehicleHal.getInstance().stopMocking();
+ mICarImpl.stopMocking();
+ }
+}
diff --git a/service/src/com/android/car/DayNightModePolicy.java b/service/src/com/android/car/DayNightModePolicy.java
index 23f36d9..892c077 100644
--- a/service/src/com/android/car/DayNightModePolicy.java
+++ b/service/src/com/android/car/DayNightModePolicy.java
@@ -17,6 +17,7 @@
package com.android.car;
import android.content.Context;
+import android.os.SystemClock;
import android.support.car.Car;
import android.support.car.CarSensorEvent;
import android.support.car.CarSensorManager;
@@ -47,10 +48,8 @@
// TODO Auto-generated method stub
}
- @Override
- public synchronized CarSensorEvent getDefaultValue(int sensorType) {
- // TODO Auto-generated method stub
- return null;
+ public static CarSensorEvent getDefaultValue(int sensorType) {
+ return createEvent(true /* isNight */);
}
@Override
@@ -89,6 +88,13 @@
// TODO Auto-generated method stub
}
+ private static CarSensorEvent createEvent(boolean isNight) {
+ CarSensorEvent event = new CarSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT,
+ SystemClock.elapsedRealtimeNanos(), 0, 1);
+ event.intValues[0] = isNight ? 1 : 0;
+ return event;
+ }
+
@Override
public synchronized void dump(PrintWriter writer) {
// TODO Auto-generated method stub
diff --git a/service/src/com/android/car/DrivingStatePolicy.java b/service/src/com/android/car/DrivingStatePolicy.java
index e1eed18..11fad66 100644
--- a/service/src/com/android/car/DrivingStatePolicy.java
+++ b/service/src/com/android/car/DrivingStatePolicy.java
@@ -91,14 +91,13 @@
// TODO Auto-generated method stub
}
- @Override
- public synchronized CarSensorEvent getDefaultValue(int sensorType) {
+ public static CarSensorEvent getDefaultValue(int sensorType) {
if (sensorType != CarSensorManager.SENSOR_TYPE_DRIVING_STATUS) {
- Log.w(CarLog.TAG_SENSOR, "getCurrentValue to DrivingStatePolicy with sensorType:" +
+ Log.w(CarLog.TAG_SENSOR, "getDefaultValue to DrivingStatePolicy with sensorType:" +
sensorType);
return null;
}
- return createEvent(mDringState);
+ return createEvent(CarSensorEvent.DRIVE_STATUS_FULLY_RESTRICTED);
}
@Override
@@ -202,7 +201,7 @@
return gear == CarSensorEvent.GEAR_PARK;
}
- private CarSensorEvent createEvent(int drivingState) {
+ private static CarSensorEvent createEvent(int drivingState) {
CarSensorEvent event = new CarSensorEvent(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS,
SystemClock.elapsedRealtimeNanos(), 0, 1);
event.intValues[0] = drivingState;
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index b02bce6..779a48f 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.IBinder;
import android.support.car.Car;
import android.support.car.ICar;
@@ -41,6 +42,9 @@
private final CarSensorService mCarSensorService;
private final CarInfoService mCarInfoService;
private final CarAudioService mCarAudioService;
+ /** Test only service. Populate it only when necessary. */
+ @GuardedBy("this")
+ private CarTestService mCarTestService;
private final CarServiceBase[] mAllServices;
public synchronized static ICarImpl getInstance(Context serviceContext) {
@@ -86,6 +90,23 @@
VehicleHal.releaseInstance();
}
+ public void startMocking() {
+ reinitServices();
+ }
+
+ public void stopMocking() {
+ reinitServices();
+ }
+
+ private void reinitServices() {
+ for (int i = mAllServices.length - 1; i >= 0; i--) {
+ mAllServices[i].release();
+ }
+ for (CarServiceBase service: mAllServices) {
+ service.init();
+ }
+ }
+
@Override
public int getVersion() {
return VERSION;
@@ -98,6 +119,15 @@
return mCarSensorService;
case Car.INFO_SERVICE:
return mCarInfoService;
+ case CarSystemTest.TEST_SERVICE: {
+ assertVehicleHalMockPermission(mContext);
+ synchronized (this) {
+ if (mCarTestService == null) {
+ mCarTestService = new CarTestService(mContext, this);
+ }
+ return mCarTestService;
+ }
+ }
default:
Log.w(CarLog.TAG_SERVICE, "getCarService for unknown service:" + serviceName);
return null;
@@ -130,10 +160,21 @@
return false;
}
+ public static void assertVehicleHalMockPermission(Context context) {
+ if (context.checkCallingOrSelfPermission(CarSystemTest.PERMISSION_MOCK_VEHICLE_HAL)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("requires CAR_MOCK_VEHICLE_HAL permission");
+ }
+ }
+
void dump(PrintWriter writer) {
writer.println("*Dump all services*");
for (CarServiceBase service: mAllServices) {
service.dump(writer);
}
+ CarTestService testService = mCarTestService;
+ if (testService != null) {
+ testService.dump(writer);
+ }
}
}
diff --git a/service/src/com/android/car/hal/AudioHalService.java b/service/src/com/android/car/hal/AudioHalService.java
index 59fb6c8..e83cfe9 100644
--- a/service/src/com/android/car/hal/AudioHalService.java
+++ b/service/src/com/android/car/hal/AudioHalService.java
@@ -16,8 +16,8 @@
package com.android.car.hal;
import com.android.car.vehiclenetwork.VehicleNetworkConsts;
-import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusRequestType;
-import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusStateType;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusRequest;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusState;
import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioStreamState;
import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig;
import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
@@ -29,33 +29,33 @@
public class AudioHalService extends HalServiceBase {
public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN =
- VehicleAudioFocusRequestType.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN;
+ VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN;
public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT =
- VehicleAudioFocusRequestType.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT;
+ VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT;
public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK =
- VehicleAudioFocusRequestType.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK;
+ VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK;
public static final int VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE =
- VehicleAudioFocusRequestType.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE;
+ VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE;
public static String audioFocusRequestToString(int request) {
- return VehicleAudioFocusRequestType.enumToString(request);
+ return VehicleAudioFocusRequest.enumToString(request);
}
public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN =
- VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_GAIN;
+ VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN;
public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT =
- VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT;
+ VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT;
public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK =
- VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK;
+ VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK;
public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT =
- VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT;
+ VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT;
public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS =
- VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_LOSS;
+ VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS;
public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE =
- VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE;
+ VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE;
public static String audioFocusStateToString(int state) {
- return VehicleAudioFocusStateType.enumToString(state);
+ return VehicleAudioFocusState.enumToString(state);
}
public static final int VEHICLE_AUDIO_STREAM_STATE_STOPPED =
@@ -115,10 +115,12 @@
VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS);
mVehicleHal.unsubscribeProperty(this,
VehicleNetworkConsts.VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE);
+ mFocusSupported = false;
}
if (mVolumeSupported) {
mVehicleHal.unsubscribeProperty(this,
VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME);
+ mVolumeSupported = false;
}
}
diff --git a/service/src/com/android/car/hal/SensorHalService.java b/service/src/com/android/car/hal/SensorHalService.java
index 4fb8398..e7fb8f4 100644
--- a/service/src/com/android/car/hal/SensorHalService.java
+++ b/service/src/com/android/car/hal/SensorHalService.java
@@ -38,7 +38,7 @@
*/
public class SensorHalService extends SensorHalServiceBase {
- private static final boolean DBG_EVENTS = true;
+ private static final boolean DBG_EVENTS = false;
private static final int SENSOR_TYPE_INVALD = -1;
diff --git a/service/src/com/android/car/hal/VehicleHal.java b/service/src/com/android/car/hal/VehicleHal.java
index d41def1..4652324 100644
--- a/service/src/com/android/car/hal/VehicleHal.java
+++ b/service/src/com/android/car/hal/VehicleHal.java
@@ -147,6 +147,19 @@
// keep the looper thread as should be kept for the whole life cycle.
}
+ public void startMocking() {
+ reinitHals();
+ }
+
+ public void stopMocking() {
+ reinitHals();
+ }
+
+ private void reinitHals() {
+ release();
+ doInit();
+ }
+
public SensorHalService getSensorHal() {
return mSensorHal;
}
@@ -159,18 +172,6 @@
return mAudioHal;
}
- /**
- * Start mocking HAL with given mock. Actual H/W will be stop functioning until mocking is
- * stopped. The call will be blocked until all pending events are delivered to upper layer.
- */
- public void startHalMocking(HalMock mock) {
- //TODO
- }
-
- public void stopHalMocking() {
- //TODO
- }
-
private void assertServiceOwner(HalServiceBase service, int property) {
if (service != mPropertyHandlers.get(property)) {
throw new IllegalArgumentException("not owned");