Merge "Add heart beat event to Default VHAL."
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
index f410f4c..5b06c33 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
@@ -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>
@@ -32,6 +33,10 @@
namespace impl {
+namespace {
+constexpr std::chrono::nanoseconds kHeartBeatIntervalNs = 3s;
+} // namespace
+
DefaultVehicleHal::DefaultVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client)
: mPropStore(propStore), mRecurrentTimer(getTimerAction()), mVehicleClient(client) {
initStaticConfig();
@@ -297,6 +302,41 @@
}
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) {
@@ -309,6 +349,10 @@
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;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
index 2a0d430..ecdb9a8 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
@@ -35,9 +35,9 @@
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,
@@ -65,6 +65,12 @@
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.
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
index 1b20bf5..bbefce7 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
@@ -56,14 +56,21 @@
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,
@@ -71,7 +78,14 @@
}
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*/) {
}
@@ -82,6 +96,7 @@
std::unique_ptr<VehiclePropertyStore> mPropStore;
VehiclePropValuePool mValueObjectPool;
android::ConcurrentQueue<VehiclePropValuePtr> mEventQueue;
+ android::ConcurrentQueue<VehiclePropValuePtr> mHeartBeatQueue;
};
TEST_F(DefaultVhalImplTest, testListProperties) {
@@ -724,4 +739,14 @@
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