Migrate VHAL VTS to be AIDL compatible.

Migrate VHAL VTS to be compatible with both HIDL and AIDL VHAL. The
test cases remains the same.

Test: atest VtsHalAutomotiveVehicle_TargetTest
Bug: 216736141
Change-Id: I5010b9c205656187e890b91dadc69e97ddc96862
diff --git a/automotive/vehicle/2.0/vts/functional/Android.bp b/automotive/vehicle/2.0/vts/functional/Android.bp
deleted file mode 100644
index e64e942..0000000
--- a/automotive/vehicle/2.0/vts/functional/Android.bp
+++ /dev/null
@@ -1,30 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_test {
-    name: "VtsHalAutomotiveVehicleV2_0TargetTest",
-    defaults: [
-        "VtsHalTargetTestDefaults",
-    ],
-    srcs: [
-        "VtsHalAutomotiveVehicleV2_0TargetTest.cpp",
-    ],
-    shared_libs: [
-        "libbase",
-        "libhidlbase",
-        "liblog",
-    ],
-    static_libs: [
-        "android.hardware.automotive.vehicle@2.0",
-    ],
-    test_suites: [
-        "vts",
-        "general-tests",
-    ],
-}
diff --git a/automotive/vehicle/2.0/vts/functional/VtsHalAutomotiveVehicleV2_0TargetTest.cpp b/automotive/vehicle/2.0/vts/functional/VtsHalAutomotiveVehicleV2_0TargetTest.cpp
deleted file mode 100644
index 8adec84..0000000
--- a/automotive/vehicle/2.0/vts/functional/VtsHalAutomotiveVehicleV2_0TargetTest.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "VtsHalAutomotiveVehicle"
-
-#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
-#include <utils/Log.h>
-#include <unordered_set>
-
-#include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/ServiceManagement.h>
-
-using namespace android::hardware::automotive::vehicle::V2_0;
-using ::android::sp;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-
-constexpr auto kTimeout = std::chrono::milliseconds(500);
-constexpr auto kInvalidProp = 0x31600207;
-
-class VtsVehicleCallback : public IVehicleCallback {
-  private:
-    using MutexGuard = std::lock_guard<std::mutex>;
-    using HidlVecOfValues = hidl_vec<VehiclePropValue>;
-    std::mutex mLock;
-    std::condition_variable mEventCond;
-    std::vector<HidlVecOfValues> mReceivedEvents;
-
-  public:
-    Return<void> onPropertyEvent(const hidl_vec<VehiclePropValue>& values) override {
-        {
-            MutexGuard guard(mLock);
-            mReceivedEvents.push_back(values);
-        }
-        mEventCond.notify_one();
-        return Return<void>();
-    }
-
-    Return<void> onPropertySet(const VehiclePropValue& /* value */) override {
-        return Return<void>();
-    }
-    Return<void> onPropertySetError(StatusCode /* errorCode */, int32_t /* propId */,
-                                    int32_t /* areaId */) override {
-        return Return<void>();
-    }
-
-    bool waitForExpectedEvents(size_t expectedEvents) {
-        std::unique_lock<std::mutex> g(mLock);
-
-        if (expectedEvents == 0 && mReceivedEvents.size() == 0) {
-            return mEventCond.wait_for(g, kTimeout) == std::cv_status::timeout;
-        }
-
-        while (expectedEvents != mReceivedEvents.size()) {
-            if (mEventCond.wait_for(g, kTimeout) == std::cv_status::timeout) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    void reset() { mReceivedEvents.clear(); }
-};
-
-class VehicleHalHidlTest : public testing::TestWithParam<std::string> {
-  public:
-    virtual void SetUp() override {
-        mVehicle = IVehicle::getService(GetParam());
-        ASSERT_NE(mVehicle.get(), nullptr);
-    }
-    virtual void TearDown() override {}
-
-    sp<IVehicle> mVehicle;
-
-    bool isBooleanGlobalProp(int32_t property) {
-        return (property & (int)VehiclePropertyType::MASK) == (int)VehiclePropertyType::BOOLEAN &&
-               (property & (int)VehicleArea::MASK) == (int)VehicleArea::GLOBAL;
-    }
-
-    void invokeGet(int32_t property, int32_t areaId) {
-        VehiclePropValue requestedValue{};
-        requestedValue.prop = property;
-        requestedValue.areaId = areaId;
-
-        invokeGet(requestedValue);
-    }
-
-    void invokeGet(const VehiclePropValue& requestedPropValue) {
-        mActualValue = VehiclePropValue{};  // reset previous values
-
-        StatusCode refStatus;
-        VehiclePropValue refValue;
-        bool isCalled = false;
-        mVehicle->get(requestedPropValue,
-                      [&refStatus, &refValue, &isCalled](StatusCode status,
-                                                         const VehiclePropValue& value) {
-                          refStatus = status;
-                          refValue = value;
-                          isCalled = true;
-                      });
-        ASSERT_TRUE(isCalled) << "callback wasn't called for property: " << requestedPropValue.prop;
-
-        mActualValue = refValue;
-        mActualStatusCode = refStatus;
-    }
-
-    VehiclePropValue mActualValue;
-    StatusCode mActualStatusCode;
-};
-
-// Test getAllPropConfig() returns at least 4 property configs.
-TEST_P(VehicleHalHidlTest, getAllPropConfigs) {
-    ALOGD("VehicleHalHidlTest::getAllPropConfigs");
-    bool isCalled = false;
-    hidl_vec<VehiclePropConfig> propConfigs;
-    mVehicle->getAllPropConfigs([&isCalled, &propConfigs](const hidl_vec<VehiclePropConfig>& cfgs) {
-        propConfigs = cfgs;
-        isCalled = true;
-    });
-    ASSERT_TRUE(isCalled);
-    ASSERT_GE(propConfigs.size(), 4);
-}
-
-// Test getPropConfig() can query all properties listed in CDD.
-TEST_P(VehicleHalHidlTest, getPropConfigs) {
-    ALOGD("VehicleHalHidlTest::getPropConfigs");
-    // Check the properties listed in CDD
-    hidl_vec<int32_t> properties = {
-            (int)VehicleProperty::GEAR_SELECTION, (int)VehicleProperty::NIGHT_MODE,
-            (int)VehicleProperty::PARKING_BRAKE_ON, (int)VehicleProperty::PERF_VEHICLE_SPEED};
-    bool isCalled = false;
-    mVehicle->getPropConfigs(
-            properties, [&isCalled](StatusCode status, const hidl_vec<VehiclePropConfig>& cfgs) {
-                ASSERT_EQ(StatusCode::OK, status);
-                ASSERT_EQ(4u, cfgs.size());
-                isCalled = true;
-            });
-    ASSERT_TRUE(isCalled);
-}
-
-// Test getPropConfig() with an invalid propertyId returns an error code.
-TEST_P(VehicleHalHidlTest, getPropConfigsWithInvalidProp) {
-    ALOGD("VehicleHalHidlTest::getPropConfigsWithInvalidProp");
-    hidl_vec<int32_t> properties = {kInvalidProp};
-    bool isCalled = false;
-    mVehicle->getPropConfigs(
-            properties, [&isCalled](StatusCode status, const hidl_vec<VehiclePropConfig>& cfgs) {
-                ASSERT_NE(StatusCode::OK, status);
-                ASSERT_EQ(0, cfgs.size());
-                isCalled = true;
-            });
-    ASSERT_TRUE(isCalled);
-}
-
-// Test get() return current value for properties.
-TEST_P(VehicleHalHidlTest, get) {
-    ALOGD("VehicleHalHidlTest::get");
-    invokeGet((int)VehicleProperty::PERF_VEHICLE_SPEED, 0);
-    ASSERT_EQ(StatusCode::OK, mActualStatusCode);
-}
-
-// Test get() with an invalid propertyId return an error codes.
-TEST_P(VehicleHalHidlTest, getInvalidProp) {
-    ALOGD("VehicleHalHidlTest::getInvalidProp");
-
-    invokeGet(kInvalidProp, 0);
-    ASSERT_NE(StatusCode::OK, mActualStatusCode);
-}
-
-// Test set() on read_write properties.
-TEST_P(VehicleHalHidlTest, setProp) {
-    ALOGD("VehicleHalHidlTest::setProp");
-    hidl_vec<VehiclePropConfig> propConfigs;
-    // skip hvac related properties
-    std::unordered_set<int32_t> hvacProps = {(int)VehicleProperty::HVAC_DEFROSTER,
-                                             (int)VehicleProperty::HVAC_AC_ON,
-                                             (int)VehicleProperty::HVAC_MAX_AC_ON,
-                                             (int)VehicleProperty::HVAC_MAX_DEFROST_ON,
-                                             (int)VehicleProperty::HVAC_RECIRC_ON,
-                                             (int)VehicleProperty::HVAC_DUAL_ON,
-                                             (int)VehicleProperty::HVAC_AUTO_ON,
-                                             (int)VehicleProperty::HVAC_POWER_ON,
-                                             (int)VehicleProperty::HVAC_AUTO_RECIRC_ON,
-                                             (int)VehicleProperty::HVAC_ELECTRIC_DEFROSTER_ON};
-    mVehicle->getAllPropConfigs(
-            [&propConfigs](const hidl_vec<VehiclePropConfig>& cfgs) { propConfigs = cfgs; });
-    for (const VehiclePropConfig& cfg : propConfigs) {
-        // test on boolean and writable property
-        if (cfg.access == VehiclePropertyAccess::READ_WRITE && isBooleanGlobalProp(cfg.prop) &&
-            !hvacProps.count(cfg.prop)) {
-            invokeGet(cfg.prop, 0);
-            int setValue = mActualValue.value.int32Values[0] == 1 ? 0 : 1;
-            VehiclePropValue propToSet = mActualValue;
-            propToSet.value.int32Values[0] = setValue;
-            ASSERT_EQ(StatusCode::OK, mVehicle->set(propToSet))
-                    << "Invalid status code for setting property: " << cfg.prop;
-            // check set success
-            invokeGet(cfg.prop, 0);
-            ASSERT_EQ(StatusCode::OK, mActualStatusCode);
-            ASSERT_EQ(setValue, mActualValue.value.int32Values[0])
-                    << "Failed to set value for property: " << cfg.prop;
-        }
-    }
-}
-
-// Test set() on an read_only property.
-TEST_P(VehicleHalHidlTest, setNotWritableProp) {
-    ALOGD("VehicleHalHidlTest::setNotWritableProp");
-    invokeGet(static_cast<int>(VehicleProperty::PERF_VEHICLE_SPEED), 0);
-    ASSERT_EQ(StatusCode::OK, mActualStatusCode);
-    VehiclePropValue vehicleSpeed = mActualValue;
-
-    ASSERT_EQ(StatusCode::ACCESS_DENIED, mVehicle->set(vehicleSpeed));
-}
-
-// Test subscribe() and unsubscribe().
-TEST_P(VehicleHalHidlTest, subscribeAndUnsubscribe) {
-    ALOGD("VehicleHalHidlTest::subscribeAndUnsubscribe");
-    const auto prop = static_cast<int>(VehicleProperty::PERF_VEHICLE_SPEED);
-    sp<VtsVehicleCallback> cb = new VtsVehicleCallback();
-
-    hidl_vec<SubscribeOptions> options = {
-            SubscribeOptions{.propId = prop, 100.0, .flags = SubscribeFlags::EVENTS_FROM_CAR}};
-
-    ASSERT_EQ(StatusCode::OK, mVehicle->subscribe(cb, options));
-    ASSERT_TRUE(cb->waitForExpectedEvents(10));
-
-    ASSERT_EQ(StatusCode::OK, mVehicle->unsubscribe(cb, prop));
-    cb->reset();
-    ASSERT_FALSE(cb->waitForExpectedEvents(10));
-}
-
-// Test subscribe() with an invalid property.
-TEST_P(VehicleHalHidlTest, subscribeInvalidProp) {
-    ALOGD("VehicleHalHidlTest::subscribeInvalidProp");
-
-    sp<VtsVehicleCallback> cb = new VtsVehicleCallback();
-
-    hidl_vec<SubscribeOptions> options = {SubscribeOptions{
-            .propId = kInvalidProp, 10.0, .flags = SubscribeFlags::EVENTS_FROM_CAR}};
-
-    ASSERT_NE(StatusCode::OK, mVehicle->subscribe(cb, options));
-}
-
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VehicleHalHidlTest);
-INSTANTIATE_TEST_SUITE_P(
-        PerInstance, VehicleHalHidlTest,
-        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVehicle::descriptor)),
-        android::hardware::PrintInstanceNameToString);
diff --git a/automotive/vehicle/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index ff6f3be..7e42554 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -24,5 +24,10 @@
     {
       "name": "DefaultVehicleHalTest"
     }
+  ],
+  "auto-presubmit": [
+    {
+      "name": "VtsHalAutomotiveVehicle_TargetTest"
+    }
   ]
 }
diff --git a/automotive/vehicle/vts/Android.bp b/automotive/vehicle/vts/Android.bp
new file mode 100644
index 0000000..c8276d7
--- /dev/null
+++ b/automotive/vehicle/vts/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+    name: "VtsHalAutomotiveVehicle_TargetTest",
+    srcs: [
+        "src/*.cpp",
+    ],
+    static_libs: [
+        "libgtest",
+        "libvhalclient",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libvndksupport",
+    ],
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+        "vhalclient_defaults",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    require_root: true,
+}
diff --git a/automotive/vehicle/2.0/vts/functional/OWNERS b/automotive/vehicle/vts/OWNERS
similarity index 71%
rename from automotive/vehicle/2.0/vts/functional/OWNERS
rename to automotive/vehicle/vts/OWNERS
index 8a0f2af..c93a843 100644
--- a/automotive/vehicle/2.0/vts/functional/OWNERS
+++ b/automotive/vehicle/vts/OWNERS
@@ -1,2 +1,3 @@
 # Bug component: 533426
+shanyu@google.com
 kwangsudo@google.com
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
new file mode 100644
index 0000000..32382f2
--- /dev/null
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalAutomotiveVehicle"
+
+#include <IVhalClient.h>
+#include <VehicleHalTypes.h>
+#include <VehicleUtils.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/automotive/vehicle/IVehicle.h>
+#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <inttypes.h>
+#include <utils/Log.h>
+
+#include <chrono>
+#include <mutex>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+using ::aidl::android::hardware::automotive::vehicle::IVehicle;
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
+using ::android::getAidlHalInstanceNames;
+using ::android::base::ScopedLockAssertion;
+using ::android::base::StringPrintf;
+using ::android::frameworks::automotive::vhal::HalPropError;
+using ::android::frameworks::automotive::vhal::IHalPropConfig;
+using ::android::frameworks::automotive::vhal::IHalPropValue;
+using ::android::frameworks::automotive::vhal::ISubscriptionCallback;
+using ::android::frameworks::automotive::vhal::IVhalClient;
+using ::android::hardware::getAllHalInstanceNames;
+using ::android::hardware::Sanitize;
+using ::android::hardware::automotive::vehicle::toInt;
+
+constexpr int32_t kInvalidProp = 0x31600207;
+
+struct ServiceDescriptor {
+    std::string name;
+    bool isAidlService;
+};
+
+class VtsVehicleCallback final : public ISubscriptionCallback {
+  private:
+    std::mutex mLock;
+    std::unordered_map<int32_t, size_t> mEventsCount GUARDED_BY(mLock);
+    std::condition_variable mEventCond;
+
+  public:
+    void onPropertyEvent(const std::vector<std::unique_ptr<IHalPropValue>>& values) override {
+        {
+            std::lock_guard<std::mutex> lockGuard(mLock);
+            for (auto& value : values) {
+                mEventsCount[value->getPropId()] += 1;
+            }
+        }
+        mEventCond.notify_one();
+    }
+
+    void onPropertySetError([[maybe_unused]] const std::vector<HalPropError>& errors) override {
+        // Do nothing.
+    }
+
+    template <class Rep, class Period>
+    bool waitForExpectedEvents(int32_t propId, size_t expectedEvents,
+                               const std::chrono::duration<Rep, Period>& timeout) {
+        std::unique_lock<std::mutex> uniqueLock(mLock);
+        return mEventCond.wait_for(uniqueLock, timeout, [this, propId, expectedEvents] {
+            ScopedLockAssertion lockAssertion(mLock);
+            return mEventsCount[propId] >= expectedEvents;
+        });
+    }
+
+    void reset() {
+        std::lock_guard<std::mutex> lockGuard(mLock);
+        mEventsCount.clear();
+    }
+};
+
+class VtsHalAutomotiveVehicleTargetTest : public testing::TestWithParam<ServiceDescriptor> {
+  public:
+    virtual void SetUp() override {
+        auto descriptor = GetParam();
+        if (descriptor.isAidlService) {
+            mVhalClient = IVhalClient::tryCreateAidlClient(descriptor.name.c_str());
+        } else {
+            mVhalClient = IVhalClient::tryCreateHidlClient(descriptor.name.c_str());
+        }
+
+        ASSERT_NE(mVhalClient, nullptr) << "Failed to connect to VHAL";
+
+        mCallback = std::make_shared<VtsVehicleCallback>();
+    }
+
+    static bool isBooleanGlobalProp(int32_t property) {
+        return (property & toInt(VehiclePropertyType::MASK)) ==
+                       toInt(VehiclePropertyType::BOOLEAN) &&
+               (property & toInt(VehicleArea::MASK)) == toInt(VehicleArea::GLOBAL);
+    }
+
+  protected:
+    std::shared_ptr<IVhalClient> mVhalClient;
+    std::shared_ptr<VtsVehicleCallback> mCallback;
+};
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, useAidlBackend) {
+    if (!mVhalClient->isAidlVhal()) {
+        GTEST_SKIP() << "AIDL backend is not available, HIDL backend is used instead";
+    }
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, useHidlBackend) {
+    if (mVhalClient->isAidlVhal()) {
+        GTEST_SKIP() << "AIDL backend is available, HIDL backend is not used";
+    }
+}
+
+// Test getAllPropConfig() returns at least 4 property configs.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, getAllPropConfigs) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::getAllPropConfigs");
+
+    auto result = mVhalClient->getAllPropConfigs();
+
+    ASSERT_TRUE(result.ok()) << "Failed to get all property configs, error: "
+                             << result.error().message();
+    ASSERT_GE(result.value().size(), 4u) << StringPrintf(
+            "Expect to get at least 4 property configs, got %zu", result.value().size());
+}
+
+// Test getPropConfigs() can query all properties listed in CDD.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, getRequiredPropConfigs) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::getRequiredPropConfigs");
+
+    // Check the properties listed in CDD
+    std::vector<int32_t> properties = {
+            toInt(VehicleProperty::GEAR_SELECTION), toInt(VehicleProperty::NIGHT_MODE),
+            toInt(VehicleProperty::PARKING_BRAKE_ON), toInt(VehicleProperty::PERF_VEHICLE_SPEED)};
+
+    auto result = mVhalClient->getPropConfigs(properties);
+
+    ASSERT_TRUE(result.ok()) << "Failed to get required property config, error: "
+                             << result.error().message();
+    ASSERT_EQ(result.value().size(), 4u)
+            << StringPrintf("Expect to get exactly 4 configs, got %zu", result.value().size());
+}
+
+// Test getPropConfig() with an invalid propertyId returns an error code.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, getPropConfigsWithInvalidProp) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::getPropConfigsWithInvalidProp");
+
+    auto result = mVhalClient->getPropConfigs({kInvalidProp});
+
+    ASSERT_FALSE(result.ok()) << StringPrintf(
+            "Expect failure to get prop configs for invalid prop: %" PRId32, kInvalidProp);
+    ASSERT_NE(result.error().message(), "") << "Expect error message not to be empty";
+}
+
+// Test get() return current value for properties.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, get) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::get");
+
+    int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
+    auto result = mVhalClient->getValueSync(*mVhalClient->createHalPropValue(propId));
+
+    ASSERT_TRUE(result.ok()) << StringPrintf("Failed to get value for property: %" PRId32
+                                             ", error: %s",
+                                             propId, result.error().message().c_str());
+    ASSERT_NE(result.value(), nullptr) << "Result value must not be null";
+}
+
+// Test get() with an invalid propertyId return an error codes.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, getInvalidProp) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::getInvalidProp");
+
+    auto result = mVhalClient->getValueSync(*mVhalClient->createHalPropValue(kInvalidProp));
+
+    ASSERT_FALSE(result.ok()) << StringPrintf(
+            "Expect failure to get property for invalid prop: %" PRId32, kInvalidProp);
+}
+
+// Test set() on read_write properties.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, setProp) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::setProp");
+
+    // skip hvac related properties
+    std::unordered_set<int32_t> hvacProps = {toInt(VehicleProperty::HVAC_DEFROSTER),
+                                             toInt(VehicleProperty::HVAC_AC_ON),
+                                             toInt(VehicleProperty::HVAC_MAX_AC_ON),
+                                             toInt(VehicleProperty::HVAC_MAX_DEFROST_ON),
+                                             toInt(VehicleProperty::HVAC_RECIRC_ON),
+                                             toInt(VehicleProperty::HVAC_DUAL_ON),
+                                             toInt(VehicleProperty::HVAC_AUTO_ON),
+                                             toInt(VehicleProperty::HVAC_POWER_ON),
+                                             toInt(VehicleProperty::HVAC_AUTO_RECIRC_ON),
+                                             toInt(VehicleProperty::HVAC_ELECTRIC_DEFROSTER_ON)};
+    auto result = mVhalClient->getAllPropConfigs();
+    ASSERT_TRUE(result.ok());
+
+    for (const auto& cfgPtr : result.value()) {
+        const IHalPropConfig& cfg = *cfgPtr;
+        int32_t propId = cfg.getPropId();
+        // test on boolean and writable property
+        if (cfg.getAccess() == toInt(VehiclePropertyAccess::READ_WRITE) &&
+            isBooleanGlobalProp(propId) && !hvacProps.count(propId)) {
+            auto propToGet = mVhalClient->createHalPropValue(propId);
+            auto getValueResult = mVhalClient->getValueSync(*propToGet);
+
+            ASSERT_TRUE(getValueResult.ok())
+                    << StringPrintf("Failed to get value for property: %" PRId32 ", error: %s",
+                                    propId, getValueResult.error().message().c_str());
+            ASSERT_NE(getValueResult.value(), nullptr)
+                    << StringPrintf("Result value must not be null for property: %" PRId32, propId);
+
+            const IHalPropValue& value = *getValueResult.value();
+            size_t intValueSize = value.getInt32Values().size();
+            ASSERT_EQ(intValueSize, 1u) << StringPrintf(
+                    "Expect exactly 1 int value for boolean property: %" PRId32 ", got %zu", propId,
+                    intValueSize);
+
+            int setValue = value.getInt32Values()[0] == 1 ? 0 : 1;
+            auto propToSet = mVhalClient->createHalPropValue(propId);
+            propToSet->setInt32Values({setValue});
+            auto setValueResult = mVhalClient->setValueSync(*propToSet);
+
+            ASSERT_TRUE(setValueResult.ok())
+                    << StringPrintf("Failed to set value for property: %" PRId32 ", error: %s",
+                                    propId, setValueResult.error().message().c_str());
+
+            // check set success
+            getValueResult = mVhalClient->getValueSync(*propToGet);
+            ASSERT_TRUE(getValueResult.ok())
+                    << StringPrintf("Failed to get value for property: %" PRId32 ", error: %s",
+                                    propId, getValueResult.error().message().c_str());
+            ASSERT_NE(getValueResult.value(), nullptr)
+                    << StringPrintf("Result value must not be null for property: %" PRId32, propId);
+            ASSERT_EQ(getValueResult.value()->getInt32Values(), std::vector<int32_t>({setValue}))
+                    << StringPrintf("Boolean value not updated after set for property: %" PRId32,
+                                    propId);
+        }
+    }
+}
+
+// Test set() on an read_only property.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, setNotWritableProp) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::setNotWritableProp");
+
+    int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
+    auto getValueResult = mVhalClient->getValueSync(*mVhalClient->createHalPropValue(propId));
+    ASSERT_TRUE(getValueResult.ok())
+            << StringPrintf("Failed to get value for property: %" PRId32 ", error: %s", propId,
+                            getValueResult.error().message().c_str());
+
+    auto setValueResult = mVhalClient->setValueSync(*getValueResult.value());
+
+    ASSERT_FALSE(setValueResult.ok()) << "Expect set a read-only value to fail";
+    ASSERT_EQ(setValueResult.error().code(), toInt(StatusCode::ACCESS_DENIED));
+}
+
+// Test subscribe() and unsubscribe().
+TEST_P(VtsHalAutomotiveVehicleTargetTest, subscribeAndUnsubscribe) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::subscribeAndUnsubscribe");
+
+    int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
+
+    std::vector<SubscribeOptions> options = {
+            SubscribeOptions{.propId = propId, .sampleRate = 10.0}};
+
+    auto client = mVhalClient->getSubscriptionClient(mCallback);
+    ASSERT_NE(client, nullptr) << "Failed to get subscription client";
+
+    auto result = client->subscribe(options);
+
+    ASSERT_TRUE(result.ok()) << StringPrintf("Failed to subscribe to property: %" PRId32
+                                             ", error: %s",
+                                             propId, result.error().message().c_str());
+    ASSERT_TRUE(mCallback->waitForExpectedEvents(propId, 10, std::chrono::seconds(10)))
+            << "Didn't get enough events for subscription";
+
+    result = client->unsubscribe({propId});
+    ASSERT_TRUE(result.ok()) << StringPrintf("Failed to unsubscribe to property: %" PRId32
+                                             ", error: %s",
+                                             propId, result.error().message().c_str());
+
+    mCallback->reset();
+    ASSERT_FALSE(mCallback->waitForExpectedEvents(propId, 10, std::chrono::seconds(1)))
+            << "Expect not to get events after unsubscription";
+}
+
+// Test subscribe() with an invalid property.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, subscribeInvalidProp) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::subscribeInvalidProp");
+
+    std::vector<SubscribeOptions> options = {
+            SubscribeOptions{.propId = kInvalidProp, .sampleRate = 10.0}};
+
+    auto client = mVhalClient->getSubscriptionClient(mCallback);
+    ASSERT_NE(client, nullptr) << "Failed to get subscription client";
+
+    auto result = client->subscribe(options);
+
+    ASSERT_FALSE(result.ok()) << StringPrintf("Expect subscribing to property: %" PRId32 " to fail",
+                                              kInvalidProp);
+}
+
+std::vector<ServiceDescriptor> getDescriptors() {
+    std::vector<ServiceDescriptor> descriptors;
+    for (std::string name : getAidlHalInstanceNames(IVehicle::descriptor)) {
+        descriptors.push_back({
+                .name = name,
+                .isAidlService = true,
+        });
+    }
+    for (std::string name : getAllHalInstanceNames(IVehicle::descriptor)) {
+        descriptors.push_back({
+                .name = name,
+                .isAidlService = false,
+        });
+    }
+    return descriptors;
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VtsHalAutomotiveVehicleTargetTest);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, VtsHalAutomotiveVehicleTargetTest,
+                         testing::ValuesIn(getDescriptors()),
+                         [](const testing::TestParamInfo<ServiceDescriptor>& info) {
+                             std::string name = "";
+                             if (info.param.isAidlService) {
+                                 name += "aidl_";
+                             } else {
+                                 name += "hidl_";
+                             }
+                             name += info.param.name;
+                             return Sanitize(name);
+                         });
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    return RUN_ALL_TESTS();
+}