Lazy init property configs.
This is the first step towards supporting delayed property config
discovery. Right now this does not bring too much benefit since
essential system service such as carwatchdog is still querying
property conifg early in the boot process. In the future once
we separate essential properties with non-essential properties,
we can improve more.
Test: atest DefaultVehicleHalTest
Bug: 342470570
Change-Id: Ie85aa163fa9128aa061dd5b3221954c7acac050c
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index 250b30c..fa2a310 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -42,10 +42,11 @@
namespace automotive {
namespace vehicle {
-class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehicle::BnVehicle {
+namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
+
+class DefaultVehicleHal final : public aidlvhal::BnVehicle {
public:
- using CallbackType =
- std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
+ using CallbackType = std::shared_ptr<aidlvhal::IVehicleCallback>;
explicit DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware);
@@ -54,26 +55,16 @@
~DefaultVehicleHal();
- ndk::ScopedAStatus getAllPropConfigs(
- aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
- override;
- ndk::ScopedAStatus getValues(
- const CallbackType& callback,
- const aidl::android::hardware::automotive::vehicle::GetValueRequests& requests)
- override;
- ndk::ScopedAStatus setValues(
- const CallbackType& callback,
- const aidl::android::hardware::automotive::vehicle::SetValueRequests& requests)
- override;
- ndk::ScopedAStatus getPropConfigs(
- const std::vector<int32_t>& props,
- aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
- override;
- ndk::ScopedAStatus subscribe(
- const CallbackType& callback,
- const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
- options,
- int32_t maxSharedMemoryFileCount) override;
+ ndk::ScopedAStatus getAllPropConfigs(aidlvhal::VehiclePropConfigs* returnConfigs) override;
+ ndk::ScopedAStatus getValues(const CallbackType& callback,
+ const aidlvhal::GetValueRequests& requests) override;
+ ndk::ScopedAStatus setValues(const CallbackType& callback,
+ const aidlvhal::SetValueRequests& requests) override;
+ ndk::ScopedAStatus getPropConfigs(const std::vector<int32_t>& props,
+ aidlvhal::VehiclePropConfigs* returnConfigs) override;
+ ndk::ScopedAStatus subscribe(const CallbackType& callback,
+ const std::vector<aidlvhal::SubscribeOptions>& options,
+ int32_t maxSharedMemoryFileCount) override;
ndk::ScopedAStatus unsubscribe(const CallbackType& callback,
const std::vector<int32_t>& propIds) override;
ndk::ScopedAStatus returnSharedMemory(const CallbackType& callback,
@@ -86,12 +77,8 @@
// friend class for unit testing.
friend class DefaultVehicleHalTest;
- using GetValuesClient =
- GetSetValuesClient<aidl::android::hardware::automotive::vehicle::GetValueResult,
- aidl::android::hardware::automotive::vehicle::GetValueResults>;
- using SetValuesClient =
- GetSetValuesClient<aidl::android::hardware::automotive::vehicle::SetValueResult,
- aidl::android::hardware::automotive::vehicle::SetValueResults>;
+ using GetValuesClient = GetSetValuesClient<aidlvhal::GetValueResult, aidlvhal::GetValueResults>;
+ using SetValuesClient = GetSetValuesClient<aidlvhal::SetValueResult, aidlvhal::SetValueResults>;
// A wrapper for binder lifecycle operations to enable stubbing for test.
class BinderLifecycleInterface {
@@ -137,28 +124,27 @@
bool mShouldRefreshPropertyConfigs;
std::unique_ptr<IVehicleHardware> mVehicleHardware;
- // mConfigsByPropId and mConfigFile are only modified during initialization, so no need to
- // lock guard them.
- std::unordered_map<int32_t, aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
- mConfigsByPropId;
- // Only modified in constructor, so thread-safe.
- std::unique_ptr<ndk::ScopedFileDescriptor> mConfigFile;
// PendingRequestPool is thread-safe.
std::shared_ptr<PendingRequestPool> mPendingRequestPool;
// SubscriptionManager is thread-safe.
std::shared_ptr<SubscriptionManager> mSubscriptionManager;
// ConcurrentQueue is thread-safe.
- std::shared_ptr<ConcurrentQueue<aidl::android::hardware::automotive::vehicle::VehiclePropValue>>
- mBatchedEventQueue;
+ std::shared_ptr<ConcurrentQueue<aidlvhal::VehiclePropValue>> mBatchedEventQueue;
// BatchingConsumer is thread-safe.
- std::shared_ptr<
- BatchingConsumer<aidl::android::hardware::automotive::vehicle::VehiclePropValue>>
+ std::shared_ptr<BatchingConsumer<aidlvhal::VehiclePropValue>>
mPropertyChangeEventsBatchingConsumer;
// Only set once during initialization.
std::chrono::nanoseconds mEventBatchingWindow;
// Only used for testing.
int32_t mTestInterfaceVersion = 0;
+ // mConfigsByPropId and mConfigFile is lazy initialized.
+ mutable std::mutex mConfigInitLock;
+ mutable bool mConfigInit GUARDED_BY(mConfigInitLock) = false;
+ mutable std::unordered_map<int32_t, aidlvhal::VehiclePropConfig> mConfigsByPropId
+ GUARDED_BY(mConfigInitLock);
+ mutable std::unique_ptr<ndk::ScopedFileDescriptor> mConfigFile GUARDED_BY(mConfigInitLock);
+
std::mutex mLock;
std::unordered_map<const AIBinder*, std::unique_ptr<OnBinderDiedContext>> mOnBinderDiedContexts
GUARDED_BY(mLock);
@@ -182,32 +168,23 @@
// A thread to handle onBinderDied or onBinderUnlinked event.
std::thread mOnBinderDiedUnlinkedHandlerThread;
- android::base::Result<void> checkProperty(
- const aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
+ android::base::Result<void> checkProperty(const aidlvhal::VehiclePropValue& propValue);
android::base::Result<std::vector<int64_t>> checkDuplicateRequests(
- const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&
- requests);
+ const std::vector<aidlvhal::GetValueRequest>& requests);
android::base::Result<std::vector<int64_t>> checkDuplicateRequests(
- const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
- requests);
- VhalResult<void> checkSubscribeOptions(
- const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
- options);
+ const std::vector<aidlvhal::SetValueRequest>& requests);
+ VhalResult<void> checkSubscribeOptions(const std::vector<aidlvhal::SubscribeOptions>& options);
- VhalResult<void> checkPermissionHelper(
- const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
- aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess accessToTest) const;
+ VhalResult<void> checkPermissionHelper(const aidlvhal::VehiclePropValue& value,
+ aidlvhal::VehiclePropertyAccess accessToTest) const;
- VhalResult<void> checkReadPermission(
- const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+ VhalResult<void> checkReadPermission(const aidlvhal::VehiclePropValue& value) const;
- VhalResult<void> checkWritePermission(
- const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+ VhalResult<void> checkWritePermission(const aidlvhal::VehiclePropValue& value) const;
- android::base::Result<const aidl::android::hardware::automotive::vehicle::VehiclePropConfig*>
- getConfig(int32_t propId) const;
+ android::base::Result<const aidlvhal::VehiclePropConfig*> getConfig(int32_t propId) const;
void onBinderDiedWithContext(const AIBinder* clientId);
@@ -219,7 +196,7 @@
bool checkDumpPermission();
- bool getAllPropConfigsFromHardware();
+ bool getAllPropConfigsFromHardwareLocked() const REQUIRES(mConfigInitLock);
// The looping handler function to process all onBinderDied or onBinderUnlinked events in
// mBinderEvents.
@@ -228,19 +205,19 @@
size_t countSubscribeClients();
// Handles the property change events in batch.
- void handleBatchedPropertyEvents(
- std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
- batchedEvents);
+ void handleBatchedPropertyEvents(std::vector<aidlvhal::VehiclePropValue>&& batchedEvents);
- int32_t getVhalInterfaceVersion();
+ int32_t getVhalInterfaceVersion() const;
+
+ // Gets mConfigsByPropId, lazy init it if necessary.
+ const std::unordered_map<int32_t, aidlvhal::VehiclePropConfig>& getConfigsByPropId() const;
+ // Gets mConfigFile, lazy init it if necessary.
+ const ndk::ScopedFileDescriptor* getConfigFile() const;
// Puts the property change events into a queue so that they can handled in batch.
static void batchPropertyChangeEvent(
- const std::weak_ptr<ConcurrentQueue<
- aidl::android::hardware::automotive::vehicle::VehiclePropValue>>&
- batchedEventQueue,
- std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
- updatedValues);
+ const std::weak_ptr<ConcurrentQueue<aidlvhal::VehiclePropValue>>& batchedEventQueue,
+ std::vector<aidlvhal::VehiclePropValue>&& updatedValues);
// Gets or creates a {@code T} object for the client to or from {@code clients}.
template <class T>
@@ -248,10 +225,8 @@
std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
- static void onPropertyChangeEvent(
- const std::weak_ptr<SubscriptionManager>& subscriptionManager,
- std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
- updatedValues);
+ static void onPropertyChangeEvent(const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+ std::vector<aidlvhal::VehiclePropValue>&& updatedValues);
static void onPropertySetErrorEvent(
const std::weak_ptr<SubscriptionManager>& subscriptionManager,
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index a29861f..9dc039d 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -24,6 +24,7 @@
#include <VehicleUtils.h>
#include <VersionForVehicleProperty.h>
+#include <android-base/logging.h>
#include <android-base/result.h>
#include <android-base/stringprintf.h>
#include <android/binder_ibinder.h>
@@ -71,6 +72,7 @@
using ::ndk::ScopedAIBinder_DeathRecipient;
using ::ndk::ScopedAStatus;
+using ::ndk::ScopedFileDescriptor;
std::string toString(const std::unordered_set<int64_t>& values) {
std::string str = "";
@@ -103,10 +105,7 @@
: mVehicleHardware(std::move(vehicleHardware)),
mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)),
mTestInterfaceVersion(testInterfaceVersion) {
- if (!getAllPropConfigsFromHardware()) {
- return;
- }
-
+ ALOGD("DefaultVehicleHal init");
IVehicleHardware* vehicleHardwarePtr = mVehicleHardware.get();
mSubscriptionManager = std::make_shared<SubscriptionManager>(vehicleHardwarePtr);
mEventBatchingWindow = mVehicleHardware->getPropertyOnChangeEventBatchingWindow();
@@ -319,16 +318,18 @@
mPendingRequestPool = std::make_unique<PendingRequestPool>(timeoutInNano);
}
-int32_t DefaultVehicleHal::getVhalInterfaceVersion() {
+int32_t DefaultVehicleHal::getVhalInterfaceVersion() const {
if (mTestInterfaceVersion != 0) {
return mTestInterfaceVersion;
}
int32_t myVersion = 0;
- getInterfaceVersion(&myVersion);
+ // getInterfaceVersion is in-reality a const method.
+ const_cast<DefaultVehicleHal*>(this)->getInterfaceVersion(&myVersion);
return myVersion;
}
-bool DefaultVehicleHal::getAllPropConfigsFromHardware() {
+bool DefaultVehicleHal::getAllPropConfigsFromHardwareLocked() const {
+ ALOGD("Get all property configs from hardware");
auto configs = mVehicleHardware->getAllPropertyConfigs();
std::vector<VehiclePropConfig> filteredConfigs;
int32_t myVersion = getVhalInterfaceVersion();
@@ -373,22 +374,46 @@
return true;
}
+const ScopedFileDescriptor* DefaultVehicleHal::getConfigFile() const {
+ std::scoped_lock lockGuard(mConfigInitLock);
+ if (!mConfigInit) {
+ CHECK(getAllPropConfigsFromHardwareLocked())
+ << "Failed to get property configs from hardware";
+ mConfigInit = true;
+ }
+ return mConfigFile.get();
+}
+
+const std::unordered_map<int32_t, VehiclePropConfig>& DefaultVehicleHal::getConfigsByPropId()
+ const {
+ std::scoped_lock lockGuard(mConfigInitLock);
+ if (!mConfigInit) {
+ CHECK(getAllPropConfigsFromHardwareLocked())
+ << "Failed to get property configs from hardware";
+ mConfigInit = true;
+ }
+ return mConfigsByPropId;
+}
+
ScopedAStatus DefaultVehicleHal::getAllPropConfigs(VehiclePropConfigs* output) {
- if (mConfigFile != nullptr) {
+ const ScopedFileDescriptor* configFile = getConfigFile();
+ const auto& configsByPropId = getConfigsByPropId();
+ if (configFile != nullptr) {
output->payloads.clear();
- output->sharedMemoryFd.set(dup(mConfigFile->get()));
+ output->sharedMemoryFd.set(dup(configFile->get()));
return ScopedAStatus::ok();
}
- output->payloads.reserve(mConfigsByPropId.size());
- for (const auto& [_, config] : mConfigsByPropId) {
+ output->payloads.reserve(configsByPropId.size());
+ for (const auto& [_, config] : configsByPropId) {
output->payloads.push_back(config);
}
return ScopedAStatus::ok();
}
Result<const VehiclePropConfig*> DefaultVehicleHal::getConfig(int32_t propId) const {
- auto it = mConfigsByPropId.find(propId);
- if (it == mConfigsByPropId.end()) {
+ const auto& configsByPropId = getConfigsByPropId();
+ auto it = configsByPropId.find(propId);
+ if (it == configsByPropId.end()) {
return Error() << "no config for property, ID: " << propId;
}
return &(it->second);
@@ -634,9 +659,11 @@
ScopedAStatus DefaultVehicleHal::getPropConfigs(const std::vector<int32_t>& props,
VehiclePropConfigs* output) {
std::vector<VehiclePropConfig> configs;
+ const auto& configsByPropId = getConfigsByPropId();
for (int32_t prop : props) {
- if (mConfigsByPropId.find(prop) != mConfigsByPropId.end()) {
- configs.push_back(mConfigsByPropId[prop]);
+ auto it = configsByPropId.find(prop);
+ if (it != configsByPropId.end()) {
+ configs.push_back(it->second);
} else {
return ScopedAStatus::fromServiceSpecificErrorWithMessage(
toInt(StatusCode::INVALID_ARG),
@@ -665,13 +692,15 @@
VhalResult<void> DefaultVehicleHal::checkSubscribeOptions(
const std::vector<SubscribeOptions>& options) {
+ const auto& configsByPropId = getConfigsByPropId();
for (const auto& option : options) {
int32_t propId = option.propId;
- if (mConfigsByPropId.find(propId) == mConfigsByPropId.end()) {
+ auto it = configsByPropId.find(propId);
+ if (it == configsByPropId.end()) {
return StatusError(StatusCode::INVALID_ARG)
<< StringPrintf("no config for property, ID: %" PRId32, propId);
}
- const VehiclePropConfig& config = mConfigsByPropId[propId];
+ const VehiclePropConfig& config = it->second;
std::vector<VehicleAreaConfig> areaConfigs;
if (option.areaIds.empty()) {
areaConfigs = config.areaConfigs;
@@ -744,10 +773,11 @@
}
std::vector<SubscribeOptions> onChangeSubscriptions;
std::vector<SubscribeOptions> continuousSubscriptions;
+ const auto& configsByPropId = getConfigsByPropId();
for (const auto& option : options) {
int32_t propId = option.propId;
// We have already validate config exists.
- const VehiclePropConfig& config = mConfigsByPropId[propId];
+ const VehiclePropConfig& config = configsByPropId.at(propId);
SubscribeOptions optionCopy = option;
// If areaIds is empty, subscribe to all areas.
@@ -871,7 +901,7 @@
(areaConfig == nullptr || !hasRequiredAccess(areaConfig->access, accessToTest))) {
return StatusError(StatusCode::ACCESS_DENIED)
<< StringPrintf("Property %" PRId32 " does not have the following access: %" PRId32,
- propId, accessToTest);
+ propId, static_cast<int32_t>(accessToTest));
}
return {};
}
@@ -936,17 +966,19 @@
}
DumpResult result = mVehicleHardware->dump(options);
if (result.refreshPropertyConfigs) {
- getAllPropConfigsFromHardware();
+ std::scoped_lock lockGuard(mConfigInitLock);
+ getAllPropConfigsFromHardwareLocked();
}
dprintf(fd, "%s", (result.buffer + "\n").c_str());
if (!result.callerShouldDumpState) {
return STATUS_OK;
}
dprintf(fd, "Vehicle HAL State: \n");
+ const auto& configsByPropId = getConfigsByPropId();
{
std::scoped_lock<std::mutex> lockGuard(mLock);
dprintf(fd, "Interface version: %" PRId32 "\n", getVhalInterfaceVersion());
- dprintf(fd, "Containing %zu property configs\n", mConfigsByPropId.size());
+ dprintf(fd, "Containing %zu property configs\n", configsByPropId.size());
dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size());
dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size());
dprintf(fd, "Currently have %zu subscribe clients\n", countSubscribeClients());