Implement getAllPropConfigs for VHAL cpp client.

Test: atest libvhalclient_test
Bug: 214635003
Change-Id: Idfc808730d9dc5a124eb1a4ffae6a0f5cf9df5f0
diff --git a/cpp/vhal/client/include/AidlVhalClient.h b/cpp/vhal/client/include/AidlVhalClient.h
index c09ab7e..e94bf30 100644
--- a/cpp/vhal/client/include/AidlVhalClient.h
+++ b/cpp/vhal/client/include/AidlVhalClient.h
@@ -72,6 +72,8 @@
 
     ::android::base::Result<std::vector<std::unique_ptr<IHalPropConfig>>> getAllPropConfigs()
             override;
+    ::android::base::Result<std::vector<std::unique_ptr<IHalPropConfig>>> getPropConfigs(
+            std::vector<int32_t> propIds) override;
 
     std::unique_ptr<ISubscriptionClient> getSubscriptionClient(
             std::shared_ptr<ISubscriptionCallback> callback) override;
@@ -112,6 +114,9 @@
     void onBinderDiedWithContext();
     void onBinderUnlinkedWithContext();
 
+    ::android::base::Result<std::vector<std::unique_ptr<IHalPropConfig>>> parseVehiclePropConfigs(
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs& configs);
+
     // Test-only functions:
     AidlVhalClient(std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicle> hal,
                    int64_t timeoutInMs, std::unique_ptr<ILinkUnlinkToDeath> linkUnlinkImpl);
diff --git a/cpp/vhal/client/include/IVhalClient.h b/cpp/vhal/client/include/IVhalClient.h
index 6156503..9b1775f 100644
--- a/cpp/vhal/client/include/IVhalClient.h
+++ b/cpp/vhal/client/include/IVhalClient.h
@@ -89,6 +89,9 @@
     virtual ::android::base::Result<std::vector<std::unique_ptr<IHalPropConfig>>>
     getAllPropConfigs() = 0;
 
+    virtual ::android::base::Result<std::vector<std::unique_ptr<IHalPropConfig>>> getPropConfigs(
+            std::vector<int32_t> propIds) = 0;
+
     virtual std::unique_ptr<ISubscriptionClient> getSubscriptionClient(
             std::shared_ptr<ISubscriptionCallback> callback) = 0;
 };
diff --git a/cpp/vhal/client/src/AidlVhalClient.cpp b/cpp/vhal/client/src/AidlVhalClient.cpp
index cd59ece..ddf5362 100644
--- a/cpp/vhal/client/src/AidlVhalClient.cpp
+++ b/cpp/vhal/client/src/AidlVhalClient.cpp
@@ -16,6 +16,9 @@
 
 #include "AidlVhalClient.h"
 
+#include <android-base/strings.h>
+
+#include <AidlHalPropConfig.h>
 #include <AidlHalPropValue.h>
 #include <ParcelableUtils.h>
 #include <VehicleUtils.h>
@@ -26,7 +29,10 @@
 namespace automotive {
 namespace vhal {
 
+namespace {
+
 using ::android::base::Error;
+using ::android::base::Join;
 using ::android::base::Result;
 using ::android::hardware::automotive::vehicle::fromStableLargeParcelable;
 using ::android::hardware::automotive::vehicle::PendingRequestPool;
@@ -43,6 +49,8 @@
 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
 using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
@@ -50,6 +58,16 @@
 using ::ndk::ScopedAIBinder_DeathRecipient;
 using ::ndk::ScopedAStatus;
 
+std::string toString(const std::vector<int32_t>& values) {
+    std::vector<std::string> strings;
+    for (int32_t value : values) {
+        strings.push_back(std::to_string(value));
+    }
+    return "[" + Join(strings, ",") + "]";
+}
+
+}  // namespace
+
 AidlVhalClient::AidlVhalClient(std::shared_ptr<IVehicle> hal) :
       AidlVhalClient(hal, DEFAULT_TIMEOUT_IN_SEC * 1'000) {}
 
@@ -117,8 +135,39 @@
 }
 
 Result<std::vector<std::unique_ptr<IHalPropConfig>>> AidlVhalClient::getAllPropConfigs() {
-    // TODO(b/214635003): implement this.
-    return {};
+    VehiclePropConfigs configs;
+    if (ScopedAStatus status = mHal->getAllPropConfigs(&configs); !status.isOk()) {
+        return Error(status.getServiceSpecificError())
+                << "failed to get all property configs, error: " << status.getMessage();
+    }
+    return parseVehiclePropConfigs(configs);
+}
+
+Result<std::vector<std::unique_ptr<IHalPropConfig>>> AidlVhalClient::getPropConfigs(
+        std::vector<int32_t> propIds) {
+    VehiclePropConfigs configs;
+    if (ScopedAStatus status = mHal->getPropConfigs(propIds, &configs); !status.isOk()) {
+        return Error(status.getServiceSpecificError())
+                << "failed to prop configs for prop IDs: " << toString(propIds)
+                << ", error: " << status.getMessage();
+    }
+    return parseVehiclePropConfigs(configs);
+}
+
+Result<std::vector<std::unique_ptr<IHalPropConfig>>> AidlVhalClient::parseVehiclePropConfigs(
+        const VehiclePropConfigs& configs) {
+    auto parcelableResult = fromStableLargeParcelable(configs);
+    if (!parcelableResult.ok()) {
+        return Error(toInt(StatusCode::INTERNAL_ERROR))
+                << "failed to parse VehiclePropConfigs returned from VHAL, error: "
+                << parcelableResult.error().getMessage();
+    }
+    std::vector<std::unique_ptr<IHalPropConfig>> out;
+    for (const VehiclePropConfig& config : parcelableResult.value().getObject()->payloads) {
+        VehiclePropConfig configCopy = config;
+        out.push_back(std::make_unique<AidlHalPropConfig>(std::move(configCopy)));
+    }
+    return out;
 }
 
 void AidlVhalClient::onBinderDied(void* cookie) {
diff --git a/cpp/vhal/client/test/AidlVhalClientTest.cpp b/cpp/vhal/client/test/AidlVhalClientTest.cpp
index 2f7810b..9185c18 100644
--- a/cpp/vhal/client/test/AidlVhalClientTest.cpp
+++ b/cpp/vhal/client/test/AidlVhalClientTest.cpp
@@ -51,6 +51,7 @@
 using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 
@@ -66,7 +67,12 @@
         mCv.wait_for(lk, std::chrono::milliseconds(1000), [this] { return mThreadCount == 0; });
     }
 
-    ScopedAStatus getAllPropConfigs([[maybe_unused]] VehiclePropConfigs* returnConfigs) override {
+    ScopedAStatus getAllPropConfigs(VehiclePropConfigs* returnConfigs) override {
+        if (mStatus != StatusCode::OK) {
+            return ScopedAStatus::fromServiceSpecificError(toInt(mStatus));
+        }
+
+        returnConfigs->payloads = mPropConfigs;
         return ScopedAStatus::ok();
     }
 
@@ -120,8 +126,14 @@
         return ScopedAStatus::ok();
     }
 
-    ScopedAStatus getPropConfigs([[maybe_unused]] const std::vector<int32_t>& props,
-                                 [[maybe_unused]] VehiclePropConfigs* returnConfigs) override {
+    ScopedAStatus getPropConfigs(const std::vector<int32_t>& props,
+                                 VehiclePropConfigs* returnConfigs) override {
+        mGetPropConfigPropIds = props;
+        if (mStatus != StatusCode::OK) {
+            return ScopedAStatus::fromServiceSpecificError(toInt(mStatus));
+        }
+
+        returnConfigs->payloads = mPropConfigs;
         return ScopedAStatus::ok();
     }
 
@@ -155,12 +167,18 @@
 
     void setStatus(StatusCode status) { mStatus = status; }
 
+    void setPropConfigs(std::vector<VehiclePropConfig> configs) { mPropConfigs = configs; }
+
+    std::vector<int32_t> getGetPropConfigPropIds() { return mGetPropConfigPropIds; }
+
 private:
     std::mutex mLock;
     std::vector<GetValueResult> mGetValueResults;
     std::vector<GetValueRequest> mGetValueRequests;
     std::vector<SetValueResult> mSetValueResults;
     std::vector<SetValueRequest> mSetValueRequests;
+    std::vector<VehiclePropConfig> mPropConfigs;
+    std::vector<int32_t> mGetPropConfigPropIds;
     int64_t mWaitTimeInMs = 0;
     StatusCode mStatus = StatusCode::OK;
     std::condition_variable mCv;
@@ -191,6 +209,7 @@
 
     constexpr static int32_t TEST_PROP_ID = 1;
     constexpr static int32_t TEST_AREA_ID = 2;
+    constexpr static int32_t TEST_PROP_ID_2 = 3;
     constexpr static int64_t TEST_TIMEOUT_IN_MS = 100;
 
     void SetUp() override {
@@ -624,6 +643,92 @@
     ASSERT_EQ(countOnBinderDiedCallbacks(), static_cast<size_t>(0));
 }
 
+TEST_F(AidlVhalClientTest, testGetAllPropConfigs) {
+    getVhal()->setPropConfigs({
+            VehiclePropConfig{
+                    .prop = TEST_PROP_ID,
+                    .areaConfigs = {{
+                            .areaId = TEST_AREA_ID,
+                            .minInt32Value = 0,
+                            .maxInt32Value = 1,
+                    }},
+            },
+            VehiclePropConfig{
+                    .prop = TEST_PROP_ID_2,
+            },
+    });
+
+    auto result = getClient()->getAllPropConfigs();
+
+    ASSERT_TRUE(result.ok());
+    std::vector<std::unique_ptr<IHalPropConfig>> configs = std::move(result.value());
+
+    ASSERT_EQ(configs.size(), static_cast<size_t>(2));
+    ASSERT_EQ(configs[0]->getPropId(), TEST_PROP_ID);
+    ASSERT_EQ(configs[0]->getAreaConfigSize(), static_cast<size_t>(1));
+
+    const IHalAreaConfig* areaConfig = configs[0]->getAreaConfigs();
+    ASSERT_EQ(areaConfig->getAreaId(), TEST_AREA_ID);
+    ASSERT_EQ(areaConfig->getMinInt32Value(), 0);
+    ASSERT_EQ(areaConfig->getMaxInt32Value(), 1);
+
+    ASSERT_EQ(configs[1]->getPropId(), TEST_PROP_ID_2);
+    ASSERT_EQ(configs[1]->getAreaConfigSize(), static_cast<size_t>(0));
+}
+
+TEST_F(AidlVhalClientTest, testGetAllPropConfigsError) {
+    getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
+
+    auto result = getClient()->getAllPropConfigs();
+
+    ASSERT_FALSE(result.ok());
+    ASSERT_EQ(result.error().code(), toInt(StatusCode::INTERNAL_ERROR));
+}
+
+TEST_F(AidlVhalClientTest, testGetPropConfigs) {
+    getVhal()->setPropConfigs({
+            VehiclePropConfig{
+                    .prop = TEST_PROP_ID,
+                    .areaConfigs = {{
+                            .areaId = TEST_AREA_ID,
+                            .minInt32Value = 0,
+                            .maxInt32Value = 1,
+                    }},
+            },
+            VehiclePropConfig{
+                    .prop = TEST_PROP_ID_2,
+            },
+    });
+
+    std::vector<int32_t> propIds = {TEST_PROP_ID, TEST_PROP_ID_2};
+    auto result = getClient()->getPropConfigs(propIds);
+
+    ASSERT_EQ(getVhal()->getGetPropConfigPropIds(), propIds);
+    ASSERT_TRUE(result.ok());
+    std::vector<std::unique_ptr<IHalPropConfig>> configs = std::move(result.value());
+
+    ASSERT_EQ(configs.size(), static_cast<size_t>(2));
+    ASSERT_EQ(configs[0]->getPropId(), TEST_PROP_ID);
+    ASSERT_EQ(configs[0]->getAreaConfigSize(), static_cast<size_t>(1));
+
+    const IHalAreaConfig* areaConfig = configs[0]->getAreaConfigs();
+    ASSERT_EQ(areaConfig->getAreaId(), TEST_AREA_ID);
+    ASSERT_EQ(areaConfig->getMinInt32Value(), 0);
+    ASSERT_EQ(areaConfig->getMaxInt32Value(), 1);
+
+    ASSERT_EQ(configs[1]->getPropId(), TEST_PROP_ID_2);
+    ASSERT_EQ(configs[1]->getAreaConfigSize(), static_cast<size_t>(0));
+}
+
+TEST_F(AidlVhalClientTest, testGetPropConfigsError) {
+    getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
+
+    std::vector<int32_t> propIds = {TEST_PROP_ID, TEST_PROP_ID_2};
+    auto result = getClient()->getPropConfigs(propIds);
+
+    ASSERT_FALSE(result.ok());
+}
+
 }  // namespace test
 }  // namespace vhal
 }  // namespace automotive