Loading automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp +44 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ #define LOG_TAG "DefaultVehicleHal_v2_0" #include <android-base/chrono_utils.h> #include <assert.h> #include <utils/Log.h> #include <utils/SystemClock.h> Loading @@ -32,6 +33,10 @@ namespace V2_0 { namespace impl { namespace { constexpr std::chrono::nanoseconds kHeartBeatIntervalNs = 3s; } // namespace DefaultVehicleHal::DefaultVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client) : mPropStore(propStore), mRecurrentTimer(getTimerAction()), mVehicleClient(client) { initStaticConfig(); Loading Loading @@ -297,6 +302,41 @@ void DefaultVehicleHal::onCreate() { } mVehicleClient->triggerSendAllValues(); registerHeartBeatEvent(); } DefaultVehicleHal::~DefaultVehicleHal() { mRecurrentTimer.unregisterRecurrentEvent(static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)); } void DefaultVehicleHal::registerHeartBeatEvent() { mRecurrentTimer.registerRecurrentEvent(kHeartBeatIntervalNs, static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)); } VehicleHal::VehiclePropValuePtr DefaultVehicleHal::doInternalHealthCheck() { VehicleHal::VehiclePropValuePtr v = nullptr; // This is an example of very simple health checking. VHAL is considered healthy if we can read // PERF_VEHICLE_SPEED. The more comprehensive health checking is required. VehiclePropValue propValue = { .prop = static_cast<int32_t>(VehicleProperty::PERF_VEHICLE_SPEED), }; auto internalPropValue = mPropStore->readValueOrNull(propValue); if (internalPropValue != nullptr) { v = createVhalHeartBeatProp(); } else { ALOGW("VHAL health check failed"); } return v; } VehicleHal::VehiclePropValuePtr DefaultVehicleHal::createVhalHeartBeatProp() { VehicleHal::VehiclePropValuePtr v = getValuePool()->obtainInt64(uptimeMillis()); v->prop = static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT); v->areaId = 0; v->status = VehiclePropertyStatus::AVAILABLE; return v; } void DefaultVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) { Loading @@ -309,6 +349,10 @@ void DefaultVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& pr if (internalPropValue != nullptr) { v = pool.obtain(*internalPropValue); } } else if (property == static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)) { // VHAL_HEARTBEAT is not a continuous value, but it needs to be updated periodically. // So, the update is done through onContinuousPropertyTimer. v = doInternalHealthCheck(); } else { ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property); continue; Loading automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h +8 −2 Original line number Diff line number Diff line Loading @@ -35,9 +35,9 @@ namespace impl { class DefaultVehicleHal : public VehicleHal { public: DefaultVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client); ~DefaultVehicleHal() = default; ~DefaultVehicleHal(); // Methods from VehicleHal // Initialize VHAL. Should always call registerHeartBeatEvent() during onCreate. void onCreate() override; std::vector<VehiclePropConfig> listProperties() override; VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue, Loading Loading @@ -65,6 +65,12 @@ class DefaultVehicleHal : public VehicleHal { StatusCode checkPropValue(const VehiclePropValue& propValue, const VehiclePropConfig* config); // Check whether the property value is within the range according to area config. StatusCode checkValueRange(const VehiclePropValue& propValue, const VehiclePropConfig* config); // Register the heart beat event to be sent every 3s. This is required to inform watch dog that // VHAL is alive. Subclasses should always calls this function during onCreate. void registerHeartBeatEvent(); VehicleHal::VehiclePropValuePtr doInternalHealthCheck(); VehicleHal::VehiclePropValuePtr createVhalHeartBeatProp(); private: // Check whether a vendor mixed value property is valid according to its config array. Loading automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp +28 −3 Original line number Diff line number Diff line Loading @@ -56,14 +56,21 @@ const size_t MAX_PROP_ID_LENGTH = 100; class DefaultVhalImplTest : public ::testing::Test { public: ~DefaultVhalImplTest() { mEventQueue.deactivate(); } ~DefaultVhalImplTest() { mEventQueue.deactivate(); mHeartBeatQueue.deactivate(); // Destroy mHal before destroying its dependencies. mHal.reset(); mConnector.reset(); mPropStore.reset(); } protected: void SetUp() override { mPropStore.reset(new VehiclePropertyStore); mConnector.reset(new DefaultVehicleConnector); mHal.reset(new DefaultVehicleHal(mPropStore.get(), mConnector.get())); mConnector->setValuePool(&mValueObjectPool); mHal.reset(new DefaultVehicleHal(mPropStore.get(), mConnector.get())); mHal->init(&mValueObjectPool, std::bind(&DefaultVhalImplTest::onHalEvent, this, std::placeholders::_1), std::bind(&DefaultVhalImplTest::onHalPropertySetError, this, Loading @@ -71,7 +78,14 @@ class DefaultVhalImplTest : public ::testing::Test { } private: void onHalEvent(VehiclePropValuePtr v) { mEventQueue.push(std::move(v)); } void onHalEvent(VehiclePropValuePtr v) { if (v->prop != toInt(VehicleProperty::VHAL_HEARTBEAT)) { // Ignore heartbeat properties. mEventQueue.push(std::move(v)); } else { mHeartBeatQueue.push(std::move(v)); } } void onHalPropertySetError(StatusCode /*errorCode*/, int32_t /*property*/, int32_t /*areaId*/) { } Loading @@ -82,6 +96,7 @@ class DefaultVhalImplTest : public ::testing::Test { std::unique_ptr<VehiclePropertyStore> mPropStore; VehiclePropValuePool mValueObjectPool; android::ConcurrentQueue<VehiclePropValuePtr> mEventQueue; android::ConcurrentQueue<VehiclePropValuePtr> mHeartBeatQueue; }; TEST_F(DefaultVhalImplTest, testListProperties) { Loading Loading @@ -724,4 +739,14 @@ TEST_F(DefaultVhalImplTest, testDebugGenFakeDataKeyPress) { EXPECT_EQ(2, events[1]->value.int32Values[2]); } TEST_F(DefaultVhalImplTest, testHeartBeatEvent) { // A heart beat would be sent every 3s, but let's wait for 6s to be sure at least 2 events have // been generated (at 0s and 3s). std::this_thread::sleep_for(std::chrono::milliseconds(6000)); auto events = mHeartBeatQueue.flush(); ASSERT_GE(events.size(), (size_t)2); ASSERT_EQ(toInt(VehicleProperty::VHAL_HEARTBEAT), events[0]->prop); } } // namespace Loading
automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp +44 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ #define LOG_TAG "DefaultVehicleHal_v2_0" #include <android-base/chrono_utils.h> #include <assert.h> #include <utils/Log.h> #include <utils/SystemClock.h> Loading @@ -32,6 +33,10 @@ namespace V2_0 { namespace impl { namespace { constexpr std::chrono::nanoseconds kHeartBeatIntervalNs = 3s; } // namespace DefaultVehicleHal::DefaultVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client) : mPropStore(propStore), mRecurrentTimer(getTimerAction()), mVehicleClient(client) { initStaticConfig(); Loading Loading @@ -297,6 +302,41 @@ void DefaultVehicleHal::onCreate() { } mVehicleClient->triggerSendAllValues(); registerHeartBeatEvent(); } DefaultVehicleHal::~DefaultVehicleHal() { mRecurrentTimer.unregisterRecurrentEvent(static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)); } void DefaultVehicleHal::registerHeartBeatEvent() { mRecurrentTimer.registerRecurrentEvent(kHeartBeatIntervalNs, static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)); } VehicleHal::VehiclePropValuePtr DefaultVehicleHal::doInternalHealthCheck() { VehicleHal::VehiclePropValuePtr v = nullptr; // This is an example of very simple health checking. VHAL is considered healthy if we can read // PERF_VEHICLE_SPEED. The more comprehensive health checking is required. VehiclePropValue propValue = { .prop = static_cast<int32_t>(VehicleProperty::PERF_VEHICLE_SPEED), }; auto internalPropValue = mPropStore->readValueOrNull(propValue); if (internalPropValue != nullptr) { v = createVhalHeartBeatProp(); } else { ALOGW("VHAL health check failed"); } return v; } VehicleHal::VehiclePropValuePtr DefaultVehicleHal::createVhalHeartBeatProp() { VehicleHal::VehiclePropValuePtr v = getValuePool()->obtainInt64(uptimeMillis()); v->prop = static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT); v->areaId = 0; v->status = VehiclePropertyStatus::AVAILABLE; return v; } void DefaultVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) { Loading @@ -309,6 +349,10 @@ void DefaultVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& pr if (internalPropValue != nullptr) { v = pool.obtain(*internalPropValue); } } else if (property == static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)) { // VHAL_HEARTBEAT is not a continuous value, but it needs to be updated periodically. // So, the update is done through onContinuousPropertyTimer. v = doInternalHealthCheck(); } else { ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property); continue; Loading
automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h +8 −2 Original line number Diff line number Diff line Loading @@ -35,9 +35,9 @@ namespace impl { class DefaultVehicleHal : public VehicleHal { public: DefaultVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client); ~DefaultVehicleHal() = default; ~DefaultVehicleHal(); // Methods from VehicleHal // Initialize VHAL. Should always call registerHeartBeatEvent() during onCreate. void onCreate() override; std::vector<VehiclePropConfig> listProperties() override; VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue, Loading Loading @@ -65,6 +65,12 @@ class DefaultVehicleHal : public VehicleHal { StatusCode checkPropValue(const VehiclePropValue& propValue, const VehiclePropConfig* config); // Check whether the property value is within the range according to area config. StatusCode checkValueRange(const VehiclePropValue& propValue, const VehiclePropConfig* config); // Register the heart beat event to be sent every 3s. This is required to inform watch dog that // VHAL is alive. Subclasses should always calls this function during onCreate. void registerHeartBeatEvent(); VehicleHal::VehiclePropValuePtr doInternalHealthCheck(); VehicleHal::VehiclePropValuePtr createVhalHeartBeatProp(); private: // Check whether a vendor mixed value property is valid according to its config array. Loading
automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp +28 −3 Original line number Diff line number Diff line Loading @@ -56,14 +56,21 @@ const size_t MAX_PROP_ID_LENGTH = 100; class DefaultVhalImplTest : public ::testing::Test { public: ~DefaultVhalImplTest() { mEventQueue.deactivate(); } ~DefaultVhalImplTest() { mEventQueue.deactivate(); mHeartBeatQueue.deactivate(); // Destroy mHal before destroying its dependencies. mHal.reset(); mConnector.reset(); mPropStore.reset(); } protected: void SetUp() override { mPropStore.reset(new VehiclePropertyStore); mConnector.reset(new DefaultVehicleConnector); mHal.reset(new DefaultVehicleHal(mPropStore.get(), mConnector.get())); mConnector->setValuePool(&mValueObjectPool); mHal.reset(new DefaultVehicleHal(mPropStore.get(), mConnector.get())); mHal->init(&mValueObjectPool, std::bind(&DefaultVhalImplTest::onHalEvent, this, std::placeholders::_1), std::bind(&DefaultVhalImplTest::onHalPropertySetError, this, Loading @@ -71,7 +78,14 @@ class DefaultVhalImplTest : public ::testing::Test { } private: void onHalEvent(VehiclePropValuePtr v) { mEventQueue.push(std::move(v)); } void onHalEvent(VehiclePropValuePtr v) { if (v->prop != toInt(VehicleProperty::VHAL_HEARTBEAT)) { // Ignore heartbeat properties. mEventQueue.push(std::move(v)); } else { mHeartBeatQueue.push(std::move(v)); } } void onHalPropertySetError(StatusCode /*errorCode*/, int32_t /*property*/, int32_t /*areaId*/) { } Loading @@ -82,6 +96,7 @@ class DefaultVhalImplTest : public ::testing::Test { std::unique_ptr<VehiclePropertyStore> mPropStore; VehiclePropValuePool mValueObjectPool; android::ConcurrentQueue<VehiclePropValuePtr> mEventQueue; android::ConcurrentQueue<VehiclePropValuePtr> mHeartBeatQueue; }; TEST_F(DefaultVhalImplTest, testListProperties) { Loading Loading @@ -724,4 +739,14 @@ TEST_F(DefaultVhalImplTest, testDebugGenFakeDataKeyPress) { EXPECT_EQ(2, events[1]->value.int32Values[2]); } TEST_F(DefaultVhalImplTest, testHeartBeatEvent) { // A heart beat would be sent every 3s, but let's wait for 6s to be sure at least 2 events have // been generated (at 0s and 3s). std::this_thread::sleep_for(std::chrono::milliseconds(6000)); auto events = mHeartBeatQueue.flush(); ASSERT_GE(events.size(), (size_t)2); ASSERT_EQ(toInt(VehicleProperty::VHAL_HEARTBEAT), events[0]->prop); } } // namespace