[1/N] Migrate VehicleStub to AIDL types.
This is part of CLs migrating car service from HIDL types to
AIDL types. This CL updates VehicleStub methods to expose HalPropValue
and AIDLtypes.
Test: atest CarServiceUnitTest:com.android.car.hal
Bug: 205774940
Change-Id: If8809392e5a87f2bab98ceb58d50f6d494e6ea25
diff --git a/service/src/com/android/car/AidlVehicleStub.java b/service/src/com/android/car/AidlVehicleStub.java
new file mode 100644
index 0000000..5cdec1b
--- /dev/null
+++ b/service/src/com/android/car/AidlVehicleStub.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2021 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.annotation.Nullable;
+import android.car.builtin.os.ServiceManagerHelper;
+import android.car.builtin.util.Slogf;
+import android.hardware.automotive.vehicle.IVehicle;
+import android.hardware.automotive.vehicle.SubscribeOptions;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+
+import com.android.car.hal.HalClientCallback;
+import com.android.car.hal.HalPropConfig;
+import com.android.car.hal.HalPropValue;
+import com.android.car.hal.HalPropValueBuilder;
+import com.android.internal.annotations.VisibleForTesting;
+
+final class AidlVehicleStub extends VehicleStub {
+
+ private static final String AIDL_VHAL_SERVICE =
+ "android.hardware.automotive.vehicle.IVehicle/default";
+
+ private final IVehicle mAidlVehicle;
+ private final HalPropValueBuilder mPropValueBuilder;
+
+ AidlVehicleStub() {
+ this(getAidlVehicle());
+ }
+
+ @VisibleForTesting
+ AidlVehicleStub(IVehicle aidlVehicle) {
+ mAidlVehicle = aidlVehicle;
+ mPropValueBuilder = new HalPropValueBuilder(/*isAidl=*/true);
+ }
+
+
+ /**
+ * Gets a HalPropValueBuilder that could be used to build a HalPropValue.
+ *
+ * @return a builder to build HalPropValue.
+ */
+ @Override
+ public HalPropValueBuilder getHalPropValueBuilder() {
+ return mPropValueBuilder;
+ }
+
+ /**
+ * Returns whether this vehicle stub is connecting to a valid vehicle HAL.
+ *
+ * @return Whether this vehicle stub is connecting to a valid vehicle HAL.
+ */
+ @Override
+ public boolean isValid() {
+ return mAidlVehicle != null;
+ }
+
+ /**
+ * Gets the interface descriptor for the connecting vehicle HAL.
+ *
+ * @return the interface descriptor.
+ * @throws IllegalStateException If unable to get the descriptor.
+ */
+ @Override
+ public String getInterfaceDescriptor() throws IllegalStateException {
+ try {
+ return mAidlVehicle.asBinder().getInterfaceDescriptor();
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Unable to get Vehicle HAL interface descriptor", e);
+ }
+ }
+
+ /**
+ * Register a death recipient that would be called when vehicle HAL died.
+ *
+ * @param recipient A death recipient.
+ * @throws IllegalStateException If unable to register the death recipient.
+ */
+ @Override
+ public void linkToDeath(IVehicleDeathRecipient recipient) throws IllegalStateException {
+ try {
+ mAidlVehicle.asBinder().linkToDeath(recipient, /*flag=*/ 0);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Failed to linkToDeath Vehicle HAL");
+ }
+ }
+
+ /**
+ * Unlink a previously linked death recipient.
+ *
+ * @param recipient A previously linked death recipient.
+ */
+ @Override
+ public void unlinkToDeath(IVehicleDeathRecipient recipient) {
+ mAidlVehicle.asBinder().unlinkToDeath(recipient, /*flag=*/ 0);
+ }
+
+ /**
+ * Get all property configs.
+ *
+ * @return All the property configs.
+ * @throws RemoteException if the remote operation fails.
+ * @throws ServiceSpecificException if VHAL returns service specific error.
+ */
+ @Override
+ public HalPropConfig[] getAllPropConfigs()
+ throws RemoteException, ServiceSpecificException {
+ // TODO(b/205774940): Call AIDL APIs.
+ return null;
+ }
+
+ /**
+ * Subscribe to a property.
+ *
+ * @param callback The VehicleStubCallback that would be called for subscribe events.
+ * @param options The list of subscribe options.
+ * @throws RemoteException if the remote operation fails.
+ * @throws ServiceSpecificException if VHAL returns service specific error.
+ */
+ @Override
+ public void subscribe(VehicleStubCallback callback, SubscribeOptions[] options)
+ throws RemoteException, ServiceSpecificException {
+ // TODO(b/205774940): Call AIDL APIs.
+ return;
+ }
+
+ /**
+ * Unsubscribe to a property.
+ *
+ * @param callback The previously subscribed callback to unsubscribe.
+ * @param prop The ID for the property to unsubscribe.
+ * @throws RemoteException if the remote operation fails.
+ * @throws ServiceSpecificException if VHAL returns service specific error.
+ */
+ @Override
+ public void unsubscribe(VehicleStubCallback callback, int prop)
+ throws RemoteException, ServiceSpecificException {
+ // TODO(b/205774940): Call AIDL APIs.
+ return;
+ }
+
+ /**
+ * Get a new {@code VehicleStubCallback} that could be used to subscribe/unsubscribe.
+ *
+ * @param callback A callback that could be used to receive events.
+ * @return a {@code VehicleStubCallback} that could be passed to subscribe/unsubscribe.
+ */
+ @Override
+ public VehicleStubCallback newCallback(HalClientCallback callback) {
+ // TODO(b/205774940): Return AIDL callback.
+ return null;
+ }
+
+ /**
+ * Get a property.
+ *
+ * @param requestedPropValue The property to get.
+ * @return The vehicle property value.
+ * @throws RemoteException if the remote operation fails.
+ * @throws ServiceSpecificException if VHAL returns service specific error.
+ */
+ @Override
+ @Nullable
+ public HalPropValue get(HalPropValue requestedPropValue)
+ throws RemoteException, ServiceSpecificException {
+ // TODO(b/205774940): Call AIDL APIs.
+ return null;
+ }
+
+ /**
+ * Set a property.
+ *
+ * @param propValue The property to set.
+ * @throws RemoteException if the remote operation fails.
+ * @throws ServiceSpecificException if VHAL returns service specific error.
+ */
+ @Override
+ public void set(HalPropValue propValue) throws RemoteException, ServiceSpecificException {
+ // TODO(b/205774940): Call AIDL APIs.
+ return;
+ }
+
+ @Nullable
+ private static IVehicle getAidlVehicle() {
+ try {
+ return IVehicle.Stub.asInterface(
+ ServiceManagerHelper.waitForDeclaredService(AIDL_VHAL_SERVICE));
+ } catch (RuntimeException e) {
+ Slogf.w(CarLog.TAG_SERVICE, "Failed to get \"" + AIDL_VHAL_SERVICE + "\" service", e);
+ }
+ return null;
+ }
+}
diff --git a/service/src/com/android/car/CarServiceImpl.java b/service/src/com/android/car/CarServiceImpl.java
index dec3b99..fe77f17 100644
--- a/service/src/com/android/car/CarServiceImpl.java
+++ b/service/src/com/android/car/CarServiceImpl.java
@@ -55,7 +55,7 @@
initTiming.traceBegin("CarService.onCreate");
initTiming.traceBegin("getVehicle");
- mVehicle = new VehicleStub();
+ mVehicle = VehicleStub.newVehicleStub();
initTiming.traceEnd(); // "getVehicle"
EventLogHelper.writeCarServiceCreate(/* hasVhal= */ mVehicle.isValid());
diff --git a/service/src/com/android/car/HidlVehicleStub.java b/service/src/com/android/car/HidlVehicleStub.java
new file mode 100644
index 0000000..88db8bb
--- /dev/null
+++ b/service/src/com/android/car/HidlVehicleStub.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2021 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 static com.android.car.CarServiceUtils.subscribeOptionsToHidl;
+
+import android.annotation.Nullable;
+import android.car.builtin.util.Slogf;
+import android.hardware.automotive.vehicle.SubscribeOptions;
+import android.hardware.automotive.vehicle.V2_0.IVehicle;
+import android.hardware.automotive.vehicle.V2_0.IVehicleCallback;
+import android.hardware.automotive.vehicle.V2_0.StatusCode;
+import android.hardware.automotive.vehicle.VehiclePropError;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.os.SystemProperties;
+
+import com.android.car.hal.HalClientCallback;
+import com.android.car.hal.HalPropConfig;
+import com.android.car.hal.HalPropValue;
+import com.android.car.hal.HalPropValueBuilder;
+import com.android.car.hal.HidlHalPropConfig;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
+final class HidlVehicleStub extends VehicleStub {
+
+ private final IVehicle mHidlVehicle;
+ private final HalPropValueBuilder mPropValueBuilder;
+
+ HidlVehicleStub() {
+ this(getHidlVehicle());
+ }
+
+ @VisibleForTesting
+ HidlVehicleStub(IVehicle hidlVehicle) {
+ mHidlVehicle = hidlVehicle;
+ mPropValueBuilder = new HalPropValueBuilder(/*isAidl=*/false);
+ }
+
+ /**
+ * Gets a HalPropValueBuilder that could be used to build a HalPropValue.
+ *
+ * @return a builder to build HalPropValue.
+ */
+ @Override
+ public HalPropValueBuilder getHalPropValueBuilder() {
+ return mPropValueBuilder;
+ }
+
+ /**
+ * Returns whether this vehicle stub is connecting to a valid vehicle HAL.
+ *
+ * @return Whether this vehicle stub is connecting to a valid vehicle HAL.
+ */
+ @Override
+ public boolean isValid() {
+ return mHidlVehicle != null;
+ }
+
+ /**
+ * Gets the interface descriptor for the connecting vehicle HAL.
+ *
+ * @return the interface descriptor.
+ * @throws IllegalStateException If unable to get the descriptor.
+ */
+ @Override
+ public String getInterfaceDescriptor() throws IllegalStateException {
+ try {
+ return mHidlVehicle.interfaceDescriptor();
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Unable to get Vehicle HAL interface descriptor", e);
+ }
+ }
+
+ /**
+ * Register a death recipient that would be called when vehicle HAL died.
+ *
+ * @param recipient A death recipient.
+ * @throws IllegalStateException If unable to register the death recipient.
+ */
+ @Override
+ public void linkToDeath(IVehicleDeathRecipient recipient) throws IllegalStateException {
+ try {
+ mHidlVehicle.linkToDeath(recipient, /*flag=*/ 0);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Failed to linkToDeath Vehicle HAL");
+ }
+ }
+
+ /**
+ * Unlink a previously linked death recipient.
+ *
+ * @param recipient A previously linked death recipient.
+ */
+ @Override
+ public void unlinkToDeath(IVehicleDeathRecipient recipient) {
+ try {
+ mHidlVehicle.unlinkToDeath(recipient);
+ } catch (RemoteException e) {
+ // Ignore errors on shutdown path.
+ }
+ }
+
+ /**
+ * Get all property configs.
+ *
+ * @return All the property configs.
+ */
+ @Override
+ public HalPropConfig[] getAllPropConfigs() throws RemoteException {
+ ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig> hidlConfigs =
+ mHidlVehicle.getAllPropConfigs();
+ int configSize = hidlConfigs.size();
+ HalPropConfig[] configs = new HalPropConfig[configSize];
+ for (int i = 0; i < configSize; i++) {
+ configs[i] = new HidlHalPropConfig(hidlConfigs.get(i));
+ }
+ return configs;
+ }
+
+ /**
+ * Subscribe to a property.
+ *
+ * @param callback The VehicleStubCallback that would be called for subscribe events.
+ * @param options The list of subscribe options.
+ * @throws RemoteException if the subscription fails.
+ */
+ @Override
+ public void subscribe(VehicleStubCallback callback, SubscribeOptions[] options)
+ throws RemoteException {
+ ArrayList<android.hardware.automotive.vehicle.V2_0.SubscribeOptions> hidlOptions =
+ new ArrayList<android.hardware.automotive.vehicle.V2_0.SubscribeOptions>();
+ for (SubscribeOptions option : options) {
+ hidlOptions.add(subscribeOptionsToHidl(option));
+ }
+ mHidlVehicle.subscribe(callback.getHidlCallback(), hidlOptions);
+ }
+
+ /**
+ * Unsubscribe to a property.
+ *
+ * @param callback The previously subscribed callback to unsubscribe.
+ * @param prop The ID for the property to unsubscribe.
+ * @throws RemoteException if the unsubscription fails.
+ */
+ @Override
+ public void unsubscribe(VehicleStubCallback callback, int prop) throws RemoteException {
+ mHidlVehicle.unsubscribe((IVehicleCallback.Stub)
+ callback, prop);
+ }
+
+ /**
+ * Get a new {@code VehicleStubCallback} that could be used to subscribe/unsubscribe.
+ *
+ * @param callback A callback that could be used to receive events.
+ * @return a {@code VehicleStubCallback} that could be passed to subscribe/unsubscribe.
+ */
+ @Override
+ public VehicleStubCallback newCallback(HalClientCallback callback) {
+ return new HidlVehicleCallback(callback, mPropValueBuilder);
+ }
+
+ private static class GetValueResult {
+ public int status;
+ public android.hardware.automotive.vehicle.V2_0.VehiclePropValue value;
+ }
+
+ /**
+ * Get a property.
+ *
+ * @param requestedPropValue The property to get.
+ * @return The vehicle property value.
+ * @throws RemoteException if the remote operation fails.
+ * @throws ServiceSpecificException if VHAL returns service specific error.
+ */
+ @Override
+ @Nullable
+ public HalPropValue get(HalPropValue requestedPropValue)
+ throws RemoteException, ServiceSpecificException {
+ android.hardware.automotive.vehicle.V2_0.VehiclePropValue hidlPropValue =
+ (android.hardware.automotive.vehicle.V2_0.VehiclePropValue) requestedPropValue
+ .toVehiclePropValue();
+ GetValueResult result = new GetValueResult();
+ mHidlVehicle.get(
+ hidlPropValue,
+ (s, p) -> {
+ result.status = s;
+ result.value = p;
+ });
+
+ if (result.status != android.hardware.automotive.vehicle.V2_0.StatusCode.OK) {
+ throw new ServiceSpecificException(
+ result.status,
+ "failed to get value for property: " + Integer.toString(hidlPropValue.prop));
+ }
+
+ if (result.value == null) {
+ return null;
+ }
+
+ return getHalPropValueBuilder().build(result.value);
+ }
+
+ /**
+ * Set a property.
+ *
+ * @param propValue The property to set.
+ * @throws RemoteException if the remote operation fails.
+ * @throws ServiceSpecificException if VHAL returns service specific error.
+ */
+ @Override
+ public void set(HalPropValue propValue) throws RemoteException {
+ android.hardware.automotive.vehicle.V2_0.VehiclePropValue hidlPropValue =
+ (android.hardware.automotive.vehicle.V2_0.VehiclePropValue) propValue
+ .toVehiclePropValue();
+ int status = mHidlVehicle.set(hidlPropValue);
+ if (status != StatusCode.OK) {
+ throw new ServiceSpecificException(status, "failed to set value for property: "
+ + Integer.toString(hidlPropValue.prop));
+ }
+ }
+
+ @Nullable
+ private static IVehicle getHidlVehicle() {
+ String instanceName = SystemProperties.get("ro.vehicle.hal", "default");
+
+ try {
+ return IVehicle.getService(instanceName);
+ } catch (RemoteException e) {
+ Slogf.e(CarLog.TAG_SERVICE, "Failed to get IVehicle/" + instanceName + " service", e);
+ } catch (NoSuchElementException e) {
+ Slogf.e(CarLog.TAG_SERVICE, "IVehicle/" + instanceName + " service not registered yet");
+ }
+ return null;
+ }
+
+ private static class HidlVehicleCallback
+ extends IVehicleCallback.Stub
+ implements VehicleStubCallback {
+ private final HalClientCallback mCallback;
+ private final HalPropValueBuilder mBuilder;
+
+ HidlVehicleCallback(HalClientCallback callback, HalPropValueBuilder builder) {
+ mCallback = callback;
+ mBuilder = builder;
+ }
+
+ @Override
+ public android.hardware.automotive.vehicle.IVehicleCallback getAidlCallback() {
+ throw new UnsupportedOperationException(
+ "getAidlCallback should never be called on a HidlVehicleCallback");
+ }
+
+ public android.hardware.automotive.vehicle.V2_0.IVehicleCallback.Stub getHidlCallback() {
+ return this;
+ }
+
+ @Override
+ public void onPropertyEvent(
+ ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropValue> propValues) {
+ ArrayList<HalPropValue> values = new ArrayList<>();
+ for (android.hardware.automotive.vehicle.V2_0.VehiclePropValue value : propValues) {
+ values.add(mBuilder.build(value));
+ }
+ mCallback.onPropertyEvent(values);
+ }
+
+ @Override
+ public void onPropertySet(
+ android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue) {
+ // Deprecated, do nothing.
+ }
+
+ @Override
+ public void onPropertySetError(int errorCode, int propId, int areaId) {
+ VehiclePropError error = new VehiclePropError();
+ error.propId = propId;
+ error.areaId = areaId;
+ error.errorCode = errorCode;
+ ArrayList<VehiclePropError> errors = new ArrayList<VehiclePropError>();
+ errors.add(error);
+ mCallback.onPropertySetError(errors);
+ }
+ }
+}
diff --git a/service/src/com/android/car/VehicleStub.java b/service/src/com/android/car/VehicleStub.java
index fa05845..4218220 100644
--- a/service/src/com/android/car/VehicleStub.java
+++ b/service/src/com/android/car/VehicleStub.java
@@ -17,59 +17,66 @@
package com.android.car;
import android.annotation.Nullable;
-import android.car.builtin.os.ServiceManagerHelper;
import android.car.builtin.util.Slogf;
-import android.hardware.automotive.vehicle.IVehicle;
+import android.hardware.automotive.vehicle.SubscribeOptions;
import android.os.RemoteException;
-import android.os.SystemProperties;
+import android.os.ServiceSpecificException;
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.NoSuchElementException;
+import com.android.car.hal.HalClientCallback;
+import com.android.car.hal.HalPropConfig;
+import com.android.car.hal.HalPropValue;
+import com.android.car.hal.HalPropValueBuilder;
/**
* VehicleStub represents an IVehicle service interface in either AIDL or legacy HIDL version. It
* exposes common interface so that the client does not need to care about which version the
* underlying IVehicle service is in.
*/
-public class VehicleStub {
- private static final String AIDL_VHAL_SERVICE = "android.hardware.automotive.vehicle";
+public abstract class VehicleStub {
+ /** VehicleStubCallback is either an AIDL or a HIDL callback. */
+ public interface VehicleStubCallback {
+ /**
+ * Get the callback interface for AIDL backend.
+ */
+ android.hardware.automotive.vehicle.IVehicleCallback getAidlCallback();
+ /**
+ * Get the callback interface for HIDL backend.
+ */
+ android.hardware.automotive.vehicle.V2_0.IVehicleCallback.Stub getHidlCallback();
+ }
- private final IVehicle mAidlVehicle;
- private final android.hardware.automotive.vehicle.V2_0.IVehicle mHidlVehicle;
-
- public VehicleStub() {
- mAidlVehicle = getAidlVehicle();
- if (mAidlVehicle != null) {
- mHidlVehicle = null;
- return;
+ /**
+ * Create a new VehicleStub to connect to Vehicle HAL.
+ *
+ * Create a new VehicleStub to connect to Vehicle HAL according to which backend (AIDL or HIDL)
+ * is available. Caller must call isValid to check the returned {@code VehicleStub} before using
+ * it.
+ *
+ * @return a vehicle stub to connect to Vehicle HAL.
+ */
+ public static VehicleStub newVehicleStub() {
+ VehicleStub stub = new AidlVehicleStub();
+ if (stub.isValid()) {
+ return stub;
}
Slogf.w(CarLog.TAG_SERVICE, "No AIDL vehicle HAL found, fall back to HIDL version");
- mHidlVehicle = getHidlVehicle();
+ return new HidlVehicleStub();
}
- @VisibleForTesting
- public VehicleStub(IVehicle aidlVehicle) {
- mAidlVehicle = aidlVehicle;
- mHidlVehicle = null;
- }
-
- @VisibleForTesting
- public VehicleStub(android.hardware.automotive.vehicle.V2_0.IVehicle hidlVehicle) {
- mHidlVehicle = hidlVehicle;
- mAidlVehicle = null;
- }
+ /**
+ * Gets a HalPropValueBuilder that could be used to build a HalPropValue.
+ *
+ * @return a builder to build HalPropValue.
+ */
+ public abstract HalPropValueBuilder getHalPropValueBuilder();
/**
* Returns whether this vehicle stub is connecting to a valid vehicle HAL.
*
* @return Whether this vehicle stub is connecting to a valid vehicle HAL.
*/
- public boolean isValid() {
- return mAidlVehicle != null || mHidlVehicle != null;
- }
+ public abstract boolean isValid();
/**
* Gets the interface descriptor for the connecting vehicle HAL.
@@ -77,16 +84,7 @@
* @return the interface descriptor.
* @throws IllegalStateException If unable to get the descriptor.
*/
- public String getInterfaceDescriptor() throws IllegalStateException {
- try {
- if (mAidlVehicle != null) {
- return mAidlVehicle.asBinder().getInterfaceDescriptor();
- }
- return mHidlVehicle.interfaceDescriptor();
- } catch (RemoteException e) {
- throw new IllegalStateException("Unable to get Vehicle HAL interface descriptor", e);
- }
- }
+ public abstract String getInterfaceDescriptor() throws IllegalStateException;
/**
* Register a death recipient that would be called when vehicle HAL died.
@@ -94,141 +92,74 @@
* @param recipient A death recipient.
* @throws IllegalStateException If unable to register the death recipient.
*/
- public void linkToDeath(IVehicleDeathRecipient recipient) throws IllegalStateException {
- try {
- if (mAidlVehicle != null) {
- mAidlVehicle.asBinder().linkToDeath(recipient, /*flag=*/ 0);
- return;
- }
- mHidlVehicle.linkToDeath(recipient, /*flag=*/ 0);
- } catch (RemoteException e) {
- throw new IllegalStateException("Failed to linkToDeath Vehicle HAL");
- }
- }
+ public abstract void linkToDeath(IVehicleDeathRecipient recipient) throws IllegalStateException;
/**
* Unlink a previously linked death recipient.
*
* @param recipient A previously linked death recipient.
*/
- public void unlinkToDeath(IVehicleDeathRecipient recipient) {
- if (mAidlVehicle != null) {
- mAidlVehicle.asBinder().unlinkToDeath(recipient, /*flag=*/ 0);
- return;
- }
-
- try {
- mHidlVehicle.unlinkToDeath(recipient);
- } catch (RemoteException e) {
- // Ignore errors on shutdown path.
- }
- }
+ public abstract void unlinkToDeath(IVehicleDeathRecipient recipient);
/**
* Get all property configs.
*
* @return All the property configs.
+ * @throws RemoteException if the remote operation fails.
+ * @throws ServiceSpecificException if VHAL returns service specific error.
*/
- public ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig> getAllPropConfigs()
- throws RemoteException {
- if (mAidlVehicle != null) {
- // TODO(b/205774940): Call AIDL APIs.
- return null;
- }
- return mHidlVehicle.getAllPropConfigs();
- }
+ public abstract HalPropConfig[] getAllPropConfigs()
+ throws RemoteException, ServiceSpecificException;
/**
* Subscribe to a property.
*
- * @param callback The IVehicleCallback that would be called for subscribe events.
+ * @param callback The VehicleStubCallback that would be called for subscribe events.
* @param options The list of subscribe options.
- * @throws RemoteException if the subscription fails.
+ * @throws RemoteException if the remote operation fails.
+ * @throws ServiceSpecificException if VHAL returns service specific error.
*/
- public void subscribe(
- android.hardware.automotive.vehicle.V2_0.IVehicleCallback callback,
- ArrayList<android.hardware.automotive.vehicle.V2_0.SubscribeOptions> options)
- throws RemoteException {
- if (mAidlVehicle != null) {
- // TODO(b/205774940): Call AIDL APIs.
- return;
- }
- mHidlVehicle.subscribe(callback, options);
- }
+ public abstract void subscribe(VehicleStubCallback callback,
+ SubscribeOptions[] options) throws RemoteException, ServiceSpecificException;
/**
* Unsubscribe to a property.
*
* @param callback The previously subscribed callback to unsubscribe.
* @param prop The ID for the property to unsubscribe.
- * @throws RemoteException if the unsubscription fails.
+ * @throws RemoteException if the remote operation fails.
+ * @throws ServiceSpecificException if VHAL returns service specific error.
*/
- public void unsubscribe(
- android.hardware.automotive.vehicle.V2_0.IVehicleCallback callback, int prop)
- throws RemoteException {
- if (mAidlVehicle != null) {
- // TODO(b/205774940): Call AIDL APIs.
- return;
- }
- mHidlVehicle.unsubscribe(callback, prop);
- }
+ public abstract void unsubscribe(VehicleStubCallback callback, int prop)
+ throws RemoteException, ServiceSpecificException;
+
+ /**
+ * Get a new {@code VehicleStubCallback} that could be used to subscribe/unsubscribe.
+ *
+ * @param callback A callback that could be used to receive events.
+ * @return a {@code VehicleStubCallback} that could be passed to subscribe/unsubscribe.
+ */
+ public abstract VehicleStubCallback newCallback(HalClientCallback callback);
/**
* Get a property.
*
* @param requestedPropValue The property to get.
- * @param callback The callback to be called for the result.
- * @throws RemoteException if the operation fails.
+ * @return The vehicle property value.
+ * @throws RemoteException if the remote operation fails.
+ * @throws ServiceSpecificException if VHAL returns service specific error.
*/
- public void get(
- android.hardware.automotive.vehicle.V2_0.VehiclePropValue requestedPropValue,
- android.hardware.automotive.vehicle.V2_0.IVehicle.getCallback callback)
- throws RemoteException {
- if (mAidlVehicle != null) {
- // TODO(b/205774940): Call AIDL APIs.
- return;
- }
- mHidlVehicle.get(requestedPropValue, callback);
- }
+ @Nullable
+ public abstract HalPropValue get(HalPropValue requestedPropValue)
+ throws RemoteException, ServiceSpecificException;
/**
* Set a property.
*
* @param propValue The property to set.
- * @return The status code.
- * @throws RemoteException if the operation fails.
+ * @throws RemoteException if the remote operation fails.
+ * @throws ServiceSpecificException if VHAL returns service specific error.
*/
- public int set(android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue)
- throws RemoteException {
- if (mAidlVehicle != null) {
- // TODO(b/205774940): Call AIDL APIs.
- return 0;
- }
- return mHidlVehicle.set(propValue);
- }
-
- @Nullable
- private static android.hardware.automotive.vehicle.V2_0.IVehicle getHidlVehicle() {
- String instanceName = SystemProperties.get("ro.vehicle.hal", "default");
-
- try {
- return android.hardware.automotive.vehicle.V2_0.IVehicle.getService(instanceName);
- } catch (RemoteException e) {
- Slogf.e(CarLog.TAG_SERVICE, "Failed to get IVehicle/" + instanceName + " service", e);
- } catch (NoSuchElementException e) {
- Slogf.e(CarLog.TAG_SERVICE, "IVehicle/" + instanceName + " service not registered yet");
- }
- return null;
- }
-
- @Nullable
- private IVehicle getAidlVehicle() {
- try {
- return IVehicle.Stub.asInterface(
- ServiceManagerHelper.waitForDeclaredService(AIDL_VHAL_SERVICE));
- } catch (RuntimeException e) {
- Slogf.w(CarLog.TAG_SERVICE, "Failed to get \"" + AIDL_VHAL_SERVICE + "\" service", e);
- }
- return null;
- }
+ public abstract void set(HalPropValue propValue)
+ throws RemoteException, ServiceSpecificException;
}
diff --git a/service/src/com/android/car/hal/HalClientCallback.java b/service/src/com/android/car/hal/HalClientCallback.java
new file mode 100644
index 0000000..6950a4f
--- /dev/null
+++ b/service/src/com/android/car/hal/HalClientCallback.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 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.hal;
+
+import android.hardware.automotive.vehicle.VehiclePropError;
+
+import java.util.ArrayList;
+
+/**
+ * HalClientCallback is the callback functions that HalClient supports.
+ */
+public interface HalClientCallback {
+ /**
+ * Called when new property events happen.
+ */
+ void onPropertyEvent(ArrayList<HalPropValue> values);
+
+ /**
+ * Called when property set errors happen.
+ */
+ void onPropertySetError(ArrayList<VehiclePropError> errors);
+}
diff --git a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
index ecf02f3..60912fe 100644
--- a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
+++ b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
@@ -234,7 +234,7 @@
// This should be done here as feature property is accessed inside the constructor.
initMockedHal();
- mMockedVehicleStub = new VehicleStub(mMockedVehicleHal);
+ mMockedVehicleStub = new HidlVehicleStub(mMockedVehicleHal);
ICarImpl carImpl = new ICarImpl(mMockedCarTestContext, /*builtinContext=*/null,
mMockedVehicleStub, mFakeSystemInterface, /*vehicleInterfaceName=*/"MockedCar",
diff --git a/tests/carservice_unit_test/src/com/android/car/VehicleStubTest.java b/tests/carservice_unit_test/src/com/android/car/VehicleStubTest.java
new file mode 100644
index 0000000..1671e74
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/VehicleStubTest.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2021 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 static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.automotive.vehicle.IVehicle;
+import android.hardware.automotive.vehicle.StatusCode;
+import android.hardware.automotive.vehicle.SubscribeOptions;
+import android.hardware.automotive.vehicle.VehiclePropError;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+
+import com.android.car.hal.HalClientCallback;
+import com.android.car.hal.HalPropConfig;
+import com.android.car.hal.HalPropValue;
+import com.android.car.hal.HalPropValueBuilder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+@RunWith(MockitoJUnitRunner.class)
+public class VehicleStubTest {
+
+ private static final int TEST_PROP = 1;
+ private static final int TEST_ACCESS = 2;
+ private static final float TEST_SAMPLE_RATE = 3.0f;
+ private static final int TEST_VALUE = 3;
+ private static final int TEST_AREA = 4;
+ private static final int TEST_STATUS = 5;
+
+ @Mock
+ private IVehicle mAidlVehicle;
+ @Mock
+ private IBinder mAidlBinder;
+ @Mock
+ private android.hardware.automotive.vehicle.V2_0.IVehicle mHidlVehicle;
+
+ private VehicleStub mAidlVehicleStub;
+ private VehicleStub mHidlVehicleStub;
+
+ @Before
+ public void setUp() {
+ when(mAidlVehicle.asBinder()).thenReturn(mAidlBinder);
+
+ mAidlVehicleStub = new AidlVehicleStub(mAidlVehicle);
+ mHidlVehicleStub = new HidlVehicleStub(mHidlVehicle);
+
+ assertThat(mAidlVehicleStub.isValid()).isTrue();
+ assertThat(mHidlVehicleStub.isValid()).isTrue();
+ }
+
+ @Test
+ public void testGetInterfaceDescriptorHidl() throws Exception {
+ mHidlVehicleStub.getInterfaceDescriptor();
+
+ verify(mHidlVehicle).interfaceDescriptor();
+ }
+
+ @Test
+ public void testGetInterfaceDescriptorAidl() throws Exception {
+ mAidlVehicleStub.getInterfaceDescriptor();
+
+ verify(mAidlBinder).getInterfaceDescriptor();
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testGetInterfaceDescriptorRemoteException() throws Exception {
+ when(mAidlBinder.getInterfaceDescriptor()).thenThrow(new RemoteException());
+
+ mAidlVehicleStub.getInterfaceDescriptor();
+ }
+
+ @Test
+ public void testLinkToDeathHidl() throws Exception {
+ IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
+
+ mHidlVehicleStub.linkToDeath(recipient);
+
+ verify(mHidlVehicle).linkToDeath(recipient, 0);
+ }
+
+ @Test
+ public void testLinkToDeathAidl() throws Exception {
+ IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
+
+ mAidlVehicleStub.linkToDeath(recipient);
+
+ verify(mAidlBinder).linkToDeath(recipient, 0);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testLinkToDeathRemoteException() throws Exception {
+ IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
+ doThrow(new RemoteException()).when(mAidlBinder).linkToDeath(recipient, 0);
+
+ mAidlVehicleStub.linkToDeath(recipient);
+ }
+
+ @Test
+ public void testUnlinkToDeathHidl() throws Exception {
+ IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
+
+ mHidlVehicleStub.unlinkToDeath(recipient);
+
+ verify(mHidlVehicle).unlinkToDeath(recipient);
+ }
+
+ @Test
+ public void testUnlinkToDeathAidl() throws Exception {
+ IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
+
+ mAidlVehicleStub.unlinkToDeath(recipient);
+
+ verify(mAidlBinder).unlinkToDeath(recipient, 0);
+ }
+
+ @Test
+ public void testUnlinkToDeathRemoteException() throws Exception {
+ IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
+ doThrow(new RemoteException()).when(mHidlVehicle).unlinkToDeath(recipient);
+
+ mHidlVehicleStub.unlinkToDeath(recipient);
+ }
+
+ @Test
+ public void testGetAllPropConfigsHidl() throws Exception {
+ ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig> hidlConfigs = new
+ ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig>();
+ android.hardware.automotive.vehicle.V2_0.VehiclePropConfig hidlConfig =
+ new android.hardware.automotive.vehicle.V2_0.VehiclePropConfig();
+ hidlConfig.prop = TEST_PROP;
+ hidlConfig.access = TEST_ACCESS;
+ hidlConfigs.add(hidlConfig);
+
+ when(mHidlVehicle.getAllPropConfigs()).thenReturn(hidlConfigs);
+
+ HalPropConfig[] configs = mHidlVehicleStub.getAllPropConfigs();
+
+ assertThat(configs.length).isEqualTo(1);
+ assertThat(configs[0].getPropId()).isEqualTo(TEST_PROP);
+ assertThat(configs[0].getAccess()).isEqualTo(TEST_ACCESS);
+ }
+
+ @Test
+ public void testSubscribeHidl() throws Exception {
+ SubscribeOptions aidlOptions = new SubscribeOptions();
+ aidlOptions.propId = TEST_PROP;
+ aidlOptions.sampleRate = TEST_SAMPLE_RATE;
+ android.hardware.automotive.vehicle.V2_0.SubscribeOptions hidlOptions =
+ new android.hardware.automotive.vehicle.V2_0.SubscribeOptions();
+ hidlOptions.propId = TEST_PROP;
+ hidlOptions.sampleRate = TEST_SAMPLE_RATE;
+ hidlOptions.flags = android.hardware.automotive.vehicle.V2_0.SubscribeFlags.EVENTS_FROM_CAR;
+
+ HalClientCallback callback = mock(HalClientCallback.class);
+ VehicleStub.VehicleStubCallback stubCallback = mHidlVehicleStub.newCallback(callback);
+
+ mHidlVehicleStub.subscribe(stubCallback, new SubscribeOptions[]{aidlOptions});
+
+ verify(mHidlVehicle).subscribe(
+ stubCallback.getHidlCallback(),
+ new ArrayList<android.hardware.automotive.vehicle.V2_0.SubscribeOptions>(
+ Arrays.asList(hidlOptions)));
+ }
+
+ @Test
+ public void testUnsubscribeHidl() throws Exception {
+ HalClientCallback callback = mock(HalClientCallback.class);
+ VehicleStub.VehicleStubCallback stubCallback = mHidlVehicleStub.newCallback(callback);
+
+ mHidlVehicleStub.unsubscribe(stubCallback, TEST_PROP);
+
+ verify(mHidlVehicle).unsubscribe(stubCallback.getHidlCallback(), TEST_PROP);
+ }
+
+ @Test
+ public void testGetHidl() throws Exception {
+ doAnswer(new Answer() {
+ public Object answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue =
+ (android.hardware.automotive.vehicle.V2_0.VehiclePropValue) args[0];
+ assertThat(propValue.prop).isEqualTo(TEST_PROP);
+ android.hardware.automotive.vehicle.V2_0.IVehicle.getCallback callback =
+ (android.hardware.automotive.vehicle.V2_0.IVehicle.getCallback) args[1];
+ callback.onValues(StatusCode.OK, propValue);
+ return null;
+ }
+ }).when(mHidlVehicle).get(any(), any());
+
+ HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/false);
+ HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
+
+ HalPropValue gotValue = mHidlVehicleStub.get(value);
+
+ assertThat(gotValue).isEqualTo(value);
+ }
+
+ @Test(expected = ServiceSpecificException.class)
+ public void testGetHidlError() throws Exception {
+ doAnswer(new Answer() {
+ public Object answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue =
+ (android.hardware.automotive.vehicle.V2_0.VehiclePropValue) args[0];
+ assertThat(propValue.prop).isEqualTo(TEST_PROP);
+ android.hardware.automotive.vehicle.V2_0.IVehicle.getCallback callback =
+ (android.hardware.automotive.vehicle.V2_0.IVehicle.getCallback) args[1];
+ callback.onValues(StatusCode.INVALID_ARG, propValue);
+ return null;
+ }
+ }).when(mHidlVehicle).get(any(), any());
+
+ HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/false);
+ HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
+
+ mHidlVehicleStub.get(value);
+ }
+
+ @Test
+ public void testSetHidl() throws Exception {
+ HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/false);
+ HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
+ android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue =
+ new android.hardware.automotive.vehicle.V2_0.VehiclePropValue();
+ propValue.prop = TEST_PROP;
+ propValue.value.int32Values.add(TEST_VALUE);
+
+ when(mHidlVehicle.set(propValue)).thenReturn(StatusCode.OK);
+
+ mHidlVehicleStub.set(value);
+ }
+
+ @Test
+ public void testSetHidlError() throws Exception {
+ HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/false);
+ HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
+ android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue =
+ new android.hardware.automotive.vehicle.V2_0.VehiclePropValue();
+ propValue.prop = TEST_PROP;
+ propValue.value.int32Values.add(TEST_VALUE);
+
+ when(mHidlVehicle.set(propValue)).thenReturn(StatusCode.INVALID_ARG);
+
+ ServiceSpecificException exception = assertThrows(ServiceSpecificException.class, () -> {
+ mHidlVehicleStub.set(value);
+ });
+ assertThat(exception.errorCode).isEqualTo(StatusCode.INVALID_ARG);
+ }
+
+ @Test
+ public void testHidlVehicleCallbackOnPropertyEvent() throws Exception {
+ HalClientCallback callback = mock(HalClientCallback.class);
+ android.hardware.automotive.vehicle.V2_0.IVehicleCallback.Stub hidlCallback =
+ mHidlVehicleStub.newCallback(callback).getHidlCallback();
+ android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue =
+ new android.hardware.automotive.vehicle.V2_0.VehiclePropValue();
+ propValue.prop = TEST_PROP;
+ propValue.value.int32Values.add(TEST_VALUE);
+ HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/false);
+ HalPropValue halPropValue = builder.build(TEST_PROP, 0, TEST_VALUE);
+
+ hidlCallback.onPropertyEvent(
+ new ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropValue>(
+ Arrays.asList(propValue)));
+
+ verify(callback).onPropertyEvent(new ArrayList<HalPropValue>(Arrays.asList(halPropValue)));
+ }
+
+ @Test
+ public void testHidlVehicleCallbackOnPropertySetError() throws Exception {
+ HalClientCallback callback = mock(HalClientCallback.class);
+ android.hardware.automotive.vehicle.V2_0.IVehicleCallback.Stub hidlCallback =
+ mHidlVehicleStub.newCallback(callback).getHidlCallback();
+ VehiclePropError error = new VehiclePropError();
+ error.propId = TEST_PROP;
+ error.areaId = TEST_AREA;
+ error.errorCode = TEST_STATUS;
+
+ hidlCallback.onPropertySetError(TEST_STATUS, TEST_PROP, TEST_AREA);
+
+ verify(callback).onPropertySetError(new ArrayList<VehiclePropError>(Arrays.asList(error)));
+ }
+}