Merge "Declare android.hardware.radio@1.6 as system_ext module" into tm-dev
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/aidl/android/hardware/automotive/vehicle/IVehicle.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
index a947963..dc9b876 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
@@ -165,6 +165,11 @@
      *    a property set failure message sent from the vehicle bus.
      * @param options List of options to subscribe. SubscribeOption contains
      *    information such as property Id, area Id, sample rate, etc.
+     *    For continuous properties, sample rate must be provided. If sample
+     *    rate is less than {@link VehiclePropConfig#minSampleRate}, the sample
+     *    rate would be minSampleRate. If sample rate is larger than
+     *    {@link VehiclePropValue#maxSampleRate}, the sample rate would be
+     *    maxSampleRate.
      * @param maxSharedMemoryFileCount The maximum number of shared memory files
      *    allocated for in VHAL for this subscription. When a memory file is
      *    handled back to the client, it cannot be used by VHAL to deliver
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index fa494c6..1c076d3 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -41,7 +41,7 @@
 
 class FakeVehicleHardware : public IVehicleHardware {
   public:
-    using ValueResultType = android::base::Result<VehiclePropValuePool::RecyclableType, VhalError>;
+    using ValueResultType = VhalResult<VehiclePropValuePool::RecyclableType>;
 
     FakeVehicleHardware();
 
@@ -90,7 +90,7 @@
     ValueResultType getValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
 
-    android::base::Result<void, VhalError> setValue(
+    VhalResult<void> setValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
 
   private:
@@ -117,17 +117,17 @@
     // Override the properties using config files in 'overrideDir'.
     void overrideProperties(const char* overrideDir);
 
-    android::base::Result<void, VhalError> maybeSetSpecialValue(
+    VhalResult<void> maybeSetSpecialValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
             bool* isSpecialValue);
     ValueResultType maybeGetSpecialValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
             bool* isSpecialValue) const;
-    android::base::Result<void, VhalError> setApPowerStateReport(
+    VhalResult<void> setApPowerStateReport(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
     VehiclePropValuePool::RecyclableType createApPowerStateReq(
             aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq state);
-    android::base::Result<void, VhalError> setUserHalProp(
+    VhalResult<void> setUserHalProp(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
     ValueResultType getUserHalProp(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 233efc8..462506d 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -68,8 +68,6 @@
 using ::android::base::StartsWith;
 using ::android::base::StringPrintf;
 
-using StatusError = android::base::Error<VhalError>;
-
 const char* VENDOR_OVERRIDE_DIR = "/vendor/etc/automotive/vhaloverride/";
 const char* OVERRIDE_PROPERTY = "persist.vendor.vhal_init_value_override";
 
@@ -193,7 +191,7 @@
     return req;
 }
 
-Result<void, VhalError> FakeVehicleHardware::setApPowerStateReport(const VehiclePropValue& value) {
+VhalResult<void> FakeVehicleHardware::setApPowerStateReport(const VehiclePropValue& value) {
     auto updatedValue = mValuePool->obtain(value);
     updatedValue->timestamp = elapsedRealtimeNano();
 
@@ -270,7 +268,7 @@
     return false;
 }
 
-Result<void, VhalError> FakeVehicleHardware::setUserHalProp(const VehiclePropValue& value) {
+VhalResult<void> FakeVehicleHardware::setUserHalProp(const VehiclePropValue& value) {
     auto result = mFakeUserHal->onSetProperty(value);
     if (!result.ok()) {
         return StatusError(getErrorCode(result))
@@ -345,8 +343,8 @@
     return nullptr;
 }
 
-Result<void, VhalError> FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValue& value,
-                                                                  bool* isSpecialValue) {
+VhalResult<void> FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValue& value,
+                                                           bool* isSpecialValue) {
     *isSpecialValue = false;
     VehiclePropValuePool::RecyclableType updatedValue;
     int32_t propId = value.prop;
@@ -442,7 +440,7 @@
     return StatusCode::OK;
 }
 
-Result<void, VhalError> FakeVehicleHardware::setValue(const VehiclePropValue& value) {
+VhalResult<void> FakeVehicleHardware::setValue(const VehiclePropValue& value) {
     bool isSpecialValue = false;
     auto setSpecialValueResult = maybeSetSpecialValue(value, &isSpecialValue);
 
diff --git a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/include/FakeObd2Frame.h b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/include/FakeObd2Frame.h
index ba40f60..4d2ffd0 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/include/FakeObd2Frame.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/include/FakeObd2Frame.h
@@ -38,11 +38,11 @@
             const aidl::android::hardware::automotive::vehicle::VehiclePropConfig& propConfig);
     void initObd2FreezeFrame(
             const aidl::android::hardware::automotive::vehicle::VehiclePropConfig& propConfig);
-    android::base::Result<VehiclePropValuePool::RecyclableType, VhalError> getObd2FreezeFrame(
+    VhalResult<VehiclePropValuePool::RecyclableType> getObd2FreezeFrame(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue&
                     requestedPropValue) const;
-    android::base::Result<VehiclePropValuePool::RecyclableType, VhalError> getObd2DtcInfo() const;
-    android::base::Result<void, VhalError> clearObd2FreezeFrames(
+    VhalResult<VehiclePropValuePool::RecyclableType> getObd2DtcInfo() const;
+    VhalResult<void> clearObd2FreezeFrames(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
     static bool isDiagnosticProperty(
             const aidl::android::hardware::automotive::vehicle::VehiclePropConfig& propConfig);
diff --git a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/src/FakeObd2Frame.cpp b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/src/FakeObd2Frame.cpp
index 0a4affc..5f9f217 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/src/FakeObd2Frame.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/src/FakeObd2Frame.cpp
@@ -46,8 +46,6 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::android::base::Result;
 
-using StatusError = android::base::Error<VhalError>;
-
 std::unique_ptr<Obd2SensorStore> FakeObd2Frame::fillDefaultObd2Frame(size_t numVendorIntegerSensors,
                                                                      size_t numVendorFloatSensors) {
     std::unique_ptr<Obd2SensorStore> sensorStore(new Obd2SensorStore(
@@ -127,7 +125,7 @@
     }
 }
 
-Result<VehiclePropValuePool::RecyclableType, VhalError> FakeObd2Frame::getObd2FreezeFrame(
+VhalResult<VehiclePropValuePool::RecyclableType> FakeObd2Frame::getObd2FreezeFrame(
         const VehiclePropValue& requestedPropValue) const {
     if (requestedPropValue.value.int64Values.size() != 1) {
         return StatusError(StatusCode::INVALID_ARG)
@@ -153,7 +151,7 @@
     return readValueResult;
 }
 
-Result<VehiclePropValuePool::RecyclableType, VhalError> FakeObd2Frame::getObd2DtcInfo() const {
+VhalResult<VehiclePropValuePool::RecyclableType> FakeObd2Frame::getObd2DtcInfo() const {
     std::vector<int64_t> timestamps;
     auto result = mPropStore->readValuesForProperty(OBD2_FREEZE_FRAME);
     if (!result.ok()) {
@@ -170,7 +168,7 @@
     return outValue;
 }
 
-Result<void, VhalError> FakeObd2Frame::clearObd2FreezeFrames(const VehiclePropValue& propValue) {
+VhalResult<void> FakeObd2Frame::clearObd2FreezeFrames(const VehiclePropValue& propValue) {
     if (propValue.value.int64Values.size() == 0) {
         mPropStore->removeValuesForProperty(OBD2_FREEZE_FRAME);
         return {};
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h b/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
index 9c4887c..4ae9c8c 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
@@ -39,7 +39,7 @@
 // Class used to emulate a real User HAL behavior through lshal debug requests.
 class FakeUserHal final {
   public:
-    using ValueResultType = android::base::Result<VehiclePropValuePool::RecyclableType, VhalError>;
+    using ValueResultType = VhalResult<VehiclePropValuePool::RecyclableType>;
 
     explicit FakeUserHal(std::shared_ptr<VehiclePropValuePool> valuePool) : mValuePool(valuePool) {}
 
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp b/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
index e37f619..7748fb6 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
@@ -44,8 +44,6 @@
 using ::android::base::Error;
 using ::android::base::Result;
 
-using StatusError = android::base::Error<VhalError>;
-
 constexpr int32_t INITIAL_USER_INFO = toInt(VehicleProperty::INITIAL_USER_INFO);
 constexpr int32_t SWITCH_USER = toInt(VehicleProperty::SWITCH_USER);
 constexpr int32_t CREATE_USER = toInt(VehicleProperty::CREATE_USER);
@@ -53,7 +51,7 @@
 constexpr int32_t USER_IDENTIFICATION_ASSOCIATION =
         toInt(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
 
-Result<int32_t, VhalError> getRequestId(const VehiclePropValue& value) {
+VhalResult<int32_t> getRequestId(const VehiclePropValue& value) {
     if (value.value.int32Values.size() < 1) {
         return StatusError(StatusCode::INVALID_ARG)
                << "no int32Values on property: " << value.toString();
@@ -61,7 +59,7 @@
     return value.value.int32Values[0];
 }
 
-Result<SwitchUserMessageType, VhalError> getSwitchUserMessageType(const VehiclePropValue& value) {
+VhalResult<SwitchUserMessageType> getSwitchUserMessageType(const VehiclePropValue& value) {
     if (value.value.int32Values.size() < 2) {
         return StatusError(StatusCode::INVALID_ARG)
                << "missing switch user message type on property: " << value.toString();
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/PendingRequestPool.h b/automotive/vehicle/aidl/impl/utils/common/include/PendingRequestPool.h
index 4ab8acd..3f8db93 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/PendingRequestPool.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/PendingRequestPool.h
@@ -50,9 +50,9 @@
     // added. Otherwise, they would be added to the request pool.
     // The callback would be called if requests are not finished within {@code mTimeoutInNano}
     // seconds.
-    android::base::Result<void, VhalError> addRequests(
-            const void* clientId, const std::unordered_set<int64_t>& requestIds,
-            std::shared_ptr<const TimeoutCallbackFunc> callback);
+    VhalResult<void> addRequests(const void* clientId,
+                                 const std::unordered_set<int64_t>& requestIds,
+                                 std::shared_ptr<const TimeoutCallbackFunc> callback);
 
     // Checks whether the request is currently pending.
     bool isRequestPending(const void* clientId, int64_t requestId) const;
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h b/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
index cebf95c..ddc4f68 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
@@ -43,9 +43,8 @@
 // This class is thread-safe, however it uses blocking synchronization across all methods.
 class VehiclePropertyStore final {
   public:
-    using ValueResultType = android::base::Result<VehiclePropValuePool::RecyclableType, VhalError>;
-    using ValuesResultType =
-            android::base::Result<std::vector<VehiclePropValuePool::RecyclableType>, VhalError>;
+    using ValueResultType = VhalResult<VehiclePropValuePool::RecyclableType>;
+    using ValuesResultType = VhalResult<std::vector<VehiclePropValuePool::RecyclableType>>;
 
     explicit VehiclePropertyStore(std::shared_ptr<VehiclePropValuePool> valuePool)
         : mValuePool(valuePool) {}
@@ -73,8 +72,8 @@
     // 'status' would be initialized to {@code VehiclePropertyStatus::AVAILABLE}, if this is to
     // override an existing value, the status for the existing value would be used for the
     // overridden value.
-    android::base::Result<void, VhalError> writeValue(
-            VehiclePropValuePool::RecyclableType propValue, bool updateStatus = false);
+    VhalResult<void> writeValue(VehiclePropValuePool::RecyclableType propValue,
+                                bool updateStatus = false);
 
     // Remove a given property value from the property store. The 'propValue' would be used to
     // generate the key for the value to remove.
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index 8ef0218..6d7d131 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -251,9 +251,16 @@
     aidl::android::hardware::automotive::vehicle::StatusCode mCode;
 };
 
+// VhalResult is a {@code Result} that contains {@code StatusCode} as error type.
 template <class T>
-aidl::android::hardware::automotive::vehicle::StatusCode getErrorCode(
-        const android::base::Result<T, VhalError>& result) {
+using VhalResult = android::base::Result<T, VhalError>;
+
+// StatusError could be cast to {@code ResultError} with a {@code StatusCode} and should be used
+// as error type for {@VhalResult}.
+using StatusError = android::base::Error<VhalError>;
+
+template <class T>
+aidl::android::hardware::automotive::vehicle::StatusCode getErrorCode(const VhalResult<T>& result) {
     if (result.ok()) {
         return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
     }
@@ -261,7 +268,7 @@
 }
 
 template <class T>
-int getIntErrorCode(const android::base::Result<T, VhalError>& result) {
+int getIntErrorCode(const VhalResult<T>& result) {
     return toInt(getErrorCode(result));
 }
 
@@ -293,12 +300,12 @@
 }
 
 template <class T>
-ndk::ScopedAStatus toScopedAStatus(const android::base::Result<T, VhalError>& result) {
+ndk::ScopedAStatus toScopedAStatus(const VhalResult<T>& result) {
     return toScopedAStatus(result, getErrorCode(result));
 }
 
 template <class T>
-ndk::ScopedAStatus toScopedAStatus(const android::base::Result<T, VhalError>& result,
+ndk::ScopedAStatus toScopedAStatus(const VhalResult<T>& result,
                                    const std::string& additionalErrorMsg) {
     return toScopedAStatus(result, getErrorCode(result), additionalErrorMsg);
 }
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/PendingRequestPool.cpp b/automotive/vehicle/aidl/impl/utils/common/src/PendingRequestPool.cpp
index f8a042d..0196edd 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/PendingRequestPool.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/PendingRequestPool.cpp
@@ -37,8 +37,6 @@
 // At least check every 1s.
 constexpr int64_t CHECK_TIME_IN_NANO = 1'000'000'000;
 
-using StatusError = android::base::Error<VhalError>;
-
 }  // namespace
 
 PendingRequestPool::PendingRequestPool(int64_t timeoutInNano)
@@ -73,7 +71,7 @@
     }
 }
 
-Result<void, VhalError> PendingRequestPool::addRequests(
+VhalResult<void> PendingRequestPool::addRequests(
         const void* clientId, const std::unordered_set<int64_t>& requestIds,
         std::shared_ptr<const TimeoutCallbackFunc> callback) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index 776caed..c8fb994 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -39,8 +39,6 @@
 using ::android::base::Result;
 using ::android::base::StringPrintf;
 
-using StatusError = android::base::Error<VhalError>;
-
 bool VehiclePropertyStore::RecordId::operator==(const VehiclePropertyStore::RecordId& other) const {
     return area == other.area && token == other.token;
 }
@@ -88,7 +86,7 @@
     return recId;
 }
 
-Result<VehiclePropValuePool::RecyclableType, VhalError> VehiclePropertyStore::readValueLocked(
+VhalResult<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValueLocked(
         const RecordId& recId, const Record& record) const REQUIRES(mLock) {
     if (auto it = record.values.find(recId); it != record.values.end()) {
         return mValuePool->obtain(*(it->second));
@@ -107,8 +105,8 @@
     };
 }
 
-Result<void, VhalError> VehiclePropertyStore::writeValue(
-        VehiclePropValuePool::RecyclableType propValue, bool updateStatus) {
+VhalResult<void> VehiclePropertyStore::writeValue(VehiclePropValuePool::RecyclableType propValue,
+                                                  bool updateStatus) {
     std::scoped_lock<std::mutex> g(mLock);
 
     int32_t propId = propValue->prop;
@@ -248,7 +246,7 @@
     return configs;
 }
 
-Result<const VehiclePropConfig*, VhalError> VehiclePropertyStore::getConfig(int32_t propId) const {
+VhalResult<const VehiclePropConfig*> VehiclePropertyStore::getConfig(int32_t propId) const {
     std::scoped_lock<std::mutex> g(mLock);
 
     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
index c8bf1d8..4d6f811 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
@@ -37,7 +37,6 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
-using ::android::base::Result;
 using ::testing::ElementsAre;
 using ::testing::Eq;
 using ::testing::WhenSortedBy;
@@ -103,7 +102,7 @@
 }
 
 TEST_F(VehiclePropertyStoreTest, testGetConfig) {
-    Result<const VehiclePropConfig*, VhalError> result =
+    VhalResult<const VehiclePropConfig*> result =
             mStore->getConfig(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
 
     ASSERT_RESULT_OK(result);
@@ -111,7 +110,7 @@
 }
 
 TEST_F(VehiclePropertyStoreTest, testGetConfigWithInvalidPropId) {
-    Result<const VehiclePropConfig*, VhalError> result = mStore->getConfig(INVALID_PROP_ID);
+    VhalResult<const VehiclePropConfig*> result = mStore->getConfig(INVALID_PROP_ID);
 
     EXPECT_FALSE(result.ok()) << "expect error when getting a config for an invalid property ID";
     EXPECT_EQ(result.error().code(), StatusCode::INVALID_ARG);
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
index cc29964..411539b 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
@@ -763,7 +763,7 @@
 }
 
 TEST(VehicleUtilsTest, testVhalError) {
-    Result<void, VhalError> result = Error<VhalError>(StatusCode::INVALID_ARG) << "error message";
+    VhalResult<void> result = Error<VhalError>(StatusCode::INVALID_ARG) << "error message";
 
     ASSERT_EQ(result.error().message(), "error message: INVALID_ARG");
 }
diff --git a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
index 6ab0e1e..2e7298f 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
@@ -58,8 +58,7 @@
     // Returns {@code INVALID_ARG} error if any of the requestIds are duplicate with one of the
     // pending request IDs or {@code TRY_AGAIN} error if the pending request pool is full and could
     // no longer add requests.
-    android::base::Result<void, VhalError> addRequests(
-            const std::unordered_set<int64_t>& requestIds);
+    VhalResult<void> addRequests(const std::unordered_set<int64_t>& requestIds);
 
     // Marks the requests as finished. Returns a list of request IDs that was pending and has been
     // finished. It must be a set of the requested request IDs.
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index 2db7675..f646b6b 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -45,7 +45,6 @@
   public:
     using CallbackType =
             std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
-    using StatusError = android::base::Error<VhalError>;
 
     explicit DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware);
 
@@ -211,14 +210,14 @@
             const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
                     requests);
 
-    android::base::Result<void, VhalError> checkSubscribeOptions(
+    VhalResult<void> checkSubscribeOptions(
             const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
                     options);
 
-    android::base::Result<void, VhalError> checkReadPermission(
+    VhalResult<void> checkReadPermission(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
 
-    android::base::Result<void, VhalError> checkWritePermission(
+    VhalResult<void> checkWritePermission(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
 
     android::base::Result<const aidl::android::hardware::automotive::vehicle::VehiclePropConfig*>
diff --git a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
index 4cfc2be..81d231c 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
@@ -196,8 +196,7 @@
     return reinterpret_cast<const void*>(this);
 }
 
-Result<void, VhalError> ConnectedClient::addRequests(
-        const std::unordered_set<int64_t>& requestIds) {
+VhalResult<void> ConnectedClient::addRequests(const std::unordered_set<int64_t>& requestIds) {
     return mRequestPool->addRequests(id(), requestIds, getTimeoutCallback());
 }
 
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index 886f897..82f2c1b 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -78,6 +78,16 @@
     return str;
 }
 
+float getDefaultSampleRate(float sampleRate, float minSampleRate, float maxSampleRate) {
+    if (sampleRate < minSampleRate) {
+        return minSampleRate;
+    }
+    if (sampleRate > maxSampleRate) {
+        return maxSampleRate;
+    }
+    return sampleRate;
+}
+
 }  // namespace
 
 std::shared_ptr<SubscriptionClient> DefaultVehicleHal::SubscriptionClients::maybeAddClient(
@@ -590,7 +600,7 @@
     return vectorToStableLargeParcelable(std::move(configs), output);
 }
 
-Result<void, VhalError> DefaultVehicleHal::checkSubscribeOptions(
+VhalResult<void> DefaultVehicleHal::checkSubscribeOptions(
         const std::vector<SubscribeOptions>& options) {
     for (const auto& option : options) {
         int32_t propId = option.propId;
@@ -617,9 +627,10 @@
             float minSampleRate = config.minSampleRate;
             float maxSampleRate = config.maxSampleRate;
             if (sampleRate < minSampleRate || sampleRate > maxSampleRate) {
-                return StatusError(StatusCode::INVALID_ARG)
-                       << StringPrintf("sample rate: %f out of range, must be within %f and %f",
-                                       sampleRate, minSampleRate, maxSampleRate);
+                float defaultRate = getDefaultSampleRate(sampleRate, minSampleRate, maxSampleRate);
+                ALOGW("sample rate: %f out of range, must be within %f and %f, set to %f",
+                      sampleRate, minSampleRate, maxSampleRate, defaultRate);
+                sampleRate = defaultRate;
             }
             if (!SubscriptionManager::checkSampleRate(sampleRate)) {
                 return StatusError(StatusCode::INVALID_ARG)
@@ -673,6 +684,8 @@
         }
 
         if (config.changeMode == VehiclePropertyChangeMode::CONTINUOUS) {
+            optionCopy.sampleRate = getDefaultSampleRate(
+                    optionCopy.sampleRate, config.minSampleRate, config.maxSampleRate);
             continuousSubscriptions.push_back(std::move(optionCopy));
         } else {
             onChangeSubscriptions.push_back(std::move(optionCopy));
@@ -718,8 +731,7 @@
     return mVehicleHardware.get();
 }
 
-Result<void, VhalError> DefaultVehicleHal::checkWritePermission(
-        const VehiclePropValue& value) const {
+VhalResult<void> DefaultVehicleHal::checkWritePermission(const VehiclePropValue& value) const {
     int32_t propId = value.prop;
     auto result = getConfig(propId);
     if (!result.ok()) {
@@ -735,8 +747,7 @@
     return {};
 }
 
-Result<void, VhalError> DefaultVehicleHal::checkReadPermission(
-        const VehiclePropValue& value) const {
+VhalResult<void> DefaultVehicleHal::checkReadPermission(const VehiclePropValue& value) const {
     int32_t propId = value.prop;
     auto result = getConfig(propId);
     if (!result.ok()) {
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index 6f8eb1d..49f5b7e 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -197,14 +197,6 @@
                             },
             },
             {
-                    .name = "sample_rate_out_of_range",
-                    .option =
-                            {
-                                    .propId = GLOBAL_CONTINUOUS_PROP,
-                                    .sampleRate = 1000.0,
-                            },
-            },
-            {
                     .name = "static_property",
                     .option =
                             {
@@ -1360,6 +1352,51 @@
     EXPECT_EQ(countClients(), static_cast<size_t>(1));
 }
 
+TEST_F(DefaultVehicleHalTest, testSubscribeGlobalContinuousRateOutOfRange) {
+    VehiclePropValue testValue{
+            .prop = GLOBAL_CONTINUOUS_PROP,
+            .value.int32Values = {0},
+    };
+    // Set responses for all the hardware getValues requests.
+    getHardware()->setGetValueResponder(
+            [](std::shared_ptr<const IVehicleHardware::GetValuesCallback> callback,
+               const std::vector<GetValueRequest>& requests) {
+                std::vector<GetValueResult> results;
+                for (auto& request : requests) {
+                    VehiclePropValue prop = request.prop;
+                    prop.value.int32Values = {0};
+                    results.push_back({
+                            .requestId = request.requestId,
+                            .status = StatusCode::OK,
+                            .prop = prop,
+                    });
+                }
+                (*callback)(results);
+                return StatusCode::OK;
+            });
+
+    // The maxSampleRate is 100, so the sample rate should be the default max 100.
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .sampleRate = 1000.0,
+            },
+    };
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+    // Sleep for 1s, which should generate ~100 events.
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    size_t eventCount = getCallback()->countOnPropertyEventResults();
+    ASSERT_GE(eventCount, 50u) << "expect at least 50 events to be generated";
+    ASSERT_LE(eventCount, 150u) << "expect no more than 150 events to be generated";
+
+    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
 TEST_F(DefaultVehicleHalTest, testSubscribeAreaContinuous) {
     // Set responses for all the hardware getValues requests.
     getHardware()->setGetValueResponder(
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
index 5e3e03c..0e46357 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
@@ -82,6 +82,11 @@
     return pop(mOnPropertyEventResults);
 }
 
+size_t MockVehicleCallback::countOnPropertyEventResults() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mOnPropertyEventResults.size();
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
index 03bfd5b..0faaa1f 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
@@ -62,6 +62,7 @@
     nextSetValueResults();
     std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropValues>
     nextOnPropertyEventResults();
+    size_t countOnPropertyEventResults();
 
   private:
     std::mutex mLock;
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..c33f3e9
--- /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(), 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();
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
index bb7d800..90c9e03 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
@@ -38,5 +38,5 @@
   double latitudeDegrees;
   double longitudeDegrees;
   double altitudeMeters;
-  double azimuthDegrees;
+  double reflectingPlaneAzimuthDegrees;
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
index 53baa01..ebbe684 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
@@ -40,11 +40,24 @@
   int svid;
   long carrierFrequencyHz;
   float probSatIsLos;
-  float excessPathLengthMeters;
-  float excessPathLengthUncertaintyMeters;
-  android.hardware.gnss.measurement_corrections.ReflectingPlane reflectingPlane;
+  float combinedExcessPathLengthMeters;
+  float combinedExcessPathLengthUncertaintyMeters;
+  float combinedAttenuationDb;
+  android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo[] excessPathInfos;
   const int SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY = 1;
-  const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH = 2;
-  const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC = 4;
-  const int SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE = 8;
+  const int SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH = 2;
+  const int SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC = 4;
+  const int SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION = 16;
+  @VintfStability
+  parcelable ExcessPathInfo {
+    int excessPathInfoFlags;
+    float excessPathLengthMeters;
+    float excessPathLengthUncertaintyMeters;
+    android.hardware.gnss.measurement_corrections.ReflectingPlane reflectingPlane;
+    float attenuationDb;
+    const int EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH = 1;
+    const int EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC = 2;
+    const int EXCESS_PATH_INFO_HAS_REFLECTING_PLANE = 4;
+    const int EXCESS_PATH_INFO_HAS_ATTENUATION = 8;
+  }
 }
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
index abd29f0..8104372 100644
--- a/gnss/aidl/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
@@ -41,5 +41,5 @@
     double altitudeMeters;
 
     /** Represents azimuth clockwise from north of the reflecting plane in degrees. */
-    double azimuthDegrees;
+    double reflectingPlaneAzimuthDegrees;
 }
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
index 36320eb..56c691c 100644
--- a/gnss/aidl/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
@@ -29,14 +29,14 @@
 @VintfStability
 parcelable SingleSatCorrection {
     /** Bit mask to indicate which values are valid in a SingleSatCorrection object. */
-    /** GnssSingleSatCorrectionFlags has valid satellite-is-line-of-sight-probability field. */
+    /** GnssSingleSatCorrectionFlags has valid probSatIsLos field. */
     const int SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY = 0x0001;
-    /** GnssSingleSatCorrectionFlags has valid Excess Path Length field. */
-    const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH = 0x0002;
-    /** GnssSingleSatCorrectionFlags has valid Excess Path Length Uncertainty field. */
-    const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC = 0x0004;
-    /** GnssSingleSatCorrectionFlags has valid Reflecting Plane field. */
-    const int SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE = 0x0008;
+    /** GnssSingleSatCorrectionFlags has valid combinedExcessPathLengthMeters field. */
+    const int SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH = 0x0002;
+    /** GnssSingleSatCorrectionFlags has valid combinedExcessPathLengthUncertaintyMeters field. */
+    const int SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC = 0x0004;
+    /** GnssSingleSatCorrectionFlags has valid combinedAttenuationDb field. */
+    const int SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION = 0x0010;
 
     /** Contains GnssSingleSatCorrectionFlags bits. */
     int singleSatCorrectionFlags;
@@ -67,21 +67,74 @@
     float probSatIsLos;
 
     /**
-     * Excess path length to be subtracted from pseudorange before using it in calculating location.
+     * Combined excess path length to be subtracted from pseudorange before using it in
+     * calculating location.
      *
-     * Note this value is NOT to be used to adjust the GnsseasurementCallback outputs.
+     * The value is computed by correlating the individual paths and picking the delay at the
+     * highest peak.
+     *
+     * Note this value is NOT to be used to adjust the GnssMeasurementCallback outputs.
      */
-    float excessPathLengthMeters;
-
-    /** Error estimate (1-sigma) for the Excess path length estimate */
-    float excessPathLengthUncertaintyMeters;
+    float combinedExcessPathLengthMeters;
 
     /**
-     * Defines the reflecting plane characteristics such as location and azimuth
+     * Error estimate (1-sigma) for the Excess path length estimate.
      *
-     * The value is only valid if HAS_REFLECTING_PLANE flag is set. An invalid reflecting plane
-     * means either reflection planes serving is not supported or the satellite signal has gone
-     * through multiple reflections.
+     * The value is computed by combining the individual excessPathLengthUncertaintyMeters values
+     * into a single value for this satellite.
      */
-    ReflectingPlane reflectingPlane;
+    float combinedExcessPathLengthUncertaintyMeters;
+
+    /**
+     * Combined expected reduction of signal strength for this satellite in non-negative dB.
+     */
+    float combinedAttenuationDb;
+
+    /**
+     * A struct for the info of an excess path caused by reflection.
+     */
+    @VintfStability
+    parcelable ExcessPathInfo {
+        /** ExcessPathInfo has valid Excess Path Length field. */
+        const int EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH = 0x0001;
+        /** ExcessPathInfo has valid Excess Path Length Uncertainty field. */
+        const int EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC = 0x0002;
+        /** ExcessPathInfo has valid Reflecting Plane field. */
+        const int EXCESS_PATH_INFO_HAS_REFLECTING_PLANE = 0x0004;
+        /** ExcessPathInfo has valid Attenuation field. */
+        const int EXCESS_PATH_INFO_HAS_ATTENUATION = 0x0008;
+
+        /** Contains flag bits to indicate which fields exist in the ExcessPathInfo object. */
+        int excessPathInfoFlags;
+
+        /**
+         * Excess path length to be subtracted from pseudorange before using it in calculating
+         * location.
+         *
+         * Note this value is NOT to be used to adjust the GnssMeasurementCallback outputs.
+         */
+        float excessPathLengthMeters;
+
+        /** Error estimate (1-sigma) for the Excess path length estimate. */
+        float excessPathLengthUncertaintyMeters;
+
+        /**
+         * Defines the reflecting plane characteristics such as location and azimuth.
+         *
+         * The value is only valid if HAS_REFLECTING_PLANE flag is set. An invalid reflecting plane
+         * means either reflection planes serving is not supported or the satellite signal has gone
+         * through multiple reflections.
+         */
+        ReflectingPlane reflectingPlane;
+
+        /**
+         * The expected reduction of signal strength of this path in non-negative dB.
+         */
+        float attenuationDb;
+    }
+
+    /**
+     * A list of excess path info.
+     */
+    ExcessPathInfo[] excessPathInfos;
 }
diff --git a/gnss/aidl/default/MeasurementCorrectionsInterface.cpp b/gnss/aidl/default/MeasurementCorrectionsInterface.cpp
index 0f1851c..66270c8 100644
--- a/gnss/aidl/default/MeasurementCorrectionsInterface.cpp
+++ b/gnss/aidl/default/MeasurementCorrectionsInterface.cpp
@@ -37,16 +37,26 @@
           static_cast<int>(corrections.satCorrections.size()));
     for (auto singleSatCorrection : corrections.satCorrections) {
         ALOGD("singleSatCorrection = flags: %d, constellation: %d, svid: %d"
-              ", cfHz: %" PRId64 ", probLos: %f, epl: %f, eplUnc: %f",
+              ", cfHz: %" PRId64
+              ", probLos: %f, combinedEpl: %f, combinedEplUnc: %f, combinedAttenuation: %f"
+              ", excessPathInfos.size: %d",
               singleSatCorrection.singleSatCorrectionFlags, singleSatCorrection.constellation,
               singleSatCorrection.svid, singleSatCorrection.carrierFrequencyHz,
-              singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters,
-              singleSatCorrection.excessPathLengthUncertaintyMeters);
-        ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f",
-              singleSatCorrection.reflectingPlane.latitudeDegrees,
-              singleSatCorrection.reflectingPlane.longitudeDegrees,
-              singleSatCorrection.reflectingPlane.altitudeMeters,
-              singleSatCorrection.reflectingPlane.azimuthDegrees);
+              singleSatCorrection.probSatIsLos, singleSatCorrection.combinedExcessPathLengthMeters,
+              singleSatCorrection.combinedExcessPathLengthUncertaintyMeters,
+              singleSatCorrection.combinedAttenuationDb,
+              static_cast<int>(singleSatCorrection.excessPathInfos.size()));
+
+        for (auto excessPathInfo : singleSatCorrection.excessPathInfos) {
+            ALOGD("excessPathInfo = epl: %f, eplUnc: %f, attenuation: %f",
+                  excessPathInfo.excessPathLengthMeters,
+                  excessPathInfo.excessPathLengthUncertaintyMeters, excessPathInfo.attenuationDb);
+            ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f",
+                  excessPathInfo.reflectingPlane.latitudeDegrees,
+                  excessPathInfo.reflectingPlane.longitudeDegrees,
+                  excessPathInfo.reflectingPlane.altitudeMeters,
+                  excessPathInfo.reflectingPlane.reflectingPlaneAzimuthDegrees);
+        }
     }
     return ndk::ScopedAStatus::ok();
 }
diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp
index 4c725a8..69e2b34 100644
--- a/gnss/common/utils/vts/Utils.cpp
+++ b/gnss/common/utils/vts/Utils.cpp
@@ -38,6 +38,7 @@
 using ReflectingPlaneAidl = android::hardware::gnss::measurement_corrections::ReflectingPlane;
 using SingleSatCorrectionAidl =
         android::hardware::gnss::measurement_corrections::SingleSatCorrection;
+using ExcessPathInfo = SingleSatCorrectionAidl::ExcessPathInfo;
 
 template <>
 int64_t Utils::getLocationTimestampMillis(const android::hardware::gnss::GnssLocation& location) {
@@ -170,38 +171,68 @@
     return mockCorrections_1_1;
 }
 
+namespace {
+const ExcessPathInfo createExcessPathInfo(float excessPathLengthMeters,
+                                          float excessPathLengthUncertaintyMeters,
+                                          const ReflectingPlaneAidl* reflectingPlane,
+                                          float attenuationDb) {
+    ExcessPathInfo excessPathInfo;
+    excessPathInfo.excessPathInfoFlags =
+            ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH |
+            ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC |
+            ExcessPathInfo::EXCESS_PATH_INFO_HAS_ATTENUATION |
+            (reflectingPlane == nullptr ? 0
+                                        : ExcessPathInfo::EXCESS_PATH_INFO_HAS_REFLECTING_PLANE);
+    excessPathInfo.excessPathLengthMeters = excessPathLengthMeters;
+    excessPathInfo.excessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+    if (reflectingPlane != nullptr) {
+        excessPathInfo.reflectingPlane = *reflectingPlane;
+    }
+    excessPathInfo.attenuationDb = attenuationDb;
+    return excessPathInfo;
+}
+}  // anonymous namespace
+
 const MeasurementCorrectionsAidl Utils::getMockMeasurementCorrections_aidl() {
     ReflectingPlaneAidl reflectingPlane;
     reflectingPlane.latitudeDegrees = 37.4220039;
     reflectingPlane.longitudeDegrees = -122.0840991;
     reflectingPlane.altitudeMeters = 250.35;
-    reflectingPlane.azimuthDegrees = 203.0;
+    reflectingPlane.reflectingPlaneAzimuthDegrees = 203.0;
 
     SingleSatCorrectionAidl singleSatCorrection1;
     singleSatCorrection1.singleSatCorrectionFlags =
             SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY |
-            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH |
-            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC |
-            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE;
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH |
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC |
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
     singleSatCorrection1.constellation = android::hardware::gnss::GnssConstellationType::GPS;
     singleSatCorrection1.svid = 12;
     singleSatCorrection1.carrierFrequencyHz = 1.59975e+09;
     singleSatCorrection1.probSatIsLos = 0.50001;
-    singleSatCorrection1.excessPathLengthMeters = 137.4802;
-    singleSatCorrection1.excessPathLengthUncertaintyMeters = 25.5;
-    singleSatCorrection1.reflectingPlane = reflectingPlane;
+    singleSatCorrection1.combinedExcessPathLengthMeters = 203.5;
+    singleSatCorrection1.combinedExcessPathLengthUncertaintyMeters = 59.1;
+    singleSatCorrection1.combinedAttenuationDb = -4.3;
+    singleSatCorrection1.excessPathInfos.push_back(
+            createExcessPathInfo(137.4, 25.5, &reflectingPlane, -3.5));
+    singleSatCorrection1.excessPathInfos.push_back(
+            createExcessPathInfo(296.3, 87.2, &reflectingPlane, -5.1));
 
     SingleSatCorrectionAidl singleSatCorrection2;
     singleSatCorrection2.singleSatCorrectionFlags =
             SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY |
-            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH |
-            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC;
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH |
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC |
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
     singleSatCorrection2.constellation = GnssConstellationType::GPS;
     singleSatCorrection2.svid = 9;
     singleSatCorrection2.carrierFrequencyHz = 1.59975e+09;
     singleSatCorrection2.probSatIsLos = 0.873;
-    singleSatCorrection2.excessPathLengthMeters = 26.294;
-    singleSatCorrection2.excessPathLengthUncertaintyMeters = 10.0;
+    singleSatCorrection2.combinedExcessPathLengthMeters = 26.294;
+    singleSatCorrection2.combinedExcessPathLengthUncertaintyMeters = 10.0;
+    singleSatCorrection2.combinedAttenuationDb = -0.5;
+    singleSatCorrection2.excessPathInfos.push_back(
+            createExcessPathInfo(26.294, 10.0, nullptr, -0.5));
 
     std::vector<SingleSatCorrectionAidl> singleSatCorrections = {singleSatCorrection1,
                                                                  singleSatCorrection2};
diff --git a/radio/aidl/vts/AndroidTest.xml b/radio/aidl/vts/AndroidTest.xml
new file mode 100644
index 0000000..36381d1
--- /dev/null
+++ b/radio/aidl/vts/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs VtsHalRadioTargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalRadioTargetTest->/data/local/tmp/VtsHalRadioTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="native-test-timeout" value="300000" /> <!-- 5 min -->
+        <option name="module-name" value="VtsHalRadioTargetTest" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.cpp b/radio/aidl/vts/radio_aidl_hal_utils.cpp
index 1f73930..8618851 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.cpp
+++ b/radio/aidl/vts/radio_aidl_hal_utils.cpp
@@ -108,7 +108,7 @@
 
 bool stringEndsWith(std::string const& string, std::string const& end) {
     if (string.size() >= end.size()) {
-        return (0 == string.compare(string.size() - end.size() - 1, end.size(), end));
+        return std::equal(end.rbegin(), end.rend(), string.rbegin());
     } else {
         return false;
     }
@@ -117,7 +117,7 @@
 bool isServiceValidForDeviceConfiguration(std::string& serviceName) {
     if (isSsSsEnabled()) {
         // Device is configured as SSSS.
-        if (stringEndsWith(serviceName, RADIO_SERVICE_SLOT1_NAME)) {
+        if (!stringEndsWith(serviceName, RADIO_SERVICE_SLOT1_NAME)) {
             ALOGI("%s instance is not valid for SSSS device.", serviceName.c_str());
             return false;
         }
diff --git a/radio/aidl/vts/radio_config_test.cpp b/radio/aidl/vts/radio_config_test.cpp
index a124907..83c4de0 100644
--- a/radio/aidl/vts/radio_config_test.cpp
+++ b/radio/aidl/vts/radio_config_test.cpp
@@ -24,11 +24,6 @@
 void RadioConfigTest::SetUp() {
     std::string serviceName = GetParam();
 
-    if (!isServiceValidForDeviceConfiguration(serviceName)) {
-        ALOGI("Skipped the test due to device configuration.");
-        GTEST_SKIP();
-    }
-
     radio_config = IRadioConfig::fromBinder(
             ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
     ASSERT_NE(nullptr, radio_config.get());
diff --git a/security/dice/aidl/default/Android.bp b/security/dice/aidl/default/Android.bp
new file mode 100644
index 0000000..b67a44a
--- /dev/null
+++ b/security/dice/aidl/default/Android.bp
@@ -0,0 +1,30 @@
+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"],
+}
+
+rust_binary {
+    name: "android.hardware.security.dice-service.non-secure-software",
+    srcs: ["service.rs"],
+    relative_install_path: "hw",
+    vendor: true,
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "libdiced_open_dice_cbor",
+        "libdiced_sample_inputs",
+        "libdiced_vendor",
+        "libandroid_logger",
+        "libanyhow",
+        "libbinder_rs",
+        "liblog_rust",
+        "libserde",
+    ],
+    init_rc: ["android.hardware.security.dice-service.non-secure-software.rc"],
+    vintf_fragments: [
+        "android.hardware.security.dice-service.non-secure-software.xml",
+    ],
+}
diff --git a/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.rc b/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.rc
new file mode 100644
index 0000000..28e43c3
--- /dev/null
+++ b/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.rc
@@ -0,0 +1,9 @@
+service vendor.dice /vendor/bin/hw/android.hardware.security.dice-service.non-secure-software
+    class early_hal
+    user nobody
+    # The diced HAL cannot be allowed to restart. When it crashes for any reason.
+    # it loses security critical state. The only remedy is to restart the device.
+    # This may be implementation depended. It is safe to restart the HAL if the
+    # state change during a call to "demote" is is preserved.
+    # see android/hardware/security/dice/IDiceDevice.aidl for details on "demote".
+    oneshot
diff --git a/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.xml b/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.xml
new file mode 100644
index 0000000..94ef243
--- /dev/null
+++ b/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.security.dice</name>
+        <fqname>IDiceDevice/default</fqname>
+    </hal>
+</manifest>
\ No newline at end of file
diff --git a/security/dice/aidl/default/service.rs b/security/dice/aidl/default/service.rs
new file mode 100644
index 0000000..eebf333
--- /dev/null
+++ b/security/dice/aidl/default/service.rs
@@ -0,0 +1,107 @@
+// Copyright 2021, 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.
+
+//! Main entry point for the android.hardware.security.dice service.
+
+use anyhow::Result;
+use diced::{
+    dice,
+    hal_node::{DiceArtifacts, DiceDevice, ResidentHal, UpdatableDiceArtifacts},
+};
+use diced_sample_inputs::make_sample_bcc_and_cdis;
+use serde::{Deserialize, Serialize};
+use std::convert::TryInto;
+use std::panic;
+use std::sync::Arc;
+
+static DICE_HAL_SERVICE_NAME: &str = "android.hardware.security.dice.IDiceDevice/default";
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+struct InsecureSerializableArtifacts {
+    cdi_attest: [u8; dice::CDI_SIZE],
+    cdi_seal: [u8; dice::CDI_SIZE],
+    bcc: Vec<u8>,
+}
+
+impl DiceArtifacts for InsecureSerializableArtifacts {
+    fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE] {
+        &self.cdi_attest
+    }
+    fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE] {
+        &self.cdi_seal
+    }
+    fn bcc(&self) -> Vec<u8> {
+        self.bcc.clone()
+    }
+}
+
+impl UpdatableDiceArtifacts for InsecureSerializableArtifacts {
+    fn with_artifacts<F, T>(&self, f: F) -> Result<T>
+    where
+        F: FnOnce(&dyn DiceArtifacts) -> Result<T>,
+    {
+        f(self)
+    }
+    fn update(self, new_artifacts: &impl DiceArtifacts) -> Result<Self> {
+        Ok(Self {
+            cdi_attest: *new_artifacts.cdi_attest(),
+            cdi_seal: *new_artifacts.cdi_seal(),
+            bcc: new_artifacts.bcc(),
+        })
+    }
+}
+
+fn main() {
+    android_logger::init_once(
+        android_logger::Config::default()
+            .with_tag("android.hardware.security.dice")
+            .with_min_level(log::Level::Debug),
+    );
+    // Redirect panic messages to logcat.
+    panic::set_hook(Box::new(|panic_info| {
+        log::error!("{}", panic_info);
+    }));
+
+    // Saying hi.
+    log::info!("android.hardware.security.dice is starting.");
+
+    let (cdi_attest, cdi_seal, bcc) =
+        make_sample_bcc_and_cdis().expect("Failed to construct sample dice chain.");
+
+    let hal_impl = Arc::new(
+        unsafe {
+            // Safety: ResidentHal cannot be used in multi threaded processes.
+            // This service does not start a thread pool. The main thread is the only thread
+            // joining the thread pool, thereby keeping the process single threaded.
+            ResidentHal::new(InsecureSerializableArtifacts {
+                cdi_attest: cdi_attest[..]
+                    .try_into()
+                    .expect("Failed to convert cdi_attest to array reference."),
+                cdi_seal: cdi_seal[..]
+                    .try_into()
+                    .expect("Failed to convert cdi_seal to array reference."),
+                bcc,
+            })
+        }
+        .expect("Failed to create ResidentHal implementation."),
+    );
+
+    let hal = DiceDevice::new_as_binder(hal_impl).expect("Failed to construct hal service.");
+
+    binder::add_service(DICE_HAL_SERVICE_NAME, hal.as_binder())
+        .expect("Failed to register IDiceDevice Service");
+
+    log::info!("Joining thread pool now.");
+    binder::ProcessState::join_thread_pool();
+}
diff --git a/security/dice/aidl/vts/functional/Android.bp b/security/dice/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..f5bc949
--- /dev/null
+++ b/security/dice/aidl/vts/functional/Android.bp
@@ -0,0 +1,54 @@
+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"],
+}
+
+rust_test {
+    name: "VtsAidlDiceTargetTest",
+    srcs: [
+        "dice_test.rs",
+    ],
+    require_root: true,
+    auto_gen_config: true,
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "libanyhow",
+        "libbinder_rs",
+        "libdiced_open_dice_cbor",
+        "libdiced_sample_inputs",
+        "libdiced_utils",
+        "libkeystore2_vintf_rust",
+    ],
+}
+
+rust_test {
+    name: "VtsAidlDiceDemoteTargetTest",
+    srcs: [
+        "dice_demote_test.rs",
+    ],
+
+    test_config: "VtsAidlDiceDemoteTargetTest.xml",
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "libanyhow",
+        "libbinder_rs",
+        "libdiced_open_dice_cbor",
+        "libdiced_sample_inputs",
+        "libdiced_utils",
+        "libkeystore2_vintf_rust",
+    ],
+}
diff --git a/security/dice/aidl/vts/functional/VtsAidlDiceDemoteTargetTest.xml b/security/dice/aidl/vts/functional/VtsAidlDiceDemoteTargetTest.xml
new file mode 100644
index 0000000..2991580
--- /dev/null
+++ b/security/dice/aidl/vts/functional/VtsAidlDiceDemoteTargetTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<configuration description="Config to run VtsAidlDiceDemoteTargetTest device tests.">
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsAidlDiceDemoteTargetTest->/data/local/tmp/VtsAidlDiceDemoteTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+        <option name="test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsAidlDiceDemoteTargetTest" />
+    </test>
+    <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer" />
+
+</configuration>
\ No newline at end of file
diff --git a/security/dice/aidl/vts/functional/dice_demote_test.rs b/security/dice/aidl/vts/functional/dice_demote_test.rs
new file mode 100644
index 0000000..02ff2a4
--- /dev/null
+++ b/security/dice/aidl/vts/functional/dice_demote_test.rs
@@ -0,0 +1,67 @@
+// Copyright 2021, 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.
+
+use diced_open_dice_cbor as dice;
+use diced_sample_inputs;
+use diced_utils;
+use std::convert::TryInto;
+
+mod utils;
+use utils::with_connection;
+
+// This test calls derive with an empty argument vector, then demotes the HAL using
+// a set of three input values, and then calls derive with empty argument vector again.
+// It then performs the same three derivation steps on the result of the former and compares
+// the result to the result of the latter.
+#[test]
+fn demote_test() {
+    with_connection(|device| {
+        let input_values = diced_sample_inputs::get_input_values_vector();
+        let former = device.derive(&[]).expect("Trying to call derive.");
+        device
+            .demote(&input_values)
+            .expect("Trying to call demote with input values.");
+
+        let latter = device
+            .derive(&[])
+            .expect("Trying to call derive after demote.");
+
+        let artifacts = diced_utils::ResidentArtifacts::new(
+            former.cdiAttest[..].try_into().unwrap(),
+            former.cdiSeal[..].try_into().unwrap(),
+            &former.bcc.data,
+        )
+        .unwrap();
+
+        let input_values: Vec<diced_utils::InputValues> = input_values
+            .iter()
+            .map(|v| v.into())
+            .collect();
+
+        let artifacts = artifacts
+            .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))
+            .unwrap();
+        let (cdi_attest, cdi_seal, bcc) = artifacts.into_tuple();
+        let from_former = diced_utils::make_bcc_handover(
+            cdi_attest[..].try_into().unwrap(),
+            cdi_seal[..].try_into().unwrap(),
+            &bcc,
+        )
+        .unwrap();
+        // TODO b/204938506 when we have a parser/verifier, check equivalence rather
+        // than bit by bit equality.
+        assert_eq!(latter, from_former);
+        Ok(())
+    })
+}
diff --git a/security/dice/aidl/vts/functional/dice_test.rs b/security/dice/aidl/vts/functional/dice_test.rs
new file mode 100644
index 0000000..574b634
--- /dev/null
+++ b/security/dice/aidl/vts/functional/dice_test.rs
@@ -0,0 +1,82 @@
+// Copyright 2021, 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.
+
+use diced_open_dice_cbor as dice;
+use diced_sample_inputs;
+use diced_utils;
+use std::convert::{TryInto, Into};
+
+mod utils;
+use utils::with_connection;
+
+static TEST_MESSAGE: &[u8] = &[
+    // "My test message!"
+    0x4d, 0x79, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x21,
+    0x0a,
+];
+
+// This test calls derive with an empty argument vector and with a set of three input values.
+// It then performs the same three derivation steps on the result of the former and compares
+// the result to the result of the latter.
+#[test]
+fn equivalence_test() {
+    with_connection(|device| {
+        let input_values = diced_sample_inputs::get_input_values_vector();
+        let former = device.derive(&[]).expect("Trying to call derive.");
+        let latter = device
+            .derive(&input_values)
+            .expect("Trying to call derive with input values.");
+        let artifacts = diced_utils::ResidentArtifacts::new(
+            former.cdiAttest[..].try_into().unwrap(),
+            former.cdiSeal[..].try_into().unwrap(),
+            &former.bcc.data,
+        )
+        .unwrap();
+
+        let input_values: Vec<diced_utils::InputValues> = input_values
+            .iter()
+            .map(|v| v.into())
+            .collect();
+
+        let artifacts = artifacts
+            .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))
+            .unwrap();
+        let (cdi_attest, cdi_seal, bcc) = artifacts.into_tuple();
+        let from_former = diced_utils::make_bcc_handover(
+            cdi_attest[..].try_into().unwrap(),
+            cdi_seal[..].try_into().unwrap(),
+            &bcc,
+        )
+        .unwrap();
+        // TODO b/204938506 when we have a parser/verifier, check equivalence rather
+        // than bit by bit equality.
+        assert_eq!(latter, from_former);
+        Ok(())
+    })
+}
+
+#[test]
+fn sign_and_verify() {
+    with_connection(|device| {
+        let _signature = device
+            .sign(&[], TEST_MESSAGE)
+            .expect("Trying to call sign.");
+
+        let _bcc = device
+            .getAttestationChain(&[])
+            .expect("Trying to call getAttestationChain.");
+        // TODO b/204938506 check the signature with the bcc when the verifier is available.
+        Ok(())
+    })
+}
diff --git a/security/dice/aidl/vts/functional/utils.rs b/security/dice/aidl/vts/functional/utils.rs
new file mode 100644
index 0000000..4e6708e
--- /dev/null
+++ b/security/dice/aidl/vts/functional/utils.rs
@@ -0,0 +1,53 @@
+// Copyright 2021, 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.
+
+use android_hardware_security_dice::aidl::android::hardware::security::dice::IDiceDevice::IDiceDevice;
+use anyhow::Result;
+use binder::Strong;
+use keystore2_vintf::get_aidl_instances;
+use std::sync::Arc;
+
+static DICE_DEVICE_SERVICE_NAME: &str = &"android.hardware.security.dice";
+static DICE_DEVICE_INTERFACE_NAME: &str = &"IDiceDevice";
+
+/// This function iterates through all announced IDiceDevice services and runs the given test
+/// closure against connections to each of them. It also modifies the panic hook to indicate
+/// on which instance the test failed in case the test closure panics.
+pub fn with_connection<R, F>(test: F)
+where
+    F: Fn(&Strong<dyn IDiceDevice>) -> Result<R>,
+{
+    let instances = get_aidl_instances(DICE_DEVICE_SERVICE_NAME, 1, DICE_DEVICE_INTERFACE_NAME);
+    let panic_hook = Arc::new(std::panic::take_hook());
+    for i in instances.into_iter() {
+        let panic_hook_clone = panic_hook.clone();
+        let instance_clone = i.clone();
+        std::panic::set_hook(Box::new(move |v| {
+            println!("While testing instance: \"{}\"", instance_clone);
+            panic_hook_clone(v)
+        }));
+        let connection: Strong<dyn IDiceDevice> = binder::get_interface(&format!(
+            "{}.{}/{}",
+            DICE_DEVICE_SERVICE_NAME, DICE_DEVICE_INTERFACE_NAME, i
+        ))
+        .unwrap();
+        test(&connection).unwrap();
+        drop(std::panic::take_hook());
+    }
+    // Cannot call unwrap here because the panic hook is not Debug.
+    std::panic::set_hook(match Arc::try_unwrap(panic_hook) {
+        Ok(hook) => hook,
+        _ => panic!("Failed to unwrap and reset previous panic hook."),
+    })
+}
diff --git a/sensors/aidl/default/multihal/ConvertUtils.cpp b/sensors/aidl/default/multihal/ConvertUtils.cpp
index 7751fd2..9b2d8fe 100644
--- a/sensors/aidl/default/multihal/ConvertUtils.cpp
+++ b/sensors/aidl/default/multihal/ConvertUtils.cpp
@@ -173,7 +173,7 @@
                 }
                 default:
                     ALOGE("Invalid sensor additioanl info tag: %d",
-                          additionalInfo.payload.getTag());
+                          static_cast<int32_t>(additionalInfo.payload.getTag()));
                     break;
             }
             break;