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/carsupport-lib/src/android/support/car/Car.java b/carsupport-lib/src/android/support/car/Car.java
index 7b2fcfd..49246cf 100644
--- a/carsupport-lib/src/android/support/car/Car.java
+++ b/carsupport-lib/src/android/support/car/Car.java
@@ -51,12 +51,6 @@
/** Service name for {@link CarInfoManager}, to be used in {@link #getCarManager(String)}. */
public static final String INFO_SERVICE = "info";
- /**
- * Service for testing. This is system app only feature.
- * @hide
- */
- public static final String TEST_SERVICE = "car-service-test";
-
/** Type of car connection: car emulator, not physical connection. */
public static final int CONNECTION_TYPE_EMULATOR = 0;
/** Type of car connection: connected to a car via USB. */
@@ -120,7 +114,7 @@
private final ServiceConnectionListener mServiceConnectionListener =
new ServiceConnectionListener () {
public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (this) {
+ synchronized (Car.this) {
mService = ICar.Stub.asInterface(service);
mConnectionState = STATE_CONNECTED;
// getVersion can fail but let it pass through as it is better to
@@ -139,7 +133,7 @@
}
public void onServiceDisconnected(ComponentName name) {
- synchronized (this) {
+ synchronized (Car.this) {
mService = null;
if (mConnectionState == STATE_DISCONNECTED) {
return;
@@ -166,6 +160,17 @@
private final CarServiceLoader mCarServiceLoader;
/**
+ * This defines CarServiceLoader that will be tried for FEATURE_AUTOMOTIVE case.
+ * For system test and system api, there are separate static libraries. If those
+ * libraries are linked, CarServiceLoader from those libraries are loaded so that
+ * custom car managers can be populated from there.
+ * This is done to prevent bloating the library which is not relevant for the app.
+ */
+ private static final String[] CAR_SERVICE_LOADERS_FOR_FEATURE_AUTOMOTIVE = {
+ "com.android.car.SystemTestApiCarServiceLoader",
+ "com.android.car.SystemApiCarServiceLoader",
+ };
+ /**
* Create Car instance for all Car API access.
* @param context
* @param serviceConnectionListener listner for monitoring service connection.
@@ -182,33 +187,56 @@
mLooper = looper;
}
if (mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE)) {
- //TODO allow overriding this for system api
- mCarServiceLoader = new DefaultCarServiceLoader(context, mServiceConnectionListener);
+ CarServiceLoader loader = null;
+ for (String classToTry : CAR_SERVICE_LOADERS_FOR_FEATURE_AUTOMOTIVE) {
+ try {
+ loader = loadCarServiceLoader(classToTry, context, mServiceConnectionListener,
+ mLooper);
+ } catch (IllegalArgumentException e) {
+ // expected when only lower level libraries are linked.
+ }
+ if (loader != null) {
+ break;
+ }
+ }
+ if (loader == null) {
+ mCarServiceLoader = new DefaultCarServiceLoader(context,
+ mServiceConnectionListener, mLooper);
+ } else {
+ mCarServiceLoader = loader;
+ }
} else {
- Class carServiceLoaderClass = null;
- try {
- carServiceLoaderClass = Class.forName(PROJECTED_CAR_SERVICE_LOADER);
- } catch (ClassNotFoundException e) {
- throw new RuntimeException("Cannot find CarServiceLoader implementation:" +
- PROJECTED_CAR_SERVICE_LOADER, e);
- }
- Constructor<?> ctor;
- try {
- ctor = carServiceLoaderClass.getDeclaredConstructor(Context.class,
- ServiceConnectionListener.class);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("Cannot construct CarServiceLoader, no constructor: " +
- PROJECTED_CAR_SERVICE_LOADER, e);
- }
- try {
- mCarServiceLoader = (CarServiceLoader) ctor.newInstance(context,
- serviceConnectionListener);
- } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
- | InvocationTargetException e) {
- throw new RuntimeException(
- "Cannot construct CarServiceLoader, constructor failed for "
- + carServiceLoaderClass.getName(), e);
- }
+ mCarServiceLoader = loadCarServiceLoader(PROJECTED_CAR_SERVICE_LOADER, context,
+ mServiceConnectionListener, mLooper);
+ }
+ }
+
+ private CarServiceLoader loadCarServiceLoader(String carServiceLoaderClassName,
+ Context context, ServiceConnectionListener serviceConnectionListener, Looper looper)
+ throws IllegalArgumentException {
+ Class carServiceLoaderClass = null;
+ try {
+ carServiceLoaderClass = Class.forName(carServiceLoaderClassName);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("Cannot find CarServiceLoader implementation:" +
+ carServiceLoaderClassName, e);
+ }
+ Constructor<?> ctor;
+ try {
+ ctor = carServiceLoaderClass.getDeclaredConstructor(Context.class,
+ ServiceConnectionListener.class, Looper.class);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException("Cannot construct CarServiceLoader, no constructor: "
+ + carServiceLoaderClassName, e);
+ }
+ try {
+ return (CarServiceLoader) ctor.newInstance(context,
+ serviceConnectionListener, looper);
+ } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e) {
+ throw new IllegalArgumentException(
+ "Cannot construct CarServiceLoader, constructor failed for "
+ + carServiceLoaderClass.getName(), e);
}
}
@@ -297,17 +325,18 @@
*/
public Object getCarManager(String serviceName) throws CarNotConnectedException {
CarManagerBase manager = null;
+ ICar service = getICarOrThrow();
synchronized (mCarManagerLock) {
manager = mServiceMap.get(serviceName);
if (manager == null) {
try {
- IBinder binder = mService.getCarService(serviceName);
+ IBinder binder = service.getCarService(serviceName);
if (binder == null) {
Log.w(CarLibLog.TAG_CAR, "getCarManager could not get binder for service:" +
serviceName);
return null;
}
- manager = createCarManager(serviceName, binder);
+ manager = mCarServiceLoader.createCarManager(serviceName, binder);
if (manager == null) {
Log.w(CarLibLog.TAG_CAR,
"getCarManager could not create manager for service:" +
@@ -339,23 +368,6 @@
return Car.CONNECTION_TYPE_EMULATOR;
}
- private CarManagerBase createCarManager(String serviceName, IBinder binder) {
- CarManagerBase manager = null;
- switch (serviceName) {
- case SENSOR_SERVICE:
- manager = new CarSensorManager(mContext, ICarSensor.Stub.asInterface(binder),
- mLooper);
- break;
- case INFO_SERVICE:
- manager = new CarInfoManager(ICarInfo.Stub.asInterface(binder));
- break;
- default:
- manager = mCarServiceLoader.createCustomCarManager(serviceName, binder);
- break;
- }
- return manager;
- }
-
private synchronized ICar getICarOrThrow() throws IllegalStateException {
if (mService == null) {
throw new IllegalStateException("not connected");
diff --git a/carsupport-lib/src/android/support/car/CarManagerBase.java b/carsupport-lib/src/android/support/car/CarManagerBase.java
index 832188c..79a28f8 100644
--- a/carsupport-lib/src/android/support/car/CarManagerBase.java
+++ b/carsupport-lib/src/android/support/car/CarManagerBase.java
@@ -18,7 +18,8 @@
/**
* Common interface for Car*Manager
+ * @hide
*/
-interface CarManagerBase {
+public interface CarManagerBase {
void onCarDisconnected();
}
diff --git a/carsupport-lib/src/android/support/car/CarServiceLoader.java b/carsupport-lib/src/android/support/car/CarServiceLoader.java
index 1989093..ac5c29e 100644
--- a/carsupport-lib/src/android/support/car/CarServiceLoader.java
+++ b/carsupport-lib/src/android/support/car/CarServiceLoader.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.os.IBinder;
+import android.os.Looper;
/**
* CarServiceLoader is the abstraction for loading different types of car service.
@@ -27,26 +28,39 @@
private final Context mContext;
private final ServiceConnectionListener mListener;
+ private final Looper mLooper;
- public CarServiceLoader(Context context, ServiceConnectionListener listener) {
+ public CarServiceLoader(Context context, ServiceConnectionListener listener, Looper looper) {
mContext = context;
mListener = listener;
+ mLooper = looper;
}
public abstract void connect() throws IllegalStateException;
public abstract void disconnect();
/**
- * Factory method to create non-standard Car*Manager for the given car service implementation.
- * This is necessary for Car*Manager which is relevant for one specific implementation like
- * projected.
+ * Factory method to create Car*Manager for the given car service implementation.
+ * Each implementation can add its own custom Car*Manager while default implementation will
+ * handle all standard Car*Managers.
* @param serviceName service name for the given Car*Manager.
* @param binder binder implementation received from car service
* @return Car*Manager instance for the given serviceName / binder. null if given service is
* not supported.
*/
- public CarManagerBase createCustomCarManager(String serviceName, IBinder binder) {
- return null;
+ public CarManagerBase createCarManager(String serviceName,
+ IBinder binder) {
+ CarManagerBase manager = null;
+ switch (serviceName) {
+ case Car.SENSOR_SERVICE:
+ manager = new CarSensorManager(mContext, ICarSensor.Stub.asInterface(binder),
+ mLooper);
+ break;
+ case Car.INFO_SERVICE:
+ manager = new CarInfoManager(ICarInfo.Stub.asInterface(binder));
+ break;
+ }
+ return manager;
}
protected Context getContext() {
@@ -56,4 +70,8 @@
protected ServiceConnectionListener getConnectionListener() {
return mListener;
}
+
+ protected Looper getLooper() {
+ return mLooper;
+ }
}
diff --git a/carsupport-lib/src/android/support/car/DefaultCarServiceLoader.java b/carsupport-lib/src/android/support/car/DefaultCarServiceLoader.java
index f3fcc68..b008017 100644
--- a/carsupport-lib/src/android/support/car/DefaultCarServiceLoader.java
+++ b/carsupport-lib/src/android/support/car/DefaultCarServiceLoader.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
+import android.os.Looper;
/**
* Default CarServiceLoader for system with built-in car service.
@@ -45,8 +46,9 @@
}
};
- public DefaultCarServiceLoader(Context context, ServiceConnectionListener listener) {
- super(context, listener);
+ public DefaultCarServiceLoader(Context context, ServiceConnectionListener listener,
+ Looper looper) {
+ super(context, listener, looper);
}
@Override
diff --git a/carsystem-lib/Android.mk b/carsystem-lib/Android.mk
new file mode 100644
index 0000000..baca9ae
--- /dev/null
+++ b/carsystem-lib/Android.mk
@@ -0,0 +1,28 @@
+# 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.
+#
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libcarsystem
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES += libcarsupport
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/carsystem-lib/src/com/android/car/CarSystem.java b/carsystem-lib/src/com/android/car/CarSystem.java
new file mode 100644
index 0000000..aee4bf1
--- /dev/null
+++ b/carsystem-lib/src/com/android/car/CarSystem.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+/**
+ * Container class to hold static definitions for system api for Car.
+ * Client should still use Car api for all operations, and this class is only for defining
+ * additional parameters available when car api becomes system api.
+ * @hide
+ */
+public class CarSystem {
+
+}
diff --git a/carsystem-lib/src/com/android/car/SystemApiCarServiceLoader.java b/carsystem-lib/src/com/android/car/SystemApiCarServiceLoader.java
new file mode 100644
index 0000000..258bc0d
--- /dev/null
+++ b/carsystem-lib/src/com/android/car/SystemApiCarServiceLoader.java
@@ -0,0 +1,39 @@
+/*
+ * 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.os.IBinder;
+import android.os.Looper;
+import android.support.car.CarManagerBase;
+import android.support.car.DefaultCarServiceLoader;
+import android.support.car.ServiceConnectionListener;
+
+public class SystemApiCarServiceLoader extends DefaultCarServiceLoader {
+
+ public SystemApiCarServiceLoader(Context context, ServiceConnectionListener listener,
+ Looper looper) {
+ super(context, listener, looper);
+ }
+
+ @Override
+ public CarManagerBase createCarManager(String serviceName, IBinder binder) {
+ //TODO populate system only Car*Managers
+ //switch (serviceName) {
+ //}
+ return super.createCarManager(serviceName, binder);
+ }
+}
diff --git a/carsystemtest-lib/Android.mk b/carsystemtest-lib/Android.mk
new file mode 100644
index 0000000..2852bfd
--- /dev/null
+++ b/carsystemtest-lib/Android.mk
@@ -0,0 +1,31 @@
+# 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.
+#
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libcarsystemtest
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
+
+LOCAL_AIDL_INCLUDES += packages/services/Car/libvehiclenetwork/java/src/
+
+LOCAL_STATIC_JAVA_LIBRARIES += libcarsystem libvehiclenetwork-java
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/carsystemtest-lib/src/com/android/car/CarSystemTest.java b/carsystemtest-lib/src/com/android/car/CarSystemTest.java
new file mode 100644
index 0000000..b7997c0
--- /dev/null
+++ b/carsystemtest-lib/src/com/android/car/CarSystemTest.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+/**
+ * Container class to hold static definitions for system test api for Car.
+ * Client should still use Car api for all operations, and this class is only for defining
+ * additional parameters available when car api becomes system api.
+ * @hide
+ */
+public class CarSystemTest {
+ /**
+ * Service for testing. This is system app only feature.
+ * Service name for {@link CarTestManager}, to be used in {@link #getCarManager(String)}.
+ * @hide
+ */
+ public static final String TEST_SERVICE = "car-service-test";
+
+ /** permission necessary to mock vehicle hal for testing */
+ public static final String PERMISSION_MOCK_VEHICLE_HAL =
+ "android.support.car.permission.CAR_MOCK_VEHICLE_HAL";
+}
diff --git a/carsystemtest-lib/src/com/android/car/CarTestManager.java b/carsystemtest-lib/src/com/android/car/CarTestManager.java
new file mode 100644
index 0000000..6c65954
--- /dev/null
+++ b/carsystemtest-lib/src/com/android/car/CarTestManager.java
@@ -0,0 +1,145 @@
+/*
+ * 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.os.RemoteException;
+import android.support.car.CarManagerBase;
+
+import com.android.car.vehiclenetwork.IVehicleNetworkHalMock;
+import com.android.car.vehiclenetwork.VehicleNetwork.VehicleNetworkHalMock;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfigs;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
+import com.android.car.vehiclenetwork.VehicleNetwork;
+import com.android.car.vehiclenetwork.VehiclePropConfigsParcelable;
+import com.android.car.vehiclenetwork.VehiclePropValueParcelable;
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.ref.WeakReference;
+
+public class CarTestManager implements CarManagerBase {
+
+ private final ICarTest mService;
+
+ @GuardedBy("this")
+ private VehicleNetworkHalMock mHalMock;
+ private IVehicleNetworkHalMockImpl mHalMockImpl;
+
+ public CarTestManager(ICarTest service) {
+ mService = service;
+ }
+
+ @Override
+ public void onCarDisconnected() {
+ // should not happen for embedded
+ }
+
+ public synchronized void injectEvent(VehiclePropValue value) {
+ try {
+ mService.injectEvent(new VehiclePropValueParcelable(value));
+ } catch (RemoteException e) {
+ handleRemoteException(e);
+ }
+ }
+
+ /**
+ * Start mocking vehicle HAL. It is somewhat strange to re-use interface in lower level
+ * API, but this is only for testing, and interface is exactly the same.
+ * @param mock
+ */
+ public synchronized void startMocking(VehicleNetworkHalMock mock) {
+ mHalMock = mock;
+ mHalMockImpl = new IVehicleNetworkHalMockImpl(this);
+ try {
+ mService.startMocking(mHalMockImpl);
+ } catch (RemoteException e) {
+ handleRemoteException(e);
+ }
+ }
+
+ public synchronized void stopMocking() {
+ try {
+ mService.stopMocking(mHalMockImpl);
+ } catch (RemoteException e) {
+ handleRemoteException(e);
+ } finally {
+ mHalMock = null;
+ mHalMockImpl = null;
+ }
+ }
+
+ private synchronized VehicleNetworkHalMock getHalMock() {
+ return mHalMock;
+ }
+
+ private void handleRemoteException(RemoteException e) {
+ //TODO
+ }
+
+ private static class IVehicleNetworkHalMockImpl extends IVehicleNetworkHalMock.Stub {
+ private final WeakReference<CarTestManager> mTestManager;
+
+ private IVehicleNetworkHalMockImpl(CarTestManager testManager) {
+ mTestManager = new WeakReference<CarTestManager>(testManager);
+ }
+
+ @Override
+ public VehiclePropConfigsParcelable onListProperties() {
+ CarTestManager testManager = mTestManager.get();
+ if (testManager == null) {
+ return null;
+ }
+ VehiclePropConfigs configs = testManager.getHalMock().onListProperties();
+ return new VehiclePropConfigsParcelable(configs);
+ }
+
+ @Override
+ public void onPropertySet(VehiclePropValueParcelable value) {
+ CarTestManager testManager = mTestManager.get();
+ if (testManager == null) {
+ return;
+ }
+ testManager.getHalMock().onPropertySet(value.value);
+ }
+
+ @Override
+ public VehiclePropValueParcelable onPropertyGet(int property) {
+ CarTestManager testManager = mTestManager.get();
+ if (testManager == null) {
+ return null;
+ }
+ VehiclePropValue value = testManager.getHalMock().onPropertyGet(property);
+ return new VehiclePropValueParcelable(value);
+ }
+
+ @Override
+ public void onPropertySubscribe(int property, int sampleRate) {
+ CarTestManager testManager = mTestManager.get();
+ if (testManager == null) {
+ return;
+ }
+ testManager.getHalMock().onPropertySubscribe(property, sampleRate);
+ }
+
+ @Override
+ public void onPropertyUnsubscribe(int property) {
+ CarTestManager testManager = mTestManager.get();
+ if (testManager == null) {
+ return;
+ }
+ testManager.getHalMock().onPropertyUnsubscribe(property);
+ }
+ }
+}
diff --git a/carsystemtest-lib/src/com/android/car/ICarTest.aidl b/carsystemtest-lib/src/com/android/car/ICarTest.aidl
new file mode 100644
index 0000000..23f0b42
--- /dev/null
+++ b/carsystemtest-lib/src/com/android/car/ICarTest.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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 com.android.car.vehiclenetwork.IVehicleNetworkHalMock;
+import com.android.car.vehiclenetwork.VehiclePropValueParcelable;
+
+/** @hide */
+interface ICarTest {
+ int getVersion() = 0;
+ /** For testing only. inject events. */
+ void injectEvent(in VehiclePropValueParcelable value) = 1;
+ /** For testing only. Start in mocking mode. */
+ void startMocking(in IVehicleNetworkHalMock mock) = 2;
+ /** Finish mocking mode. */
+ void stopMocking(in IVehicleNetworkHalMock mock) = 3;
+}
diff --git a/carsystemtest-lib/src/com/android/car/SystemTestApiCarServiceLoader.java b/carsystemtest-lib/src/com/android/car/SystemTestApiCarServiceLoader.java
new file mode 100644
index 0000000..2025748
--- /dev/null
+++ b/carsystemtest-lib/src/com/android/car/SystemTestApiCarServiceLoader.java
@@ -0,0 +1,39 @@
+/*
+ * 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.os.IBinder;
+import android.os.Looper;
+import android.support.car.CarManagerBase;
+import android.support.car.ServiceConnectionListener;
+
+public class SystemTestApiCarServiceLoader extends SystemApiCarServiceLoader {
+
+ public SystemTestApiCarServiceLoader(Context context, ServiceConnectionListener listener,
+ Looper looper) {
+ super(context, listener, looper);
+ }
+
+ @Override
+ public CarManagerBase createCarManager(String serviceName, IBinder binder) {
+ switch (serviceName) {
+ case CarSystemTest.TEST_SERVICE:
+ return new CarTestManager(ICarTest.Stub.asInterface(binder));
+ }
+ return super.createCarManager(serviceName, binder);
+ }
+}
diff --git a/carsystemtest-lib/src/com/android/car/VehicleHalEmulator.java b/carsystemtest-lib/src/com/android/car/VehicleHalEmulator.java
new file mode 100644
index 0000000..25dc9b5
--- /dev/null
+++ b/carsystemtest-lib/src/com/android/car/VehicleHalEmulator.java
@@ -0,0 +1,332 @@
+/*
+ * 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.support.car.Car;
+import android.support.car.CarNotConnectedException;
+
+import com.android.car.vehiclenetwork.VehicleNetwork.VehicleNetworkHalMock;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePermissionModel;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropAccess;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropChangeMode;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfigs;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
+import com.android.car.vehiclenetwork.VehiclePropValueUtil;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+
+/**
+ * This is for mocking vehicle HAL and testing system's internal behavior.
+ * By default, emulated vehicle HAL will have all properties defined with default values
+ * returned for get call. For interested properties, each test can replace default behavior with
+ * {@link #addProperty(VehiclePropConfig, VehicleHalPropertyHandler)} or
+ * {@link #addStaticProperty(VehiclePropConfig, VehiclePropValue)}.
+ * To test a case where specific property should not be present, test can call
+ * {@link #removeProperty(int)}.
+ *
+ * Adding / removing properties should be done before calling {@link #start()} as the call will
+ * start emulating with properties added / removed up to now.
+ * @hide
+ */
+public class VehicleHalEmulator {
+
+ /**
+ * Interface for handler of each property.
+ */
+ public interface VehicleHalPropertyHandler {
+ void onPropertySet(VehiclePropValue value);
+ VehiclePropValue onPropertyGet(int property);
+ void onPropertySubscribe(int property, int sampleRate);
+ void onPropertyUnsubscribe(int property);
+ }
+
+ private final HashMap<Integer, VehicleHalProperty> mProperties =
+ new HashMap<Integer, VehicleHalProperty>();
+
+ private final CarTestManager mCarTestManager;
+ private final HalMock mMock = new HalMock();
+ private boolean mDefaultPropertiesPopulated = false;
+ private boolean mStarted = false;
+
+ /**
+ * Constructor. Car instance passed should be already connected to car service.
+ * @param car
+ */
+ public VehicleHalEmulator(Car car) {
+ try {
+ mCarTestManager = (CarTestManager) car.getCarManager(CarSystemTest.TEST_SERVICE);
+ } catch (CarNotConnectedException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Add property to mocked vehicle hal.
+ * @param config
+ * @param handler
+ */
+ public synchronized void addProperty(VehiclePropConfig config,
+ VehicleHalPropertyHandler handler) {
+ populateDefaultPropertiesIfNecessary();
+ VehicleHalProperty halProp = new VehicleHalProperty(config, handler);
+ mProperties.put(config.getProp(), halProp);
+ }
+
+ /**
+ * Add static property to mocked vehicle hal.
+ * @param config
+ * @param value
+ */
+ public synchronized void addStaticProperty(VehiclePropConfig config, VehiclePropValue value) {
+ populateDefaultPropertiesIfNecessary();
+ DefaultPropertyHandler handler = new DefaultPropertyHandler(config, value);
+ VehicleHalProperty halProp = new VehicleHalProperty(config, handler);
+ mProperties.put(config.getProp(), halProp);
+ }
+
+ /**
+ * Remove this property from vehicle HAL properties. Emulated vehicle HAL will not have this
+ * property. This is useful to test the case where specific property is not present.
+ * @param property
+ */
+ public synchronized void removeProperty(int property) {
+ populateDefaultPropertiesIfNecessary();
+ mProperties.remove(property);
+ }
+
+ /**
+ * Start emulation. All necessary properties should have been added / removed before this.
+ */
+ public void start() {
+ mCarTestManager.startMocking(mMock);
+ synchronized (this) {
+ mStarted = true;
+ }
+ }
+
+ /** Whether emulation is started or not. */
+ public synchronized boolean isStarted() {
+ return mStarted;
+ }
+
+ /**
+ * Stop emulation. should be done before finishing test.
+ */
+ public void stop() {
+ mCarTestManager.stopMocking();
+ synchronized (this) {
+ mStarted = false;
+ }
+ }
+
+ public void injectEvent(VehiclePropValue value) {
+ mCarTestManager.injectEvent(value);
+ }
+
+ public static void assertPropertyForGet(VehiclePropConfig config, int property) {
+ assertProperty(config, property);
+ if ((config.getAccess() & VehiclePropAccess.VEHICLE_PROP_ACCESS_READ) == 0) {
+ throw new IllegalArgumentException("cannot set write-only property 0x" +
+ Integer.toHexString(config.getProp()));
+ }
+ }
+
+ public static void assertPropertyForSet(VehiclePropConfig config, VehiclePropValue value) {
+ assertProperty(config, value.getProp());
+ if ((config.getAccess() & VehiclePropAccess.VEHICLE_PROP_ACCESS_WRITE) == 0) {
+ throw new IllegalArgumentException("cannot set read-only property 0x" +
+ Integer.toHexString(config.getProp()));
+ }
+ }
+
+ public static void assertPropertyForSubscribe(VehiclePropConfig config, int property,
+ float sampleRate) {
+ assertPropertyForGet(config, property);
+ if (config.getChangeMode() == VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC) {
+ throw new IllegalStateException("cannot subscribe static property 0x" +
+ Integer.toHexString(config.getProp()));
+ }
+ }
+
+ public static void assertProperty(VehiclePropConfig config, int property) {
+ if (config.getProp() != property) {
+ throw new IllegalStateException("Wrong prop, expecting 0x" +
+ Integer.toHexString(config.getProp()) + " while got 0x" +
+ Integer.toHexString(property));
+ }
+ }
+
+ private synchronized void populateDefaultPropertiesIfNecessary() {
+ if (mDefaultPropertiesPopulated) {
+ return;
+ }
+ for (Field f : VehicleNetworkConsts.class.getDeclaredFields()) {
+ if (f.getType() == int.class) {
+ int property = 0;
+ try {
+ property = f.getInt(null);
+ } catch (IllegalAccessException e) {
+ continue;
+ }
+ int valueType = VehicleNetworkConsts.getVehicleValueType(property);
+ if (valueType == VehicleValueType.VEHICLE_VALUE_TYPE_SHOUD_NOT_USE) {
+ // invalid property or not a property
+ continue;
+ }
+ int changeMode = VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC;
+ int[] changeModes = VehicleNetworkConsts.getVehicleChangeMode(property);
+ if (changeModes != null) {
+ changeMode = changeModes[0];
+ }
+ int access = VehicleNetworkConsts.getVehicleAccess(property);
+ if (access == 0) { // invalid
+ continue;
+ }
+ VehiclePropConfig config = VehiclePropConfig.newBuilder().
+ setProp(property).
+ setAccess(access).
+ setChangeMode(changeMode).
+ setValueType(valueType).
+ setPermissionModel(
+ VehiclePermissionModel.VEHICLE_PERMISSION_NO_RESTRICTION).
+ setConfigFlags(0).
+ setSampleRateMax(0).
+ setSampleRateMin(0).
+ build();
+ VehiclePropValue initialValue = VehiclePropValueUtil.createDummyValue(property,
+ valueType);
+ DefaultPropertyHandler handler = new DefaultPropertyHandler(config, initialValue);
+ VehicleHalProperty halProp = new VehicleHalProperty(config, handler);
+ mProperties.put(property, halProp);
+ }
+ }
+ mDefaultPropertiesPopulated = true;
+ }
+
+ private synchronized VehiclePropConfigs handleListProperties() {
+ VehiclePropConfigs.Builder builder = VehiclePropConfigs.newBuilder();
+ for (VehicleHalProperty halProp : mProperties.values()) {
+ builder.addConfigs(halProp.config);
+ }
+ return builder.build();
+ }
+
+ private synchronized void handlePropertySet(VehiclePropValue value) {
+ getHalPropertyLocked(value.getProp()).handler.onPropertySet(value);
+ }
+
+ private synchronized VehiclePropValue handlePropertyGet(int property) {
+ return getHalPropertyLocked(property).handler.onPropertyGet(property);
+ }
+
+ private synchronized void handlePropertySubscribe(int property, int sampleRate) {
+ getHalPropertyLocked(property).handler.onPropertySubscribe(property, sampleRate);
+ }
+
+ private synchronized void handlePropertyUnsubscribe(int property) {
+ getHalPropertyLocked(property).handler.onPropertyUnsubscribe(property);
+ }
+
+ private VehicleHalProperty getHalPropertyLocked(int property) {
+ VehicleHalProperty halProp = mProperties.get(property);
+ if (halProp == null) {
+ throw new IllegalArgumentException();
+ }
+ return halProp;
+ }
+
+ private static class VehicleHalProperty {
+ public final VehiclePropConfig config;
+ public final VehicleHalPropertyHandler handler;
+
+ public VehicleHalProperty(VehiclePropConfig config, VehicleHalPropertyHandler handler) {
+ this.config = config;
+ this.handler = handler;
+ }
+ }
+
+ private static class DefaultPropertyHandler implements VehicleHalPropertyHandler {
+ private final VehiclePropConfig mConfig;
+ private VehiclePropValue mValue;
+ private boolean mSubscribed = false;
+
+ public DefaultPropertyHandler(VehiclePropConfig config, VehiclePropValue initialValue) {
+ mConfig = config;
+ mValue = initialValue;
+ }
+
+ @Override
+ public synchronized void onPropertySet(VehiclePropValue value) {
+ assertPropertyForSet(mConfig, value);
+ mValue = value;
+ }
+
+ @Override
+ public synchronized VehiclePropValue onPropertyGet(int property) {
+ assertPropertyForGet(mConfig, property);
+ return mValue;
+ }
+
+ @Override
+ public synchronized void onPropertySubscribe(int property, int sampleRate) {
+ assertPropertyForSubscribe(mConfig, property, sampleRate);
+ mSubscribed = true;
+ }
+
+ @Override
+ public synchronized void onPropertyUnsubscribe(int property) {
+ assertProperty(mConfig, property);
+ if (!mSubscribed) {
+ throw new IllegalArgumentException("unsubscibe for not subscribed property 0x" +
+ Integer.toHexString(property));
+ }
+ mSubscribed = false;
+ }
+
+ }
+
+ private class HalMock implements VehicleNetworkHalMock {
+
+ @Override
+ public VehiclePropConfigs onListProperties() {
+ return handleListProperties();
+ }
+
+ @Override
+ public void onPropertySet(VehiclePropValue value) {
+ handlePropertySet(value);
+ }
+
+ @Override
+ public VehiclePropValue onPropertyGet(int property) {
+ return handlePropertyGet(property);
+ }
+
+ @Override
+ public void onPropertySubscribe(int property, int sampleRate) {
+ handlePropertySubscribe(property, sampleRate);
+ }
+
+ @Override
+ public void onPropertyUnsubscribe(int property) {
+ handlePropertyUnsubscribe(property);
+ }
+ }
+}
diff --git a/libvehiclenetwork/include/IVehicleNetwork.h b/libvehiclenetwork/include/IVehicleNetwork.h
index 5c5f84e..f577703 100644
--- a/libvehiclenetwork/include/IVehicleNetwork.h
+++ b/libvehiclenetwork/include/IVehicleNetwork.h
@@ -29,6 +29,7 @@
#include <binder/Parcel.h>
#include <VehicleNetworkDataTypes.h>
+#include <IVehicleNetworkHalMock.h>
#include <IVehicleNetworkListener.h>
namespace android {
@@ -50,6 +51,9 @@
virtual status_t subscribe(const sp<IVehicleNetworkListener> &listener, int32_t property,
float sampleRate) = 0;
virtual void unsubscribe(const sp<IVehicleNetworkListener> &listener, int32_t property) = 0;
+ virtual status_t injectEvent(const vehicle_prop_value_t& value) = 0;
+ virtual status_t startMocking(const sp<IVehicleNetworkHalMock>& mock) = 0;
+ virtual void stopMocking(const sp<IVehicleNetworkHalMock>& mock) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/libvehiclenetwork/include/IVehicleNetworkHalMock.h b/libvehiclenetwork/include/IVehicleNetworkHalMock.h
new file mode 100644
index 0000000..4311693
--- /dev/null
+++ b/libvehiclenetwork/include/IVehicleNetworkHalMock.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_IVEHICLE_NETWORK_HAL_MOCK_H
+#define ANDROID_IVEHICLE_NETWORK_HAL_MOCK_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+
+#include <VehicleNetworkDataTypes.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IVehicleNetworkHalMock : public IInterface
+{
+public:
+ static const char SERVICE_NAME[];
+ DECLARE_META_INTERFACE(VehicleNetworkHalMock);
+
+ virtual sp<VehiclePropertiesHolder> onListProperties() = 0;
+ virtual status_t onPropertySet(const vehicle_prop_value_t& value) = 0;
+ virtual status_t onPropertyGet(vehicle_prop_value_t* value) = 0;
+ virtual status_t onPropertySubscribe(int32_t property, float sampleRate) = 0;
+ virtual void onPropertyUnsubscribe(int32_t property) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnVehicleNetworkHalMock : public BnInterface<IVehicleNetworkHalMock>
+{
+ virtual status_t onTransact(uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif /* ANDROID_IVEHICLE_NETWORK_HAL_MOCK_H */
diff --git a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/IVehicleNetwork.aidl b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/IVehicleNetwork.aidl
index 1f5fec3..bfaf0d3 100644
--- a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/IVehicleNetwork.aidl
+++ b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/IVehicleNetwork.aidl
@@ -16,12 +16,12 @@
package com.android.car.vehiclenetwork;
+import com.android.car.vehiclenetwork.IVehicleNetworkHalMock;
+import com.android.car.vehiclenetwork.IVehicleNetworkListener;
import com.android.car.vehiclenetwork.VehiclePropConfigsParcelable;
import com.android.car.vehiclenetwork.VehiclePropValueParcelable;
import com.android.car.vehiclenetwork.VehiclePropValuesParcelable;
-import com.android.car.vehiclenetwork.IVehicleNetworkListener;
-
/**
* Binder API to access vehicle network service.
* @hide
@@ -34,5 +34,12 @@
/** For error case, exception will be thrown. */
void subscribe(in IVehicleNetworkListener listener, int property, float sampleRate) = 3;
void unsubscribe(in IVehicleNetworkListener listener, int property) = 4;
+ /** For testing only. inject events. */
+ void injectEvent(in VehiclePropValueParcelable value) = 5;
+ /** For testing only. Start in mocking mode. */
+ void startMocking(in IVehicleNetworkHalMock mock) = 6;
+ /** Finish mocking mode. */
+ void stopMocking(in IVehicleNetworkHalMock mock) = 7;
+
//TODO add specialized set for byte array for efficiency
}
diff --git a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/IVehicleNetworkHalMock.aidl b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/IVehicleNetworkHalMock.aidl
new file mode 100644
index 0000000..d5187a8
--- /dev/null
+++ b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/IVehicleNetworkHalMock.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.vehiclenetwork;
+
+import com.android.car.vehiclenetwork.VehiclePropConfigsParcelable;
+import com.android.car.vehiclenetwork.VehiclePropValueParcelable;
+
+/**
+ * Listener for vehicle HAL mock. This is used for internal testing only.
+ * @hide
+ */
+interface IVehicleNetworkHalMock {
+ VehiclePropConfigsParcelable onListProperties() = 0;
+ void onPropertySet(in VehiclePropValueParcelable value) = 1;
+ VehiclePropValueParcelable onPropertyGet(int property) = 2;
+ void onPropertySubscribe(int property, int sampleRate) = 3;
+ void onPropertyUnsubscribe(int property) = 4;
+}
diff --git a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetwork.java b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetwork.java
index 7514c8c..b9cd870 100644
--- a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetwork.java
+++ b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetwork.java
@@ -27,6 +27,7 @@
import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfigs;
import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValues;
+import com.android.internal.annotations.GuardedBy;
import java.lang.ref.WeakReference;
@@ -35,10 +36,24 @@
* not use this. All APIs will fail with security error if normal app tries this.
*/
public class VehicleNetwork {
+ /**
+ * Listener for VNS events.
+ */
public interface VehicleNetworkListener {
+ /**
+ * Notify HAL events. This requires subscribing the property
+ */
void onVehicleNetworkEvents(VehiclePropValues values);
}
+ public interface VehicleNetworkHalMock {
+ VehiclePropConfigs onListProperties();
+ void onPropertySet(VehiclePropValue value);
+ VehiclePropValue onPropertyGet(int property);
+ void onPropertySubscribe(int property, int sampleRate);
+ void onPropertyUnsubscribe(int property);
+ }
+
private static final String TAG = VehicleNetwork.class.getSimpleName();
private final IVehicleNetwork mService;
@@ -46,6 +61,10 @@
private final IVehicleNetworkListenerImpl mVehicleNetworkListener;
private final EventHandler mEventHandler;
+ @GuardedBy("this")
+ private VehicleNetworkHalMock mHalMock;
+ private IVehicleNetworkHalMock mHalMockImpl;
+
public static VehicleNetwork createVehicleNetwork(VehicleNetworkListener listener,
Looper looper) {
IVehicleNetwork service = IVehicleNetwork.Stub.asInterface(ServiceManager.getService(
@@ -91,52 +110,28 @@
}
public void setIntProperty(int property, int value) {
- VehiclePropValue v = VehiclePropValue.newBuilder().
- setProp(property).
- setValueType(VehicleValueType.VEHICLE_VALUE_TYPE_INT32).
- addInt32Values(value).
- build();
+ VehiclePropValue v = VehiclePropValueUtil.createIntValue(property, value, 0);
setProperty(v);
}
public void setIntVectorProperty(int property, int[] values) {
- int len = values.length;
- VehiclePropValue.Builder builder = VehiclePropValue.newBuilder().
- setProp(property).
- setValueType(VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2 + len - 2);
- for (int v : values) {
- builder.addInt32Values(v);
- }
- setProperty(builder.build());
+ VehiclePropValue v = VehiclePropValueUtil.createIntVectorValue(property, values, 0);
+ setProperty(v);
}
public void setLongProperty(int property, long value) {
- VehiclePropValue v = VehiclePropValue.newBuilder().
- setProp(property).
- setValueType(VehicleValueType.VEHICLE_VALUE_TYPE_INT64).
- setInt64Value(value).
- build();
+ VehiclePropValue v = VehiclePropValueUtil.createLongValue(property, value, 0);
setProperty(v);
}
public void setFloatProperty(int property, float value) {
- VehiclePropValue v = VehiclePropValue.newBuilder().
- setProp(property).
- setValueType(VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT).
- addFloatValues(value).
- build();
+ VehiclePropValue v = VehiclePropValueUtil.createFloatValue(property, value, 0);
setProperty(v);
}
public void setFloatVectorProperty(int property, float[] values) {
- int len = values.length;
- VehiclePropValue.Builder builder = VehiclePropValue.newBuilder().
- setProp(property).
- setValueType(VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT_VEC2 + len - 2);
- for (float v : values) {
- builder.addFloatValues(v);
- }
- setProperty(builder.build());
+ VehiclePropValue v = VehiclePropValueUtil.createFloatVectorValue(property, values, 0);
+ setProperty(v);
}
public VehiclePropValue getProperty(int property) {
@@ -274,6 +269,63 @@
}
}
+ public synchronized void injectEvent(VehiclePropValue value) {
+ try {
+ mService.injectEvent(new VehiclePropValueParcelable(value));
+ } catch (RemoteException e) {
+ handleRemoteException(e);
+ }
+ }
+
+ public synchronized void startMocking(VehicleNetworkHalMock mock) {
+ mHalMock = mock;
+ mHalMockImpl = new IVehicleNetworkHalMockImpl(this);
+ try {
+ mService.startMocking(mHalMockImpl);
+ } catch (RemoteException e) {
+ handleRemoteException(e);
+ }
+ }
+
+ public synchronized void stopMocking() {
+ try {
+ mService.stopMocking(mHalMockImpl);
+ } catch (RemoteException e) {
+ handleRemoteException(e);
+ } finally {
+ mHalMock = null;
+ mHalMockImpl = null;
+ }
+ }
+
+ public synchronized void startMocking(IVehicleNetworkHalMock mock) {
+ mHalMock = null;
+ mHalMockImpl = mock;
+ try {
+ mService.startMocking(mHalMockImpl);
+ } catch (RemoteException e) {
+ handleRemoteException(e);
+ }
+ }
+
+ public synchronized void stopMocking(IVehicleNetworkHalMock mock) {
+ if (mock.asBinder() != mHalMockImpl.asBinder()) {
+ return;
+ }
+ try {
+ mService.stopMocking(mHalMockImpl);
+ } catch (RemoteException e) {
+ handleRemoteException(e);
+ } finally {
+ mHalMock = null;
+ mHalMockImpl = null;
+ }
+ }
+
+ private synchronized VehicleNetworkHalMock getHalMock() {
+ return mHalMock;
+ }
+
private void handleRemoteException(RemoteException e) {
throw new RuntimeException("Vehicle network service not working ", e);
}
@@ -326,4 +378,59 @@
}
}
}
+
+ private static class IVehicleNetworkHalMockImpl extends IVehicleNetworkHalMock.Stub {
+ private final WeakReference<VehicleNetwork> mVehicleNetwork;
+
+ private IVehicleNetworkHalMockImpl(VehicleNetwork vehicleNewotk) {
+ mVehicleNetwork = new WeakReference<VehicleNetwork>(vehicleNewotk);
+ }
+
+ @Override
+ public VehiclePropConfigsParcelable onListProperties() {
+ VehicleNetwork vehicleNetwork = mVehicleNetwork.get();
+ if (vehicleNetwork == null) {
+ return null;
+ }
+ VehiclePropConfigs configs = vehicleNetwork.getHalMock().onListProperties();
+ return new VehiclePropConfigsParcelable(configs);
+ }
+
+ @Override
+ public void onPropertySet(VehiclePropValueParcelable value) {
+ VehicleNetwork vehicleNetwork = mVehicleNetwork.get();
+ if (vehicleNetwork == null) {
+ return;
+ }
+ vehicleNetwork.getHalMock().onPropertySet(value.value);
+ }
+
+ @Override
+ public VehiclePropValueParcelable onPropertyGet(int property) {
+ VehicleNetwork vehicleNetwork = mVehicleNetwork.get();
+ if (vehicleNetwork == null) {
+ return null;
+ }
+ VehiclePropValue value = vehicleNetwork.getHalMock().onPropertyGet(property);
+ return new VehiclePropValueParcelable(value);
+ }
+
+ @Override
+ public void onPropertySubscribe(int property, int sampleRate) {
+ VehicleNetwork vehicleNetwork = mVehicleNetwork.get();
+ if (vehicleNetwork == null) {
+ return;
+ }
+ vehicleNetwork.getHalMock().onPropertySubscribe(property, sampleRate);
+ }
+
+ @Override
+ public void onPropertyUnsubscribe(int property) {
+ VehicleNetwork vehicleNetwork = mVehicleNetwork.get();
+ if (vehicleNetwork == null) {
+ return;
+ }
+ vehicleNetwork.getHalMock().onPropertyUnsubscribe(property);
+ }
+ }
}
diff --git a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetworkConsts.java b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetworkConsts.java
index 2938f00..529e04b 100644
--- a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetworkConsts.java
+++ b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetworkConsts.java
@@ -46,6 +46,7 @@
public static final int VEHICLE_PROPERTY_ENV_OUTSIDE_TEMP = 0x00000703;
public static final int VEHICLE_PROPERTY_AUDIO_FOCUS = 0x00000900;
public static final int VEHICLE_PROPERTY_AUDIO_VOLUME = 0x00000901;
+public static final int VEHICLE_PROPERTY_AP_POWER_STATE = 0x00000A00;
public static final int VEHICLE_PROPERTY_CUSTOM_START = 0xf0000000;
public static final int VEHICLE_PROPERTY_CUSTOM_END = 0xf7ffffff;
public static final int VEHICLE_PROPERTY_INTERNAL_START = 0xf8000000;
@@ -78,6 +79,7 @@
case VEHICLE_PROPERTY_ENV_OUTSIDE_TEMP: return VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT;
case VEHICLE_PROPERTY_AUDIO_FOCUS: return VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2;
case VEHICLE_PROPERTY_AUDIO_VOLUME: return VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2;
+case VEHICLE_PROPERTY_AP_POWER_STATE: return VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2;
case VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE: return VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2;
default: return VehicleValueType.VEHICLE_VALUE_TYPE_SHOUD_NOT_USE;
}
@@ -109,12 +111,79 @@
case VEHICLE_PROPERTY_ENV_OUTSIDE_TEMP: return "VEHICLE_PROPERTY_ENV_OUTSIDE_TEMP";
case VEHICLE_PROPERTY_AUDIO_FOCUS: return "VEHICLE_PROPERTY_AUDIO_FOCUS";
case VEHICLE_PROPERTY_AUDIO_VOLUME: return "VEHICLE_PROPERTY_AUDIO_VOLUME";
+case VEHICLE_PROPERTY_AP_POWER_STATE: return "VEHICLE_PROPERTY_AP_POWER_STATE";
case VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE: return "VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE";
default: return "UNKNOWN_PROPERTY";
}
}
-public static class VehicleAudioFocusRequestType {
+public static int[] getVehicleChangeMode(int property) {
+switch (property) {
+case VEHICLE_PROPERTY_INFO_VIN: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC };
+case VEHICLE_PROPERTY_INFO_MAKE: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC };
+case VEHICLE_PROPERTY_INFO_MODEL: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC };
+case VEHICLE_PROPERTY_INFO_MODEL_YEAR: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC };
+case VEHICLE_PROPERTY_INFO_FUEL_CAPACITY: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC };
+case VEHICLE_PROPERTY_PERF_ODOMETER: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_PERF_VEHICLE_SPEED: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_ENGINE_COOLANT_TEMP: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_ENGINE_OIL_TEMP: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_ENGINE_RPM: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_GEAR_SELECTION: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_CURRENT_GEAR: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_PARKING_BRAKE_ON: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_DRIVING_STATUS: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_FUEL_LEVEL_LOW: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_NIGHT_MODE: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_HVAC_FAN_SPEED: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_HVAC_FAN_DIRECTION: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_HVAC_TEMPERATURE_CURRENT: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_HVAC_TEMPERATURE_SET: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_HVAC_DEFROSTER: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_HVAC_AC_ON: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_ENV_OUTSIDE_TEMP: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_AUDIO_FOCUS: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_AUDIO_VOLUME: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_AP_POWER_STATE: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+default: return null;
+}
+}
+
+public static int getVehicleAccess(int property) {
+switch (property) {
+case VEHICLE_PROPERTY_INFO_VIN: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_INFO_MAKE: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_INFO_MODEL: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_INFO_MODEL_YEAR: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_INFO_FUEL_CAPACITY: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_PERF_ODOMETER: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_PERF_VEHICLE_SPEED: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_ENGINE_COOLANT_TEMP: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_ENGINE_OIL_TEMP: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_ENGINE_RPM: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_GEAR_SELECTION: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_CURRENT_GEAR: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_PARKING_BRAKE_ON: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_DRIVING_STATUS: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_FUEL_LEVEL_LOW: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_NIGHT_MODE: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_HVAC_FAN_SPEED: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_HVAC_FAN_DIRECTION: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_HVAC_TEMPERATURE_CURRENT: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_HVAC_TEMPERATURE_SET: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_HVAC_DEFROSTER: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_HVAC_AC_ON: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_ENV_OUTSIDE_TEMP: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_AUDIO_FOCUS: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_AUDIO_VOLUME: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_AP_POWER_STATE: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+default: return 0;
+}
+}
+
+public static class VehicleAudioFocusRequest {
public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN = 0x1;
public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT = 0x2;
public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK = 0x3;
@@ -130,7 +199,7 @@
}
}
-public static class VehicleAudioFocusStateType {
+public static class VehicleAudioFocusState {
public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN = 0x1;
public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT = 0x2;
public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK = 0x3;
@@ -150,21 +219,21 @@
}
}
-public static class VehicleAudioStreamFlagType {
-public static final int VEHICLE_AUDIO_STREAM_FLAG_DEFAULT = (0x1<<0);
-public static final int VEHICLE_AUDIO_STREAM_FLAG_MEDIA = (0x1<<1);
-public static final int VEHICLE_AUDIO_STREAM_FLAG_STREAM2 = (0x1<<2);
+public static class VehicleAudioStreamFlag {
+public static final int VEHICLE_AUDIO_STREAM_DEFAULT_FLAG = (0x1<<0);
+public static final int VEHICLE_AUDIO_STREAM_MEDIA_FLAG = (0x1<<1);
+public static final int VEHICLE_AUDIO_STREAM_STREAM2_FLAG = (0x1<<2);
public static String enumToString(int v) {
switch(v) {
-case VEHICLE_AUDIO_STREAM_FLAG_DEFAULT: return "VEHICLE_AUDIO_STREAM_FLAG_DEFAULT";
-case VEHICLE_AUDIO_STREAM_FLAG_MEDIA: return "VEHICLE_AUDIO_STREAM_FLAG_MEDIA";
-case VEHICLE_AUDIO_STREAM_FLAG_STREAM2: return "VEHICLE_AUDIO_STREAM_FLAG_STREAM2";
+case VEHICLE_AUDIO_STREAM_DEFAULT_FLAG: return "VEHICLE_AUDIO_STREAM_DEFAULT_FLAG";
+case VEHICLE_AUDIO_STREAM_MEDIA_FLAG: return "VEHICLE_AUDIO_STREAM_MEDIA_FLAG";
+case VEHICLE_AUDIO_STREAM_STREAM2_FLAG: return "VEHICLE_AUDIO_STREAM_STREAM2_FLAG";
default: return "UNKNOWN";
}
}
}
-public static class VehicleAudioStreamType {
+public static class VehicleAudioStream {
public static final int VEHICLE_AUDIO_STREAM_DEFAULT = 0;
public static final int VEHICLE_AUDIO_STREAM_MEDIA = 1;
public static String enumToString(int v) {
@@ -176,6 +245,72 @@
}
}
+public static class VehicleApPowerStateConfigFlag {
+public static final int VEHICLE_AP_POWER_STATE_CONFIG_ENABLE_DEEP_SLEEP_FLAG = 0x1;
+public static final int VEHICLE_AP_POWER_STATE_CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 0x2;
+public static String enumToString(int v) {
+switch(v) {
+case VEHICLE_AP_POWER_STATE_CONFIG_ENABLE_DEEP_SLEEP_FLAG: return "VEHICLE_AP_POWER_STATE_CONFIG_ENABLE_DEEP_SLEEP_FLAG";
+case VEHICLE_AP_POWER_STATE_CONFIG_SUPPORT_TIMER_POWER_ON_FLAG: return "VEHICLE_AP_POWER_STATE_CONFIG_SUPPORT_TIMER_POWER_ON_FLAG";
+default: return "UNKNOWN";
+}
+}
+}
+
+public static class VehicleApPowerState {
+public static final int VEHICLE_AP_POWER_STATE_OFF = 0;
+public static final int VEHICLE_AP_POWER_STATE_DEEP_SLEEP = 1;
+public static final int VEHICLE_AP_POWER_STATE_ON_DISP_OFF = 2;
+public static final int VEHICLE_AP_POWER_STATE_ON_FULL = 3;
+public static final int VEHICLE_AP_POWER_STATE_SHUTDOWN_PREPARE = 4;
+public static String enumToString(int v) {
+switch(v) {
+case VEHICLE_AP_POWER_STATE_OFF: return "VEHICLE_AP_POWER_STATE_OFF";
+case VEHICLE_AP_POWER_STATE_DEEP_SLEEP: return "VEHICLE_AP_POWER_STATE_DEEP_SLEEP";
+case VEHICLE_AP_POWER_STATE_ON_DISP_OFF: return "VEHICLE_AP_POWER_STATE_ON_DISP_OFF";
+case VEHICLE_AP_POWER_STATE_ON_FULL: return "VEHICLE_AP_POWER_STATE_ON_FULL";
+case VEHICLE_AP_POWER_STATE_SHUTDOWN_PREPARE: return "VEHICLE_AP_POWER_STATE_SHUTDOWN_PREPARE";
+default: return "UNKNOWN";
+}
+}
+}
+
+public static class VehicleApPowerStateShutdownParam {
+public static final int VEHICLE_AP_POWER_SHUTDOWN_PARAM_SHUTDOWN_IMMEDIATELY = 1;
+public static final int VEHICLE_AP_POWER_SHUTDOWN_PARAM_CAN_SLEEP = 2;
+public static final int VEHICLE_AP_POWER_SHUTDOWN_PARAM_SHUTDOWN_ONLY = 3;
+public static String enumToString(int v) {
+switch(v) {
+case VEHICLE_AP_POWER_SHUTDOWN_PARAM_SHUTDOWN_IMMEDIATELY: return "VEHICLE_AP_POWER_SHUTDOWN_PARAM_SHUTDOWN_IMMEDIATELY";
+case VEHICLE_AP_POWER_SHUTDOWN_PARAM_CAN_SLEEP: return "VEHICLE_AP_POWER_SHUTDOWN_PARAM_CAN_SLEEP";
+case VEHICLE_AP_POWER_SHUTDOWN_PARAM_SHUTDOWN_ONLY: return "VEHICLE_AP_POWER_SHUTDOWN_PARAM_SHUTDOWN_ONLY";
+default: return "UNKNOWN";
+}
+}
+}
+
+public static class VehicleApPowerSetState {
+public static final int VEHICLE_AP_POWER_SET_BOOT_COMPLETE = 0x1;
+public static final int VEHICLE_AP_POWER_SET_DEEP_SLEEP_ENTRY = 0x2;
+public static final int VEHICLE_AP_POWER_SET_DEEP_SLEEP_EXIT = 0x3;
+public static final int VEHICLE_AP_POWER_SET_SHUTDOWN_POSTPONE = 0x4;
+public static final int VEHICLE_AP_POWER_SET_SHUTDOWN_READY = 0x5;
+public static final int VEHICLE_AP_POWER_SET_DISPLAY_OFF = 0x6;
+public static final int VEHICLE_AP_POWER_SET_DISPLAY_ON = 0x7;
+public static String enumToString(int v) {
+switch(v) {
+case VEHICLE_AP_POWER_SET_BOOT_COMPLETE: return "VEHICLE_AP_POWER_SET_BOOT_COMPLETE";
+case VEHICLE_AP_POWER_SET_DEEP_SLEEP_ENTRY: return "VEHICLE_AP_POWER_SET_DEEP_SLEEP_ENTRY";
+case VEHICLE_AP_POWER_SET_DEEP_SLEEP_EXIT: return "VEHICLE_AP_POWER_SET_DEEP_SLEEP_EXIT";
+case VEHICLE_AP_POWER_SET_SHUTDOWN_POSTPONE: return "VEHICLE_AP_POWER_SET_SHUTDOWN_POSTPONE";
+case VEHICLE_AP_POWER_SET_SHUTDOWN_READY: return "VEHICLE_AP_POWER_SET_SHUTDOWN_READY";
+case VEHICLE_AP_POWER_SET_DISPLAY_OFF: return "VEHICLE_AP_POWER_SET_DISPLAY_OFF";
+case VEHICLE_AP_POWER_SET_DISPLAY_ON: return "VEHICLE_AP_POWER_SET_DISPLAY_ON";
+default: return "UNKNOWN";
+}
+}
+}
+
public static class VehicleValueType {
public static final int VEHICLE_VALUE_TYPE_SHOUD_NOT_USE = 0x00;
public static final int VEHICLE_VALUE_TYPE_STRING = 0x01;
diff --git a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehiclePropConfigUtil.java b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehiclePropConfigUtil.java
new file mode 100644
index 0000000..4e7137f
--- /dev/null
+++ b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehiclePropConfigUtil.java
@@ -0,0 +1,52 @@
+/*
+ * 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.vehiclenetwork;
+
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePermissionModel;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropAccess;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropChangeMode;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig;
+
+/**
+ * Utility class to help creating VehiclePropConfig.
+ */
+public class VehiclePropConfigUtil {
+
+ public static VehiclePropConfig createStaticStringProperty(int property) {
+ return getBuilder(property,
+ VehiclePropAccess.VEHICLE_PROP_ACCESS_READ,
+ VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC,
+ VehicleValueType.VEHICLE_VALUE_TYPE_STRING,
+ VehiclePermissionModel.VEHICLE_PERMISSION_NO_RESTRICTION,
+ 0, 0f, 0f).
+ build();
+ }
+
+ public static VehiclePropConfig.Builder getBuilder(int property, int access, int changeMode,
+ int type, int permissionModel, int configFlags, float sampleRateMax,
+ float sampleRateMin) {
+ return VehiclePropConfig.newBuilder().
+ setProp(property).
+ setAccess(access).
+ setChangeMode(changeMode).
+ setValueType(type).
+ setPermissionModel(permissionModel).
+ setConfigFlags(configFlags).
+ setSampleRateMax(sampleRateMax).
+ setSampleRateMin(sampleRateMin);
+ }
+}
diff --git a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehiclePropValueUtil.java b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehiclePropValueUtil.java
new file mode 100644
index 0000000..2b72163
--- /dev/null
+++ b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehiclePropValueUtil.java
@@ -0,0 +1,170 @@
+/*
+ * 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.vehiclenetwork;
+
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.ZonedValue;
+import com.google.protobuf.ByteString;
+
+/**
+ * Utility class to help creating VehiclePropValue.
+ */
+public class VehiclePropValueUtil {
+
+ public static VehiclePropValue createIntValue(int property, int value, long timestamp) {
+ return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_INT32,timestamp).
+ addInt32Values(value).
+ build();
+ }
+
+ public static VehiclePropValue createIntVectorValue(int property, int[] values,
+ long timestamp) {
+ int len = values.length;
+ VehiclePropValue.Builder builder =createBuilder(property,
+ VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2 + len - 2,
+ timestamp);
+ for (int v : values) {
+ builder.addInt32Values(v);
+ }
+ return builder.build();
+ }
+
+ public static VehiclePropValue createFloatValue(int property, float value, long timestamp) {
+ return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT,timestamp).
+ addFloatValues(value).
+ build();
+ }
+
+ public static VehiclePropValue createFloatVectorValue(int property, float[] values,
+ long timestamp) {
+ int len = values.length;
+ VehiclePropValue.Builder builder =createBuilder(property,
+ VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT_VEC2 + len - 2,
+ timestamp);
+ for (float v : values) {
+ builder.addFloatValues(v);
+ }
+ return builder.build();
+ }
+
+ public static VehiclePropValue createLongValue(int property, long value, long timestamp) {
+ return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_INT64,timestamp).
+ setInt64Value(value).
+ build();
+ }
+
+ public static VehiclePropValue createStringValue(int property, String value, long timestamp) {
+ return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_STRING,timestamp).
+ setStringValue(value).
+ build();
+ }
+
+ public static VehiclePropValue createBooleanValue(int property, boolean value, long timestamp) {
+ return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_BOOLEAN,timestamp).
+ addInt32Values(value ? 1 : 0).
+ build();
+ }
+
+ public static VehiclePropValue createBytesValue(int property, byte[] value, long timestamp) {
+ return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_BYTES,timestamp).
+ setBytesValue(ByteString.copyFrom(value)).
+ build();
+ }
+
+ public static VehiclePropValue createZonedIntValue(int property, int zone, int value,
+ long timestamp) {
+ return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_INT32,timestamp).
+ setZonedValue(ZonedValue.newBuilder().setZoneOrWindow(zone).setInt32Value(value).
+ build()).
+ build();
+ }
+
+ public static VehiclePropValue createZonedBooleanValue(int property, int zone, boolean value,
+ long timestamp) {
+ return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_BOOLEAN,timestamp).
+ setZonedValue(ZonedValue.newBuilder().setZoneOrWindow(zone).
+ setInt32Value(value ? 1 : 0).build()).
+ build();
+ }
+
+ public static VehiclePropValue createZonedFloatValue(int property, int zone, float value,
+ long timestamp) {
+ return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_FLOAT,timestamp).
+ setZonedValue(ZonedValue.newBuilder().setZoneOrWindow(zone).setFloatValue(value).
+ build()).
+ build();
+ }
+
+ public static VehiclePropValue createDummyValue(int property, int valueType) {
+ switch (valueType) {
+ case VehicleValueType.VEHICLE_VALUE_TYPE_STRING: {
+ return createStringValue(property, "dummy", 0);
+ }
+ case VehicleValueType.VEHICLE_VALUE_TYPE_BYTES: {
+ return createBytesValue(property, new byte[1], 0);
+ }
+ case VehicleValueType.VEHICLE_VALUE_TYPE_BOOLEAN: {
+ return createBooleanValue(property, false, 0);
+ }
+ case VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_INT32: {
+ return createZonedIntValue(property, 0, 0, 0);
+ }
+ case VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_FLOAT: {
+ return createZonedFloatValue(property, 0, 0, 0);
+ }
+ case VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_BOOLEAN: {
+ return createZonedBooleanValue(property, 0, false, 0);
+ }
+ case VehicleValueType.VEHICLE_VALUE_TYPE_INT64: {
+ return createLongValue(property, 0, 0);
+ }
+ case VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT: {
+ return createFloatValue(property, 0, 0);
+ }
+ case VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT_VEC2: {
+ return createFloatVectorValue(property, new float[] {0, 0}, 0);
+ }
+ case VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT_VEC3: {
+ return createFloatVectorValue(property, new float[] {0, 0, 0}, 0);
+ }
+ case VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT_VEC4: {
+ return createFloatVectorValue(property, new float[] {0, 0, 0, 0}, 0);
+ }
+ case VehicleValueType.VEHICLE_VALUE_TYPE_INT32: {
+ return createIntValue(property, 0, 0);
+ }
+ case VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2: {
+ return createIntVectorValue(property, new int[] {0, 0}, 0);
+ }
+ case VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC3: {
+ return createIntVectorValue(property, new int[] {0, 0, 0}, 0);
+ }
+ case VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC4: {
+ return createIntVectorValue(property, new int[] {0, 0, 0, 0}, 0);
+ }
+ }
+ return null;
+ }
+
+ public static VehiclePropValue.Builder createBuilder(int property, int valueType,
+ long timestamp) {
+ return VehiclePropValue.newBuilder().
+ setProp(property).
+ setValueType(valueType).
+ setTimestamp(timestamp);
+ }
+}
diff --git a/libvehiclenetwork/native/IVehicleNetwork.cpp b/libvehiclenetwork/native/IVehicleNetwork.cpp
index a3b17a5..388715d 100644
--- a/libvehiclenetwork/native/IVehicleNetwork.cpp
+++ b/libvehiclenetwork/native/IVehicleNetwork.cpp
@@ -37,6 +37,9 @@
GET_PROPERTY,
SUBSCRIBE,
UNSUBSCRIBE,
+ INJECT_EVENT,
+ START_MOCKING,
+ STOP_MOCKING,
};
// ----------------------------------------------------------------------------
@@ -163,6 +166,41 @@
ALOGI("unsubscribing property %d failed %d", property, status);
}
}
+
+ virtual status_t injectEvent(const vehicle_prop_value_t& value) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetwork::getInterfaceDescriptor());
+ data.writeInt32(1); // 0 means no value. For compatibility with aidl based code.
+ std::unique_ptr<VehiclePropValue> v(new VehiclePropValue());
+ ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY);
+ VehicleNetworkProtoUtil::toVehiclePropValue(value, *v.get());
+ int size = v->ByteSize();
+ WritableBlobHolder blob(new Parcel::WritableBlob());
+ ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
+ data.writeInt32(size);
+ data.writeBlob(size, false, blob.blob);
+ v->SerializeToArray(blob.blob->data(), size);
+ status_t status = remote()->transact(INJECT_EVENT, data, &reply);
+ return status;
+ }
+
+ virtual status_t startMocking(const sp<IVehicleNetworkHalMock>& mock) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetwork::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(mock));
+ status_t status = remote()->transact(START_MOCKING, data, &reply);
+ return status;
+ }
+
+ virtual void stopMocking(const sp<IVehicleNetworkHalMock>& mock) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetwork::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(mock));
+ status_t status = remote()->transact(STOP_MOCKING, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGI("stop mocking failed %d", status);
+ }
+ }
};
IMPLEMENT_META_INTERFACE(VehicleNetwork, IVehicleNetwork::SERVICE_NAME);
@@ -280,6 +318,51 @@
BinderUtil::fillNoResultReply(reply);
return NO_ERROR;
} break;
+ case INJECT_EVENT: {
+ CHECK_INTERFACE(IVehicleNetwork, data, reply);
+ if (data.readInt32() == 0) { // java side allows passing null with this.
+ return BAD_VALUE;
+ }
+ ScopedVehiclePropValue value;
+ ReadableBlobHolder blob(new Parcel::ReadableBlob());
+ ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
+ int32_t size = data.readInt32();
+ r = data.readBlob(size, blob.blob);
+ if (r != NO_ERROR) {
+ ALOGE("injectEvent:service, cannot read blob");
+ return r;
+ }
+ std::unique_ptr<VehiclePropValue> v(new VehiclePropValue());
+ ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY);
+ if (!v->ParseFromArray(blob.blob->data(), size)) {
+ ALOGE("injectEvent:service, cannot parse data");
+ return BAD_VALUE;
+ }
+ r = VehicleNetworkProtoUtil::fromVehiclePropValue(*v.get(), value.value);
+ if (r != NO_ERROR) {
+ ALOGE("injectEvent:service, cannot convert data");
+ return BAD_VALUE;
+ }
+ r = injectEvent(value.value);
+ BinderUtil::fillNoResultReply(reply);
+ return r;
+ } break;
+ case START_MOCKING: {
+ CHECK_INTERFACE(IVehicleNetwork, data, reply);
+ sp<IVehicleNetworkHalMock> mock =
+ interface_cast<IVehicleNetworkHalMock>(data.readStrongBinder());
+ r = startMocking(mock);
+ BinderUtil::fillNoResultReply(reply);
+ return r;
+ } break;
+ case STOP_MOCKING: {
+ CHECK_INTERFACE(IVehicleNetwork, data, reply);
+ sp<IVehicleNetworkHalMock> mock =
+ interface_cast<IVehicleNetworkHalMock>(data.readStrongBinder());
+ stopMocking(mock);
+ BinderUtil::fillNoResultReply(reply);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libvehiclenetwork/native/IVehicleNetworkHalMock.cpp b/libvehiclenetwork/native/IVehicleNetworkHalMock.cpp
new file mode 100644
index 0000000..8652f17
--- /dev/null
+++ b/libvehiclenetwork/native/IVehicleNetworkHalMock.cpp
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VehicleNetwork"
+
+#include <memory>
+
+#include <binder/IPCThreadState.h>
+#include <private/android_filesystem_config.h>
+
+#include <utils/Log.h>
+
+#include <IVehicleNetwork.h>
+#include <IVehicleNetworkHalMock.h>
+#include <VehicleNetworkProto.pb.h>
+
+#include "BinderUtil.h"
+#include "VehicleNetworkProtoUtil.h"
+
+namespace android {
+
+enum {
+ ON_LIST_PROPERTIES = IBinder::FIRST_CALL_TRANSACTION,
+ ON_PROPERTY_SET,
+ ON_PROPERTY_GET,
+ ON_SUBSCRIBE,
+ ON_UNSUBSCRIBE,
+};
+
+// ----------------------------------------------------------------------------
+
+const char IVehicleNetworkHalMock::SERVICE_NAME[] =
+ "com.android.car.vehiclenetwork.IVehicleNetworkHalMock";
+
+// ----------------------------------------------------------------------------
+
+class BpVehicleNetworkHalMock : public BpInterface<IVehicleNetworkHalMock> {
+public:
+ BpVehicleNetworkHalMock(const sp<IBinder> & impl)
+ : BpInterface<IVehicleNetworkHalMock>(impl) {
+ }
+
+ virtual sp<VehiclePropertiesHolder> onListProperties() {
+ sp<VehiclePropertiesHolder> holder;
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
+ status_t status = remote()->transact(ON_LIST_PROPERTIES, data, &reply);
+ if (status == NO_ERROR) {
+ reply.readExceptionCode(); // for compatibility with java
+ if (reply.readInt32() == 0) { // no result
+ return holder;
+ }
+ ReadableBlobHolder blob(new Parcel::ReadableBlob());
+ if (blob.blob == NULL) {
+ ALOGE("listProperties, no memory");
+ return holder;
+ }
+ int32_t size = reply.readInt32();
+ status = reply.readBlob(size, blob.blob);
+ if (status != NO_ERROR) {
+ ALOGE("listProperties, cannot read blob %d", status);
+ return holder;
+ }
+ //TODO make this more memory efficient
+ std::unique_ptr<VehiclePropConfigs> configs(new VehiclePropConfigs());
+ if (configs.get() == NULL) {
+ return holder;
+ }
+ if(!configs->ParseFromArray(blob.blob->data(), size)) {
+ ALOGE("listProperties, cannot parse reply");
+ return holder;
+ }
+ holder = new VehiclePropertiesHolder();
+ ASSERT_OR_HANDLE_NO_MEMORY(holder.get(), return);
+ status = VehicleNetworkProtoUtil::fromVehiclePropConfigs(*configs.get(),
+ holder->getList());
+ if (status != NO_ERROR) {
+ ALOGE("listProperties, cannot convert VehiclePropConfigs %d", status);
+ return holder;
+ }
+
+ }
+ return holder;
+ }
+
+ virtual status_t onPropertySet(const vehicle_prop_value_t& value) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
+ data.writeInt32(1); // 0 means no value. For compatibility with aidl based code.
+ std::unique_ptr<VehiclePropValue> v(new VehiclePropValue());
+ ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY);
+ VehicleNetworkProtoUtil::toVehiclePropValue(value, *v.get());
+ int size = v->ByteSize();
+ WritableBlobHolder blob(new Parcel::WritableBlob());
+ ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
+ data.writeInt32(size);
+ data.writeBlob(size, false, blob.blob);
+ v->SerializeToArray(blob.blob->data(), size);
+ status_t status = remote()->transact(ON_PROPERTY_SET, data, &reply);
+ return status;
+ }
+
+ virtual status_t onPropertyGet(vehicle_prop_value_t* value) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
+ // only needs to send property itself.
+ data.writeInt32(value->prop);
+ status_t status = remote()->transact(ON_PROPERTY_GET, data, &reply);
+ if (status == NO_ERROR) {
+ reply.readExceptionCode(); // for compatibility with java
+ if (reply.readInt32() == 0) { // no result
+ return BAD_VALUE;
+ }
+ ReadableBlobHolder blob(new Parcel::ReadableBlob());
+ ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
+ int32_t size = reply.readInt32();
+ status = reply.readBlob(size, blob.blob);
+ if (status != NO_ERROR) {
+ ALOGE("getProperty, cannot read blob");
+ return status;
+ }
+ std::unique_ptr<VehiclePropValue> v(new VehiclePropValue());
+ ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY);
+ if (!v->ParseFromArray(blob.blob->data(), size)) {
+ ALOGE("getProperty, cannot parse reply");
+ return BAD_VALUE;
+ }
+ status = VehicleNetworkProtoUtil::fromVehiclePropValue(*v.get(), *value);
+ }
+ return status;
+ }
+
+ virtual status_t onPropertySubscribe(int32_t property, float sampleRate) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
+ data.writeInt32(property);
+ data.writeFloat(sampleRate);
+ status_t status = remote()->transact(ON_SUBSCRIBE, data, &reply);
+ return status;
+ }
+
+ virtual void onPropertyUnsubscribe(int32_t property) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
+ data.writeInt32(property);
+ status_t status = remote()->transact(ON_UNSUBSCRIBE, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGI("onPropertyUnsubscribe property %d failed %d", property, status);
+ }
+ }
+};
+
+IMPLEMENT_META_INTERFACE(VehicleNetworkHalMock, IVehicleNetworkHalMock::SERVICE_NAME);
+
+// ----------------------------------------------------------------------
+
+static bool isSystemUser() {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ switch (uid) {
+ // This list will be expanded. Only those UIDs are allowed to access vehicle network
+ // for now. There can be per property based UID check built-in as well.
+ case AID_ROOT:
+ case AID_SYSTEM:
+ case AID_AUDIO: {
+ return true;
+ } break;
+ default: {
+ ALOGE("non-system user tried access, uid %d", uid);
+ } break;
+ }
+ return false;
+}
+
+status_t BnVehicleNetworkHalMock::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
+ if (!isSystemUser()) {
+ return PERMISSION_DENIED;
+ }
+ status_t r;
+ switch (code) {
+ case ON_LIST_PROPERTIES: {
+ CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
+ sp<VehiclePropertiesHolder> holder = onListProperties();
+ if (holder.get() == NULL) { // given property not found
+ BinderUtil::fillObjectResultReply(reply, false /* isValid */);
+ return NO_ERROR;
+ }
+ std::unique_ptr<VehiclePropConfigs> configs(new VehiclePropConfigs());
+ ASSERT_OR_HANDLE_NO_MEMORY(configs.get(), return NO_MEMORY);
+ VehicleNetworkProtoUtil::toVehiclePropConfigs(holder->getList(), *configs.get());
+ int size = configs->ByteSize();
+ WritableBlobHolder blob(new Parcel::WritableBlob());
+ ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
+ BinderUtil::fillObjectResultReply(reply, true);
+ reply->writeInt32(size);
+ reply->writeBlob(size, false, blob.blob);
+ configs->SerializeToArray(blob.blob->data(), size);
+ return NO_ERROR;
+ } break;
+ case ON_PROPERTY_SET: {
+ CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
+ if (data.readInt32() == 0) { // java side allows passing null with this.
+ return BAD_VALUE;
+ }
+ ScopedVehiclePropValue value;
+ ReadableBlobHolder blob(new Parcel::ReadableBlob());
+ ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
+ int32_t size = data.readInt32();
+ r = data.readBlob(size, blob.blob);
+ if (r != NO_ERROR) {
+ ALOGE("setProperty:service, cannot read blob");
+ return r;
+ }
+ std::unique_ptr<VehiclePropValue> v(new VehiclePropValue());
+ ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY);
+ if (!v->ParseFromArray(blob.blob->data(), size)) {
+ ALOGE("setProperty:service, cannot parse data");
+ return BAD_VALUE;
+ }
+ r = VehicleNetworkProtoUtil::fromVehiclePropValue(*v.get(), value.value);
+ if (r != NO_ERROR) {
+ ALOGE("setProperty:service, cannot convert data");
+ return BAD_VALUE;
+ }
+ r = onPropertySet(value.value);
+ BinderUtil::fillNoResultReply(reply);
+ return r;
+ } break;
+ case ON_PROPERTY_GET: {
+ CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
+ ScopedVehiclePropValue value;
+ value.value.prop = data.readInt32();
+ r = onPropertyGet(&(value.value));
+ if (r == NO_ERROR) {
+ BinderUtil::fillObjectResultReply(reply, true);
+ std::unique_ptr<VehiclePropValue> v(new VehiclePropValue());
+ ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY);
+ VehicleNetworkProtoUtil::toVehiclePropValue(value.value, *v.get());
+ int size = v->ByteSize();
+ WritableBlobHolder blob(new Parcel::WritableBlob());
+ ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
+ reply->writeInt32(size);
+ reply->writeBlob(size, false, blob.blob);
+ v->SerializeToArray(blob.blob->data(), size);
+ }
+ return r;
+ } break;
+ case ON_SUBSCRIBE: {
+ CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
+ int32_t property = data.readInt32();
+ float sampleRate = data.readFloat();
+ r = onPropertySubscribe(property, sampleRate);
+ BinderUtil::fillNoResultReply(reply);
+ return r;
+ } break;
+ case ON_UNSUBSCRIBE: {
+ CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
+ int32_t property = data.readInt32();
+ onPropertyUnsubscribe(property);
+ BinderUtil::fillNoResultReply(reply);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
diff --git a/libvehiclenetwork/native/VehicleNetworkProtoUtil.cpp b/libvehiclenetwork/native/VehicleNetworkProtoUtil.cpp
index 78b77a6..ee7447b 100644
--- a/libvehiclenetwork/native/VehicleNetworkProtoUtil.cpp
+++ b/libvehiclenetwork/native/VehicleNetworkProtoUtil.cpp
@@ -304,8 +304,9 @@
out.float_max_value = in.float_max();
out.float_min_value = in.float_min();
} else {
- ALOGE("no float max/min");
- return BAD_VALUE;
+ ALOGW("no float max/min for property 0x%x", out.prop);
+ out.float_max_value = 0;
+ out.float_min_value = 0;
}
} break;
case VEHICLE_VALUE_TYPE_INT64: {
@@ -313,8 +314,9 @@
out.int64_max_value = in.int64_max();
out.int64_min_value = in.int64_min();
} else {
- ALOGE("no int64 max/min");
- return BAD_VALUE;
+ ALOGW("no int64 max/min for property 0x%x", out.prop);
+ out.int64_max_value = 0;
+ out.int64_min_value = 0;
}
} break;
case VEHICLE_VALUE_TYPE_INT32:
@@ -323,8 +325,9 @@
out.int32_max_value = in.int32_max();
out.int32_min_value = in.int32_min();
} else {
- ALOGE("no int32 max/min");
- return BAD_VALUE;
+ ALOGW("no int32 max/min for property 0x%x", out.prop);
+ out.int32_max_value = 0;
+ out.int32_min_value = 0;
}
} break;
}
diff --git a/libvehiclenetwork/tool/vehiclehal_code_gen.py b/libvehiclenetwork/tool/vehiclehal_code_gen.py
index 72b9ab3..8f64e9b 100755
--- a/libvehiclenetwork/tool/vehiclehal_code_gen.py
+++ b/libvehiclenetwork/tool/vehiclehal_code_gen.py
@@ -117,7 +117,6 @@
}
}
"""
-
#now implement getVehiclePropertyName
print \
"""public static String getVehiclePropertyName(int property) {
@@ -130,6 +129,34 @@
}
}
"""
+ #now implement getVehicleChangeMode
+ print \
+"""public static int[] getVehicleChangeMode(int property) {
+switch (property) {"""
+ for p in props:
+ if p.changeMode != "":
+ modes = p.changeMode.split('|')
+ modesString = []
+ for m in modes:
+ modesString.append("VehiclePropChangeMode." + m)
+ print "case " + p.name + ": return new int[] { " + " , ".join(modesString) + " };"
+ print \
+"""default: return null;
+}
+}
+"""
+ #now implement getVehicleAccess
+ print \
+"""public static int getVehicleAccess(int property) {
+switch (property) {"""
+ for p in props:
+ if p.access != "":
+ print "case " + p.name + ": return VehiclePropAccess." + p.access + ";"
+ print \
+"""default: return 0;
+}
+}
+"""
def printEnum(e):
print "public static class " + toJavaStyleName(e.name) + " {"
@@ -189,7 +216,7 @@
prop.access = words[i]
elif words[i] == "@unit":
i += 1
- prop.changeMode = words[i]
+ prop.unit = words[i]
elif words[i] == "@range_start" or words[i] == "@range_end":
prop.startEnd = 1
i += 1
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");
diff --git a/tests/api_test/Android.mk b/tests/api_test/Android.mk
index cecc88e..1b2b728 100644
--- a/tests/api_test/Android.mk
+++ b/tests/api_test/Android.mk
@@ -22,11 +22,17 @@
LOCAL_PACKAGE_NAME := CarApiTest
+# for system|priviledged permission.
+LOCAL_CERTIFICATE := platform
+
LOCAL_MODULE_TAGS := tests
+# When built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_STATIC_JAVA_LIBRARIES += libcarsupport
+LOCAL_STATIC_JAVA_LIBRARIES += libcarsystemtest
LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/tests/api_test/AndroidManifest.xml b/tests/api_test/AndroidManifest.xml
index 41c158f..1ddc478 100644
--- a/tests/api_test/AndroidManifest.xml
+++ b/tests/api_test/AndroidManifest.xml
@@ -16,7 +16,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- package="com.android.support.car.apitest" >
+ package="com.android.support.car.apitest"
+ android:sharedUserId="android.uid.system" >
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.android.support.car.apitest"
diff --git a/tests/api_test/src/com/android/support/car/apitest/CarInfoManagerTest.java b/tests/api_test/src/com/android/support/car/apitest/CarInfoManagerTest.java
index 1321982..d14a1ed 100644
--- a/tests/api_test/src/com/android/support/car/apitest/CarInfoManagerTest.java
+++ b/tests/api_test/src/com/android/support/car/apitest/CarInfoManagerTest.java
@@ -24,69 +24,37 @@
import android.test.AndroidTestCase;
import android.util.Log;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts;
+import com.android.car.vehiclenetwork.VehiclePropConfigUtil;
+import com.android.car.vehiclenetwork.VehiclePropValueUtil;
+
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
-public class CarInfoManagerTest extends AndroidTestCase {
- private static final long DEFAULT_WAIT_TIMEOUT_MS = 3000;
+public class CarInfoManagerTest extends MockedCarTestBase {
private static final String TAG = CarInfoManagerTest.class.getSimpleName();
- private final Semaphore mConnectionWait = new Semaphore(0);
+ private static final String MAKE_NAME = "ANDROID";
- private Car mCar;
private CarInfoManager mCarInfoManager;
- private final ServiceConnectionListener mConnectionListener = new ServiceConnectionListener() {
-
- @Override
- public void onServiceSuspended(int cause) {
- assertMainThread();
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- assertMainThread();
- }
-
- @Override
- public void onServiceConnectionFailed(int cause) {
- assertMainThread();
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- assertMainThread();
- mConnectionWait.release();
- }
- };
-
- private void assertMainThread() {
- assertTrue(Looper.getMainLooper().isCurrentThread());
- }
- private void waitForConnection(long timeoutMs) throws InterruptedException {
- mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
- }
-
@Override
protected void setUp() throws Exception {
super.setUp();
- mCar = new Car(getContext(), mConnectionListener, null);
- mCar.connect();
- waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
+ getVehicleHalEmulator().addStaticProperty(
+ VehiclePropConfigUtil.createStaticStringProperty(
+ VehicleNetworkConsts.VEHICLE_PROPERTY_INFO_MAKE),
+ VehiclePropValueUtil.createStringValue(
+ VehicleNetworkConsts.VEHICLE_PROPERTY_INFO_MAKE, MAKE_NAME, 0));
+ getVehicleHalEmulator().start();
mCarInfoManager =
- (CarInfoManager) mCar.getCarManager(Car.INFO_SERVICE);
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- mCar.disconnect();
+ (CarInfoManager) getCarApi().getCarManager(Car.INFO_SERVICE);
}
public void testManufactuter() throws Exception {
String name = mCarInfoManager.getString(CarInfoManager.KEY_MANUFACTURER);
- assertNotNull(name);
+ assertEquals(MAKE_NAME, name);
Log.i(TAG, CarInfoManager.KEY_MANUFACTURER + ":" + name);
try {
Float v = mCarInfoManager.getFloat(CarInfoManager.KEY_MANUFACTURER);
diff --git a/tests/api_test/src/com/android/support/car/apitest/CarTest.java b/tests/api_test/src/com/android/support/car/apitest/CarTest.java
index caf99a4..60f7ee6 100644
--- a/tests/api_test/src/com/android/support/car/apitest/CarTest.java
+++ b/tests/api_test/src/com/android/support/car/apitest/CarTest.java
@@ -60,6 +60,7 @@
private void assertMainThread() {
assertTrue(Looper.getMainLooper().isCurrentThread());
}
+
private void waitForConnection(long timeoutMs) throws InterruptedException {
mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
}
diff --git a/tests/api_test/src/com/android/support/car/apitest/MockedCarTestBase.java b/tests/api_test/src/com/android/support/car/apitest/MockedCarTestBase.java
new file mode 100644
index 0000000..db3d52d
--- /dev/null
+++ b/tests/api_test/src/com/android/support/car/apitest/MockedCarTestBase.java
@@ -0,0 +1,94 @@
+/*
+ * 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.support.car.apitest;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import com.android.car.VehicleHalEmulator;
+
+import android.content.ComponentName;
+import android.os.IBinder;
+import android.support.car.Car;
+import android.support.car.ServiceConnectionListener;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+/**
+ * Base class for testing with mocked vehicle HAL (=car).
+ * It is up to each app to start emulation by getVehicleHalEmulator().start() as there will be
+ * per test set up that should be done before starting.
+ */
+public class MockedCarTestBase extends AndroidTestCase {
+ private static final String TAG = MockedCarTestBase.class.getSimpleName();
+ private static final long DEFAULT_WAIT_TIMEOUT_MS = 3000;
+
+ private Car mCar;
+ private VehicleHalEmulator mVehicleHalEmulator;
+
+ private final Semaphore mConnectionWait = new Semaphore(0);
+
+ private final ServiceConnectionListener mConnectionListener = new ServiceConnectionListener() {
+
+ @Override
+ public void onServiceSuspended(int cause) {
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ }
+
+ @Override
+ public void onServiceConnectionFailed(int cause) {
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.i(TAG, "onServiceConnected, component" + name + " binder " + service);
+ mConnectionWait.release();
+ }
+ };
+
+ @Override
+ protected synchronized void setUp() throws Exception {
+ super.setUp();
+ mCar = new Car(getContext(), mConnectionListener, null);
+ mCar.connect();
+ assertTrue(waitForConnection(DEFAULT_WAIT_TIMEOUT_MS));
+ mVehicleHalEmulator = new VehicleHalEmulator(mCar);
+ }
+
+ @Override
+ protected synchronized void tearDown() throws Exception {
+ super.tearDown();
+ if (mVehicleHalEmulator.isStarted()) {
+ mVehicleHalEmulator.stop();
+ }
+ mCar.disconnect();
+ }
+
+ protected synchronized Car getCarApi() {
+ return mCar;
+ }
+
+ protected synchronized VehicleHalEmulator getVehicleHalEmulator() {
+ return mVehicleHalEmulator;
+ }
+
+ private boolean waitForConnection(long timeoutMs) throws InterruptedException {
+ return mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
+ }
+}
diff --git a/tests/car_activity_test_app/Android.mk b/tests/car_activity_test_app/Android.mk
index 9ee9186..27a377d 100644
--- a/tests/car_activity_test_app/Android.mk
+++ b/tests/car_activity_test_app/Android.mk
@@ -24,6 +24,9 @@
LOCAL_MODULE_TAGS := tests
+# When built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_STATIC_JAVA_LIBRARIES += libcarsupport
diff --git a/tests/libvehiclenetwork-java-test/Android.mk b/tests/libvehiclenetwork-java-test/Android.mk
index fb28c65..bde7dda 100644
--- a/tests/libvehiclenetwork-java-test/Android.mk
+++ b/tests/libvehiclenetwork-java-test/Android.mk
@@ -26,6 +26,9 @@
LOCAL_MODULE_TAGS := tests
+# When built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_STATIC_JAVA_LIBRARIES += libvehiclenetwork-java
diff --git a/vehicle_network_service/VehicleNetworkService.cpp b/vehicle_network_service/VehicleNetworkService.cpp
index b58c075..a4857ca 100644
--- a/vehicle_network_service/VehicleNetworkService.cpp
+++ b/vehicle_network_service/VehicleNetworkService.cpp
@@ -76,6 +76,14 @@
mLooper->sendMessage(this, Message(HAL_ERROR));
}
+void VehicleHalMessageHandler::handleMockStart() {
+ Mutex::Autolock autoLock(mLock);
+ mHalPropertyList[0].clear();
+ mHalPropertyList[1].clear();
+ sp<MessageHandler> self(this);
+ mLooper->removeMessages(self);
+}
+
void VehicleHalMessageHandler::doHandleInit() {
// nothing to do
}
@@ -230,8 +238,8 @@
}
VehicleNetworkService::VehicleNetworkService()
- : mModule(NULL) {
- //TODO
+ : mModule(NULL),
+ mMockingEnabled(false) {
sInstance = this;
}
@@ -331,8 +339,9 @@
mHandlerThread.quit();
}
-vehicle_prop_config_t const * VehicleNetworkService::findConfig(int32_t property) {
- for (auto& config : mProperties->getList()) {
+vehicle_prop_config_t const * VehicleNetworkService::findConfigLocked(int32_t property) {
+ for (auto& config : (mMockingEnabled ?
+ mPropertiesForMocking->getList() : mProperties->getList())) {
if (config->prop == property) {
return config;
}
@@ -340,8 +349,8 @@
return NULL;
}
-bool VehicleNetworkService::isGettable(int32_t property) {
- vehicle_prop_config_t const * config = findConfig(property);
+bool VehicleNetworkService::isGettableLocked(int32_t property) {
+ vehicle_prop_config_t const * config = findConfigLocked(property);
if (config == NULL) {
return false;
}
@@ -352,8 +361,8 @@
return true;
}
-bool VehicleNetworkService::isSettable(int32_t property) {
- vehicle_prop_config_t const * config = findConfig(property);
+bool VehicleNetworkService::isSettableLocked(int32_t property) {
+ vehicle_prop_config_t const * config = findConfigLocked(property);
if (config == NULL) {
return false;
}
@@ -364,8 +373,8 @@
return true;
}
-bool VehicleNetworkService::isSubscribable(int32_t property) {
- vehicle_prop_config_t const * config = findConfig(property);
+bool VehicleNetworkService::isSubscribableLocked(int32_t property) {
+ vehicle_prop_config_t const * config = findConfigLocked(property);
if (config == NULL) {
return false;
}
@@ -383,10 +392,14 @@
sp<VehiclePropertiesHolder> VehicleNetworkService::listProperties(int32_t property) {
Mutex::Autolock autoLock(mLock);
if (property == 0) {
- return mProperties;
+ if (!mMockingEnabled) {
+ return mProperties;
+ } else {
+ return mPropertiesForMocking;
+ }
} else {
sp<VehiclePropertiesHolder> p;
- const vehicle_prop_config_t* config = findConfig(property);
+ const vehicle_prop_config_t* config = findConfigLocked(property);
if (config != NULL) {
p = new VehiclePropertiesHolder(false /* deleteConfigsInDestructor */);
p->getList().push_back(config);
@@ -397,9 +410,10 @@
}
status_t VehicleNetworkService::getProperty(vehicle_prop_value_t *data) {
+ bool inMocking = false;
do { // for lock scoping
Mutex::Autolock autoLock(mLock);
- if (!isGettable(data->prop)) {
+ if (!isGettableLocked(data->prop)) {
return BAD_VALUE;
}
if ((data->prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
@@ -410,24 +424,40 @@
return NO_ERROR;
}
//TODO caching for static, on-change type?
+ if (mMockingEnabled) {
+ inMocking = true;
+ }
} while (false);
// set done outside lock to allow concurrent access
+ if (inMocking) {
+ mHalMock->onPropertyGet(data);
+ return NO_ERROR;
+ }
return mDevice->get(mDevice, data);
}
status_t VehicleNetworkService::setProperty(const vehicle_prop_value_t& data) {
+ bool isInternalProperty = false;
+ bool inMocking = false;
do { // for lock scoping
Mutex::Autolock autoLock(mLock);
- if (!isSettable(data.prop)) {
+ if (!isSettableLocked(data.prop)) {
return BAD_VALUE;
}
- } while (false);
- if ((data.prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
- (data.prop <= (int32_t)VEHICLE_PROPERTY_INTERNAL_END)) {
- do {
- Mutex::Autolock autoLock(mLock);
+ if ((data.prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
+ (data.prop <= (int32_t)VEHICLE_PROPERTY_INTERNAL_END)) {
+ isInternalProperty = true;
mCache.writeToCache(data);
- } while (false);
+ }
+ if (mMockingEnabled) {
+ inMocking = true;
+ }
+ } while (false);
+ if (inMocking) {
+ mHalMock->onPropertySet(data);
+ return NO_ERROR;
+ }
+ if (isInternalProperty) {
// for internal property, just publish it.
onHalEvent(&data);
return NO_ERROR;
@@ -439,125 +469,188 @@
status_t VehicleNetworkService::subscribe(const sp<IVehicleNetworkListener> &listener, int32_t prop,
float sampleRate) {
- Mutex::Autolock autoLock(mLock);
- if (!isSubscribable(prop)) {
- return BAD_VALUE;
- }
- vehicle_prop_config_t const * config = findConfig(prop);
- if (config->change_mode == VEHICLE_PROP_CHANGE_MODE_ON_CHANGE) {
- if (sampleRate != 0) {
- ALOGW("Sample rate set to non-zeo for on change type. Ignore it");
- sampleRate = 0;
- }
- } else {
- if (sampleRate > config->max_sample_rate) {
- ALOGW("sample rate %f higher than max %f. limit to max", sampleRate,
- config->max_sample_rate);
- sampleRate = config->max_sample_rate;
- }
- if (sampleRate < config->min_sample_rate) {
- ALOGW("sample rate %f lower than min %f. limit to min", sampleRate,
- config->min_sample_rate);
- sampleRate = config->min_sample_rate;
- }
- }
- sp<IBinder> iBinder = IInterface::asBinder(listener);
- ALOGD("subscribe, binder 0x%x prop 0x%x", iBinder.get(), prop);
- sp<HalClient> client;
- sp<HalClientSpVector> clientsForProperty;
- bool createClient = false;
- ssize_t index = mBinderToClientMap.indexOfKey(iBinder);
- if (index < 0) {
- createClient = true;
- } else {
- client = mBinderToClientMap.editValueAt(index);
- index = mPropertyToClientsMap.indexOfKey(prop);
- if (index >= 0) {
- clientsForProperty = mPropertyToClientsMap.editValueAt(index);
- }
- }
- if (clientsForProperty.get() == NULL) {
- clientsForProperty = new HalClientSpVector();
- ASSERT_OR_HANDLE_NO_MEMORY(clientsForProperty.get(), return NO_MEMORY);
- mPropertyToClientsMap.add(prop, clientsForProperty);
- }
- if (createClient) {
- client = new HalClient(listener);
- ASSERT_OR_HANDLE_NO_MEMORY(client.get(), return NO_MEMORY);
- iBinder->linkToDeath(this);
- ALOGV("add binder 0x%x to map", iBinder.get());
- mBinderToClientMap.add(iBinder, client);
- }
- clientsForProperty->add(client);
-
- index = mSampleRates.indexOfKey(prop);
bool shouldSubscribe = false;
- if (index < 0) {
- // first time subscription for this property
- shouldSubscribe = true;
- } else {
- float currentSampleRate = mSampleRates.valueAt(index);
- if (currentSampleRate < sampleRate) {
+ bool inMock = false;
+ do {
+ Mutex::Autolock autoLock(mLock);
+ if (!isSubscribableLocked(prop)) {
+ return BAD_VALUE;
+ }
+ vehicle_prop_config_t const * config = findConfigLocked(prop);
+ if (config->change_mode == VEHICLE_PROP_CHANGE_MODE_ON_CHANGE) {
+ if (sampleRate != 0) {
+ ALOGW("Sample rate set to non-zeo for on change type. Ignore it");
+ sampleRate = 0;
+ }
+ } else {
+ if (sampleRate > config->max_sample_rate) {
+ ALOGW("sample rate %f higher than max %f. limit to max", sampleRate,
+ config->max_sample_rate);
+ sampleRate = config->max_sample_rate;
+ }
+ if (sampleRate < config->min_sample_rate) {
+ ALOGW("sample rate %f lower than min %f. limit to min", sampleRate,
+ config->min_sample_rate);
+ sampleRate = config->min_sample_rate;
+ }
+ }
+ sp<IBinder> iBinder = IInterface::asBinder(listener);
+ ALOGD("subscribe, binder 0x%x prop 0x%x", iBinder.get(), prop);
+ sp<HalClient> client;
+ sp<HalClientSpVector> clientsForProperty;
+ bool createClient = false;
+ ssize_t index = mBinderToClientMap.indexOfKey(iBinder);
+ if (index < 0) {
+ createClient = true;
+ } else {
+ client = mBinderToClientMap.editValueAt(index);
+ index = mPropertyToClientsMap.indexOfKey(prop);
+ if (index >= 0) {
+ clientsForProperty = mPropertyToClientsMap.editValueAt(index);
+ }
+ }
+ if (clientsForProperty.get() == NULL) {
+ clientsForProperty = new HalClientSpVector();
+ ASSERT_OR_HANDLE_NO_MEMORY(clientsForProperty.get(), return NO_MEMORY);
+ mPropertyToClientsMap.add(prop, clientsForProperty);
+ }
+ if (createClient) {
+ client = new HalClient(listener);
+ ASSERT_OR_HANDLE_NO_MEMORY(client.get(), return NO_MEMORY);
+ iBinder->linkToDeath(this);
+ ALOGV("add binder 0x%x to map", iBinder.get());
+ mBinderToClientMap.add(iBinder, client);
+ }
+ clientsForProperty->add(client);
+
+ index = mSampleRates.indexOfKey(prop);
+ if (index < 0) {
+ // first time subscription for this property
shouldSubscribe = true;
+ } else {
+ float currentSampleRate = mSampleRates.valueAt(index);
+ if (currentSampleRate < sampleRate) {
+ shouldSubscribe = true;
+ }
}
- }
- client->setSampleRate(prop, sampleRate);
+ client->setSampleRate(prop, sampleRate);
+ if (shouldSubscribe) {
+ inMock = mMockingEnabled;
+ mSampleRates.add(prop, sampleRate);
+ if ((prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
+ (prop <= (int32_t)VEHICLE_PROPERTY_INTERNAL_END)) {
+ ALOGD("subscribe to internal property, prop 0x%x", prop);
+ return NO_ERROR;
+ }
+ }
+ } while (false);
if (shouldSubscribe) {
- mSampleRates.add(prop, sampleRate);
- if ((prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
- (prop <= (int32_t)VEHICLE_PROPERTY_INTERNAL_END)) {
- ALOGD("subscribe to internal property, prop 0x%x", prop);
- return NO_ERROR;
+ if (inMock) {
+ return mHalMock->onPropertySubscribe(prop, sampleRate);
+ } else {
+ ALOGD("subscribe to HAL, prop 0x%x sample rate:%f", prop, sampleRate);
+ return mDevice->subscribe(mDevice, prop, sampleRate);
}
- ALOGD("subscribe to HAL, prop 0x%x sample rate:%f", prop, sampleRate);
- return mDevice->subscribe(mDevice, prop, sampleRate);
- } else {
- return NO_ERROR;
}
+ return NO_ERROR;
}
void VehicleNetworkService::unsubscribe(const sp<IVehicleNetworkListener> &listener, int32_t prop) {
- Mutex::Autolock autoLock(mLock);
- if (!isSubscribable(prop)) {
- return;
- }
- sp<IBinder> iBinder = IInterface::asBinder(listener);
- ALOGD("unsubscribe, binder 0x%x, prop 0x%x", iBinder.get(), prop);
- ssize_t index = mBinderToClientMap.indexOfKey(iBinder);
- if (index < 0) {
- // client not found
- ALOGD("unsubscribe client not found in binder map");
- return;
- }
- sp<HalClient>& client = mBinderToClientMap.editValueAt(index);
- index = mPropertyToClientsMap.indexOfKey(prop);
- if (index < 0) {
- // not found
- ALOGD("unsubscribe client not found in prop map, prop:0x%x", prop);
- return;
- }
- sp<HalClientSpVector> clientsForProperty = mPropertyToClientsMap.editValueAt(index);
- //TODO share code with binderDied
- clientsForProperty->remove(client);
- if(!client->removePropertyAndCheckIfActive(prop)) {
- // client is no longer necessary
- mBinderToClientMap.removeItem(iBinder);
- iBinder->unlinkToDeath(this);
- }
- //TODO reset sample rate. do not care for now.
- if (clientsForProperty->size() == 0) {
- if ((prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
- (prop <= (int32_t)VEHICLE_PROPERTY_INTERNAL_END)) {
- ALOGD("unsubscribe to internal property, prop 0x%x", prop);
+ bool shouldUnsubscribe = false;
+ bool inMocking = false;
+ do {
+ Mutex::Autolock autoLock(mLock);
+ if (!isSubscribableLocked(prop)) {
+ return;
+ }
+ sp<IBinder> iBinder = IInterface::asBinder(listener);
+ ALOGD("unsubscribe, binder 0x%x, prop 0x%x", iBinder.get(), prop);
+ ssize_t index = mBinderToClientMap.indexOfKey(iBinder);
+ if (index < 0) {
+ // client not found
+ ALOGD("unsubscribe client not found in binder map");
+ return;
+ }
+ sp<HalClient>& client = mBinderToClientMap.editValueAt(index);
+ index = mPropertyToClientsMap.indexOfKey(prop);
+ if (index < 0) {
+ // not found
+ ALOGD("unsubscribe client not found in prop map, prop:0x%x", prop);
+ return;
+ }
+ sp<HalClientSpVector> clientsForProperty = mPropertyToClientsMap.editValueAt(index);
+ //TODO share code with binderDied
+ clientsForProperty->remove(client);
+ if(!client->removePropertyAndCheckIfActive(prop)) {
+ // client is no longer necessary
+ mBinderToClientMap.removeItem(iBinder);
+ iBinder->unlinkToDeath(this);
+ }
+ //TODO reset sample rate. do not care for now.
+ if (clientsForProperty->size() == 0) {
+ if ((prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
+ (prop <= (int32_t)VEHICLE_PROPERTY_INTERNAL_END)) {
+ ALOGD("unsubscribe to internal property, prop 0x%x", prop);
+ } else if (mMockingEnabled) {
+ inMocking = true;
+ }
+ mPropertyToClientsMap.removeItem(prop);
+ mSampleRates.removeItem(prop);
+ }
+ } while (false);
+ if (shouldUnsubscribe) {
+ if (inMocking) {
+ mHalMock->onPropertyUnsubscribe(prop);
} else {
mDevice->unsubscribe(mDevice, prop);
}
- mPropertyToClientsMap.removeItem(prop);
- mSampleRates.removeItem(prop);
}
}
-void VehicleNetworkService::onHalEvent(const vehicle_prop_value_t* eventData) {
+status_t VehicleNetworkService::injectEvent(const vehicle_prop_value_t& value) {
+ onHalEvent(&value);
+ return NO_ERROR;
+}
+
+status_t VehicleNetworkService::startMocking(const sp<IVehicleNetworkHalMock>& mock) {
+ Mutex::Autolock autoLock(mLock);
+ mHalMock = mock;
+ mMockingEnabled = true;
+ mHandler->handleMockStart();
+ // Mock implementation should make sure that its startMocking call is not blocking its
+ // onlistProperties call. Otherwise, this will lead into dead-lock.
+ mPropertiesForMocking = mock->onListProperties();
+ //TODO save all old states before dropping all clients
+ mBinderToClientMap.clear();
+ mPropertyToClientsMap.clear();
+ mSampleRates.clear();
+ //TODO handle binder death
+ return NO_ERROR;
+}
+
+void VehicleNetworkService::stopMocking(const sp<IVehicleNetworkHalMock>& mock) {
+ Mutex::Autolock autoLock(mLock);
+ if (mHalMock.get() == NULL) {
+ return;
+ }
+ if (IInterface::asBinder(mock) != IInterface::asBinder(mHalMock)) {
+ ALOGE("stopMocking, not the one started");
+ return;
+ }
+ mHalMock = NULL;
+ mMockingEnabled = false;
+ mPropertiesForMocking = NULL;
+ //TODO restore old states
+}
+
+void VehicleNetworkService::onHalEvent(const vehicle_prop_value_t* eventData, bool isInjection) {
+ if (!isInjection) {
+ Mutex::Autolock autoLock(mLock);
+ if (mMockingEnabled) {
+ // drop real HAL event if mocking is enabled
+ return;
+ }
+ }
//TODO add memory pool
vehicle_prop_value_t* copy = VehiclePropValueUtil::allocVehicleProp(*eventData);
ASSERT_OR_HANDLE_NO_MEMORY(copy, return);
diff --git a/vehicle_network_service/VehicleNetworkService.h b/vehicle_network_service/VehicleNetworkService.h
index e696a95..b0c0a40 100644
--- a/vehicle_network_service/VehicleNetworkService.h
+++ b/vehicle_network_service/VehicleNetworkService.h
@@ -73,6 +73,7 @@
void handleRelease();
void handleHalEvent(vehicle_prop_value_t *eventData);
void handleHalError(int errorCode);
+ void handleMockStart();
private:
void handleMessage(const Message& message);
@@ -215,7 +216,7 @@
~VehicleNetworkService();
virtual status_t dump(int fd, const Vector<String16>& args);
void release();
- void onHalEvent(const vehicle_prop_value_t *eventData);
+ void onHalEvent(const vehicle_prop_value_t *eventData, bool isInjection = false);
void onHalError(int errorCode);
/**
* Called by VehicleHalMessageHandler for batching events
@@ -227,6 +228,9 @@
virtual status_t subscribe(const sp<IVehicleNetworkListener> &listener, int32_t property,
float sampleRate);
virtual void unsubscribe(const sp<IVehicleNetworkListener> &listener, int32_t property);
+ virtual status_t injectEvent(const vehicle_prop_value_t& value);
+ virtual status_t startMocking(const sp<IVehicleNetworkHalMock>& mock);
+ virtual void stopMocking(const sp<IVehicleNetworkHalMock>& mock);
virtual void binderDied(const wp<IBinder>& who);
bool isPropertySubsribed(int32_t property);
private:
@@ -234,10 +238,10 @@
virtual void onFirstRef();
status_t loadHal();
void closeHal();
- vehicle_prop_config_t const * findConfig(int32_t property);
- bool isGettable(int32_t property);
- bool isSettable(int32_t property);
- bool isSubscribable(int32_t property);
+ vehicle_prop_config_t const * findConfigLocked(int32_t property);
+ bool isGettableLocked(int32_t property);
+ bool isSettableLocked(int32_t property);
+ bool isSubscribableLocked(int32_t property);
static int eventCallback(const vehicle_prop_value_t *eventData);
static int errorCallback(int32_t errorCode);
private:
@@ -252,6 +256,9 @@
KeyedVector<int32_t, sp<HalClientSpVector> > mPropertyToClientsMap;
KeyedVector<int32_t, float> mSampleRates;
PropertyValueCache mCache;
+ bool mMockingEnabled;
+ sp<IVehicleNetworkHalMock> mHalMock;
+ sp<VehiclePropertiesHolder> mPropertiesForMocking;
};
};