mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
Merge "Introduce getPropertyConfig to IVehicleHardware" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
5f812b1cd1
@@ -83,6 +83,17 @@ std::vector<aidlvhal::VehiclePropConfig> GRPCVehicleHardware::getAllPropertyConf
|
||||
return configs;
|
||||
}
|
||||
|
||||
std::optional<aidlvhal::VehiclePropConfig> GRPCVehicleHardware::getPropertyConfig(
|
||||
int32_t propId) const {
|
||||
// TODO(b/354055835): Use GRPC call to get one config instead of getting all the configs.
|
||||
for (const auto& config : getAllPropertyConfigs()) {
|
||||
if (config.prop == propId) {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
aidlvhal::StatusCode GRPCVehicleHardware::setValues(
|
||||
std::shared_ptr<const SetValuesCallback> callback,
|
||||
const std::vector<aidlvhal::SetValueRequest>& requests) {
|
||||
|
||||
@@ -50,6 +50,10 @@ class GRPCVehicleHardware : public IVehicleHardware {
|
||||
// Get all the property configs.
|
||||
std::vector<aidlvhal::VehiclePropConfig> getAllPropertyConfigs() const override;
|
||||
|
||||
// Get the config for the specified propId.
|
||||
std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
|
||||
getPropertyConfig(int32_t propId) const override;
|
||||
|
||||
// Set property values asynchronously. Server could return before the property set requests
|
||||
// are sent to vehicle bus or before property set confirmation is received. The callback is
|
||||
// safe to be called after the function returns and is safe to be called in a different thread.
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <VehicleHalTypes.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace android {
|
||||
@@ -46,33 +47,53 @@ struct SetValueErrorEvent {
|
||||
int32_t areaId;
|
||||
};
|
||||
|
||||
namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
|
||||
|
||||
// An abstract interface to access vehicle hardware.
|
||||
// For virtualized VHAL, GrpcVehicleHardware would communicate with a VehicleHardware
|
||||
// implementation in another VM through GRPC. For non-virtualzied VHAL, VHAL directly communicates
|
||||
// with a VehicleHardware through this interface.
|
||||
class IVehicleHardware {
|
||||
public:
|
||||
using SetValuesCallback = std::function<void(
|
||||
std::vector<aidl::android::hardware::automotive::vehicle::SetValueResult>)>;
|
||||
using GetValuesCallback = std::function<void(
|
||||
std::vector<aidl::android::hardware::automotive::vehicle::GetValueResult>)>;
|
||||
using PropertyChangeCallback = std::function<void(
|
||||
std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>)>;
|
||||
using SetValuesCallback = std::function<void(std::vector<aidlvhal::SetValueResult>)>;
|
||||
using GetValuesCallback = std::function<void(std::vector<aidlvhal::GetValueResult>)>;
|
||||
using PropertyChangeCallback = std::function<void(std::vector<aidlvhal::VehiclePropValue>)>;
|
||||
using PropertySetErrorCallback = std::function<void(std::vector<SetValueErrorEvent>)>;
|
||||
|
||||
virtual ~IVehicleHardware() = default;
|
||||
|
||||
// Get all the property configs.
|
||||
virtual std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
|
||||
getAllPropertyConfigs() const = 0;
|
||||
virtual std::vector<aidlvhal::VehiclePropConfig> getAllPropertyConfigs() const = 0;
|
||||
|
||||
// Get the property configs for the specified propId. This is used for early-boot
|
||||
// native VHAL clients to access certain property configs when not all property configs are
|
||||
// available. For example, a config discovery process might be required to determine the
|
||||
// property config for HVAC. However, for early boot properties, e.g. VHAL_HEARTBEAT, it
|
||||
// could return before the config discovery process.
|
||||
//
|
||||
// Currently Android system may try to access the following properties during early boot:
|
||||
// STORAGE_ENCRYPTION_BINDING_SEED, WATCHDOG_ALIVE, WATCHDOG_TERMINATE_PROCESS, VHAL_HEARTBEAT,
|
||||
// CURRENT_POWER_POLICY, POWER_POLICY_REQ, POWER_POLICY_GROUP_REQ. They should return
|
||||
// quickly otherwise the whole bootup process might be blocked.
|
||||
virtual std::optional<aidlvhal::VehiclePropConfig> getPropertyConfig(int32_t propId) const {
|
||||
// The default implementation is to use getAllPropertyConfigs(). This should be
|
||||
// overridden if getAllPropertyConfigs() takes a while to return for initial boot or
|
||||
// relies on ethernet or other communication channel that is not available during early
|
||||
// boot.
|
||||
for (const auto& config : getAllPropertyConfigs()) {
|
||||
if (config.prop == propId) {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Set property values asynchronously. Server could return before the property set requests
|
||||
// are sent to vehicle bus or before property set confirmation is received. The callback is
|
||||
// safe to be called after the function returns and is safe to be called in a different thread.
|
||||
virtual aidl::android::hardware::automotive::vehicle::StatusCode setValues(
|
||||
virtual aidlvhal::StatusCode setValues(
|
||||
std::shared_ptr<const SetValuesCallback> callback,
|
||||
const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
|
||||
requests) = 0;
|
||||
const std::vector<aidlvhal::SetValueRequest>& requests) = 0;
|
||||
|
||||
// Get property values asynchronously. Server could return before the property values are ready.
|
||||
// The callback is safe to be called after the function returns and is safe to be called in a
|
||||
@@ -86,7 +107,7 @@ class IVehicleHardware {
|
||||
virtual DumpResult dump(const std::vector<std::string>& options) = 0;
|
||||
|
||||
// Check whether the system is healthy, return {@code StatusCode::OK} for healthy.
|
||||
virtual aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() = 0;
|
||||
virtual aidlvhal::StatusCode checkHealth() = 0;
|
||||
|
||||
// Register a callback that would be called when there is a property change event from vehicle.
|
||||
// This function must only be called once during initialization.
|
||||
@@ -179,16 +200,14 @@ class IVehicleHardware {
|
||||
// 5. The second subscriber is removed, 'unsubscribe' is called.
|
||||
// The impl can optionally disable the polling for vehicle speed.
|
||||
//
|
||||
virtual aidl::android::hardware::automotive::vehicle::StatusCode subscribe(
|
||||
[[maybe_unused]] aidl::android::hardware::automotive::vehicle::SubscribeOptions
|
||||
options) {
|
||||
return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
|
||||
virtual aidlvhal::StatusCode subscribe([[maybe_unused]] aidlvhal::SubscribeOptions options) {
|
||||
return aidlvhal::StatusCode::OK;
|
||||
}
|
||||
|
||||
// A [propId, areaId] is unsubscribed. This applies for both continuous or on-change property.
|
||||
virtual aidl::android::hardware::automotive::vehicle::StatusCode unsubscribe(
|
||||
[[maybe_unused]] int32_t propId, [[maybe_unused]] int32_t areaId) {
|
||||
return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
|
||||
virtual aidlvhal::StatusCode unsubscribe([[maybe_unused]] int32_t propId,
|
||||
[[maybe_unused]] int32_t areaId) {
|
||||
return aidlvhal::StatusCode::OK;
|
||||
}
|
||||
|
||||
// This function is deprecated, subscribe/unsubscribe should be used instead.
|
||||
@@ -216,10 +235,10 @@ class IVehicleHardware {
|
||||
//
|
||||
// If the impl is always polling at {@code maxSampleRate} as specified in config, then this
|
||||
// function can be a no-op.
|
||||
virtual aidl::android::hardware::automotive::vehicle::StatusCode updateSampleRate(
|
||||
[[maybe_unused]] int32_t propId, [[maybe_unused]] int32_t areaId,
|
||||
[[maybe_unused]] float sampleRate) {
|
||||
return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
|
||||
virtual aidlvhal::StatusCode updateSampleRate([[maybe_unused]] int32_t propId,
|
||||
[[maybe_unused]] int32_t areaId,
|
||||
[[maybe_unused]] float sampleRate) {
|
||||
return aidlvhal::StatusCode::OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -199,6 +199,8 @@ class DefaultVehicleHal final : public aidlvhal::BnVehicle {
|
||||
|
||||
bool checkDumpPermission();
|
||||
|
||||
bool isConfigSupportedForCurrentVhalVersion(const aidlvhal::VehiclePropConfig& config) const;
|
||||
|
||||
bool getAllPropConfigsFromHardwareLocked() const EXCLUDES(mConfigLock);
|
||||
|
||||
// The looping handler function to process all onBinderDied or onBinderUnlinked events in
|
||||
|
||||
@@ -340,32 +340,37 @@ int32_t DefaultVehicleHal::getVhalInterfaceVersion() const {
|
||||
return myVersion;
|
||||
}
|
||||
|
||||
bool DefaultVehicleHal::isConfigSupportedForCurrentVhalVersion(
|
||||
const VehiclePropConfig& config) const {
|
||||
int32_t myVersion = getVhalInterfaceVersion();
|
||||
if (!isSystemProp(config.prop)) {
|
||||
return true;
|
||||
}
|
||||
VehicleProperty property = static_cast<VehicleProperty>(config.prop);
|
||||
std::string propertyName = aidl::android::hardware::automotive::vehicle::toString(property);
|
||||
auto it = VersionForVehicleProperty.find(property);
|
||||
if (it == VersionForVehicleProperty.end()) {
|
||||
ALOGE("The property: %s is not a supported system property, ignore", propertyName.c_str());
|
||||
return false;
|
||||
}
|
||||
int requiredVersion = it->second;
|
||||
if (myVersion < requiredVersion) {
|
||||
ALOGE("The property: %s is not supported for current client VHAL version, "
|
||||
"require %d, current version: %d, ignore",
|
||||
propertyName.c_str(), requiredVersion, myVersion);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DefaultVehicleHal::getAllPropConfigsFromHardwareLocked() const {
|
||||
ALOGD("Get all property configs from hardware");
|
||||
auto configs = mVehicleHardware->getAllPropertyConfigs();
|
||||
std::vector<VehiclePropConfig> filteredConfigs;
|
||||
int32_t myVersion = getVhalInterfaceVersion();
|
||||
for (auto& config : configs) {
|
||||
if (!isSystemProp(config.prop)) {
|
||||
for (const auto& config : configs) {
|
||||
if (isConfigSupportedForCurrentVhalVersion(config)) {
|
||||
filteredConfigs.push_back(std::move(config));
|
||||
continue;
|
||||
}
|
||||
VehicleProperty property = static_cast<VehicleProperty>(config.prop);
|
||||
std::string propertyName = aidl::android::hardware::automotive::vehicle::toString(property);
|
||||
auto it = VersionForVehicleProperty.find(property);
|
||||
if (it == VersionForVehicleProperty.end()) {
|
||||
ALOGE("The property: %s is not a supported system property, ignore",
|
||||
propertyName.c_str());
|
||||
continue;
|
||||
}
|
||||
int requiredVersion = it->second;
|
||||
if (myVersion < requiredVersion) {
|
||||
ALOGE("The property: %s is not supported for current client VHAL version, "
|
||||
"require %d, current version: %d, ignore",
|
||||
propertyName.c_str(), requiredVersion, myVersion);
|
||||
continue;
|
||||
}
|
||||
filteredConfigs.push_back(std::move(config));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -431,6 +436,19 @@ ScopedAStatus DefaultVehicleHal::getAllPropConfigs(VehiclePropConfigs* output) {
|
||||
|
||||
Result<VehiclePropConfig> DefaultVehicleHal::getConfig(int32_t propId) const {
|
||||
Result<VehiclePropConfig> result;
|
||||
|
||||
if (!mConfigInit) {
|
||||
std::optional<VehiclePropConfig> config = mVehicleHardware->getPropertyConfig(propId);
|
||||
if (!config.has_value()) {
|
||||
return Error() << "no config for property, ID: " << propId;
|
||||
}
|
||||
if (!isConfigSupportedForCurrentVhalVersion(config.value())) {
|
||||
return Error() << "property not supported for current VHAL interface, ID: " << propId;
|
||||
}
|
||||
|
||||
return config.value();
|
||||
}
|
||||
|
||||
getConfigsByPropId([this, &result, propId](const auto& configsByPropId) {
|
||||
SharedScopedLockAssertion lockAssertion(mConfigLock);
|
||||
|
||||
@@ -685,6 +703,22 @@ ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback,
|
||||
ScopedAStatus DefaultVehicleHal::getPropConfigs(const std::vector<int32_t>& props,
|
||||
VehiclePropConfigs* output) {
|
||||
std::vector<VehiclePropConfig> configs;
|
||||
|
||||
if (!mConfigInit) {
|
||||
for (int32_t prop : props) {
|
||||
auto maybeConfig = mVehicleHardware->getPropertyConfig(prop);
|
||||
if (!maybeConfig.has_value() ||
|
||||
!isConfigSupportedForCurrentVhalVersion(maybeConfig.value())) {
|
||||
return ScopedAStatus::fromServiceSpecificErrorWithMessage(
|
||||
toInt(StatusCode::INVALID_ARG),
|
||||
StringPrintf("no config for property, ID: %" PRId32, prop).c_str());
|
||||
}
|
||||
configs.push_back(maybeConfig.value());
|
||||
}
|
||||
|
||||
return vectorToStableLargeParcelable(std::move(configs), output);
|
||||
}
|
||||
|
||||
ScopedAStatus status = ScopedAStatus::ok();
|
||||
getConfigsByPropId([this, &configs, &status, &props](const auto& configsByPropId) {
|
||||
SharedScopedLockAssertion lockAssertion(mConfigLock);
|
||||
|
||||
@@ -650,6 +650,8 @@ TEST_F(DefaultVehicleHalTest, testGetPropConfigs) {
|
||||
|
||||
auto hardware = std::make_unique<MockVehicleHardware>();
|
||||
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());
|
||||
|
||||
@@ -658,6 +660,7 @@ TEST_F(DefaultVehicleHalTest, testGetPropConfigs) {
|
||||
|
||||
ASSERT_TRUE(status.isOk()) << "getPropConfigs failed: " << status.getMessage();
|
||||
ASSERT_EQ(output.payloads, testConfigs);
|
||||
ASSERT_FALSE(hardwarePtr->getAllPropertyConfigsCalled());
|
||||
}
|
||||
|
||||
TEST_F(DefaultVehicleHalTest, testGetPropConfigsInvalidArg) {
|
||||
@@ -704,6 +707,34 @@ TEST_F(DefaultVehicleHalTest, testGetValuesSmall) {
|
||||
ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
|
||||
EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch";
|
||||
EXPECT_EQ(countClients(), static_cast<size_t>(1));
|
||||
ASSERT_FALSE(getHardware()->getAllPropertyConfigsCalled());
|
||||
}
|
||||
|
||||
TEST_F(DefaultVehicleHalTest, testGetValuesSmall_AfterGetAllPropConfigs) {
|
||||
GetValueRequests requests;
|
||||
std::vector<GetValueResult> expectedResults;
|
||||
std::vector<GetValueRequest> expectedHardwareRequests;
|
||||
|
||||
// If we already called getAllPropConfigs, the configs will be cached.
|
||||
VehiclePropConfigs output;
|
||||
getClient()->getAllPropConfigs(&output);
|
||||
|
||||
ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
|
||||
|
||||
getHardware()->addGetValueResponses(expectedResults);
|
||||
|
||||
auto status = getClient()->getValues(getCallbackClient(), requests);
|
||||
|
||||
ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
|
||||
|
||||
EXPECT_EQ(getHardware()->nextGetValueRequests(), expectedHardwareRequests)
|
||||
<< "requests to hardware mismatch";
|
||||
|
||||
auto maybeGetValueResults = getCallback()->nextGetValueResults();
|
||||
ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
|
||||
EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch";
|
||||
EXPECT_EQ(countClients(), static_cast<size_t>(1));
|
||||
ASSERT_TRUE(getHardware()->getAllPropertyConfigsCalled());
|
||||
}
|
||||
|
||||
TEST_F(DefaultVehicleHalTest, testGetValuesLarge) {
|
||||
@@ -1016,6 +1047,34 @@ TEST_F(DefaultVehicleHalTest, testSetValuesSmall) {
|
||||
ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
|
||||
ASSERT_EQ(maybeSetValueResults.value().payloads, expectedResults) << "results mismatch";
|
||||
EXPECT_EQ(countClients(), static_cast<size_t>(1));
|
||||
ASSERT_FALSE(getHardware()->getAllPropertyConfigsCalled());
|
||||
}
|
||||
|
||||
TEST_F(DefaultVehicleHalTest, testSetValuesSmall_AfterGetAllPropConfigs) {
|
||||
SetValueRequests requests;
|
||||
std::vector<SetValueResult> expectedResults;
|
||||
std::vector<SetValueRequest> expectedHardwareRequests;
|
||||
|
||||
// If we already called getAllPropConfigs, the configs will be cached.
|
||||
VehiclePropConfigs output;
|
||||
getClient()->getAllPropConfigs(&output);
|
||||
|
||||
ASSERT_TRUE(setValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
|
||||
|
||||
getHardware()->addSetValueResponses(expectedResults);
|
||||
|
||||
auto status = getClient()->setValues(getCallbackClient(), requests);
|
||||
|
||||
ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
|
||||
|
||||
EXPECT_EQ(getHardware()->nextSetValueRequests(), expectedHardwareRequests)
|
||||
<< "requests to hardware mismatch";
|
||||
|
||||
auto maybeSetValueResults = getCallback()->nextSetValueResults();
|
||||
ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
|
||||
ASSERT_EQ(maybeSetValueResults.value().payloads, expectedResults) << "results mismatch";
|
||||
EXPECT_EQ(countClients(), static_cast<size_t>(1));
|
||||
ASSERT_TRUE(getHardware()->getAllPropertyConfigsCalled());
|
||||
}
|
||||
|
||||
TEST_F(DefaultVehicleHalTest, testSetValuesLarge) {
|
||||
|
||||
@@ -45,9 +45,20 @@ MockVehicleHardware::~MockVehicleHardware() {
|
||||
|
||||
std::vector<VehiclePropConfig> MockVehicleHardware::getAllPropertyConfigs() const {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
mGetAllPropertyConfigsCalled = true;
|
||||
return mPropertyConfigs;
|
||||
}
|
||||
|
||||
std::optional<VehiclePropConfig> MockVehicleHardware::getPropertyConfig(int32_t propId) const {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
for (const auto& config : mPropertyConfigs) {
|
||||
if (config.prop == propId) {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
StatusCode MockVehicleHardware::setValues(std::shared_ptr<const SetValuesCallback> callback,
|
||||
const std::vector<SetValueRequest>& requests) {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
@@ -336,6 +347,11 @@ void MockVehicleHardware::sendOnPropertySetErrorEvent(
|
||||
(*mPropertySetErrorCallback)(errorEvents);
|
||||
}
|
||||
|
||||
bool MockVehicleHardware::getAllPropertyConfigsCalled() {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
return mGetAllPropertyConfigsCalled;
|
||||
}
|
||||
|
||||
} // namespace vehicle
|
||||
} // namespace automotive
|
||||
} // namespace hardware
|
||||
|
||||
@@ -47,6 +47,8 @@ class MockVehicleHardware final : public IVehicleHardware {
|
||||
|
||||
std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
|
||||
getAllPropertyConfigs() const override;
|
||||
std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
|
||||
getPropertyConfig(int32_t propId) const override;
|
||||
aidl::android::hardware::automotive::vehicle::StatusCode setValues(
|
||||
std::shared_ptr<const SetValuesCallback> callback,
|
||||
const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
|
||||
@@ -98,6 +100,9 @@ class MockVehicleHardware final : public IVehicleHardware {
|
||||
std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>
|
||||
getSubscribeOptions();
|
||||
void clearSubscribeOptions();
|
||||
// Whether getAllPropertyConfigs() has been called, which blocks all all property configs
|
||||
// being ready.
|
||||
bool getAllPropertyConfigsCalled();
|
||||
|
||||
private:
|
||||
mutable std::mutex mLock;
|
||||
@@ -143,6 +148,8 @@ class MockVehicleHardware final : public IVehicleHardware {
|
||||
|
||||
DumpResult mDumpResult;
|
||||
|
||||
mutable bool mGetAllPropertyConfigsCalled GUARDED_BY(mLock) = false;
|
||||
|
||||
// RecurrentTimer is thread-safe.
|
||||
std::shared_ptr<RecurrentTimer> mRecurrentTimer;
|
||||
std::unordered_map<int32_t, std::unordered_map<int32_t, std::shared_ptr<std::function<void()>>>>
|
||||
|
||||
Reference in New Issue
Block a user