Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b0a66d97 authored by Yu Shan's avatar Yu Shan
Browse files

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
parent 0cc6001a
Loading
Loading
Loading
Loading
+46 −71
Original line number Diff line number Diff line
@@ -42,10 +42,11 @@ namespace hardware {
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,25 +55,15 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi

    ~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,
    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;
@@ -86,12 +77,8 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi
    // 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 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi
    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 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi
    // 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 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi

    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 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi
    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 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi
            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,
+53 −21
Original line number Diff line number Diff line
@@ -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 ::android::base::StringPrintf;

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 @@ DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHa
    : 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 @@ void DefaultVehicleHal::setTimeout(int64_t timeoutInNano) {
    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 @@ bool DefaultVehicleHal::getAllPropConfigsFromHardware() {
    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::setValues(const CallbackType& callback,
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 @@ bool areaConfigsHaveRequiredAccess(const std::vector<VehicleAreaConfig>& areaCon

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 @@ ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback,
    }
    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 @@ VhalResult<void> DefaultVehicleHal::checkPermissionHelper(
        (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 @@ binder_status_t DefaultVehicleHal::dump(int fd, const char** args, uint32_t numA
    }
    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());