/* * 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. */ #include "SubscriptionManager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace android { namespace hardware { namespace automotive { namespace vehicle { using ::aidl::android::hardware::automotive::vehicle::BnVehicleCallback; using ::aidl::android::hardware::automotive::vehicle::GetValueResults; using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback; using ::aidl::android::hardware::automotive::vehicle::SetValueResults; using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions; using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors; using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues; using ::ndk::ScopedAStatus; using ::ndk::SpAIBinder; using ::testing::Contains; using ::testing::ElementsAre; using ::testing::UnorderedElementsAre; class PropertyCallback final : public BnVehicleCallback { public: ScopedAStatus onGetValues(const GetValueResults&) override { return ScopedAStatus::ok(); } ScopedAStatus onSetValues(const SetValueResults&) override { return ScopedAStatus::ok(); } ScopedAStatus onPropertyEvent(const VehiclePropValues& values, int32_t) override { std::scoped_lock lockGuard(mLock); for (const auto& value : values.payloads) { mEvents.push_back(value); } return ScopedAStatus::ok(); } ScopedAStatus onPropertySetError(const VehiclePropErrors&) override { return ScopedAStatus::ok(); } ScopedAStatus onSupportedValueChange( const std::vector<::aidl::android::hardware::automotive::vehicle::PropIdAreaId>&) override { return ScopedAStatus::ok(); } // Test functions. std::list getEvents() { std::scoped_lock lockGuard(mLock); return mEvents; } void clearEvents() { std::scoped_lock lockGuard(mLock); mEvents.clear(); } private: std::mutex mLock; std::list mEvents GUARDED_BY(mLock); }; class SubscriptionManagerTest : public testing::Test { public: void SetUp() override { mHardware = std::make_shared(); mManager = std::make_unique(mHardware.get()); mCallback = ndk::SharedRefBase::make(); // Keep the local binder alive. mBinder = mCallback->asBinder(); mCallbackClient = IVehicleCallback::fromBinder(mBinder); std::shared_ptr callbackClient = mCallbackClient; mHardware->registerOnPropertyChangeEvent( std::make_unique( [callbackClient](std::vector updatedValues) { VehiclePropValues values = { .payloads = std::move(updatedValues), }; callbackClient->onPropertyEvent(values, 0); })); } SubscriptionManager* getManager() { return mManager.get(); } std::shared_ptr getCallbackClient() { return mCallbackClient; } PropertyCallback* getCallback() { return mCallback.get(); } std::list getEvents() { return getCallback()->getEvents(); } void clearEvents() { return getCallback()->clearEvents(); } std::shared_ptr getHardware() { return mHardware; } bool isEmpty() { return mManager->isEmpty(); } private: std::unique_ptr mManager; std::shared_ptr mCallback; std::shared_ptr mCallbackClient; std::shared_ptr mHardware; SpAIBinder mBinder; }; TEST_F(SubscriptionManagerTest, testSubscribeGlobalContinuous) { std::vector options = {{ .propId = 0, .areaIds = {0}, .sampleRate = 10.0, }}; auto result = getManager()->subscribe(getCallbackClient(), options, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); ASSERT_THAT(getHardware()->getSubscribedContinuousPropIdAreaIds(), UnorderedElementsAre(std::pair(0, 0))); std::this_thread::sleep_for(std::chrono::seconds(1)); // Theoretically trigger 10 times, but check for at least 9 times to be stable. ASSERT_GE(getEvents().size(), static_cast(9)); EXPECT_EQ(getEvents().back().prop, 0); EXPECT_EQ(getEvents().back().areaId, 0); } TEST_F(SubscriptionManagerTest, testSubscribeMultiplePropsGlobalContinuous) { std::vector options = {{ .propId = 0, .areaIds = {0}, .sampleRate = 10.0, }, { .propId = 1, .areaIds = {0}, .sampleRate = 20.0, }}; auto result = getManager()->subscribe(getCallbackClient(), options, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); std::this_thread::sleep_for(std::chrono::seconds(1)); size_t event0Count = 0; size_t event1Count = 0; for (const auto& event : getEvents()) { if (event.prop == 0) { event0Count++; } else { event1Count++; } } // Theoretically trigger 10 times, but check for at least 9 times to be stable. EXPECT_GE(event0Count, static_cast(9)); // Theoretically trigger 20 times, but check for at least 15 times to be stable. EXPECT_GE(event1Count, static_cast(15)); } TEST_F(SubscriptionManagerTest, testOverrideSubscriptionContinuous) { std::vector options = {{ .propId = 0, .areaIds = {0}, .sampleRate = 20.0, }}; auto result = getManager()->subscribe(getCallbackClient(), options, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); // Override sample rate to be 10.0. options[0].sampleRate = 10.0; result = getManager()->subscribe(getCallbackClient(), options, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); std::this_thread::sleep_for(std::chrono::seconds(1)); // Theoretically trigger 10 times, but check for at least 9 times to be stable. EXPECT_GE(getEvents().size(), static_cast(9)); EXPECT_LE(getEvents().size(), static_cast(15)); } TEST_F(SubscriptionManagerTest, testSubscribeMultipleAreasContinuous) { std::vector options = { { .propId = 0, .areaIds = {0, 1}, .sampleRate = 10.0, }, }; auto result = getManager()->subscribe(getCallbackClient(), options, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); std::this_thread::sleep_for(std::chrono::seconds(1)); size_t area0Count = 0; size_t area1Count = 0; for (const auto& event : getEvents()) { if (event.areaId == 0) { area0Count++; } else { area1Count++; } } // Theoretically trigger 10 times, but check for at least 9 times to be stable. EXPECT_GE(area0Count, static_cast(9)); // Theoretically trigger 10 times, but check for at least 9 times to be stable. EXPECT_GE(area1Count, static_cast(9)); } TEST_F(SubscriptionManagerTest, testUnsubscribeGlobalContinuous) { std::vector options = {{ .propId = 0, .areaIds = {0}, .sampleRate = 100.0, }}; auto result = getManager()->subscribe(getCallbackClient(), options, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); result = getManager()->unsubscribe(getCallbackClient()->asBinder().get()); ASSERT_TRUE(result.ok()) << "failed to unsubscribe: " << result.error().message(); ASSERT_EQ(getHardware()->getSubscribedContinuousPropIdAreaIds().size(), 0u); // Wait for the last events to come. std::this_thread::sleep_for(std::chrono::milliseconds(100)); clearEvents(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); ASSERT_TRUE(getEvents().empty()); } TEST_F(SubscriptionManagerTest, testUnsubscribeMultipleAreas) { std::vector options = { { .propId = 0, .areaIds = {0, 1, 2, 3, 4}, .sampleRate = 10.0, }, { .propId = 1, .areaIds = {0}, .sampleRate = 10.0, }, }; auto result = getManager()->subscribe(getCallbackClient(), options, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(), std::vector({0})); ASSERT_TRUE(result.ok()) << "failed to unsubscribe: " << result.error().message(); // Wait for the last events to come. std::this_thread::sleep_for(std::chrono::milliseconds(100)); clearEvents(); std::this_thread::sleep_for(std::chrono::seconds(1)); // Theoretically trigger 10 times, but check for at least 9 times to be stable. EXPECT_GE(getEvents().size(), static_cast(9)); for (const auto& event : getEvents()) { EXPECT_EQ(event.prop, 1); } } TEST_F(SubscriptionManagerTest, testUnsubscribeByCallback) { std::vector options = { { .propId = 0, .areaIds = {0, 1, 2, 3, 4}, .sampleRate = 10.0, }, { .propId = 1, .areaIds = {0}, .sampleRate = 10.0, }, }; auto result = getManager()->subscribe(getCallbackClient(), options, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); result = getManager()->unsubscribe(getCallbackClient()->asBinder().get()); ASSERT_TRUE(result.ok()) << "failed to unsubscribe: " << result.error().message(); // Wait for the last events to come. std::this_thread::sleep_for(std::chrono::milliseconds(100)); clearEvents(); std::this_thread::sleep_for(std::chrono::seconds(1)); EXPECT_TRUE(getEvents().empty()); } TEST_F(SubscriptionManagerTest, testUnsubscribeUnsubscribedPropId) { std::vector options = { { .propId = 0, .areaIds = {0, 1, 2, 3, 4}, }, { .propId = 1, .areaIds = {0}, }, }; auto result = getManager()->subscribe(getCallbackClient(), options, false); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); // Property ID: 2 was not subscribed. result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(), std::vector({0, 1, 2})); ASSERT_TRUE(result.ok()) << "unsubscribe an unsubscribed property must do nothing"; result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(), std::vector({0, 1, 2})); ASSERT_TRUE(result.ok()) << "retry an unsubscribe operation must not throw error"; std::vector updatedValues = { { .prop = 0, .areaId = 0, }, { .prop = 1, .areaId = 0, }, }; auto clients = getManager()->getSubscribedClients(std::vector(updatedValues)); ASSERT_EQ(clients.size(), 0u) << "all subscribed properties must be unsubscribed"; } TEST_F(SubscriptionManagerTest, testSubscribeOnchange) { std::vector options1 = { { .propId = 0, .areaIds = {0, 1}, }, { .propId = 1, .areaIds = {0}, }, }; std::vector options2 = { { .propId = 0, .areaIds = {0}, }, }; SpAIBinder binder1 = ndk::SharedRefBase::make()->asBinder(); std::shared_ptr client1 = IVehicleCallback::fromBinder(binder1); SpAIBinder binder2 = ndk::SharedRefBase::make()->asBinder(); std::shared_ptr client2 = IVehicleCallback::fromBinder(binder2); auto result = getManager()->subscribe(client1, options1, false); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); result = getManager()->subscribe(client2, options2, false); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); ASSERT_THAT(getHardware()->getSubscribedOnChangePropIdAreaIds(), UnorderedElementsAre(std::pair(0, 0), std::pair(0, 1), std::pair(1, 0))); ASSERT_EQ(getHardware()->getSubscribedContinuousPropIdAreaIds().size(), 0u); std::vector updatedValues = { { .prop = 0, .areaId = 0, }, { .prop = 0, .areaId = 1, }, { .prop = 1, .areaId = 0, }, { .prop = 1, .areaId = 1, }, }; auto clients = getManager()->getSubscribedClients(std::vector(updatedValues)); ASSERT_THAT(clients[client1], UnorderedElementsAre(updatedValues[0], updatedValues[1], updatedValues[2])); ASSERT_THAT(clients[client2], ElementsAre(updatedValues[0])); } TEST_F(SubscriptionManagerTest, testSubscribeInvalidOption) { std::vector options = { { .propId = 0, .areaIds = {0, 1, 2, 3, 4}, // invalid sample rate. .sampleRate = 0.0, }, { .propId = 1, .areaIds = {0}, .sampleRate = 10.0, }, }; auto result = getManager()->subscribe(getCallbackClient(), options, true); ASSERT_FALSE(result.ok()) << "subscribe with invalid sample rate must fail"; ASSERT_TRUE(getManager() ->getSubscribedClients({{ .prop = 0, .areaId = 0, }, { .prop = 1, .areaId = 0, }}) .empty()) << "no property should be subscribed if error is returned"; } TEST_F(SubscriptionManagerTest, testSubscribeNoAreaIds) { std::vector options = { { .propId = 0, .areaIds = {}, .sampleRate = 1.0, }, { .propId = 1, .areaIds = {0}, .sampleRate = 10.0, }, }; auto result = getManager()->subscribe(getCallbackClient(), options, true); ASSERT_FALSE(result.ok()) << "subscribe with invalid sample rate must fail"; ASSERT_TRUE(getManager() ->getSubscribedClients({{ .prop = 1, .areaId = 0, }}) .empty()) << "no property should be subscribed if error is returned"; } TEST_F(SubscriptionManagerTest, testUnsubscribeOnchange) { std::vector options = { { .propId = 0, .areaIds = {0, 1}, }, { .propId = 1, .areaIds = {0}, }, }; auto result = getManager()->subscribe(getCallbackClient(), options, false); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(), std::vector({0})); ASSERT_TRUE(result.ok()) << "failed to unsubscribe: " << result.error().message(); std::vector updatedValues = { { .prop = 0, .areaId = 0, }, { .prop = 1, .areaId = 0, }, }; auto clients = getManager()->getSubscribedClients(std::vector(updatedValues)); ASSERT_THAT(clients[getCallbackClient()], ElementsAre(updatedValues[1])); ASSERT_THAT(getHardware()->getSubscribedOnChangePropIdAreaIds(), UnorderedElementsAre(std::pair(1, 0))); } TEST_F(SubscriptionManagerTest, testCheckSampleRateHzValid) { ASSERT_TRUE(SubscriptionManager::checkSampleRateHz(1.0)); } TEST_F(SubscriptionManagerTest, testCheckSampleRateHzInvalidTooSmall) { ASSERT_FALSE(SubscriptionManager::checkSampleRateHz(FLT_MIN)); } TEST_F(SubscriptionManagerTest, testCheckSampleRateHzInvalidZero) { ASSERT_FALSE(SubscriptionManager::checkSampleRateHz(0)); } TEST_F(SubscriptionManagerTest, testCheckResolutionValid) { ASSERT_TRUE(SubscriptionManager::checkResolution(0.0)); ASSERT_TRUE(SubscriptionManager::checkResolution(0.1)); ASSERT_TRUE(SubscriptionManager::checkResolution(1.0)); } TEST_F(SubscriptionManagerTest, testCheckResolutionInvalid) { ASSERT_FALSE(SubscriptionManager::checkResolution(2.0)); } TEST_F(SubscriptionManagerTest, testSubscribe_enableVur) { std::vector options = {{ .propId = 0, .areaIds = {0}, .sampleRate = 10.0, .enableVariableUpdateRate = true, }}; auto result = getManager()->subscribe(getCallbackClient(), options, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); ASSERT_THAT(getHardware()->getSubscribeOptions(), ElementsAre(options[0])); } TEST_F(SubscriptionManagerTest, testSubscribe_VurStateChange) { std::vector options = {{ .propId = 0, .areaIds = {0}, .sampleRate = 10.0, .enableVariableUpdateRate = true, }}; auto result = getManager()->subscribe(getCallbackClient(), options, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); ASSERT_THAT(getHardware()->getSubscribeOptions(), ElementsAre(options[0])); getHardware()->clearSubscribeOptions(); result = getManager()->subscribe(getCallbackClient(), options, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); ASSERT_TRUE(getHardware()->getSubscribeOptions().empty()); std::vector newOptions = {{ .propId = 0, .areaIds = {0}, .sampleRate = 10.0, .enableVariableUpdateRate = false, }}; result = getManager()->subscribe(getCallbackClient(), newOptions, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); ASSERT_THAT(getHardware()->getSubscribeOptions(), ElementsAre(newOptions[0])); } TEST_F(SubscriptionManagerTest, testSubscribe_enableVur_filterUnchangedEvents) { SpAIBinder binder1 = ndk::SharedRefBase::make()->asBinder(); std::shared_ptr client1 = IVehicleCallback::fromBinder(binder1); SpAIBinder binder2 = ndk::SharedRefBase::make()->asBinder(); std::shared_ptr client2 = IVehicleCallback::fromBinder(binder2); SubscribeOptions client1Option = { .propId = 0, .areaIds = {0}, .sampleRate = 10.0, .enableVariableUpdateRate = false, }; auto result = getManager()->subscribe(client1, {client1Option}, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); ASSERT_THAT(getHardware()->getSubscribeOptions(), UnorderedElementsAre(client1Option)); getHardware()->clearSubscribeOptions(); SubscribeOptions client2Option = { .propId = 0, .areaIds = {0, 1}, .sampleRate = 20.0, .enableVariableUpdateRate = true, }; result = getManager()->subscribe(client2, {client2Option}, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); ASSERT_THAT(getHardware()->getSubscribeOptions(), UnorderedElementsAre( SubscribeOptions{ .propId = 0, .areaIds = {0}, .sampleRate = 20.0, // This is enabled for client2, but disabled for client1. .enableVariableUpdateRate = false, }, SubscribeOptions{ .propId = 0, .areaIds = {1}, .sampleRate = 20.0, .enableVariableUpdateRate = true, })); std::vector propertyEvents = {{ .prop = 0, .areaId = 0, .value = {.int32Values = {0}}, .timestamp = 1, }, { .prop = 0, .areaId = 1, .value = {.int32Values = {1}}, .timestamp = 1, }}; auto clients = getManager()->getSubscribedClients(std::vector(propertyEvents)); ASSERT_THAT(clients[client1], UnorderedElementsAre(propertyEvents[0])); ASSERT_THAT(clients[client2], UnorderedElementsAre(propertyEvents[0], propertyEvents[1])); // If the same property events happen again with a new timestamp. // VUR is disabled for client1, enabled for client2. clients = getManager()->getSubscribedClients({{ .prop = 0, .areaId = 0, .value = {.int32Values = {0}}, .timestamp = 2, }}); ASSERT_FALSE(clients.find(client1) == clients.end()) << "Must not filter out property events if VUR is not enabled"; ASSERT_TRUE(clients.find(client2) == clients.end()) << "Must filter out property events if VUR is enabled"; } TEST_F(SubscriptionManagerTest, testSubscribe_enableVur_filterUnchangedEvents_withResolution) { SpAIBinder binder1 = ndk::SharedRefBase::make()->asBinder(); std::shared_ptr client1 = IVehicleCallback::fromBinder(binder1); SpAIBinder binder2 = ndk::SharedRefBase::make()->asBinder(); std::shared_ptr client2 = IVehicleCallback::fromBinder(binder2); SubscribeOptions client1Option = { .propId = 0, .areaIds = {0}, .sampleRate = 10.0, .resolution = 0.01, .enableVariableUpdateRate = false, }; auto result = getManager()->subscribe(client1, {client1Option}, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); ASSERT_THAT(getHardware()->getSubscribeOptions(), UnorderedElementsAre(client1Option)); getHardware()->clearSubscribeOptions(); SubscribeOptions client2Option = { .propId = 0, .areaIds = {0, 1}, .sampleRate = 20.0, .resolution = 0.1, .enableVariableUpdateRate = true, }; result = getManager()->subscribe(client2, {client2Option}, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); ASSERT_THAT(getHardware()->getSubscribeOptions(), UnorderedElementsAre( SubscribeOptions{ .propId = 0, .areaIds = {0}, .sampleRate = 20.0, .resolution = 0.01, // This is enabled for client2, but disabled for client1. .enableVariableUpdateRate = false, }, SubscribeOptions{ .propId = 0, .areaIds = {1}, .sampleRate = 20.0, .resolution = 0.1, .enableVariableUpdateRate = true, })); std::vector propertyEvents = {{ .prop = 0, .areaId = 0, .value = {.floatValues = {1.0}}, .timestamp = 1, }, { .prop = 0, .areaId = 1, .value = {.floatValues = {1.0}}, .timestamp = 1, }}; auto clients = getManager()->getSubscribedClients(std::vector(propertyEvents)); ASSERT_THAT(clients[client1], UnorderedElementsAre(propertyEvents[0])); ASSERT_THAT(clients[client2], UnorderedElementsAre(propertyEvents[0], propertyEvents[1])); clients = getManager()->getSubscribedClients({{ .prop = 0, .areaId = 0, .value = {.floatValues = {1.01}}, .timestamp = 2, }}); ASSERT_FALSE(clients.find(client1) == clients.end()) << "Must not filter out property events if VUR is not enabled"; ASSERT_TRUE(clients.find(client2) == clients.end()) << "Must filter out property events if VUR is enabled and change is too small"; ASSERT_TRUE(abs(clients[client1][0].value.floatValues[0] - 1.01) < 0.0000001) << "Expected property value == 1.01, instead got " << clients[client1][0].value.floatValues[0]; clients = getManager()->getSubscribedClients({{ .prop = 0, .areaId = 1, .value = {.floatValues = {1.06}}, .timestamp = 3, }}); ASSERT_TRUE(clients.find(client1) == clients.end()) << "Must not get property events for an areaId that the client hasn't subscribed to"; ASSERT_FALSE(clients.find(client2) == clients.end()) << "Must get property events significant changes"; ASSERT_TRUE(abs(clients[client2][0].value.floatValues[0] - 1.1) < 0.0000001) << "Expected property value == 1.1, instead got " << clients[client2][0].value.floatValues[0]; } TEST_F(SubscriptionManagerTest, testSubscribe_enableVur_mustNotFilterStatusChange) { SpAIBinder binder1 = ndk::SharedRefBase::make()->asBinder(); std::shared_ptr client1 = IVehicleCallback::fromBinder(binder1); SpAIBinder binder2 = ndk::SharedRefBase::make()->asBinder(); std::shared_ptr client2 = IVehicleCallback::fromBinder(binder2); SubscribeOptions client1Option = { .propId = 0, .areaIds = {0}, .sampleRate = 10.0, .enableVariableUpdateRate = false, }; auto result = getManager()->subscribe(client1, {client1Option}, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); ASSERT_THAT(getHardware()->getSubscribeOptions(), UnorderedElementsAre(client1Option)); getHardware()->clearSubscribeOptions(); SubscribeOptions client2Option = { .propId = 0, .areaIds = {0, 1}, .sampleRate = 20.0, .enableVariableUpdateRate = true, }; result = getManager()->subscribe(client2, {client2Option}, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); ASSERT_THAT(getHardware()->getSubscribeOptions(), UnorderedElementsAre( SubscribeOptions{ .propId = 0, .areaIds = {0}, .sampleRate = 20.0, // This is enabled for client2, but disabled for client1. .enableVariableUpdateRate = false, }, SubscribeOptions{ .propId = 0, .areaIds = {1}, .sampleRate = 20.0, .enableVariableUpdateRate = true, })); VehiclePropValue propValue1 = { .prop = 0, .areaId = 0, .value = {.int32Values = {0}}, .timestamp = 1, }; auto clients = getManager()->getSubscribedClients(std::vector({propValue1})); ASSERT_THAT(clients[client1], UnorderedElementsAre(propValue1)); // A new event with the same value, but different status must not be filtered out. VehiclePropValue propValue2 = { .prop = 0, .areaId = 0, .value = {.int32Values = {0}}, .status = VehiclePropertyStatus::UNAVAILABLE, .timestamp = 2, }; clients = getManager()->getSubscribedClients({propValue2}); ASSERT_THAT(clients[client1], UnorderedElementsAre(propValue2)) << "Must not filter out property events that has status change"; } TEST_F(SubscriptionManagerTest, testSubscribe_enableVur_timestampUpdated_filterOutdatedEvent) { SpAIBinder binder1 = ndk::SharedRefBase::make()->asBinder(); std::shared_ptr client1 = IVehicleCallback::fromBinder(binder1); SpAIBinder binder2 = ndk::SharedRefBase::make()->asBinder(); std::shared_ptr client2 = IVehicleCallback::fromBinder(binder2); std::vector options = {{ .propId = 0, .areaIds = {0}, .sampleRate = 10.0, .enableVariableUpdateRate = true, }}; // client1 subscribe with VUR enabled. auto result = getManager()->subscribe(client1, options, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); // Let client2 subscribe with VUR disabled so that we enabled VUR in DefaultVehicleHal layer. result = getManager()->subscribe(client2, {{ .propId = 0, .areaIds = {0}, .sampleRate = 10.0, .enableVariableUpdateRate = false, }}, true); ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message(); VehiclePropValue value0 = { .prop = 0, .areaId = 0, .value = {.int32Values = {0}}, .timestamp = 1, }; auto clients = getManager()->getSubscribedClients({value0}); ASSERT_THAT(clients[client1], UnorderedElementsAre(value0)); // A new event with the same value arrived. This must update timestamp to 3. VehiclePropValue value1 = { .prop = 0, .areaId = 0, .value = {.int32Values = {0}}, .timestamp = 3, }; clients = getManager()->getSubscribedClients({value1}); ASSERT_TRUE(clients.find(client1) == clients.end()) << "Must filter out duplicate property events if VUR is enabled"; // The latest timestamp is 3, so even though the value is not the same, this is outdated and // must be ignored. VehiclePropValue value2 = { .prop = 0, .areaId = 0, .value = {.int32Values = {1}}, .timestamp = 2, }; clients = getManager()->getSubscribedClients({value1}); ASSERT_TRUE(clients.find(client1) == clients.end()) << "Must filter out outdated property events if VUR is enabled"; } TEST_F(SubscriptionManagerTest, testSubscribeSupportedValueChange) { SpAIBinder binder1 = ndk::SharedRefBase::make()->asBinder(); std::shared_ptr client1 = IVehicleCallback::fromBinder(binder1); SpAIBinder binder2 = ndk::SharedRefBase::make()->asBinder(); std::shared_ptr 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()->asBinder(); std::shared_ptr client1 = IVehicleCallback::fromBinder(binder1); SpAIBinder binder2 = ndk::SharedRefBase::make()->asBinder(); std::shared_ptr 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"; result = getManager()->unsubscribeSupportedValueChange(binder2.get(), {propIdAreaId2}); ASSERT_TRUE(result.ok()) << "failed to call unsubscribeSupportedValueChange" << result.error().message(); result = getManager()->unsubscribeSupportedValueChange(binder1.get(), {propIdAreaId1}); ASSERT_TRUE(result.ok()) << "failed to call unsubscribeSupportedValueChange" << result.error().message(); EXPECT_EQ(getManager()->countSupportedValueChangeClients(), 0u) << "All clients cleared"; EXPECT_TRUE(isEmpty()) << "All clients cleared"; } } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android