Merge changes I2e938c7a,I7271a609,I2330bb21 into main
* changes:
Add toString method to VehicleProperty enum.
Add binder lifecycle monitor.
Implement supported value change callback.
diff --git a/automotive/vehicle/aidl/impl/current/utils/test_vendor_properties/android/hardware/automotive/vehicle/TestVendorProperty.aidl b/automotive/vehicle/aidl/impl/current/utils/test_vendor_properties/android/hardware/automotive/vehicle/TestVendorProperty.aidl
index 3c877fa..217387f 100644
--- a/automotive/vehicle/aidl/impl/current/utils/test_vendor_properties/android/hardware/automotive/vehicle/TestVendorProperty.aidl
+++ b/automotive/vehicle/aidl/impl/current/utils/test_vendor_properties/android/hardware/automotive/vehicle/TestVendorProperty.aidl
@@ -19,6 +19,7 @@
/**
* Test vendor properties used in reference VHAL implementation.
*/
+@JavaDerive(toString=true)
@Backing(type="int")
enum TestVendorProperty {
diff --git a/automotive/vehicle/aidl/impl/current/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/current/vhal/include/ConnectedClient.h
index addc901..335f5c0 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/include/ConnectedClient.h
+++ b/automotive/vehicle/aidl/impl/current/vhal/include/ConnectedClient.h
@@ -116,6 +116,10 @@
CallbackType callback,
std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>&&
vehiclePropErrors);
+
+ // Invokes onSupportedValueChange callback.
+ static void sendSupportedValueChangeEvents(CallbackType callback,
+ std::vector<PropIdAreaId> propIdAreaIds);
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/current/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/current/vhal/include/DefaultVehicleHal.h
index 02dbe9e..42902fe 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/current/vhal/include/DefaultVehicleHal.h
@@ -255,6 +255,10 @@
const std::weak_ptr<SubscriptionManager>& subscriptionManager,
const std::vector<SetValueErrorEvent>& errorEvents);
+ static void onSupportedValueChange(
+ const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+ const std::vector<PropIdAreaId>& updatedPropIdAreaIds);
+
static void checkHealth(IVehicleHardware* hardware,
std::weak_ptr<SubscriptionManager> subscriptionManager);
diff --git a/automotive/vehicle/aidl/impl/current/vhal/include/SubscriptionManager.h b/automotive/vehicle/aidl/impl/current/vhal/include/SubscriptionManager.h
index 59c21aa..fa438ec 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/include/SubscriptionManager.h
+++ b/automotive/vehicle/aidl/impl/current/vhal/include/SubscriptionManager.h
@@ -118,6 +118,11 @@
std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>>
getSubscribedClientsForErrorEvents(const std::vector<SetValueErrorEvent>& errorEvents);
+ // For a list of [propId, areaId]s that has updated supported value, returns a map that maps
+ // subscribing clients to updated [propId, areaId]s.
+ std::unordered_map<CallbackType, std::vector<PropIdAreaId>>
+ getSubscribedClientsForSupportedValueChange(const std::vector<PropIdAreaId>& propIdAreaIds);
+
// Subscribes to supported values change.
VhalResult<void> subscribeSupportedValueChange(const CallbackType& callback,
const std::vector<PropIdAreaId>& propIdAreaIds);
diff --git a/automotive/vehicle/aidl/impl/current/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/current/vhal/src/ConnectedClient.cpp
index 35b93d2..ac2691a 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/src/ConnectedClient.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/src/ConnectedClient.cpp
@@ -306,6 +306,30 @@
}
}
+void SubscriptionClient::sendSupportedValueChangeEvents(std::shared_ptr<IVehicleCallback> callback,
+ std::vector<PropIdAreaId> propIdAreaIds) {
+ if (propIdAreaIds.empty()) {
+ return;
+ }
+
+ std::vector<aidl::android::hardware::automotive::vehicle::PropIdAreaId> vhalPropIdAreaIds;
+ for (const auto& propIdAreaId : propIdAreaIds) {
+ vhalPropIdAreaIds.push_back(aidl::android::hardware::automotive::vehicle::PropIdAreaId{
+ .propId = propIdAreaId.propId,
+ .areaId = propIdAreaId.areaId,
+ });
+ }
+
+ if (ScopedAStatus callbackStatus = callback->onSupportedValueChange(vhalPropIdAreaIds);
+ !callbackStatus.isOk()) {
+ ALOGE("subscribe: failed to call onSupportedValueChange callback, client ID: %p, error: "
+ "%s, "
+ "exception: %d, service specific error: %d",
+ callback->asBinder().get(), callbackStatus.getMessage(),
+ callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
+ }
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/current/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/current/vhal/src/DefaultVehicleHal.cpp
index 25af50e..050f88d 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/src/DefaultVehicleHal.cpp
@@ -160,6 +160,11 @@
[subscriptionManagerCopy](std::vector<SetValueErrorEvent> errorEvents) {
onPropertySetErrorEvent(subscriptionManagerCopy, errorEvents);
}));
+ mVehicleHardware->registerSupportedValueChangeCallback(
+ std::make_unique<IVehicleHardware::SupportedValueChangeCallback>(
+ [subscriptionManagerCopy](std::vector<PropIdAreaId> propIdAreaIds) {
+ onSupportedValueChange(subscriptionManagerCopy, propIdAreaIds);
+ }));
// Register heartbeat event.
mRecurrentAction = std::make_shared<std::function<void()>>(
@@ -207,7 +212,8 @@
std::vector<VehiclePropValue>&& updatedValues) {
auto batchedEventQueueStrong = batchedEventQueue.lock();
if (batchedEventQueueStrong == nullptr) {
- ALOGW("the batched property events queue is destroyed, DefaultVehicleHal is ending");
+ ALOGW("%s: the batched property events queue is destroyed, DefaultVehicleHal is ending",
+ __func__);
return;
}
batchedEventQueueStrong->push(std::move(updatedValues));
@@ -223,7 +229,7 @@
ATRACE_CALL();
auto manager = subscriptionManager.lock();
if (manager == nullptr) {
- ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending");
+ ALOGW("%s: the SubscriptionManager is destroyed, DefaultVehicleHal is ending", __func__);
return;
}
auto updatedValuesByClients = manager->getSubscribedClients(std::move(updatedValues));
@@ -237,7 +243,7 @@
const std::vector<SetValueErrorEvent>& errorEvents) {
auto manager = subscriptionManager.lock();
if (manager == nullptr) {
- ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending");
+ ALOGW("%s: the SubscriptionManager is destroyed, DefaultVehicleHal is ending", __func__);
return;
}
auto vehiclePropErrorsByClient = manager->getSubscribedClientsForErrorEvents(errorEvents);
@@ -246,6 +252,22 @@
}
}
+void DefaultVehicleHal::onSupportedValueChange(
+ const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+ const std::vector<PropIdAreaId>& propIdAreaIds) {
+ auto manager = subscriptionManager.lock();
+ if (manager == nullptr) {
+ ALOGW("%s: the SubscriptionManager is destroyed, DefaultVehicleHal is ending", __func__);
+ return;
+ }
+ auto updatedPropIdAreaIdsByClient =
+ manager->getSubscribedClientsForSupportedValueChange(propIdAreaIds);
+ for (auto& [callback, updatedPropIdAreaIds] : updatedPropIdAreaIdsByClient) {
+ SubscriptionClient::sendSupportedValueChangeEvents(callback,
+ std::move(updatedPropIdAreaIds));
+ }
+}
+
template <class T>
std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
@@ -931,7 +953,9 @@
}
{
- // Lock to make sure onBinderDied would not be called concurrently.
+ // Lock to make sure onBinderDied would not be called concurrently
+ // (before subscribe). Without this, we may create a new subscription for an already dead
+ // client which will never be unsubscribed.
std::scoped_lock lockGuard(mLock);
if (!monitorBinderLifeCycleLocked(callback->asBinder().get())) {
return ScopedAStatus::fromExceptionCodeWithMessage(EX_TRANSACTION_FAILED,
@@ -1156,14 +1180,24 @@
if (propIdAreaIdsToSubscribe.empty()) {
return ScopedAStatus::ok();
}
- auto result =
- mSubscriptionManager->subscribeSupportedValueChange(callback, propIdAreaIdsToSubscribe);
- if (!result.ok()) {
- ALOGW("registerSupportedValueChangeCallback: failed to subscribe supported value change"
- " for %s, error: %s",
- fmt::format("{}", propIdAreaIdsToSubscribe).c_str(),
- result.error().message().c_str());
- return toScopedAStatus(result);
+ {
+ // Lock to make sure onBinderDied would not be called concurrently
+ // (before subscribeSupportedValueChange). Without this, we may create a new subscription
+ // for an already dead client which will never be unsubscribed.
+ std::scoped_lock lockGuard(mLock);
+ if (!monitorBinderLifeCycleLocked(callback->asBinder().get())) {
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_TRANSACTION_FAILED,
+ "client died");
+ }
+ auto result = mSubscriptionManager->subscribeSupportedValueChange(callback,
+ propIdAreaIdsToSubscribe);
+ if (!result.ok()) {
+ ALOGW("registerSupportedValueChangeCallback: failed to subscribe supported value change"
+ " for %s, error: %s",
+ fmt::format("{}", propIdAreaIdsToSubscribe).c_str(),
+ result.error().message().c_str());
+ return toScopedAStatus(result);
+ }
}
return ScopedAStatus::ok();
}
diff --git a/automotive/vehicle/aidl/impl/current/vhal/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/current/vhal/src/SubscriptionManager.cpp
index f790033..946c217 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/src/SubscriptionManager.cpp
@@ -414,6 +414,7 @@
std::scoped_lock<std::mutex> lockGuard(mLock);
ClientIdType clientId = callback->asBinder().get();
+ ALOGE("ClientId: %p", clientId);
// It is possible that some of the [propId, areaId]s are already subscribed, IVehicleHardware
// will ignore them.
@@ -581,6 +582,25 @@
return clients;
}
+std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<PropIdAreaId>>
+SubscriptionManager::getSubscribedClientsForSupportedValueChange(
+ const std::vector<PropIdAreaId>& propIdAreaIds) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<PropIdAreaId>>
+ propIdAreaIdsByClient;
+
+ for (const auto& propIdAreaId : propIdAreaIds) {
+ const auto clientIter = mSupportedValueChangeClientsByPropIdAreaId.find(propIdAreaId);
+ if (clientIter == mSupportedValueChangeClientsByPropIdAreaId.end()) {
+ continue;
+ }
+ for (const auto& [_, client] : clientIter->second) {
+ propIdAreaIdsByClient[client].push_back(propIdAreaId);
+ }
+ }
+ return propIdAreaIdsByClient;
+}
+
bool SubscriptionManager::isEmpty() {
std::scoped_lock<std::mutex> lockGuard(mLock);
return mSubscribedPropsByClient.empty() && mClientsByPropIdAreaId.empty() &&
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/current/vhal/test/DefaultVehicleHalTest.cpp
index 0526f7d..90b34c4 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/DefaultVehicleHalTest.cpp
@@ -272,6 +272,10 @@
void SetUp() override { init(std::make_unique<MockVehicleHardware>()); }
void init(std::unique_ptr<MockVehicleHardware> hardware) {
+ // Default init uses the following static configs to create the mock IVehicleHardware,
+ // individual test case may use setHardware to overwrite the underlying IVehicleHardware
+ // to use a different set of configs.
+
std::vector<VehiclePropConfig> testConfigs;
for (size_t i = 0; i < 10000; i++) {
testConfigs.push_back(VehiclePropConfig{
@@ -420,18 +424,8 @@
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
});
hardware->setPropertyConfigs(testConfigs);
- mHardwarePtr = hardware.get();
- mVhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
- mVhalClient = IVehicle::fromBinder(mVhal->asBinder());
- mCallback = ndk::SharedRefBase::make<MockVehicleCallback>();
- // Keep the local binder alive.
- mBinder = mCallback->asBinder();
- mCallbackClient = IVehicleCallback::fromBinder(mBinder);
- // Set the linkToDeath to a fake implementation that always returns OK.
- auto handler = std::make_unique<TestBinderLifecycleHandler>();
- mBinderLifecycleHandler = handler.get();
- mVhal->setBinderLifecycleHandler(std::move(handler));
+ setHardware(std::move(hardware));
}
void TearDown() override {
@@ -548,6 +542,33 @@
return {};
}
+ protected:
+ // Sets the underlying IVehicleHardware and recreates the DefaultVehicleHal objects under test.
+ // If used, caller should call this at the beginning of the test case.
+ void setHardware(std::unique_ptr<MockVehicleHardware> hardware) {
+ setHardware(std::move(hardware), 0);
+ }
+
+ void setHardware(std::unique_ptr<MockVehicleHardware> hardware, int32_t testInterfaceVersion) {
+ mHardwarePtr = hardware.get();
+ if (testInterfaceVersion == 0) {
+ mVhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
+ } else {
+ mVhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware),
+ testInterfaceVersion);
+ }
+ // Set the linkToDeath to a fake implementation that always returns OK.
+ auto handler = std::make_unique<TestBinderLifecycleHandler>();
+ mBinderLifecycleHandler = handler.get();
+ mVhal->setBinderLifecycleHandler(std::move(handler));
+
+ mVhalClient = IVehicle::fromBinder(mVhal->asBinder());
+ mCallback = ndk::SharedRefBase::make<MockVehicleCallback>();
+ // Keep the local binder alive.
+ mBinder = mCallback->asBinder();
+ mCallbackClient = IVehicleCallback::fromBinder(mBinder);
+ }
+
private:
class TestBinderLifecycleHandler final : public DefaultVehicleHal::BinderLifecycleInterface {
public:
@@ -588,11 +609,10 @@
auto hardware = std::make_unique<MockVehicleHardware>();
hardware->setPropertyConfigs(testConfigs);
- auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
- std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+ setHardware(std::move(hardware));
VehiclePropConfigs output;
- auto status = client->getAllPropConfigs(&output);
+ auto status = getClient()->getAllPropConfigs(&output);
ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
ASSERT_THAT(output.payloads, WhenSortedBy(propConfigCmp, Eq(testConfigs)));
@@ -609,11 +629,10 @@
auto hardware = std::make_unique<MockVehicleHardware>();
hardware->setPropertyConfigs(testConfigs);
- auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
- std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+ setHardware(std::move(hardware));
VehiclePropConfigs output;
- auto status = client->getAllPropConfigs(&output);
+ auto status = getClient()->getAllPropConfigs(&output);
ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
ASSERT_TRUE(output.payloads.empty());
@@ -637,12 +656,10 @@
auto hardware = std::make_unique<MockVehicleHardware>();
hardware->setPropertyConfigs(testConfigs);
- auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware),
- /* testInterfaceVersion= */ 2);
- std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+ setHardware(std::move(hardware), /* testInterfaceVersion= */ 2);
VehiclePropConfigs output;
- auto status = client->getAllPropConfigs(&output);
+ auto status = getClient()->getAllPropConfigs(&output);
ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
ASSERT_THAT(output.payloads, ElementsAre(VehiclePropConfig{
@@ -666,15 +683,14 @@
hardware->setPropertyConfigs(testConfigs);
// Store the pointer for testing. We are sure it is valid.
MockVehicleHardware* hardwarePtr = hardware.get();
- auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
- std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+ setHardware(std::move(hardware));
VehiclePropConfigs output;
- auto status = client->getPropConfigs(std::vector<int32_t>({propId1, propId2}), &output);
+ auto status = getClient()->getPropConfigs(std::vector<int32_t>({propId1, propId2}), &output);
ASSERT_TRUE(status.isOk()) << "getPropConfigs failed: " << status.getMessage();
ASSERT_EQ(output.payloads, testConfigs);
- ASSERT_FALSE(hardwarePtr->getAllPropertyConfigsCalled());
+ ASSERT_FALSE(getHardware()->getAllPropertyConfigsCalled());
}
TEST_F(DefaultVehicleHalTest, testGetPropConfigsInvalidArg) {
@@ -689,11 +705,10 @@
auto hardware = std::make_unique<MockVehicleHardware>();
hardware->setPropertyConfigs(testConfigs);
- auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
- std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+ setHardware(std::move(hardware));
VehiclePropConfigs output;
- auto status = client->getPropConfigs(
+ auto status = getClient()->getPropConfigs(
std::vector<int32_t>({testInt32VecProp(1), testInt32VecProp(2), testInt32VecProp(3)}),
&output);
@@ -2187,8 +2202,7 @@
auto response = std::vector<SupportedValuesListResult>({resultFromHardware});
hardware->setSupportedValuesListResponse(response);
- auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
- std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+ setHardware(std::move(hardware));
SupportedValuesListResults results;
@@ -2196,14 +2210,14 @@
auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
auto propIdAreaId3 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(3), .areaId = 0};
auto propIdAreaId4 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(4), .areaId = 4};
- auto status = vhal->getSupportedValuesLists(
+ auto status = getClient()->getSupportedValuesLists(
std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2, propIdAreaId3,
propIdAreaId4},
&results);
ASSERT_TRUE(status.isOk()) << "Get non-okay status from getSupportedValuesLists"
<< status.getMessage();
- ASSERT_THAT(hardwarePtr->getSupportedValuesListRequest(),
+ ASSERT_THAT(getHardware()->getSupportedValuesListRequest(),
ElementsAre(PropIdAreaId{.propId = testInt32VecWindowProp(4), .areaId = 4}))
<< "Only valid request 4 should get to hardware";
@@ -2250,8 +2264,7 @@
auto hardware = std::make_unique<MockVehicleHardware>();
hardware->setPropertyConfigs(testConfigs);
- auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
- std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+ setHardware(std::move(hardware));
SupportedValuesListResults results;
@@ -2260,7 +2273,7 @@
// areaId not valid.
auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(1), .areaId = 2};
- auto status = vhal->getSupportedValuesLists(
+ auto status = getClient()->getSupportedValuesLists(
std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2}, &results);
ASSERT_TRUE(status.isOk()) << "Get non-okay status from getSupportedValuesLists"
@@ -2328,8 +2341,7 @@
auto response = std::vector<MinMaxSupportedValueResult>({resultFromHardware});
hardware->setMinMaxSupportedValueResponse(response);
- auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
- std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+ setHardware(std::move(hardware));
MinMaxSupportedValueResults results;
@@ -2337,14 +2349,14 @@
auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
auto propIdAreaId3 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(3), .areaId = 0};
auto propIdAreaId4 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(4), .areaId = 4};
- auto status = vhal->getMinMaxSupportedValue(
+ auto status = getClient()->getMinMaxSupportedValue(
std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2, propIdAreaId3,
propIdAreaId4},
&results);
ASSERT_TRUE(status.isOk()) << "Get non-okay status from getMinMaxSupportedValue"
<< status.getMessage();
- ASSERT_THAT(hardwarePtr->getMinMaxSupportedValueRequest(),
+ ASSERT_THAT(getHardware()->getMinMaxSupportedValueRequest(),
ElementsAre(PropIdAreaId{.propId = testInt32VecWindowProp(4), .areaId = 4}))
<< "Only valid request 4 should get to hardware";
@@ -2396,8 +2408,7 @@
auto hardware = std::make_unique<MockVehicleHardware>();
hardware->setPropertyConfigs(testConfigs);
- auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
- std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+ setHardware(std::move(hardware));
MinMaxSupportedValueResults results;
@@ -2406,7 +2417,7 @@
// areaId not valid.
auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(1), .areaId = 2};
- auto status = vhal->getMinMaxSupportedValue(
+ auto status = getClient()->getMinMaxSupportedValue(
std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2}, &results);
ASSERT_TRUE(status.isOk()) << "Get non-okay status from getMinMaxSupportedValue"
@@ -2448,22 +2459,21 @@
}});
auto hardware = std::make_unique<MockVehicleHardware>();
- MockVehicleHardware* hardwarePtr = hardware.get();
hardware->setPropertyConfigs(testConfigs);
- auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
- std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+ setHardware(std::move(hardware));
// This request is ignored because it does not have supported value info.
auto propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
- auto status = client->registerSupportedValueChangeCallback(
+ auto status = getClient()->registerSupportedValueChangeCallback(
getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2});
ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
<< status.getMessage();
- ASSERT_THAT(hardwarePtr->getSubscribedSupportedValueChangePropIdAreaIds(),
- ElementsAre(PropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2}));
+ ASSERT_THAT(
+ getHardware()->getSubscribedSupportedValueChangePropIdAreaIds(),
+ UnorderedElementsAre(PropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2}));
}
TEST_F(DefaultVehicleHalTest, testRegisterSupportedValueChangeCallback_invalidRequest) {
@@ -2477,11 +2487,10 @@
auto hardware = std::make_unique<MockVehicleHardware>();
hardware->setPropertyConfigs(testConfigs);
- auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
- std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+ setHardware(std::move(hardware));
auto propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
- auto status = client->registerSupportedValueChangeCallback(
+ auto status = getClient()->registerSupportedValueChangeCallback(
getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId1});
ASSERT_FALSE(status.isOk()) << "registerSupportedValueChangeCallback must return error if one "
@@ -2508,11 +2517,10 @@
hardware->setStatus("subscribeSupportedValueChange", StatusCode::INTERNAL_ERROR);
hardware->setPropertyConfigs(testConfigs);
- auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
- std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+ setHardware(std::move(hardware));
auto propIdAreaId = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
- auto status = client->registerSupportedValueChangeCallback(
+ auto status = getClient()->registerSupportedValueChangeCallback(
getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId});
ASSERT_FALSE(status.isOk()) << "registerSupportedValueChangeCallback must return error if "
@@ -2549,30 +2557,63 @@
}});
auto hardware = std::make_unique<MockVehicleHardware>();
- MockVehicleHardware* hardwarePtr = hardware.get();
hardware->setPropertyConfigs(testConfigs);
- auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
- std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+ setHardware(std::move(hardware));
auto propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
- auto status = client->registerSupportedValueChangeCallback(
+ auto status = getClient()->registerSupportedValueChangeCallback(
getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2});
ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
<< status.getMessage();
- status = client->unregisterSupportedValueChangeCallback(
+ status = getClient()->unregisterSupportedValueChangeCallback(
getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2});
ASSERT_TRUE(status.isOk()) << "Get non-okay status from unregisterSupportedValueChangeCallback"
<< status.getMessage();
- ASSERT_TRUE(hardwarePtr->getSubscribedSupportedValueChangePropIdAreaIds().empty())
+ ASSERT_TRUE(getHardware()->getSubscribedSupportedValueChangePropIdAreaIds().empty())
<< "All registered [propId, areaId]s must be unregistered";
}
+TEST_F(DefaultVehicleHalTest, testUnregisterSupportedValueChangeCallback_errorFromHardware) {
+ auto testConfigs = std::vector<VehiclePropConfig>({VehiclePropConfig{
+ .prop = testInt32VecProp(1),
+ .areaConfigs =
+ {
+ {.areaId = 0,
+ .hasSupportedValueInfo =
+ HasSupportedValueInfo{
+ .hasMinSupportedValue = false,
+ .hasMaxSupportedValue = false,
+ .hasSupportedValuesList = true,
+ }},
+ },
+ }});
+
+ auto hardware = std::make_unique<MockVehicleHardware>();
+ hardware->setStatus("unsubscribeSupportedValueChange", StatusCode::INTERNAL_ERROR);
+ hardware->setPropertyConfigs(testConfigs);
+
+ setHardware(std::move(hardware));
+
+ auto propIdAreaId = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+ auto status = getClient()->registerSupportedValueChangeCallback(
+ getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId});
+
+ ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
+ << status.getMessage();
+
+ status = getClient()->unregisterSupportedValueChangeCallback(
+ getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId});
+
+ ASSERT_FALSE(status.isOk()) << "unregisterSupportedValueChangeCallback must return error if "
+ "VehicleHardware returns error";
+}
+
TEST_F(DefaultVehicleHalTest, testUnregisterSupportedValueChangeCallback_ignoreUnregistered) {
auto testConfigs = std::vector<VehiclePropConfig>(
{VehiclePropConfig{
@@ -2603,20 +2644,245 @@
}});
auto hardware = std::make_unique<MockVehicleHardware>();
- MockVehicleHardware* hardwarePtr = hardware.get();
hardware->setPropertyConfigs(testConfigs);
- auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
- std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+ setHardware(std::move(hardware));
auto propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
- auto status = client->unregisterSupportedValueChangeCallback(
+ auto status = getClient()->unregisterSupportedValueChangeCallback(
getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2});
ASSERT_TRUE(status.isOk());
}
+TEST_F(DefaultVehicleHalTest, testSupportedValueChangeCallback) {
+ auto testConfigs = std::vector<VehiclePropConfig>(
+ {VehiclePropConfig{
+ .prop = testInt32VecProp(1),
+ .areaConfigs =
+ {
+ {.areaId = 0,
+ .hasSupportedValueInfo =
+ HasSupportedValueInfo{
+ .hasMinSupportedValue = false,
+ .hasMaxSupportedValue = false,
+ .hasSupportedValuesList = true,
+ }},
+ },
+ },
+ VehiclePropConfig{
+ .prop = testInt32VecWindowProp(2),
+ .areaConfigs =
+ {
+ {.areaId = 2,
+ .hasSupportedValueInfo =
+ HasSupportedValueInfo{
+ .hasMinSupportedValue = true,
+ .hasMaxSupportedValue = false,
+ .hasSupportedValuesList = false,
+ }},
+ },
+ }});
+
+ auto hardware = std::make_unique<MockVehicleHardware>();
+ hardware->setPropertyConfigs(testConfigs);
+
+ setHardware(std::move(hardware));
+
+ auto vhalPropIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+ auto vhalPropIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
+ auto propIdAreaId1 = PropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+ auto propIdAreaId2 = PropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
+ auto status = getClient()->registerSupportedValueChangeCallback(
+ getCallbackClient(),
+ std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
+
+ ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
+ << status.getMessage();
+
+ getHardware()->sendSupportedValueChangeEvent(
+ std::vector<PropIdAreaId>{propIdAreaId1, propIdAreaId2});
+
+ getCallback()->waitForOnSupportedValueChange(/*size=*/2, /*timeoutInNano=*/1'000'000'000);
+
+ ASSERT_THAT(getCallback()->getOnSupportedValueChangePropIdAreaIds(),
+ ElementsAre(vhalPropIdAreaId1, vhalPropIdAreaId2));
+}
+
+TEST_F(DefaultVehicleHalTest, testSupportedValueChangeCallback_unregister) {
+ auto testConfigs = std::vector<VehiclePropConfig>(
+ {VehiclePropConfig{
+ .prop = testInt32VecProp(1),
+ .areaConfigs =
+ {
+ {.areaId = 0,
+ .hasSupportedValueInfo =
+ HasSupportedValueInfo{
+ .hasMinSupportedValue = false,
+ .hasMaxSupportedValue = false,
+ .hasSupportedValuesList = true,
+ }},
+ },
+ },
+ VehiclePropConfig{
+ .prop = testInt32VecWindowProp(2),
+ .areaConfigs =
+ {
+ {.areaId = 2,
+ .hasSupportedValueInfo =
+ HasSupportedValueInfo{
+ .hasMinSupportedValue = true,
+ .hasMaxSupportedValue = false,
+ .hasSupportedValuesList = false,
+ }},
+ },
+ }});
+
+ auto hardware = std::make_unique<MockVehicleHardware>();
+ hardware->setPropertyConfigs(testConfigs);
+
+ setHardware(std::move(hardware));
+
+ auto vhalPropIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+ auto vhalPropIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
+ auto propIdAreaId1 = PropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+ auto propIdAreaId2 = PropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
+ auto status = getClient()->registerSupportedValueChangeCallback(
+ getCallbackClient(),
+ std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
+
+ ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
+ << status.getMessage();
+
+ // After unregistering for propIdAreaId1, we should no longer receive events for it.
+ status = getClient()->unregisterSupportedValueChangeCallback(
+ getCallbackClient(), std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1});
+
+ ASSERT_TRUE(status.isOk()) << "Get non-okay status from unregisterSupportedValueChangeCallback"
+ << status.getMessage();
+
+ getHardware()->sendSupportedValueChangeEvent(
+ std::vector<PropIdAreaId>{propIdAreaId1, propIdAreaId2});
+
+ getCallback()->waitForOnSupportedValueChange(/*size=*/1, /*timeoutInNano=*/1'000'000'000);
+
+ ASSERT_THAT(getCallback()->getOnSupportedValueChangePropIdAreaIds(),
+ ElementsAre(vhalPropIdAreaId2));
+}
+
+TEST_F(DefaultVehicleHalTest, testRegisterSupportedValueChangeCallback_twoClients) {
+ auto testConfigs = std::vector<VehiclePropConfig>(
+ {VehiclePropConfig{
+ .prop = testInt32VecProp(1),
+ .areaConfigs =
+ {
+ {.areaId = 0,
+ .hasSupportedValueInfo =
+ HasSupportedValueInfo{
+ .hasMinSupportedValue = false,
+ .hasMaxSupportedValue = false,
+ .hasSupportedValuesList = true,
+ }},
+ },
+ },
+ VehiclePropConfig{
+ .prop = testInt32VecWindowProp(2),
+ .areaConfigs =
+ {
+ {.areaId = 2,
+ .hasSupportedValueInfo =
+ HasSupportedValueInfo{
+ .hasMinSupportedValue = true,
+ .hasMaxSupportedValue = false,
+ .hasSupportedValuesList = false,
+ }},
+ },
+ }});
+
+ auto hardware = std::make_unique<MockVehicleHardware>();
+ hardware->setPropertyConfigs(testConfigs);
+
+ setHardware(std::move(hardware));
+
+ auto vhalPropIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+ auto vhalPropIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
+ auto propIdAreaId1 = PropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+ auto propIdAreaId2 = PropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
+ std::shared_ptr<IVehicleCallback> callback1 = ndk::SharedRefBase::make<MockVehicleCallback>();
+ std::shared_ptr<IVehicleCallback> callback2 = ndk::SharedRefBase::make<MockVehicleCallback>();
+ // Keep binder alive to prevent binder reuse.
+ SpAIBinder binder1 = callback1->asBinder();
+ // Keep binder alive to prevent binder reuse.
+ SpAIBinder binder2 = callback2->asBinder();
+
+ auto status = getClient()->registerSupportedValueChangeCallback(
+ callback1, std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
+
+ ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
+ << status.getMessage();
+
+ status = getClient()->registerSupportedValueChangeCallback(
+ callback2, std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
+
+ ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
+ << status.getMessage();
+
+ ASSERT_THAT(getHardware()->getSubscribedSupportedValueChangePropIdAreaIds(),
+ UnorderedElementsAre(propIdAreaId1, propIdAreaId2));
+
+ status = getClient()->unregisterSupportedValueChangeCallback(
+ callback1, std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
+
+ ASSERT_TRUE(status.isOk()) << "Get non-okay status from unregisterSupportedValueChangeCallback"
+ << status.getMessage();
+
+ ASSERT_THAT(getHardware()->getSubscribedSupportedValueChangePropIdAreaIds(),
+ UnorderedElementsAre(propIdAreaId1, propIdAreaId2))
+ << "[propId, areaId] must still be subscribed if one of the two clients unsubscribe";
+
+ status = getClient()->unregisterSupportedValueChangeCallback(
+ callback2, std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
+
+ ASSERT_TRUE(status.isOk()) << "Get non-okay status from unregisterSupportedValueChangeCallback"
+ << status.getMessage();
+
+ ASSERT_TRUE(getHardware()->getSubscribedSupportedValueChangePropIdAreaIds().empty())
+ << "All registered [propId, areaId]s must be unregistered";
+}
+
+TEST_F(DefaultVehicleHalTest, testRegisterSupportedValueChange_monitorBinderLifecycle) {
+ auto testConfigs = std::vector<VehiclePropConfig>({VehiclePropConfig{
+ .prop = testInt32VecProp(1),
+ .areaConfigs =
+ {
+ {.areaId = 0,
+ .hasSupportedValueInfo =
+ HasSupportedValueInfo{
+ .hasMinSupportedValue = false,
+ .hasMaxSupportedValue = false,
+ .hasSupportedValuesList = true,
+ }},
+ },
+ }});
+
+ auto hardware = std::make_unique<MockVehicleHardware>();
+ hardware->setPropertyConfigs(testConfigs);
+
+ setHardware(std::move(hardware));
+
+ auto vhalPropIdAreaId = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+
+ auto status = getClient()->registerSupportedValueChangeCallback(
+ getCallbackClient(), std::vector<VhalPropIdAreaId>{vhalPropIdAreaId});
+
+ ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
+ << status.getMessage();
+
+ ASSERT_EQ(countOnBinderDiedContexts(), static_cast<size_t>(1))
+ << "expect one OnBinderDied context when one client is registered";
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.cpp b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.cpp
index 72c5dc5..a557b05 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.cpp
@@ -92,9 +92,14 @@
return result;
}
-ScopedAStatus MockVehicleCallback::onSupportedValueChange(const std::vector<PropIdAreaId>&) {
- // TODO(b/381020465): Add relevant implementation.
- return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ScopedAStatus MockVehicleCallback::onSupportedValueChange(
+ const std::vector<PropIdAreaId>& propIdAreaIds) {
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mOnSupportedValueChangePropIdAreaIds = propIdAreaIds;
+ }
+ mCond.notify_all();
+ return ScopedAStatus::ok();
}
std::optional<GetValueResults> MockVehicleCallback::nextGetValueResults() {
@@ -151,6 +156,19 @@
});
}
+bool MockVehicleCallback::waitForOnSupportedValueChange(size_t size, size_t timeoutInNano) {
+ std::unique_lock lk(mLock);
+ return mCond.wait_for(lk, std::chrono::nanoseconds(timeoutInNano), [this, size] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mOnSupportedValueChangePropIdAreaIds.size() >= size;
+ });
+}
+
+std::vector<PropIdAreaId> MockVehicleCallback::getOnSupportedValueChangePropIdAreaIds() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return mOnSupportedValueChangePropIdAreaIds;
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.h b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.h
index 81a85ff..be181a5 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.h
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.h
@@ -73,6 +73,9 @@
bool waitForSetValueResults(size_t size, size_t timeoutInNano);
bool waitForGetValueResults(size_t size, size_t timeoutInNano);
bool waitForOnPropertyEventResults(size_t size, size_t timeoutInNano);
+ bool waitForOnSupportedValueChange(size_t size, size_t timeoutInNano);
+ std::vector<aidl::android::hardware::automotive::vehicle::PropIdAreaId>
+ getOnSupportedValueChangePropIdAreaIds();
private:
std::mutex mLock;
@@ -86,6 +89,8 @@
int32_t mSharedMemoryFileCount GUARDED_BY(mLock);
std::list<aidl::android::hardware::automotive::vehicle::VehiclePropErrors>
mOnPropertySetErrorResults GUARDED_BY(mLock);
+ std::vector<aidl::android::hardware::automotive::vehicle::PropIdAreaId>
+ mOnSupportedValueChangePropIdAreaIds GUARDED_BY(mLock);
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.cpp
index 11f1835..197e99d 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.cpp
@@ -228,6 +228,12 @@
mPropertySetErrorCallback = std::move(callback);
}
+void MockVehicleHardware::registerSupportedValueChangeCallback(
+ std::unique_ptr<const SupportedValueChangeCallback> callback) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mSupportedValueChangeCallback = std::move(callback);
+}
+
void MockVehicleHardware::setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
std::scoped_lock<std::mutex> lockGuard(mLock);
mPropertyConfigs = configs;
@@ -419,6 +425,12 @@
(*mPropertySetErrorCallback)(errorEvents);
}
+void MockVehicleHardware::sendSupportedValueChangeEvent(
+ const std::vector<PropIdAreaId>& propIdAreaIds) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ (*mSupportedValueChangeCallback)(propIdAreaIds);
+}
+
bool MockVehicleHardware::getAllPropertyConfigsCalled() {
std::scoped_lock<std::mutex> lockGuard(mLock);
return mGetAllPropertyConfigsCalled;
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.h
index e7359db..444166b 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.h
@@ -62,6 +62,8 @@
void registerOnPropertyChangeEvent(
std::unique_ptr<const PropertyChangeCallback> callback) override;
void registerOnPropertySetErrorEvent(std::unique_ptr<const PropertySetErrorCallback>) override;
+ void registerSupportedValueChangeCallback(
+ std::unique_ptr<const SupportedValueChangeCallback>) override;
aidl::android::hardware::automotive::vehicle::StatusCode subscribe(
aidl::android::hardware::automotive::vehicle::SubscribeOptions options) override;
aidl::android::hardware::automotive::vehicle::StatusCode unsubscribe(int32_t propId,
@@ -112,6 +114,7 @@
void setDumpResult(DumpResult result);
void sendOnPropertySetErrorEvent(const std::vector<SetValueErrorEvent>& errorEvents);
void setPropertyOnChangeEventBatchingWindow(std::chrono::nanoseconds window);
+ void sendSupportedValueChangeEvent(const std::vector<PropIdAreaId>& propIdAreaIds);
std::set<std::pair<int32_t, int32_t>> getSubscribedOnChangePropIdAreaIds();
std::set<std::pair<int32_t, int32_t>> getSubscribedContinuousPropIdAreaIds();
@@ -150,6 +153,8 @@
int64_t mSleepTime GUARDED_BY(mLock) = 0;
std::unique_ptr<const PropertyChangeCallback> mPropertyChangeCallback GUARDED_BY(mLock);
std::unique_ptr<const PropertySetErrorCallback> mPropertySetErrorCallback GUARDED_BY(mLock);
+ std::unique_ptr<const SupportedValueChangeCallback> mSupportedValueChangeCallback
+ GUARDED_BY(mLock);
std::function<aidl::android::hardware::automotive::vehicle::StatusCode(
std::shared_ptr<const GetValuesCallback>,
const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&)>
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/SubscriptionManagerTest.cpp b/automotive/vehicle/aidl/impl/current/vhal/test/SubscriptionManagerTest.cpp
index 2ac3a73..6d0844a 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/SubscriptionManagerTest.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/SubscriptionManagerTest.cpp
@@ -887,6 +887,67 @@
<< "Must filter out outdated property events if VUR is enabled";
}
+TEST_F(SubscriptionManagerTest, testSubscribeSupportedValueChange) {
+ SpAIBinder binder1 = ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+ std::shared_ptr<IVehicleCallback> client1 = IVehicleCallback::fromBinder(binder1);
+ SpAIBinder binder2 = ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+ std::shared_ptr<IVehicleCallback> client2 = IVehicleCallback::fromBinder(binder2);
+
+ PropIdAreaId propIdAreaId1 = {.propId = 0, .areaId = 0};
+ PropIdAreaId propIdAreaId2 = {.propId = 1, .areaId = 1};
+
+ auto result = getManager()->subscribeSupportedValueChange(client1, {propIdAreaId1});
+
+ ASSERT_TRUE(result.ok()) << "failed to call subscribeSupportedValueChange"
+ << result.error().message();
+
+ result = getManager()->subscribeSupportedValueChange(client2, {propIdAreaId1, propIdAreaId2});
+
+ ASSERT_TRUE(result.ok()) << "failed to call subscribeSupportedValueChange"
+ << result.error().message();
+
+ auto clients = getManager()->getSubscribedClientsForSupportedValueChange(
+ {propIdAreaId1, propIdAreaId2});
+
+ ASSERT_THAT(clients[client1], UnorderedElementsAre(propIdAreaId1))
+ << "Incorrect supported value change events for client1";
+ ASSERT_THAT(clients[client2], UnorderedElementsAre(propIdAreaId1, propIdAreaId2))
+ << "Incorrect supported value change events for client2";
+}
+
+TEST_F(SubscriptionManagerTest, testUnsubscribeSupportedValueChange) {
+ SpAIBinder binder1 = ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+ std::shared_ptr<IVehicleCallback> client1 = IVehicleCallback::fromBinder(binder1);
+ SpAIBinder binder2 = ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+ std::shared_ptr<IVehicleCallback> client2 = IVehicleCallback::fromBinder(binder2);
+
+ PropIdAreaId propIdAreaId1 = {.propId = 0, .areaId = 0};
+ PropIdAreaId propIdAreaId2 = {.propId = 1, .areaId = 1};
+
+ auto result = getManager()->subscribeSupportedValueChange(client1, {propIdAreaId1});
+
+ ASSERT_TRUE(result.ok()) << "failed to call subscribeSupportedValueChange"
+ << result.error().message();
+
+ result = getManager()->subscribeSupportedValueChange(client2, {propIdAreaId1, propIdAreaId2});
+
+ ASSERT_TRUE(result.ok()) << "failed to call subscribeSupportedValueChange"
+ << result.error().message();
+
+ result = getManager()->unsubscribeSupportedValueChange(binder2.get(), {propIdAreaId1});
+
+ ASSERT_TRUE(result.ok()) << "failed to call unsubscribeSupportedValueChange"
+ << result.error().message();
+
+ auto clients = getManager()->getSubscribedClientsForSupportedValueChange(
+ {propIdAreaId1, propIdAreaId2});
+
+ ASSERT_THAT(clients[client1], UnorderedElementsAre(propIdAreaId1))
+ << "Incorrect supported value change events for client1";
+ ASSERT_THAT(clients[client2], UnorderedElementsAre(propIdAreaId2))
+ << "Incorrect supported value change events for client2";
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 6188dd9..5abf667 100644
--- a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.automotive.vehicle;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
enum VehicleProperty {
INVALID = 0x00000000,
INFO_VIN = (((0x0100 + 0x10000000) + 0x01000000) + 0x00100000) /* 286261504 */,
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
index f96472b..7f5aeb0 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -39,6 +39,7 @@
* in response to such ill formed requests.
*/
@VintfStability
+@JavaDerive(toString=true)
@Backing(type="int")
enum VehicleProperty {
/**