Merge "Revert^2 "Change ifname to interface handle in set_scan_mode api"" into main
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
index a3f0de9..56b7926 100644
--- a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
@@ -51,9 +51,7 @@
     DRAIN_PAUSED -> DRAINING [label="start"];         // consumer -> active
     DRAIN_PAUSED -> TRANSFER_PAUSED [label="burst"];  // producer -> active
     DRAIN_PAUSED -> IDLE [label="flush"];             // buffer is cleared
-    IDLE -> ERROR [label="←IStreamCallback.onError"];
-    DRAINING -> ERROR [label="←IStreamCallback.onError"];
-    TRANSFERRING -> ERROR [label="←IStreamCallback.onError"];
+    ANY_STATE -> ERROR [label="←IStreamCallback.onError"];
     ANY_STATE -> CLOSED [label="→IStream*.close"];
     CLOSED -> F;
 }
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 697ff0d..31b0645 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -183,17 +183,19 @@
     switch (command.getTag()) {
         case Tag::halReservedExit: {
             const int32_t cookie = command.get<Tag::halReservedExit>();
+            StreamInWorkerLogic::Status status = Status::CONTINUE;
             if (cookie == (mContext->getInternalCommandCookie() ^ getTid())) {
                 mDriver->shutdown();
                 setClosed();
+                status = Status::EXIT;
             } else {
                 LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
             }
             if (cookie != 0) {  // This is an internal command, no need to reply.
-                return Status::EXIT;
-            } else {
-                break;
+                return status;
             }
+            // `cookie == 0` can only occur in the context of a VTS test, need to reply.
+            break;
         }
         case Tag::getStatus:
             populateReply(&reply, mIsConnected);
@@ -315,7 +317,11 @@
 bool StreamInWorkerLogic::read(size_t clientSize, StreamDescriptor::Reply* reply) {
     ATRACE_CALL();
     StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
-    const size_t byteCount = std::min({clientSize, dataMQ->availableToWrite(), mDataBufferSize});
+    StreamContext::DataMQ::Error fmqError = StreamContext::DataMQ::Error::NONE;
+    std::string fmqErrorMsg;
+    const size_t byteCount = std::min(
+            {clientSize, dataMQ->availableToWrite(&fmqError, &fmqErrorMsg), mDataBufferSize});
+    CHECK(fmqError == StreamContext::DataMQ::Error::NONE) << fmqErrorMsg;
     const bool isConnected = mIsConnected;
     const size_t frameSize = mContext->getFrameSize();
     size_t actualFrameCount = 0;
@@ -407,17 +413,19 @@
     switch (command.getTag()) {
         case Tag::halReservedExit: {
             const int32_t cookie = command.get<Tag::halReservedExit>();
+            StreamOutWorkerLogic::Status status = Status::CONTINUE;
             if (cookie == (mContext->getInternalCommandCookie() ^ getTid())) {
                 mDriver->shutdown();
                 setClosed();
+                status = Status::EXIT;
             } else {
                 LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
             }
             if (cookie != 0) {  // This is an internal command, no need to reply.
-                return Status::EXIT;
-            } else {
-                break;
+                return status;
             }
+            // `cookie == 0` can only occur in the context of a VTS test, need to reply.
+            break;
         }
         case Tag::getStatus:
             populateReply(&reply, mIsConnected);
@@ -587,7 +595,10 @@
 bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* reply) {
     ATRACE_CALL();
     StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
-    const size_t readByteCount = dataMQ->availableToRead();
+    StreamContext::DataMQ::Error fmqError = StreamContext::DataMQ::Error::NONE;
+    std::string fmqErrorMsg;
+    const size_t readByteCount = dataMQ->availableToRead(&fmqError, &fmqErrorMsg);
+    CHECK(fmqError == StreamContext::DataMQ::Error::NONE) << fmqErrorMsg;
     const size_t frameSize = mContext->getFrameSize();
     bool fatal = false;
     int32_t latency = mContext->getNominalLatencyMs();
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index 9547865..c01eb3f 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -77,7 +77,6 @@
         <effect name="dynamics_processing" library="dynamics_processing" uuid="e0e6539b-1781-7261-676f-6d7573696340"/>
         <effect name="haptic_generator" library="haptic_generator" uuid="97c4acd1-8b82-4f2f-832e-c2fe5d7a9931"/>
         <effect name="loudness_enhancer" library="loudness_enhancer" uuid="fa415329-2034-4bea-b5dc-5b381c8d1e2c"/>
-        <effect name="env_reverb" library="env_reverbsw" uuid="fa819886-588b-11ed-9b6a-0242ac120002"/>
         <effect name="reverb_env_aux" library="reverb" uuid="4a387fc0-8ab3-11df-8bad-0002a5d5c51b"/>
         <effect name="reverb_env_ins" library="reverb" uuid="c7a511a0-a3bb-11df-860e-0002a5d5c51b"/>
         <effect name="reverb_pre_aux" library="reverb" uuid="f29a1400-a3bb-11df-8ddc-0002a5d5c51b"/>
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
index 9740d6e..66c0ff1 100644
--- a/audio/aidl/default/include/effect-impl/EffectTypes.h
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -75,49 +75,49 @@
     return out << "EnumError: " << code;
 }
 
-#define RETURN_IF_ASTATUS_NOT_OK(status, message)                                              \
-    do {                                                                                       \
-        const ::ndk::ScopedAStatus curr_status = (status);                                     \
-        if (!curr_status.isOk()) {                                                             \
-            LOG(ERROR) << __func__ << ":" << __LINE__                                          \
-                       << "return with status: " << curr_status.getDescription() << (message); \
-            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(                           \
-                    curr_status.getExceptionCode(), (message));                                \
-        }                                                                                      \
+#define RETURN_IF_ASTATUS_NOT_OK(status, message)                                               \
+    do {                                                                                        \
+        const ::ndk::ScopedAStatus curr_status = (status);                                      \
+        if (!curr_status.isOk()) {                                                              \
+            LOG(ERROR) << __func__ << ": line" << __LINE__                                      \
+                       << " return with status: " << curr_status.getDescription() << (message); \
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(                            \
+                    curr_status.getExceptionCode(), (message));                                 \
+        }                                                                                       \
     } while (0)
 
 #define RETURN_IF(expr, exception, message)                                                  \
     do {                                                                                     \
         if (expr) {                                                                          \
-            LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr " << #expr;      \
+            LOG(ERROR) << __func__ << ": line" << __LINE__ << " return with expr " << #expr; \
             return ndk::ScopedAStatus::fromExceptionCodeWithMessage((exception), (message)); \
         }                                                                                    \
     } while (0)
 
-#define RETURN_OK_IF(expr)                                                             \
-    do {                                                                               \
-        if (expr) {                                                                    \
-            LOG(INFO) << __func__ << ":" << __LINE__ << " return with expr " << #expr; \
-            return ndk::ScopedAStatus::ok();                                           \
-        }                                                                              \
+#define RETURN_OK_IF(expr)                                                                  \
+    do {                                                                                    \
+        if (expr) {                                                                         \
+            LOG(INFO) << __func__ << ": line" << __LINE__ << " return with expr " << #expr; \
+            return ndk::ScopedAStatus::ok();                                                \
+        }                                                                                   \
     } while (0)
 
-#define RETURN_VALUE_IF(expr, ret, log)                                                  \
-    do {                                                                                 \
-        if (expr) {                                                                      \
-            LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr \"" << #expr \
-                       << "\":" << (log);                                                \
-            return ret;                                                                  \
-        }                                                                                \
+#define RETURN_VALUE_IF(expr, ret, log)                                                       \
+    do {                                                                                      \
+        if (expr) {                                                                           \
+            LOG(ERROR) << __func__ << ": line" << __LINE__ << " return with expr \"" << #expr \
+                       << "\":" << (log);                                                     \
+            return ret;                                                                       \
+        }                                                                                     \
     } while (0)
 
-#define RETURN_IF_BINDER_EXCEPTION(functor)                                 \
-    {                                                                       \
-        binder_exception_t exception = functor;                             \
-        if (EX_NONE != exception) {                                         \
-            LOG(ERROR) << #functor << ":  failed with error " << exception; \
-            return ndk::ScopedAStatus::fromExceptionCode(exception);        \
-        }                                                                   \
+#define RETURN_IF_BINDER_EXCEPTION(functor)                                \
+    {                                                                      \
+        binder_exception_t exception = functor;                            \
+        if (EX_NONE != exception) {                                        \
+            LOG(ERROR) << #functor << ": failed with error " << exception; \
+            return ndk::ScopedAStatus::fromExceptionCode(exception);       \
+        }                                                                  \
     }
 
 /**
diff --git a/audio/aidl/default/spatializer/SpatializerSw.cpp b/audio/aidl/default/spatializer/SpatializerSw.cpp
index ab4a53e..fd3c192 100644
--- a/audio/aidl/default/spatializer/SpatializerSw.cpp
+++ b/audio/aidl/default/spatializer/SpatializerSw.cpp
@@ -64,7 +64,12 @@
 
 const std::string SpatializerSw::kEffectName = "SpatializerSw";
 
+const AudioChannelLayout kSupportedChannelMask =
+        AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                AudioChannelLayout::LAYOUT_5POINT1);
 const std::vector<Range::SpatializerRange> SpatializerSw::kRanges = {
+        MAKE_RANGE(Spatializer, supportedChannelLayout, {kSupportedChannelMask},
+                   {kSupportedChannelMask}),
         MAKE_RANGE(Spatializer, spatializationLevel, Spatialization::Level::NONE,
                    Spatialization::Level::BED_PLUS_OBJECTS),
         MAKE_RANGE(Spatializer, spatializationMode, Spatialization::Mode::BINAURAL,
@@ -133,6 +138,11 @@
 }
 
 std::shared_ptr<EffectContext> SpatializerSw::createContext(const Parameter::Common& common) {
+    if (common.input.base.channelMask != kSupportedChannelMask) {
+        LOG(ERROR) << __func__
+                   << " channelMask not supported: " << common.input.base.channelMask.toString();
+        return nullptr;
+    }
     if (mContext) {
         LOG(DEBUG) << __func__ << " context already exist";
     } else {
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index b236831..cbd42c0 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -121,6 +121,9 @@
     name: "VtsHalEnvironmentalReverbTargetTest",
     defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalEnvironmentalReverbTargetTest.cpp"],
+    shared_libs: [
+        "libaudioutils",
+    ],
 }
 
 cc_test {
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index 0fdf7a7..72a4667 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -18,6 +18,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <optional>
 #include <string>
 #include <type_traits>
 #include <unordered_map>
@@ -42,13 +43,18 @@
 using namespace android;
 using aidl::android::hardware::audio::effect::CommandId;
 using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::getEffectTypeUuidSpatializer;
+using aidl::android::hardware::audio::effect::getRange;
 using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::isRangeValid;
+using aidl::android::hardware::audio::effect::kEffectTypeUuidSpatializer;
 using aidl::android::hardware::audio::effect::kEventFlagDataMqNotEmpty;
 using aidl::android::hardware::audio::effect::kEventFlagDataMqUpdate;
 using aidl::android::hardware::audio::effect::kEventFlagNotEmpty;
 using aidl::android::hardware::audio::effect::kReopenSupportedVersion;
 using aidl::android::hardware::audio::effect::Parameter;
 using aidl::android::hardware::audio::effect::Range;
+using aidl::android::hardware::audio::effect::Spatializer;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
 using aidl::android::media::audio::common::AudioChannelLayout;
@@ -79,14 +85,16 @@
 
 class EffectHelper {
   public:
-    static void create(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect>& effect,
-                       Descriptor& desc, binder_status_t status = EX_NONE) {
+    void create(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect>& effect,
+                Descriptor& desc, binder_status_t status = EX_NONE) {
         ASSERT_NE(factory, nullptr);
         auto& id = desc.common.id;
         ASSERT_STATUS(status, factory->createEffect(id.uuid, &effect));
         if (status == EX_NONE) {
             ASSERT_NE(effect, nullptr) << toString(id.uuid);
         }
+        mIsSpatializer = id.type == getEffectTypeUuidSpatializer();
+        mDescriptor = desc;
     }
 
     static void destroyIgnoreRet(std::shared_ptr<IFactory> factory,
@@ -110,10 +118,9 @@
         ASSERT_STATUS(status, effect->open(common, specific, ret));
     }
 
-    static void open(std::shared_ptr<IEffect> effect, int session = 0,
-                     binder_status_t status = EX_NONE) {
+    void open(std::shared_ptr<IEffect> effect, int session = 0, binder_status_t status = EX_NONE) {
         ASSERT_NE(effect, nullptr);
-        Parameter::Common common = EffectHelper::createParamCommon(session);
+        Parameter::Common common = createParamCommon(session);
         IEffect::OpenEffectReturn ret;
         ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, status));
     }
@@ -207,15 +214,31 @@
                                                true /* retry */));
         EXPECT_TRUE(efState & kEventFlagDataMqUpdate);
     }
-    static Parameter::Common createParamCommon(
-            int session = 0, int ioHandle = -1, int iSampleRate = 48000, int oSampleRate = 48000,
-            long iFrameCount = 0x100, long oFrameCount = 0x100,
-            AudioChannelLayout inputChannelLayout =
-                    AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
-                            AudioChannelLayout::LAYOUT_STEREO),
-            AudioChannelLayout outputChannelLayout =
-                    AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
-                            AudioChannelLayout::LAYOUT_STEREO)) {
+
+    Parameter::Common createParamCommon(int session = 0, int ioHandle = -1, int iSampleRate = 48000,
+                                        int oSampleRate = 48000, long iFrameCount = 0x100,
+                                        long oFrameCount = 0x100) {
+        AudioChannelLayout defaultLayout = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                AudioChannelLayout::LAYOUT_STEREO);
+        // query supported input layout and use it as the default parameter in common
+        if (mIsSpatializer && isRangeValid<Range::spatializer>(Spatializer::supportedChannelLayout,
+                                                               mDescriptor.capability)) {
+            const auto layoutRange = getRange<Range::spatializer, Range::SpatializerRange>(
+                    mDescriptor.capability, Spatializer::supportedChannelLayout);
+            if (std::vector<AudioChannelLayout> layouts;
+                layoutRange &&
+                0 != (layouts = layoutRange->min.get<Spatializer::supportedChannelLayout>())
+                                .size()) {
+                defaultLayout = layouts[0];
+            }
+        }
+        return createParamCommon(session, ioHandle, iSampleRate, oSampleRate, iFrameCount,
+                                 oFrameCount, defaultLayout, defaultLayout);
+    }
+    static Parameter::Common createParamCommon(int session, int ioHandle, int iSampleRate,
+                                               int oSampleRate, long iFrameCount, long oFrameCount,
+                                               AudioChannelLayout inputChannelLayout,
+                                               AudioChannelLayout outputChannelLayout) {
         Parameter::Common common;
         common.session = session;
         common.ioHandle = ioHandle;
@@ -379,4 +402,7 @@
 
         return bufferMag;
     }
+
+    bool mIsSpatializer;
+    Descriptor mDescriptor;
 };
diff --git a/audio/aidl/vts/VtsHalAECTargetTest.cpp b/audio/aidl/vts/VtsHalAECTargetTest.cpp
index f972b84..53b6757 100644
--- a/audio/aidl/vts/VtsHalAECTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp
@@ -52,7 +52,7 @@
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
         auto specific = getDefaultParamSpecific();
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
         IEffect::OpenEffectReturn ret;
diff --git a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
index 75da589..f14afbc 100644
--- a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
@@ -53,7 +53,7 @@
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
         Parameter::Specific specific = getDefaultParamSpecific();
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
         IEffect::OpenEffectReturn ret;
diff --git a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
index 5f57a88..048d540 100644
--- a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
@@ -54,7 +54,7 @@
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
         Parameter::Specific specific = getDefaultParamSpecific();
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
         IEffect::OpenEffectReturn ret;
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index 5b83d73..2f47d07 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -396,7 +396,7 @@
 TEST_P(AudioEffectTest, VerifyCommonParametersAfterOpen) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
-    Parameter::Common common = EffectHelper::createParamCommon();
+    Parameter::Common common = createParamCommon();
     IEffect::OpenEffectReturn ret;
     ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
 
@@ -416,8 +416,8 @@
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
 
-    Parameter::Common common = EffectHelper::createParamCommon(
-            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+    Parameter::Common common = createParamCommon(0 /* session */, 1 /* ioHandle */,
+                                                 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::common);
     ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
 
@@ -432,8 +432,8 @@
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
     ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
-    Parameter::Common common = EffectHelper::createParamCommon(
-            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+    Parameter::Common common = createParamCommon(0 /* session */, 1 /* ioHandle */,
+                                                 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::common);
     ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
 
@@ -451,8 +451,8 @@
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
     ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    Parameter::Common common = EffectHelper::createParamCommon(
-            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+    Parameter::Common common = createParamCommon(0 /* session */, 1 /* ioHandle */,
+                                                 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::common);
     ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
 
@@ -467,8 +467,8 @@
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
     ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
-    Parameter::Common common = EffectHelper::createParamCommon(
-            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+    Parameter::Common common = createParamCommon(0 /* session */, 1 /* ioHandle */,
+                                                 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::common);
     ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
 
@@ -486,8 +486,8 @@
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
     ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
-    Parameter::Common common = EffectHelper::createParamCommon(
-            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+    Parameter::Common common = createParamCommon(0 /* session */, 1 /* ioHandle */,
+                                                 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::common);
     ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
 
@@ -621,7 +621,7 @@
 
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
-    Parameter::Common common = EffectHelper::createParamCommon(
+    Parameter::Common common = createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
@@ -666,7 +666,7 @@
 TEST_P(AudioEffectDataPathTest, ConsumeDataInProcessingState) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
-    Parameter::Common common = EffectHelper::createParamCommon(
+    Parameter::Common common = createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
@@ -700,7 +700,7 @@
 TEST_P(AudioEffectDataPathTest, ConsumeDataAfterRestart) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
-    Parameter::Common common = EffectHelper::createParamCommon(
+    Parameter::Common common = createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
@@ -744,7 +744,7 @@
 
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
-    Parameter::Common common = EffectHelper::createParamCommon(
+    Parameter::Common common = createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
@@ -797,7 +797,7 @@
 TEST_P(AudioEffectDataPathTest, SendDataAtIdleAndConsumeDataInProcessing) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
-    Parameter::Common common = EffectHelper::createParamCommon(
+    Parameter::Common common = createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
@@ -831,7 +831,7 @@
 TEST_P(AudioEffectDataPathTest, ProcessDataMultipleTimes) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
-    Parameter::Common common = EffectHelper::createParamCommon(
+    Parameter::Common common = createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
@@ -871,7 +871,7 @@
 TEST_P(AudioEffectDataPathTest, ConsumeDataAndRestart) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
-    Parameter::Common common = EffectHelper::createParamCommon(
+    Parameter::Common common = createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
@@ -913,7 +913,7 @@
 TEST_P(AudioEffectDataPathTest, NotConsumeDataByClosedEffect) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
-    Parameter::Common common = EffectHelper::createParamCommon(
+    Parameter::Common common = createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
@@ -942,10 +942,10 @@
     ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mDescriptor));
 
-    Parameter::Common common1 = EffectHelper::createParamCommon(
+    Parameter::Common common1 = createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
-    Parameter::Common common2 = EffectHelper::createParamCommon(
+    Parameter::Common common2 = createParamCommon(
             1 /* session */, 1 /* ioHandle */, 48000 /* iSampleRate */, 48000 /* oSampleRate */,
             2 * kInputFrameCount /* iFrameCount */, 2 * kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret1, ret2;
diff --git a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
index 4cb1f49..abc5a91 100644
--- a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
@@ -57,7 +57,7 @@
                 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layout);
 
         Parameter::Specific specific = getDefaultParamSpecific();
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, kSamplingFrequency /* iSampleRate */,
                 kSamplingFrequency /* oSampleRate */, mInputFrameCount /* iFrameCount */,
                 mOutputFrameCount /* oFrameCount */, channelLayout, channelLayout);
diff --git a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
index ef77f4d..844a340 100644
--- a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
@@ -97,7 +97,9 @@
         Parameter::Common common = EffectHelper::createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */,
-                inputChannelLayout);
+                inputChannelLayout,
+                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                        AudioChannelLayout::LAYOUT_STEREO));
         ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &mOpenEffectReturn, EX_NONE));
         ASSERT_NE(nullptr, mEffect);
     }
diff --git a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
index 12b1797..0c201cc 100644
--- a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
+++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
@@ -57,7 +57,7 @@
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
         Parameter::Specific specific = getDefaultParamSpecific();
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 0x100 /* iFrameCount */, 0x100 /* oFrameCount */,
                 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout),
diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
index f641fa5..c7c6505 100644
--- a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -16,28 +16,132 @@
 
 #define LOG_TAG "VtsHalEnvironmentalReverbTest"
 #include <android-base/logging.h>
+#include <audio_utils/power.h>
+#include <system/audio.h>
 
 #include "EffectHelper.h"
 
 using namespace android;
-
-using aidl::android::hardware::audio::effect::Descriptor;
-using aidl::android::hardware::audio::effect::EnvironmentalReverb;
-using aidl::android::hardware::audio::effect::getEffectTypeUuidEnvReverb;
-using aidl::android::hardware::audio::effect::IEffect;
-using aidl::android::hardware::audio::effect::IFactory;
-using aidl::android::hardware::audio::effect::Parameter;
+using namespace aidl::android::hardware::audio::effect;
+using aidl::android::hardware::audio::common::getChannelCount;
 using android::hardware::audio::common::testing::detail::TestExecutionTracer;
+using TagVectorPair = std::pair<EnvironmentalReverb::Tag, std::vector<int>>;
+using TagValuePair = std::pair<EnvironmentalReverb::Tag, int>;
 
+static constexpr int kMaxRoomLevel = 0;
+static constexpr int kMinRoomLevel = -6000;
+static constexpr int kMinRoomHfLevel = -4000;
+static constexpr int kMinDecayTime = 0;
+static constexpr int kMinHfRatio = 100;
+static constexpr int kMinLevel = -6000;
+static constexpr int kMinDensity = 0;
+static constexpr int kMinDiffusion = 0;
+static constexpr int kMinDelay = 0;
+
+static const std::vector<TagVectorPair> kParamsIncreasingVector = {
+
+        {EnvironmentalReverb::roomLevelMb, {-3500, -2800, -2100, -1400, -700, 0}},
+        {EnvironmentalReverb::roomHfLevelMb, {-4000, -3200, -2400, -1600, -800, 0}},
+        {EnvironmentalReverb::decayTimeMs, {800, 1600, 2400, 3200, 4000}},
+        {EnvironmentalReverb::decayHfRatioPm, {100, 600, 1100, 1600, 2000}},
+        {EnvironmentalReverb::levelMb, {-3500, -2800, -2100, -1400, -700, 0}},
+};
+
+static const std::vector<TagValuePair> kParamsMinimumValue = {
+        {EnvironmentalReverb::roomLevelMb, kMinRoomLevel},
+        {EnvironmentalReverb::decayTimeMs, kMinDecayTime},
+        {EnvironmentalReverb::levelMb, kMinLevel}};
+
+std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kDescPair;
+
+using Maker = std::set<int> (*)();
+static const std::array<Maker, static_cast<int>(EnvironmentalReverb::bypass) + 1>
+        kTestValueSetMaker = {
+                nullptr,
+                []() -> std::set<int> {
+                    return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+                                                         Range::environmentalReverb,
+                                                         EnvironmentalReverb::roomLevelMb>(
+                            kDescPair, EffectHelper::expandTestValueBasic<int>);
+                },
+                []() -> std::set<int> {
+                    return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+                                                         Range::environmentalReverb,
+                                                         EnvironmentalReverb::roomHfLevelMb>(
+                            kDescPair, EffectHelper::expandTestValueBasic<int>);
+                },
+                []() -> std::set<int> {
+                    return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+                                                         Range::environmentalReverb,
+                                                         EnvironmentalReverb::decayTimeMs>(
+                            kDescPair, EffectHelper::expandTestValueBasic<int>);
+                },
+                []() -> std::set<int> {
+                    return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+                                                         Range::environmentalReverb,
+                                                         EnvironmentalReverb::decayHfRatioPm>(
+                            kDescPair, EffectHelper::expandTestValueBasic<int>);
+                },
+                nullptr,
+                nullptr,
+                []() -> std::set<int> {
+                    return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+                                                         Range::environmentalReverb,
+                                                         EnvironmentalReverb::levelMb>(
+                            kDescPair, EffectHelper::expandTestValueBasic<int>);
+                },
+                []() -> std::set<int> {
+                    return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+                                                         Range::environmentalReverb,
+                                                         EnvironmentalReverb::delayMs>(
+                            kDescPair, EffectHelper::expandTestValueBasic<int>);
+                },
+                []() -> std::set<int> {
+                    return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+                                                         Range::environmentalReverb,
+                                                         EnvironmentalReverb::diffusionPm>(
+                            kDescPair, EffectHelper::expandTestValueBasic<int>);
+                },
+                []() -> std::set<int> {
+                    return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+                                                         Range::environmentalReverb,
+                                                         EnvironmentalReverb::densityPm>(
+                            kDescPair, EffectHelper::expandTestValueBasic<int>);
+                },
+                []() -> std::set<int> {
+                    return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+                                                         Range::environmentalReverb,
+                                                         EnvironmentalReverb::bypass>(
+                            kDescPair, EffectHelper::expandTestValueBasic<int>);
+                },
+};
+
+static std::vector<TagValuePair> buildSetAndGetTestParams() {
+    std::vector<TagValuePair> valueTag;
+    for (EnvironmentalReverb::Tag tag : ndk::enum_range<EnvironmentalReverb::Tag>()) {
+        std::set<int> values;
+        int intTag = static_cast<int>(tag);
+        if (intTag <= static_cast<int>(EnvironmentalReverb::bypass) &&
+            kTestValueSetMaker[intTag] != nullptr) {
+            values = kTestValueSetMaker[intTag]();
+        }
+
+        for (const auto& value : values) {
+            valueTag.push_back(std::make_pair(tag, value));
+        }
+    }
+
+    return valueTag;
+}
 /**
- * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
- * VtsAudioEffectTargetTest.
- * Testing parameter range, assuming the parameter supported by effect is in this range.
- * This range is verified with IEffect.getDescriptor() and range defined in the documentation, for
- * any index supported value test expects EX_NONE from IEffect.setParameter(), otherwise expects
- * EX_ILLEGAL_ARGUMENT.
+ * Tests do the following:
+ * - Testing parameter range supported by the effect. Range is verified with IEffect.getDescriptor()
+ *   and range defined in the documentation.
+ * - Validating the effect by comparing the outputs of the supported parameters.
  */
 
+enum ParamName { DESCRIPTOR_INDEX, TAG_VALUE_PAIR };
+
 class EnvironmentalReverbHelper : public EffectHelper {
   public:
     EnvironmentalReverbHelper(std::pair<std::shared_ptr<IFactory>, Descriptor> pair) {
@@ -49,10 +153,9 @@
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
         Parameter::Specific specific = getDefaultParamSpecific();
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
-                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
-        IEffect::OpenEffectReturn ret;
+                mFrameCount /* iFrameCount */, mFrameCount /* oFrameCount */);
         ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
         ASSERT_NE(nullptr, mEffect);
     }
@@ -63,475 +166,291 @@
     }
 
     Parameter::Specific getDefaultParamSpecific() {
-        EnvironmentalReverb er = EnvironmentalReverb::make<EnvironmentalReverb::roomLevelMb>(-6000);
+        EnvironmentalReverb er =
+                EnvironmentalReverb::make<EnvironmentalReverb::roomLevelMb>(kMaxRoomLevel);
         Parameter::Specific specific =
                 Parameter::Specific::make<Parameter::Specific::environmentalReverb>(er);
         return specific;
     }
 
-    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
-    std::shared_ptr<IFactory> mFactory;
-    std::shared_ptr<IEffect> mEffect;
-    Descriptor mDescriptor;
-    int mRoomLevel = -6000;
-    int mRoomHfLevel = 0;
-    int mDecayTime = 1000;
-    int mDecayHfRatio = 500;
-    int mLevel = -6000;
-    int mDelay = 40;
-    int mDiffusion = 1000;
-    int mDensity = 1000;
-    bool mBypass = false;
+    bool isParamValid(EnvironmentalReverb env) {
+        return isParameterValid<EnvironmentalReverb, Range::environmentalReverb>(env, mDescriptor);
+    }
 
-    void SetAndGetReverbParameters() {
-        for (auto& it : mTags) {
-            auto& tag = it.first;
-            auto& er = it.second;
+    Parameter createParam(EnvironmentalReverb env) {
+        return Parameter::make<Parameter::specific>(
+                Parameter::Specific::make<Parameter::Specific::environmentalReverb>(env));
+    }
 
-            // validate parameter
-            Descriptor desc;
-            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
-            const bool valid = isParameterValid<EnvironmentalReverb, Range::environmentalReverb>(
-                    it.second, desc);
-            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+    void setAndVerifyParam(binder_exception_t expected, EnvironmentalReverb env,
+                           EnvironmentalReverb::Tag tag) {
+        auto expectedParam = createParam(env);
 
-            // set
-            Parameter expectParam;
-            Parameter::Specific specific;
-            specific.set<Parameter::Specific::environmentalReverb>(er);
-            expectParam.set<Parameter::specific>(specific);
-            EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+        EXPECT_STATUS(expected, mEffect->setParameter(expectedParam)) << expectedParam.toString();
 
-            // only get if parameter in range and set success
-            if (expected == EX_NONE) {
-                Parameter getParam;
-                Parameter::Id id;
-                EnvironmentalReverb::Id erId;
-                erId.set<EnvironmentalReverb::Id::commonTag>(tag);
-                id.set<Parameter::Id::environmentalReverbTag>(erId);
-                // if set success, then get should match
-                EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
-                EXPECT_EQ(expectParam, getParam);
-            }
+        if (expected == EX_NONE) {
+            auto erId = EnvironmentalReverb::Id::make<EnvironmentalReverb::Id::commonTag>(
+                    EnvironmentalReverb::Tag(tag));
+
+            auto id = Parameter::Id::make<Parameter::Id::environmentalReverbTag>(erId);
+
+            // get parameter
+            Parameter getParam;
+            EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+            EXPECT_EQ(expectedParam, getParam) << "\nexpectedParam:" << expectedParam.toString()
+                                               << "\ngetParam:" << getParam.toString();
         }
     }
 
-    void addRoomLevelParam() {
-        EnvironmentalReverb er;
-        er.set<EnvironmentalReverb::roomLevelMb>(mRoomLevel);
-        mTags.push_back({EnvironmentalReverb::roomLevelMb, er});
+    bool isAuxiliary() {
+        return mDescriptor.common.flags.type ==
+               aidl::android::hardware::audio::effect::Flags::Type::AUXILIARY;
     }
 
-    void addRoomHfLevelParam(int roomHfLevel) {
-        EnvironmentalReverb er;
-        er.set<EnvironmentalReverb::roomHfLevelMb>(roomHfLevel);
-        mTags.push_back({EnvironmentalReverb::roomHfLevelMb, er});
+    float computeOutputEnergy(const std::vector<float>& input, std::vector<float> output) {
+        if (!isAuxiliary()) {
+            // Extract auxiliary output
+            for (size_t i = 0; i < output.size(); i++) {
+                output[i] -= input[i];
+            }
+        }
+        return audio_utils_compute_energy_mono(output.data(), AUDIO_FORMAT_PCM_FLOAT,
+                                               output.size());
     }
 
-    void addDecayTimeParam(int decayTime) {
-        EnvironmentalReverb er;
-        er.set<EnvironmentalReverb::decayTimeMs>(decayTime);
-        mTags.push_back({EnvironmentalReverb::decayTimeMs, er});
+    void generateSineWaveInput(std::vector<float>& input) {
+        int frequency = 1000;
+        size_t kSamplingFrequency = 44100;
+        for (size_t i = 0; i < input.size(); i++) {
+            input[i] = sin(2 * M_PI * frequency * i / kSamplingFrequency);
+        }
+    }
+    using Maker = EnvironmentalReverb (*)(int);
+
+    static constexpr std::array<Maker, static_cast<int>(EnvironmentalReverb::bypass) + 1>
+            kEnvironmentalReverbParamMaker = {
+                    nullptr,
+                    [](int value) -> EnvironmentalReverb {
+                        return EnvironmentalReverb::make<EnvironmentalReverb::roomLevelMb>(value);
+                    },
+                    [](int value) -> EnvironmentalReverb {
+                        return EnvironmentalReverb::make<EnvironmentalReverb::roomHfLevelMb>(value);
+                    },
+                    [](int value) -> EnvironmentalReverb {
+                        return EnvironmentalReverb::make<EnvironmentalReverb::decayTimeMs>(value);
+                    },
+                    [](int value) -> EnvironmentalReverb {
+                        return EnvironmentalReverb::make<EnvironmentalReverb::decayHfRatioPm>(
+                                value);
+                    },
+                    nullptr,
+                    nullptr,
+                    [](int value) -> EnvironmentalReverb {
+                        return EnvironmentalReverb::make<EnvironmentalReverb::levelMb>(value);
+                    },
+                    [](int value) -> EnvironmentalReverb {
+                        return EnvironmentalReverb::make<EnvironmentalReverb::delayMs>(value);
+                    },
+                    [](int value) -> EnvironmentalReverb {
+                        return EnvironmentalReverb::make<EnvironmentalReverb::diffusionPm>(value);
+                    },
+                    [](int value) -> EnvironmentalReverb {
+                        return EnvironmentalReverb::make<EnvironmentalReverb::densityPm>(value);
+                    },
+                    [](int value) -> EnvironmentalReverb {
+                        return EnvironmentalReverb::make<EnvironmentalReverb::bypass>(value);
+                    }};
+
+    void createEnvParam(EnvironmentalReverb::Tag tag, int paramValue) {
+        int intTag = static_cast<int>(tag);
+        if (intTag <= static_cast<int>(EnvironmentalReverb::bypass) &&
+            kEnvironmentalReverbParamMaker[intTag] != NULL) {
+            mEnvParam = kEnvironmentalReverbParamMaker[intTag](paramValue);
+        } else {
+            GTEST_SKIP() << "Invalid parameter, skipping the test\n";
+        }
     }
 
-    void addDecayHfRatioParam(int decayHfRatio) {
-        EnvironmentalReverb er;
-        er.set<EnvironmentalReverb::decayHfRatioPm>(decayHfRatio);
-        mTags.push_back({EnvironmentalReverb::decayHfRatioPm, er});
+    void setParameterAndProcess(std::vector<float>& input, std::vector<float>& output, int val,
+                                EnvironmentalReverb::Tag tag) {
+        createEnvParam(tag, val);
+        if (isParamValid(mEnvParam)) {
+            ASSERT_NO_FATAL_FAILURE(setAndVerifyParam(EX_NONE, mEnvParam, tag));
+            ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput(input, output, mEffect, &ret));
+        }
     }
 
-    void addLevelParam(int level) {
-        EnvironmentalReverb er;
-        er.set<EnvironmentalReverb::levelMb>(level);
-        mTags.push_back({EnvironmentalReverb::levelMb, er});
-    }
+    static constexpr int kSamplingFrequency = 44100;
+    static constexpr int kDurationMilliSec = 500;
+    static constexpr int kBufferSize = kSamplingFrequency * kDurationMilliSec / 1000;
 
-    void addDelayParam(int delay) {
-        EnvironmentalReverb er;
-        er.set<EnvironmentalReverb::delayMs>(delay);
-        mTags.push_back({EnvironmentalReverb::delayMs, er});
-    }
+    int mStereoChannelCount =
+            getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                    AudioChannelLayout::LAYOUT_STEREO));
+    int mFrameCount = kBufferSize / mStereoChannelCount;
 
-    void addDiffusionParam(int diffusion) {
-        EnvironmentalReverb er;
-        er.set<EnvironmentalReverb::diffusionPm>(diffusion);
-        mTags.push_back({EnvironmentalReverb::diffusionPm, er});
-    }
-
-    void addDensityParam(int density) {
-        EnvironmentalReverb er;
-        er.set<EnvironmentalReverb::densityPm>(density);
-        mTags.push_back({EnvironmentalReverb::densityPm, er});
-    }
-
-    void addBypassParam(bool bypass) {
-        EnvironmentalReverb er;
-        er.set<EnvironmentalReverb::bypass>(bypass);
-        mTags.push_back({EnvironmentalReverb::bypass, er});
-    }
-
-  private:
-    std::vector<std::pair<EnvironmentalReverb::Tag, EnvironmentalReverb>> mTags;
-    void CleanUp() { mTags.clear(); }
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    IEffect::OpenEffectReturn ret;
+    Descriptor mDescriptor;
+    EnvironmentalReverb mEnvParam;
 };
 
-class EnvironmentalReverbRoomLevelTest
+class EnvironmentalReverbParamTest
     : public ::testing::TestWithParam<
-              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, TagValuePair>>,
       public EnvironmentalReverbHelper {
   public:
-    EnvironmentalReverbRoomLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
-        mRoomLevel = std::get<1>(GetParam());
+    EnvironmentalReverbParamTest()
+        : EnvironmentalReverbHelper(std::get<DESCRIPTOR_INDEX>(GetParam())) {
+        std::tie(mTag, mParamValue) = std::get<TAG_VALUE_PAIR>(GetParam());
     }
-
     void SetUp() override { SetUpReverb(); }
-
     void TearDown() override { TearDownReverb(); }
+
+    EnvironmentalReverb::Tag mTag;
+    int mParamValue;
 };
 
-TEST_P(EnvironmentalReverbRoomLevelTest, SetAndGetRoomLevel) {
-    EXPECT_NO_FATAL_FAILURE(addRoomLevelParam());
-    SetAndGetReverbParameters();
+TEST_P(EnvironmentalReverbParamTest, SetAndGetParameter) {
+    createEnvParam(mTag, mParamValue);
+    ASSERT_NO_FATAL_FAILURE(setAndVerifyParam(
+            isParamValid(mEnvParam) ? EX_NONE : EX_ILLEGAL_ARGUMENT, mEnvParam, mTag));
 }
 
-std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kDescPair;
-
 INSTANTIATE_TEST_SUITE_P(
-        EnvironmentalReverbTest, EnvironmentalReverbRoomLevelTest,
+        EnvironmentalReverbTest, EnvironmentalReverbParamTest,
         ::testing::Combine(
                 testing::ValuesIn(kDescPair = EffectFactoryHelper::getAllEffectDescriptors(
                                           IFactory::descriptor, getEffectTypeUuidEnvReverb())),
-                testing::ValuesIn(EffectHelper::getTestValueSet<EnvironmentalReverb, int,
-                                                                Range::environmentalReverb,
-                                                                EnvironmentalReverb::roomLevelMb>(
-                        kDescPair, EffectHelper::expandTestValueBasic<int>))),
-        [](const testing::TestParamInfo<EnvironmentalReverbRoomLevelTest::ParamType>& info) {
-            auto descriptor = std::get<0>(info.param).second;
-            std::string roomLevel = std::to_string(std::get<1>(info.param));
-
-            std::string name = getPrefix(descriptor) + "_roomLevel" + roomLevel;
+                testing::ValuesIn(buildSetAndGetTestParams())),
+        [](const testing::TestParamInfo<EnvironmentalReverbParamTest::ParamType>& info) {
+            auto descriptor = std::get<DESCRIPTOR_INDEX>(info.param).second;
+            auto tag = std::get<TAG_VALUE_PAIR>(info.param).first;
+            auto val = std::get<TAG_VALUE_PAIR>(info.param).second;
+            std::string name =
+                    getPrefix(descriptor) + "_Tag_" + toString(tag) + std::to_string(val);
             std::replace_if(
                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
             return name;
         });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbRoomLevelTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbParamTest);
 
-class EnvironmentalReverbRoomHfLevelTest
+class EnvironmentalReverbDataTest
     : public ::testing::TestWithParam<
-              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, TagVectorPair>>,
       public EnvironmentalReverbHelper {
   public:
-    EnvironmentalReverbRoomHfLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
-        mRoomHfLevel = std::get<1>(GetParam());
+    EnvironmentalReverbDataTest()
+        : EnvironmentalReverbHelper(std::get<DESCRIPTOR_INDEX>(GetParam())) {
+        std::tie(mTag, mParamValues) = std::get<TAG_VALUE_PAIR>(GetParam());
+        mInput.resize(kBufferSize);
+        generateSineWaveInput(mInput);
+    }
+    void SetUp() override { SetUpReverb(); }
+    void TearDown() override { TearDownReverb(); }
+
+    void assertEnergyIncreasingWithParameter(bool bypass) {
+        createEnvParam(EnvironmentalReverb::bypass, bypass);
+        ASSERT_NO_FATAL_FAILURE(setAndVerifyParam(EX_NONE, mEnvParam, EnvironmentalReverb::bypass));
+        float baseEnergy = 0;
+        for (int val : mParamValues) {
+            std::vector<float> output(kBufferSize);
+            setParameterAndProcess(mInput, output, val, mTag);
+            float energy = computeOutputEnergy(mInput, output);
+            ASSERT_GT(energy, baseEnergy);
+            baseEnergy = energy;
+        }
     }
 
-    void SetUp() override { SetUpReverb(); }
+    void assertZeroEnergyWithBypass(bool bypass) {
+        createEnvParam(EnvironmentalReverb::bypass, bypass);
+        ASSERT_NO_FATAL_FAILURE(setAndVerifyParam(EX_NONE, mEnvParam, EnvironmentalReverb::bypass));
+        for (int val : mParamValues) {
+            std::vector<float> output(kBufferSize);
+            setParameterAndProcess(mInput, output, val, mTag);
+            float energy = computeOutputEnergy(mInput, output);
+            ASSERT_EQ(energy, 0);
+        }
+    }
 
-    void TearDown() override { TearDownReverb(); }
+    EnvironmentalReverb::Tag mTag;
+    std::vector<int> mParamValues;
+    std::vector<float> mInput;
 };
 
-TEST_P(EnvironmentalReverbRoomHfLevelTest, SetAndGetRoomHfLevel) {
-    EXPECT_NO_FATAL_FAILURE(addRoomHfLevelParam(mRoomHfLevel));
-    SetAndGetReverbParameters();
+TEST_P(EnvironmentalReverbDataTest, IncreasingParamValue) {
+    assertEnergyIncreasingWithParameter(false);
+}
+
+TEST_P(EnvironmentalReverbDataTest, WithBypassEnabled) {
+    assertZeroEnergyWithBypass(true);
 }
 
 INSTANTIATE_TEST_SUITE_P(
-        EnvironmentalReverbTest, EnvironmentalReverbRoomHfLevelTest,
-        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
-                                   IFactory::descriptor, getEffectTypeUuidEnvReverb())),
-                           testing::ValuesIn(EffectHelper::getTestValueSet<
-                                             EnvironmentalReverb, int, Range::environmentalReverb,
-                                             EnvironmentalReverb::roomHfLevelMb>(
-                                   kDescPair, EffectHelper::expandTestValueBasic<int>))),
-        [](const testing::TestParamInfo<EnvironmentalReverbRoomHfLevelTest::ParamType>& info) {
-            auto descriptor = std::get<0>(info.param).second;
-            std::string roomHfLevel = std::to_string(std::get<1>(info.param));
-
-            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
-                               descriptor.common.name + "_UUID_" +
-                               toString(descriptor.common.id.uuid) + "_roomHfLevel" + roomHfLevel;
-            std::replace_if(
-                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+        EnvironmentalReverbTest, EnvironmentalReverbDataTest,
+        ::testing::Combine(
+                testing::ValuesIn(kDescPair = EffectFactoryHelper::getAllEffectDescriptors(
+                                          IFactory::descriptor, getEffectTypeUuidEnvReverb())),
+                testing::ValuesIn(kParamsIncreasingVector)),
+        [](const testing::TestParamInfo<EnvironmentalReverbDataTest::ParamType>& info) {
+            auto descriptor = std::get<DESCRIPTOR_INDEX>(info.param).second;
+            auto tag = std::get<TAG_VALUE_PAIR>(info.param).first;
+            std::string name = getPrefix(descriptor) + "_Tag_" + toString(tag);
             return name;
         });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbRoomHfLevelTest);
 
-class EnvironmentalReverbDecayTimeTest
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDataTest);
+
+class EnvironmentalReverbMinimumParamTest
     : public ::testing::TestWithParam<
-              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, TagValuePair>>,
       public EnvironmentalReverbHelper {
   public:
-    EnvironmentalReverbDecayTimeTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
-        mDecayTime = std::get<1>(GetParam());
+    EnvironmentalReverbMinimumParamTest()
+        : EnvironmentalReverbHelper(std::get<DESCRIPTOR_INDEX>(GetParam())) {
+        std::tie(mTag, mValue) = std::get<TAG_VALUE_PAIR>(GetParam());
     }
-
-    void SetUp() override { SetUpReverb(); }
-
+    void SetUp() override {
+        SetUpReverb();
+        createEnvParam(EnvironmentalReverb::roomLevelMb, kMinRoomLevel);
+        ASSERT_NO_FATAL_FAILURE(
+                setAndVerifyParam(EX_NONE, mEnvParam, EnvironmentalReverb::roomLevelMb));
+    }
     void TearDown() override { TearDownReverb(); }
+
+    EnvironmentalReverb::Tag mTag;
+    int mValue;
 };
 
-TEST_P(EnvironmentalReverbDecayTimeTest, SetAndGetDecayTime) {
-    EXPECT_NO_FATAL_FAILURE(addDecayTimeParam(mDecayTime));
-    SetAndGetReverbParameters();
+TEST_P(EnvironmentalReverbMinimumParamTest, MinimumValueTest) {
+    std::vector<float> input(kBufferSize);
+    generateSineWaveInput(input);
+    std::vector<float> output(kBufferSize);
+    setParameterAndProcess(input, output, mValue, mTag);
+    float energy = computeOutputEnergy(input, output);
+    // No Auxiliary output for minimum param values
+    ASSERT_EQ(energy, 0);
 }
 
 INSTANTIATE_TEST_SUITE_P(
-        EnvironmentalReverbTest, EnvironmentalReverbDecayTimeTest,
-        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
-                                   IFactory::descriptor, getEffectTypeUuidEnvReverb())),
-                           testing::ValuesIn(EffectHelper::getTestValueSet<
-                                             EnvironmentalReverb, int, Range::environmentalReverb,
-                                             EnvironmentalReverb::decayTimeMs>(
-                                   kDescPair, EffectHelper::expandTestValueBasic<int>))),
-        [](const testing::TestParamInfo<EnvironmentalReverbDecayTimeTest::ParamType>& info) {
-            auto descriptor = std::get<0>(info.param).second;
-            std::string decayTime = std::to_string(std::get<1>(info.param));
-
-            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
-                               descriptor.common.name + "_UUID_" +
-                               toString(descriptor.common.id.uuid) + "_decayTime" + decayTime;
+        EnvironmentalReverbTest, EnvironmentalReverbMinimumParamTest,
+        ::testing::Combine(
+                testing::ValuesIn(kDescPair = EffectFactoryHelper::getAllEffectDescriptors(
+                                          IFactory::descriptor, getEffectTypeUuidEnvReverb())),
+                testing::ValuesIn(kParamsMinimumValue)),
+        [](const testing::TestParamInfo<EnvironmentalReverbMinimumParamTest::ParamType>& info) {
+            auto descriptor = std::get<DESCRIPTOR_INDEX>(info.param).second;
+            auto tag = std::get<TAG_VALUE_PAIR>(info.param).first;
+            auto val = std::get<TAG_VALUE_PAIR>(info.param).second;
+            std::string name =
+                    getPrefix(descriptor) + "_Tag_" + toString(tag) + std::to_string(val);
             std::replace_if(
                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
             return name;
         });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDecayTimeTest);
 
-class EnvironmentalReverbDecayHfRatioTest
-    : public ::testing::TestWithParam<
-              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
-      public EnvironmentalReverbHelper {
-  public:
-    EnvironmentalReverbDecayHfRatioTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
-        mDecayHfRatio = std::get<1>(GetParam());
-    }
-
-    void SetUp() override { SetUpReverb(); }
-
-    void TearDown() override { TearDownReverb(); }
-};
-
-TEST_P(EnvironmentalReverbDecayHfRatioTest, SetAndGetDecayHfRatio) {
-    EXPECT_NO_FATAL_FAILURE(addDecayHfRatioParam(mDecayHfRatio));
-    SetAndGetReverbParameters();
-}
-
-INSTANTIATE_TEST_SUITE_P(
-        EnvironmentalReverbTest, EnvironmentalReverbDecayHfRatioTest,
-        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
-                                   IFactory::descriptor, getEffectTypeUuidEnvReverb())),
-                           testing::ValuesIn(EffectHelper::getTestValueSet<
-                                             EnvironmentalReverb, int, Range::environmentalReverb,
-                                             EnvironmentalReverb::decayHfRatioPm>(
-                                   kDescPair, EffectHelper::expandTestValueBasic<int>))),
-        [](const testing::TestParamInfo<EnvironmentalReverbDecayHfRatioTest::ParamType>& info) {
-            auto descriptor = std::get<0>(info.param).second;
-            std::string decayHfRatio = std::to_string(std::get<1>(info.param));
-
-            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
-                               descriptor.common.name + "_UUID_" +
-                               toString(descriptor.common.id.uuid) + "_decayHfRatio" + decayHfRatio;
-            std::replace_if(
-                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
-            return name;
-        });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDecayHfRatioTest);
-
-class EnvironmentalReverbLevelTest
-    : public ::testing::TestWithParam<
-              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
-      public EnvironmentalReverbHelper {
-  public:
-    EnvironmentalReverbLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
-        mLevel = std::get<1>(GetParam());
-    }
-
-    void SetUp() override { SetUpReverb(); }
-
-    void TearDown() override { TearDownReverb(); }
-};
-
-TEST_P(EnvironmentalReverbLevelTest, SetAndGetLevel) {
-    EXPECT_NO_FATAL_FAILURE(addLevelParam(mLevel));
-    SetAndGetReverbParameters();
-}
-
-INSTANTIATE_TEST_SUITE_P(
-        EnvironmentalReverbTest, EnvironmentalReverbLevelTest,
-        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
-                                   IFactory::descriptor, getEffectTypeUuidEnvReverb())),
-                           testing::ValuesIn(EffectHelper::getTestValueSet<
-                                             EnvironmentalReverb, int, Range::environmentalReverb,
-                                             EnvironmentalReverb::levelMb>(
-                                   kDescPair, EffectHelper::expandTestValueBasic<int>))),
-        [](const testing::TestParamInfo<EnvironmentalReverbDecayHfRatioTest::ParamType>& info) {
-            auto descriptor = std::get<0>(info.param).second;
-            std::string level = std::to_string(std::get<1>(info.param));
-
-            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
-                               descriptor.common.name + "_UUID_" +
-                               toString(descriptor.common.id.uuid) + "_level" + level;
-            std::replace_if(
-                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
-            return name;
-        });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbLevelTest);
-
-class EnvironmentalReverbDelayTest
-    : public ::testing::TestWithParam<
-              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
-      public EnvironmentalReverbHelper {
-  public:
-    EnvironmentalReverbDelayTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
-        mDelay = std::get<1>(GetParam());
-    }
-
-    void SetUp() override { SetUpReverb(); }
-
-    void TearDown() override { TearDownReverb(); }
-};
-
-TEST_P(EnvironmentalReverbDelayTest, SetAndGetDelay) {
-    EXPECT_NO_FATAL_FAILURE(addDelayParam(mDelay));
-    SetAndGetReverbParameters();
-}
-
-INSTANTIATE_TEST_SUITE_P(
-        EnvironmentalReverbTest, EnvironmentalReverbDelayTest,
-        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
-                                   IFactory::descriptor, getEffectTypeUuidEnvReverb())),
-                           testing::ValuesIn(EffectHelper::getTestValueSet<
-                                             EnvironmentalReverb, int, Range::environmentalReverb,
-                                             EnvironmentalReverb::delayMs>(
-                                   kDescPair, EffectHelper::expandTestValueBasic<int>))),
-        [](const testing::TestParamInfo<EnvironmentalReverbDelayTest::ParamType>& info) {
-            auto descriptor = std::get<0>(info.param).second;
-            std::string delay = std::to_string(std::get<1>(info.param));
-
-            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
-                               descriptor.common.name + "_UUID_" +
-                               toString(descriptor.common.id.uuid) + "_delay" + delay;
-            std::replace_if(
-                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
-            return name;
-        });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDelayTest);
-
-class EnvironmentalReverbDiffusionTest
-    : public ::testing::TestWithParam<
-              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
-      public EnvironmentalReverbHelper {
-  public:
-    EnvironmentalReverbDiffusionTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
-        mDiffusion = std::get<1>(GetParam());
-    }
-
-    void SetUp() override { SetUpReverb(); }
-
-    void TearDown() override { TearDownReverb(); }
-};
-
-TEST_P(EnvironmentalReverbDiffusionTest, SetAndGetDiffusion) {
-    EXPECT_NO_FATAL_FAILURE(addDiffusionParam(mDiffusion));
-    SetAndGetReverbParameters();
-}
-
-INSTANTIATE_TEST_SUITE_P(
-        EnvironmentalReverbTest, EnvironmentalReverbDiffusionTest,
-        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
-                                   IFactory::descriptor, getEffectTypeUuidEnvReverb())),
-                           testing::ValuesIn(EffectHelper::getTestValueSet<
-                                             EnvironmentalReverb, int, Range::environmentalReverb,
-                                             EnvironmentalReverb::diffusionPm>(
-                                   kDescPair, EffectHelper::expandTestValueBasic<int>))),
-        [](const testing::TestParamInfo<EnvironmentalReverbDiffusionTest::ParamType>& info) {
-            auto descriptor = std::get<0>(info.param).second;
-            std::string diffusion = std::to_string(std::get<1>(info.param));
-
-            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
-                               descriptor.common.name + "_UUID_" +
-                               toString(descriptor.common.id.uuid) + "_diffusion" + diffusion;
-            std::replace_if(
-                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
-            return name;
-        });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDiffusionTest);
-
-class EnvironmentalReverbDensityTest
-    : public ::testing::TestWithParam<
-              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
-      public EnvironmentalReverbHelper {
-  public:
-    EnvironmentalReverbDensityTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
-        mDensity = std::get<1>(GetParam());
-    }
-
-    void SetUp() override { SetUpReverb(); }
-
-    void TearDown() override { TearDownReverb(); }
-};
-
-TEST_P(EnvironmentalReverbDensityTest, SetAndGetDensity) {
-    EXPECT_NO_FATAL_FAILURE(addDensityParam(mDensity));
-    SetAndGetReverbParameters();
-}
-
-INSTANTIATE_TEST_SUITE_P(
-        EnvironmentalReverbTest, EnvironmentalReverbDensityTest,
-        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
-                                   IFactory::descriptor, getEffectTypeUuidEnvReverb())),
-                           testing::ValuesIn(EffectHelper::getTestValueSet<
-                                             EnvironmentalReverb, int, Range::environmentalReverb,
-                                             EnvironmentalReverb::densityPm>(
-                                   kDescPair, EffectHelper::expandTestValueBasic<int>))),
-        [](const testing::TestParamInfo<EnvironmentalReverbDensityTest::ParamType>& info) {
-            auto descriptor = std::get<0>(info.param).second;
-            std::string density = std::to_string(std::get<1>(info.param));
-
-            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
-                               descriptor.common.name + "_UUID_" +
-                               toString(descriptor.common.id.uuid) + "_density" + density;
-            std::replace_if(
-                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
-            return name;
-        });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDensityTest);
-
-class EnvironmentalReverbBypassTest
-    : public ::testing::TestWithParam<
-              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, bool>>,
-      public EnvironmentalReverbHelper {
-  public:
-    EnvironmentalReverbBypassTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
-        mBypass = std::get<1>(GetParam());
-    }
-
-    void SetUp() override { SetUpReverb(); }
-
-    void TearDown() override { TearDownReverb(); }
-};
-
-TEST_P(EnvironmentalReverbBypassTest, SetAndGetBypass) {
-    EXPECT_NO_FATAL_FAILURE(addBypassParam(mBypass));
-    SetAndGetReverbParameters();
-}
-
-INSTANTIATE_TEST_SUITE_P(
-        EnvironmentalReverbTest, EnvironmentalReverbBypassTest,
-        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
-                                   IFactory::descriptor, getEffectTypeUuidEnvReverb())),
-                           testing::Bool()),
-        [](const testing::TestParamInfo<EnvironmentalReverbBypassTest::ParamType>& info) {
-            auto descriptor = std::get<0>(info.param).second;
-            std::string bypass = std::to_string(std::get<1>(info.param));
-
-            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
-                               descriptor.common.name + "_UUID_" +
-                               toString(descriptor.common.id.uuid) + "_bypass" + bypass;
-            std::replace_if(
-                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
-            return name;
-        });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbBypassTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbMinimumParamTest);
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
diff --git a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
index d7dbe38..0c931ff 100644
--- a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -71,7 +71,7 @@
         ASSERT_NE(nullptr, mFactory);
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
         IEffect::OpenEffectReturn ret;
diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
index 48e59dc..6af326d 100644
--- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
@@ -88,7 +88,7 @@
         ASSERT_NE(nullptr, mFactory);
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
         IEffect::OpenEffectReturn ret;
@@ -248,7 +248,7 @@
         ASSERT_NE(nullptr, mFactory);
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
         IEffect::OpenEffectReturn ret;
diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
index 7a53502..3c72dfa 100644
--- a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -48,7 +48,7 @@
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
         Parameter::Specific specific = getDefaultParamSpecific();
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
         ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &mOpenEffectReturn, EX_NONE));
diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp
index 5c13512..a50e1b4 100644
--- a/audio/aidl/vts/VtsHalNSTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp
@@ -49,7 +49,7 @@
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
         std::optional<Parameter::Specific> specific = getDefaultParamSpecific();
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
         IEffect::OpenEffectReturn ret;
diff --git a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
index 300939e..2229ff8 100644
--- a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
@@ -39,7 +39,7 @@
         ASSERT_NE(nullptr, mFactory);
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
         Parameter::Specific specific = getDefaultParamSpecific();
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, kSamplingFrequency /* iSampleRate */,
                 kSamplingFrequency /* oSampleRate */, mFrameCount /* iFrameCount */,
                 mFrameCount /* oFrameCount */);
diff --git a/audio/aidl/vts/VtsHalSpatializerTargetTest.cpp b/audio/aidl/vts/VtsHalSpatializerTargetTest.cpp
index f0b51b9..1f498e2 100644
--- a/audio/aidl/vts/VtsHalSpatializerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalSpatializerTargetTest.cpp
@@ -79,7 +79,7 @@
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
         Parameter::Specific specific = getDefaultParamSpecific();
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
         IEffect::OpenEffectReturn ret;
diff --git a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
index 2f6af08..f121f7c 100644
--- a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
@@ -39,7 +39,7 @@
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
         initFrameCount();
         Parameter::Specific specific = getDefaultParamSpecific();
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, kSamplingFrequency /* iSampleRate */,
                 kSamplingFrequency /* oSampleRate */, mInputFrameCount /* iFrameCount */,
                 mInputFrameCount /* oFrameCount */);
diff --git a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
index db83715..f215a8e 100644
--- a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
@@ -62,7 +62,7 @@
         ASSERT_NE(nullptr, mFactory);
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
         IEffect::OpenEffectReturn ret;
diff --git a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
index 4597b39..4115eca 100644
--- a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
@@ -37,7 +37,7 @@
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
         initFrameCount();
         Parameter::Specific specific = getDefaultParamSpecific();
-        Parameter::Common common = EffectHelper::createParamCommon(
+        Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, kSamplingFrequency /* iSampleRate */,
                 kSamplingFrequency /* oSampleRate */, mInputFrameCount /* iFrameCount */,
                 mInputFrameCount /* oFrameCount */);
diff --git a/automotive/audiocontrol/aidl/default/Android.bp b/automotive/audiocontrol/aidl/default/Android.bp
index a48d228..fd7e167 100644
--- a/automotive/audiocontrol/aidl/default/Android.bp
+++ b/automotive/audiocontrol/aidl/default/Android.bp
@@ -30,15 +30,14 @@
     defaults: [
         "latest_android_hardware_audio_common_ndk_shared",
         "latest_android_hardware_automotive_audiocontrol_ndk_shared",
+        "powerpolicyclient_defaults",
     ],
     shared_libs: [
         "android.hardware.audio.common@7.0-enums",
-        "android.frameworks.automotive.powerpolicy-V2-ndk",
         "libbase",
         "libbinder_ndk",
         "libcutils",
         "liblog",
-        "libpowerpolicyclient",
     ],
     srcs: [
         "AudioControl.cpp",
diff --git a/automotive/vehicle/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index 7306b47..77629a9 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -55,5 +55,10 @@
     {
       "name": "VehicleHalProtoMessageConverterTest"
     }
+  ],
+  "postsubmit": [
+    {
+      "name": "VehicleHalProtoMessageConverterTest"
+    }
   ]
 }
diff --git a/automotive/vehicle/aidl/Android.bp b/automotive/vehicle/aidl/Android.bp
index ed18ebc..ce9e7a1 100644
--- a/automotive/vehicle/aidl/Android.bp
+++ b/automotive/vehicle/aidl/Android.bp
@@ -60,5 +60,5 @@
         },
 
     ],
-
+    host_supported: true,
 }
diff --git a/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json b/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
index 135f30a..0dea16b 100644
--- a/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
+++ b/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
@@ -516,12 +516,12 @@
             {
                 "name": "DISPLAY_BRIGHTNESS",
                 "value": 289409539,
-                "description": "Property to represent brightness of the display.\nSome cars have single control for the brightness of all displays and this property is to share change in that control. In cars which have displays whose brightness is controlled separately, they must use PER_DISPLAY_BRIGHTNESS.\nOnly one of DISPLAY_BRIGHTNESS and PER_DISPLAY_BRIGHTNESS should be implemented. If both are available, PER_DISPLAY_BRIGHTNESS is used by AAOS.\nIf this is writable, android side can set this value when user changes display brightness from Settings. If this is read only, user may still change display brightness from Settings, but that must not be reflected to other displays."
+                "description": "Property to represent brightness of the display.\nSome cars have single control for the brightness of all displays and this property is to share change in that control. In cars which have displays whose brightness is controlled separately, they must use PER_DISPLAY_BRIGHTNESS.\nOnly one of DISPLAY_BRIGHTNESS and PER_DISPLAY_BRIGHTNESS should be implemented. If both are available, PER_DISPLAY_BRIGHTNESS is used by AAOS.\nIf this is writable, android side can set this value when user changes display brightness from Settings. If this is read only, user may still change display brightness from Settings, but that must not be reflected to other displays.\nIf this is writable, writing this property must cause an on property change event even if the new display brightness is the same as the current value."
             },
             {
                 "name": "PER_DISPLAY_BRIGHTNESS",
                 "value": 289475076,
-                "description": "Property to represent brightness of the displays which are controlled separately.\nSome cars have one or more displays whose brightness is controlled separately and this property is to inform the brightness of each passenger display. In cars where all displays' brightness is controlled together, they must use DISPLAY_BRIGHTNESS.\nOnly one of DISPLAY_BRIGHTNESS and PER_DISPLAY_BRIGHTNESS should be implemented. If both are available, PER_DISPLAY_BRIGHTNESS is used by AAOS.\nThe display port uniquely identifies a physical connector on the device for display output, ranging from 0 to 255.\nint32Values[0] : display port int32Values[1] : brightness"
+                "description": "Property to represent brightness of the displays which are controlled separately.\nSome cars have one or more displays whose brightness is controlled separately and this property is to inform the brightness of each passenger display. In cars where all displays' brightness is controlled together, they must use DISPLAY_BRIGHTNESS.\nOnly one of DISPLAY_BRIGHTNESS and PER_DISPLAY_BRIGHTNESS should be implemented. If both are available, PER_DISPLAY_BRIGHTNESS is used by AAOS.\nThe display port uniquely identifies a physical connector on the device for display output, ranging from 0 to 255.\nWriting this property must cause an on property change event that contains the same [display port, brightness] tuple even if the new display brightness is the same as the current value.\nTo get the display brightness for a specific display port, the GetValueRequest must contain a VehiclePropValue, which contains one int32Value: displayPort. Getting this property without specifying the the display port is undefined behavior.\nint32Values[0] : display port int32Values[1] : brightness"
             },
             {
                 "name": "Valet mode enabled",
diff --git a/automotive/vehicle/aidl/generated_lib/3/cpp/Android.bp b/automotive/vehicle/aidl/generated_lib/3/cpp/Android.bp
index 83043e5..7ff27a4 100644
--- a/automotive/vehicle/aidl/generated_lib/3/cpp/Android.bp
+++ b/automotive/vehicle/aidl/generated_lib/3/cpp/Android.bp
@@ -24,4 +24,5 @@
     local_include_dirs: ["."],
     export_include_dirs: ["."],
     defaults: ["VehicleHalInterfaceDefaults"],
+    host_supported: true,
 }
diff --git a/automotive/vehicle/aidl/generated_lib/4/cpp/Android.bp b/automotive/vehicle/aidl/generated_lib/4/cpp/Android.bp
index 6ece865..5bee849 100644
--- a/automotive/vehicle/aidl/generated_lib/4/cpp/Android.bp
+++ b/automotive/vehicle/aidl/generated_lib/4/cpp/Android.bp
@@ -24,6 +24,7 @@
     local_include_dirs: ["."],
     export_include_dirs: ["."],
     defaults: ["VehicleHalInterfaceDefaults"],
+    host_supported: true,
 }
 
 cc_library_headers {
@@ -32,4 +33,5 @@
     local_include_dirs: ["."],
     export_include_dirs: ["."],
     defaults: ["VehicleHalInterfaceDefaults"],
+    host_supported: true,
 }
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
index 0a33e5b..28c95ce 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
@@ -49,6 +49,7 @@
     ],
     cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"],
     shared_libs: ["libjsoncpp"],
+    host_supported: true,
 }
 
 cc_library_headers {
diff --git a/automotive/vehicle/aidl/impl/default_config/config/Android.bp b/automotive/vehicle/aidl/impl/default_config/config/Android.bp
index 8f1c7d1..c4f93c4 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/config/Android.bp
@@ -45,3 +45,24 @@
     sub_dir: "automotive/vhalconfig/",
     vendor: true,
 }
+
+prebuilt_etc_host {
+    name: "Host_Prebuilt_VehicleHalDefaultProperties_JSON",
+    filename_from_src: true,
+    src: "DefaultProperties.json",
+    relative_install_path: "automotive/vhalconfig/",
+}
+
+prebuilt_etc_host {
+    name: "Host_Prebuilt_VehicleHalTestProperties_JSON",
+    filename_from_src: true,
+    src: "TestProperties.json",
+    relative_install_path: "automotive/vhalconfig/",
+}
+
+prebuilt_etc_host {
+    name: "Host_Prebuilt_VehicleHalVendorClusterTestProperties_JSON",
+    filename_from_src: true,
+    src: "VendorClusterTestProperties.json",
+    relative_install_path: "automotive/vhalconfig/",
+}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp
index ab223d3..a250a47 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp
@@ -32,4 +32,5 @@
     shared_libs: [
         "libjsoncpp",
     ],
+    host_supported: true,
 }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
index 5fc07c9..6030e15 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
@@ -37,6 +37,7 @@
     whole_static_libs: [
         "wakeup_client_protos",
     ],
+    host_supported: true,
 }
 
 cc_defaults {
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 644d1cd..79d3e77 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -184,7 +184,7 @@
     std::unordered_set<int32_t> hvacPowerDependentProps;
 
     const bool mForceOverride;
-    bool mAddExtraTestVendorConfigs;
+    bool mAddExtraTestVendorConfigs = false;
 
     // Only used during initialization.
     JsonConfigLoader mLoader;
@@ -206,7 +206,7 @@
             EXCLUDES(mLock);
     // Load the config files in format '*.json' from the directory and parse the config files
     // into a map from property ID to ConfigDeclarations.
-    void loadPropConfigsFromDir(const std::string& dirPath,
+    bool loadPropConfigsFromDir(const std::string& dirPath,
                                 std::unordered_map<int32_t, ConfigDeclaration>* configs);
     // Function to be called when a value change event comes from vehicle bus. In our fake
     // implementation, this function is only called during "--inject-event" dump command.
@@ -269,16 +269,6 @@
     std::string dumpInjectEvent(const std::vector<std::string>& options);
     std::string dumpSubscriptions();
 
-    template <typename T>
-    android::base::Result<T> safelyParseInt(int index, const std::string& s) {
-        T out;
-        if (!::android::base::ParseInt(s, &out)) {
-            return android::base::Error() << android::base::StringPrintf(
-                           "non-integer argument at index %d: %s\n", index, s.c_str());
-        }
-        return out;
-    }
-    android::base::Result<float> safelyParseFloat(int index, const std::string& s);
     std::vector<std::string> getOptionValues(const std::vector<std::string>& options,
                                              size_t* index);
     android::base::Result<aidl::android::hardware::automotive::vehicle::VehiclePropValue>
@@ -325,6 +315,18 @@
             const aidl::android::hardware::automotive::vehicle::VehiclePropConfig&
                     vehiclePropConfig,
             int32_t areaId);
+    template <typename T>
+    static android::base::Result<T> safelyParseInt(int index, const std::string& s) {
+        T out;
+        if (!::android::base::ParseInt(s, &out)) {
+            return android::base::Error() << android::base::StringPrintf(
+                           "non-integer argument at index %d: %s\n", index, s.c_str());
+        }
+        return out;
+    }
+    static android::base::Result<float> safelyParseFloat(int index, const std::string& s);
+    static android::base::Result<int32_t> parsePropId(const std::vector<std::string>& options,
+                                                      size_t index);
 };
 
 }  // namespace fake
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 c4bcdb3..4f060e2 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -281,6 +281,19 @@
     ifs.close();
 }
 
+inline std::string vecToStringOfHexValues(const std::vector<int32_t>& vec) {
+    std::stringstream ss;
+    ss << "[";
+    for (size_t i = 0; i < vec.size(); i++) {
+        if (i != 0) {
+            ss << ",";
+        }
+        ss << std::showbase << std::hex << vec[i];
+    }
+    ss << "]";
+    return ss.str();
+}
+
 }  // namespace
 
 void FakeVehicleHardware::storePropInitialValue(const ConfigDeclaration& config) {
@@ -363,7 +376,12 @@
 
 std::unordered_map<int32_t, ConfigDeclaration> FakeVehicleHardware::loadConfigDeclarations() {
     std::unordered_map<int32_t, ConfigDeclaration> configsByPropId;
-    loadPropConfigsFromDir(mDefaultConfigDir, &configsByPropId);
+    bool defaultConfigLoaded = loadPropConfigsFromDir(mDefaultConfigDir, &configsByPropId);
+    if (!defaultConfigLoaded) {
+        // This cannot work without a valid default config.
+        ALOGE("Failed to load default config, exiting");
+        exit(1);
+    }
     if (UseOverrideConfigDir()) {
         loadPropConfigsFromDir(mOverrideConfigDir, &configsByPropId);
     }
@@ -1765,19 +1783,26 @@
     return "Usage: \n\n"
            "[no args]: dumps (id and value) all supported properties \n"
            "--help: shows this help\n"
-           "--list: lists the ids of all supported properties\n"
-           "--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties. \n"
-           "--getWithArg <PROP> [ValueArguments]: gets the value for a specific property with "
-           "arguments. \n"
-           "--set <PROP> [ValueArguments]: sets the value of property PROP. \n"
-           "--save-prop <prop> [-a AREA_ID]: saves the current value for PROP, integration test"
-           " that modifies prop value must call this before test and restore-prop after test. \n"
-           "--restore-prop <prop> [-a AREA_ID]: restores a previously saved property value. \n"
-           "--inject-event <PROP> [ValueArguments]: inject a property update event from car\n\n"
-           "ValueArguments are in the format of [-i INT_VALUE [INT_VALUE ...]] "
-           "[-i64 INT64_VALUE [INT64_VALUE ...]] [-f FLOAT_VALUE [FLOAT_VALUE ...]] [-s STR_VALUE] "
-           "[-b BYTES_VALUE] [-a AREA_ID].\n"
-           "Notice that the string, bytes and area value can be set just once, while the other can"
+           "--list: lists the property IDs and their supported area IDs for all supported "
+           "properties\n"
+           "--get <PROP_ID_1> [PROP_ID_2] [PROP_ID_N]: dumps the value of specific properties. \n"
+           "--getWithArg <PROP_ID> [ValueArguments]: gets the value for a specific property. "
+           "The value arguments constructs a VehiclePropValue used in the getValue request. \n"
+           "--set <PROP_ID> [ValueArguments]: sets the value of property PROP_ID, the value "
+           "arguments constructs a VehiclePropValue used in the setValue request. \n"
+           "--save-prop <PROP_ID> [-a AREA_ID]: saves the current value for PROP_ID, integration "
+           "tests that modify prop value must call this before test and restore-prop after test. \n"
+           "--restore-prop <PROP_ID> [-a AREA_ID]: restores a previously saved property value. \n"
+           "--inject-event <PROP_ID> [ValueArguments]: inject a property update event from car\n\n"
+           "ValueArguments are in the format of [-a OPTIONAL_AREA_ID] "
+           "[-i INT_VALUE_1 [INT_VALUE_2 ...]] "
+           "[-i64 INT64_VALUE_1 [INT64_VALUE_2 ...]] "
+           "[-f FLOAT_VALUE_1 [FLOAT_VALUE_2 ...]] "
+           "[-s STR_VALUE] "
+           "[-b BYTES_VALUE].\n"
+           "For example: to set property ID 0x1234, areaId 0x1 to int32 values: [1, 2, 3], "
+           "use \"--set 0x1234 -a 0x1 -i 1 2 3\"\n"
+           "Note that the string, bytes and area value can be set just once, while the other can"
            " have multiple values (so they're used in the respective array), "
            "BYTES_VALUE is in the form of 0xXXXX, e.g. 0xdeadbeef.\n" +
            genFakeDataHelp() + "Fake user HAL usage: \n" + mFakeUserHal->showDumpHelp();
@@ -1843,11 +1868,18 @@
         return "no properties to list\n";
     }
     int rowNumber = 1;
-    std::string msg = StringPrintf("listing %zu properties\n", configs.size());
+    std::stringstream ss;
+    ss << "listing " << configs.size() << " properties" << std::endl;
     for (const auto& config : configs) {
-        msg += StringPrintf("%d: %s\n", rowNumber++, PROP_ID_TO_CSTR(config.prop));
+        std::vector<int32_t> areaIds;
+        for (const auto& areaConfig : config.areaConfigs) {
+            areaIds.push_back(areaConfig.areaId);
+        }
+        ss << rowNumber++ << ": " << PROP_ID_TO_CSTR(config.prop) << ", propID: " << std::showbase
+           << std::hex << config.prop << std::noshowbase << std::dec
+           << ", areaIDs: " << vecToStringOfHexValues(areaIds) << std::endl;
     }
-    return msg;
+    return ss.str();
 }
 
 Result<void> FakeVehicleHardware::checkArgumentsSize(const std::vector<std::string>& options,
@@ -1860,6 +1892,16 @@
                                    minSize, size);
 }
 
+Result<int32_t> FakeVehicleHardware::parsePropId(const std::vector<std::string>& options,
+                                                 size_t index) {
+    const std::string& propIdStr = options[index];
+    auto result = stringToPropId(propIdStr);
+    if (result.ok()) {
+        return result;
+    }
+    return safelyParseInt<int32_t>(index, propIdStr);
+}
+
 std::string FakeVehicleHardware::dumpSpecificProperty(const std::vector<std::string>& options) {
     if (auto result = checkArgumentsSize(options, /*minSize=*/2); !result.ok()) {
         return getErrorMsg(result);
@@ -1870,7 +1912,7 @@
     size_t size = options.size();
     std::string msg = "";
     for (size_t i = 1; i < size; ++i) {
-        auto propResult = safelyParseInt<int32_t>(i, options[i]);
+        auto propResult = parsePropId(options, i);
         if (!propResult.ok()) {
             msg += getErrorMsg(propResult);
             continue;
@@ -1906,9 +1948,9 @@
     // --set/get/inject-event PROP [-f f1 f2...] [-i i1 i2...] [-i64 i1 i2...] [-s s1 s2...]
     // [-b b1 b2...] [-a a] [-t timestamp]
     size_t optionIndex = 1;
-    auto result = safelyParseInt<int32_t>(optionIndex, options[optionIndex]);
+    auto result = parsePropId(options, optionIndex);
     if (!result.ok()) {
-        return Error() << StringPrintf("Property value: \"%s\" is not a valid int: %s\n",
+        return Error() << StringPrintf("Property ID/Name: \"%s\" is not valid: %s\n",
                                        options[optionIndex].c_str(), getErrorMsg(result).c_str());
     }
     VehiclePropValue prop = {};
@@ -2378,30 +2420,35 @@
     (*mOnPropertyChangeCallback)(std::move(subscribedUpdatedValues));
 }
 
-void FakeVehicleHardware::loadPropConfigsFromDir(
+bool FakeVehicleHardware::loadPropConfigsFromDir(
         const std::string& dirPath,
         std::unordered_map<int32_t, ConfigDeclaration>* configsByPropId) {
     ALOGI("loading properties from %s", dirPath.c_str());
-    if (auto dir = opendir(dirPath.c_str()); dir != NULL) {
-        std::regex regJson(".*[.]json", std::regex::icase);
-        while (auto f = readdir(dir)) {
-            if (!std::regex_match(f->d_name, regJson)) {
-                continue;
-            }
-            std::string filePath = dirPath + "/" + std::string(f->d_name);
-            ALOGI("loading properties from %s", filePath.c_str());
-            auto result = mLoader.loadPropConfig(filePath);
-            if (!result.ok()) {
-                ALOGE("failed to load config file: %s, error: %s", filePath.c_str(),
-                      result.error().message().c_str());
-                continue;
-            }
-            for (auto& [propId, configDeclaration] : result.value()) {
-                (*configsByPropId)[propId] = std::move(configDeclaration);
-            }
-        }
-        closedir(dir);
+    auto dir = opendir(dirPath.c_str());
+    if (dir == nullptr) {
+        ALOGE("Failed to open config directory: %s", dirPath.c_str());
+        return false;
     }
+
+    std::regex regJson(".*[.]json", std::regex::icase);
+    while (auto f = readdir(dir)) {
+        if (!std::regex_match(f->d_name, regJson)) {
+            continue;
+        }
+        std::string filePath = dirPath + "/" + std::string(f->d_name);
+        ALOGI("loading properties from %s", filePath.c_str());
+        auto result = mLoader.loadPropConfig(filePath);
+        if (!result.ok()) {
+            ALOGE("failed to load config file: %s, error: %s", filePath.c_str(),
+                  result.error().message().c_str());
+            continue;
+        }
+        for (auto& [propId, configDeclaration] : result.value()) {
+            (*configsByPropId)[propId] = std::move(configDeclaration);
+        }
+    }
+    closedir(dir);
+    return true;
 }
 
 Result<float> FakeVehicleHardware::safelyParseFloat(int index, const std::string& s) {
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
index 664c877..9f002dd 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -56,6 +56,8 @@
     defaults: [
         "VehicleHalDefaults",
     ],
+    // Need root to use vendor lib: libgrpc++.
+    require_root: true,
     test_suites: ["device-tests"],
 }
 
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index cab33e1..0924360 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -2613,6 +2613,23 @@
                                            prop1.c_str(), prop2.c_str(), prop2.c_str())));
 }
 
+TEST_F(FakeVehicleHardwareTest, testDumpSpecificPropertiesWithName) {
+    std::vector<std::string> options;
+    options.push_back("--get");
+    std::string prop1 = "INFO_FUEL_CAPACITY";
+    std::string prop2 = "TIRE_PRESSURE";
+    int prop1Int = toInt(VehicleProperty::INFO_FUEL_CAPACITY);
+    int prop2Int = toInt(VehicleProperty::TIRE_PRESSURE);
+    options.push_back(prop1);
+    options.push_back(prop2);
+    DumpResult result = getHardware()->dump(options);
+    ASSERT_FALSE(result.callerShouldDumpState);
+    ASSERT_NE(result.buffer, "");
+    ASSERT_THAT(result.buffer,
+                ContainsRegex(StringPrintf("1:.*prop: %d.*\n2-0:.*prop: %d.*\n2-1:.*prop: %d.*\n",
+                                           prop1Int, prop2Int, prop2Int)));
+}
+
 TEST_F(FakeVehicleHardwareTest, testDumpSpecificPropertiesInvalidProp) {
     std::vector<std::string> options;
     options.push_back("--get");
@@ -2766,6 +2783,7 @@
     std::string infoMakeProperty = std::to_string(toInt(VehicleProperty::INFO_MAKE));
     return {
             {"success_set_string", {"--set", infoMakeProperty, "-s", CAR_MAKE}, true},
+            {"success_set_with_name", {"--set", "INFO_MAKE", "-s", CAR_MAKE}, true},
             {"success_set_bytes", {"--set", infoMakeProperty, "-b", "0xdeadbeef"}, true},
             {"success_set_bytes_caps", {"--set", infoMakeProperty, "-b", "0xDEADBEEF"}, true},
             {"success_set_int", {"--set", infoMakeProperty, "-i", "2147483647"}, true},
@@ -2790,10 +2808,7 @@
              false,
              "No values specified"},
             {"fail_unknown_options", {"--set", infoMakeProperty, "-abcd"}, false, "Unknown option"},
-            {"fail_invalid_property",
-             {"--set", "not valid", "-s", CAR_MAKE},
-             false,
-             "not a valid int"},
+            {"fail_invalid_property", {"--set", "not_valid", "-s", CAR_MAKE}, false, "not valid"},
             {"fail_duplicate_string",
              {"--set", infoMakeProperty, "-s", CAR_MAKE, "-s", CAR_MAKE},
              false,
diff --git a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/Android.bp
index c1cee84..8fc7341 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/Android.bp
@@ -29,4 +29,5 @@
         "VehicleHalUtils",
     ],
     export_static_lib_headers: ["VehicleHalUtils"],
+    host_supported: true,
 }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/userhal/Android.bp
index 2e95531..181fd10 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/Android.bp
@@ -29,4 +29,5 @@
         "VehicleHalUtils",
     ],
     export_static_lib_headers: ["VehicleHalUtils"],
+    host_supported: true,
 }
diff --git a/automotive/vehicle/aidl/impl/grpc/Android.bp b/automotive/vehicle/aidl/impl/grpc/Android.bp
index e5106f8..7a8da59 100644
--- a/automotive/vehicle/aidl/impl/grpc/Android.bp
+++ b/automotive/vehicle/aidl/impl/grpc/Android.bp
@@ -22,7 +22,7 @@
         "aprotoc",
         "protoc-gen-grpc-cpp-plugin",
     ],
-    cmd: "$(location aprotoc) -I$$(dirname $(location proto/VehicleServer.proto)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(location proto/VehicleServer.proto) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    cmd: "$(location aprotoc) -I$$(dirname $(location proto/VehicleServer.proto)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(location proto/VehicleServer.proto) --grpc_opt=generate_mock_code=true --grpc_out=$(genDir) --cpp_out=$(genDir)",
     srcs: [
         "proto/VehicleServer.proto",
         ":libprotobuf-internal-protos",
@@ -31,6 +31,7 @@
     out: [
         "VehicleServer.pb.h",
         "VehicleServer.grpc.pb.h",
+        "VehicleServer_mock.grpc.pb.h",
     ],
     visibility: ["//visibility:private"],
 }
@@ -127,4 +128,5 @@
     cflags: [
         "-Wno-unused-parameter",
     ],
+    host_supported: true,
 }
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
index 0742283..f44573a 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
@@ -39,6 +39,13 @@
       mGrpcStub(proto::VehicleServer::NewStub(mGrpcChannel)),
       mValuePollingThread([this] { ValuePollingLoop(); }) {}
 
+// Only used for unit testing.
+GRPCVehicleHardware::GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub)
+    : mServiceAddr(""),
+      mGrpcChannel(nullptr),
+      mGrpcStub(std::move(stub)),
+      mValuePollingThread([] {}) {}
+
 GRPCVehicleHardware::~GRPCVehicleHardware() {
     {
         std::lock_guard lck(mShutdownMutex);
@@ -181,6 +188,43 @@
     return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
 }
 
+aidlvhal::StatusCode GRPCVehicleHardware::subscribe(aidlvhal::SubscribeOptions options) {
+    proto::SubscribeRequest request;
+    ::grpc::ClientContext context;
+    proto::VehicleHalCallStatus protoStatus;
+    proto_msg_converter::aidlToProto(options, request.mutable_options());
+    auto grpc_status = mGrpcStub->Subscribe(&context, request, &protoStatus);
+    if (!grpc_status.ok()) {
+        if (grpc_status.error_code() == ::grpc::StatusCode::UNIMPLEMENTED) {
+            // This is a legacy sever. It should handle updateSampleRate.
+            LOG(INFO) << __func__ << ": GRPC Subscribe is not supported by the server";
+            return aidlvhal::StatusCode::OK;
+        }
+        LOG(ERROR) << __func__ << ": GRPC Subscribe Failed: " << grpc_status.error_message();
+        return aidlvhal::StatusCode::INTERNAL_ERROR;
+    }
+    return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
+}
+
+aidlvhal::StatusCode GRPCVehicleHardware::unsubscribe(int32_t propId, int32_t areaId) {
+    proto::UnsubscribeRequest request;
+    ::grpc::ClientContext context;
+    proto::VehicleHalCallStatus protoStatus;
+    request.set_prop_id(propId);
+    request.set_area_id(areaId);
+    auto grpc_status = mGrpcStub->Unsubscribe(&context, request, &protoStatus);
+    if (!grpc_status.ok()) {
+        if (grpc_status.error_code() == ::grpc::StatusCode::UNIMPLEMENTED) {
+            // This is a legacy sever. Ignore unsubscribe request.
+            LOG(INFO) << __func__ << ": GRPC Unsubscribe is not supported by the server";
+            return aidlvhal::StatusCode::OK;
+        }
+        LOG(ERROR) << __func__ << ": GRPC Unsubscribe Failed: " << grpc_status.error_message();
+        return aidlvhal::StatusCode::INTERNAL_ERROR;
+    }
+    return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
+}
+
 aidlvhal::StatusCode GRPCVehicleHardware::updateSampleRate(int32_t propId, int32_t areaId,
                                                            float sampleRate) {
     ::grpc::ClientContext context;
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
index ddd620e..9750f62 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
@@ -43,6 +43,9 @@
   public:
     explicit GRPCVehicleHardware(std::string service_addr);
 
+    // Only used for unit testing.
+    explicit GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub);
+
     ~GRPCVehicleHardware();
 
     // Get all the property configs.
@@ -80,6 +83,10 @@
     aidlvhal::StatusCode updateSampleRate(int32_t propId, int32_t areaId,
                                           float sampleRate) override;
 
+    aidlvhal::StatusCode subscribe(aidlvhal::SubscribeOptions options) override;
+
+    aidlvhal::StatusCode unsubscribe(int32_t propId, int32_t areaId) override;
+
     bool waitForConnected(std::chrono::milliseconds waitTime);
 
   protected:
@@ -91,7 +98,7 @@
 
     std::string mServiceAddr;
     std::shared_ptr<::grpc::Channel> mGrpcChannel;
-    std::unique_ptr<proto::VehicleServer::Stub> mGrpcStub;
+    std::unique_ptr<proto::VehicleServer::StubInterface> mGrpcStub;
     std::thread mValuePollingThread;
 
     std::unique_ptr<const PropertySetErrorCallback> mOnSetErr;
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
index af3dd59..a6abfa3 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
@@ -164,6 +164,27 @@
     return ::grpc::Status::OK;
 }
 
+::grpc::Status GrpcVehicleProxyServer::Subscribe(::grpc::ServerContext* context,
+                                                 const proto::SubscribeRequest* request,
+                                                 proto::VehicleHalCallStatus* status) {
+    const auto& protoSubscribeOptions = request->options();
+    aidlvhal::SubscribeOptions aidlSubscribeOptions = {};
+    proto_msg_converter::protoToAidl(protoSubscribeOptions, &aidlSubscribeOptions);
+    const auto status_code = mHardware->subscribe(aidlSubscribeOptions);
+    status->set_status_code(static_cast<proto::StatusCode>(status_code));
+    return ::grpc::Status::OK;
+}
+
+::grpc::Status GrpcVehicleProxyServer::Unsubscribe(::grpc::ServerContext* context,
+                                                   const proto::UnsubscribeRequest* request,
+                                                   proto::VehicleHalCallStatus* status) {
+    int32_t propId = request->prop_id();
+    int32_t areaId = request->area_id();
+    const auto status_code = mHardware->unsubscribe(propId, areaId);
+    status->set_status_code(static_cast<proto::StatusCode>(status_code));
+    return ::grpc::Status::OK;
+}
+
 ::grpc::Status GrpcVehicleProxyServer::CheckHealth(::grpc::ServerContext* context,
                                                    const ::google::protobuf::Empty*,
                                                    proto::VehicleHalCallStatus* status) {
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
index 3596354..dd9e2aa 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
@@ -57,6 +57,13 @@
                                     const proto::UpdateSampleRateRequest* request,
                                     proto::VehicleHalCallStatus* status) override;
 
+    ::grpc::Status Subscribe(::grpc::ServerContext* context, const proto::SubscribeRequest* request,
+                             proto::VehicleHalCallStatus* status) override;
+
+    ::grpc::Status Unsubscribe(::grpc::ServerContext* context,
+                               const proto::UnsubscribeRequest* request,
+                               proto::VehicleHalCallStatus* status) override;
+
     ::grpc::Status CheckHealth(::grpc::ServerContext* context, const ::google::protobuf::Empty*,
                                proto::VehicleHalCallStatus* status) override;
 
diff --git a/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto b/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto
index 22b11d8..732957f 100644
--- a/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto
+++ b/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto
@@ -20,7 +20,9 @@
 
 import "android/hardware/automotive/vehicle/DumpOptions.proto";
 import "android/hardware/automotive/vehicle/DumpResult.proto";
+import "android/hardware/automotive/vehicle/SubscribeRequest.proto";
 import "android/hardware/automotive/vehicle/StatusCode.proto";
+import "android/hardware/automotive/vehicle/UnsubscribeRequest.proto";
 import "android/hardware/automotive/vehicle/VehiclePropConfig.proto";
 import "android/hardware/automotive/vehicle/VehiclePropValue.proto";
 import "android/hardware/automotive/vehicle/VehiclePropValueRequest.proto";
@@ -40,4 +42,8 @@
     rpc Dump(DumpOptions) returns (DumpResult) {}
 
     rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream VehiclePropValues) {}
+
+    rpc Subscribe(SubscribeRequest) returns (VehicleHalCallStatus) {}
+
+    rpc Unsubscribe(UnsubscribeRequest) returns (VehicleHalCallStatus) {}
 }
diff --git a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
index f578021..3bd7e0e 100644
--- a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
@@ -15,6 +15,7 @@
 #include "GRPCVehicleHardware.h"
 #include "VehicleServer.grpc.pb.h"
 #include "VehicleServer.pb.h"
+#include "VehicleServer_mock.grpc.pb.h"
 
 #include <gmock/gmock.h>
 #include <grpc++/grpc++.h>
@@ -26,6 +27,17 @@
 
 namespace android::hardware::automotive::vehicle::virtualization {
 
+namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::SetArgPointee;
+
+using proto::MockVehicleServerStub;
+
 const std::string kFakeServerAddr = "0.0.0.0:54321";
 
 class FakeVehicleServer : public proto::VehicleServer::Service {
@@ -91,4 +103,131 @@
     }
 }
 
+class GRPCVehicleHardwareMockServerUnitTest : public ::testing::Test {
+  protected:
+    NiceMock<MockVehicleServerStub>* mGrpcStub;
+    std::unique_ptr<GRPCVehicleHardware> mHardware;
+
+    void SetUp() override {
+        auto stub = std::make_unique<NiceMock<MockVehicleServerStub>>();
+        ;
+        mGrpcStub = stub.get();
+        mHardware = std::make_unique<GRPCVehicleHardware>(std::move(stub));
+    }
+
+    void TearDown() override { mHardware.reset(); }
+};
+
+MATCHER_P(RepeatedInt32Eq, expected_values, "") {
+    return std::vector<int32_t>(arg.begin(), arg.end()) == expected_values;
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, Subscribe) {
+    proto::VehicleHalCallStatus protoStatus;
+    protoStatus.set_status_code(proto::StatusCode::OK);
+    proto::SubscribeRequest actualRequest;
+
+    EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+            .WillOnce(DoAll(SaveArg<1>(&actualRequest), SetArgPointee<2>(protoStatus),
+                            Return(::grpc::Status::OK)));
+
+    aidlvhal::SubscribeOptions options = {.propId = 1,
+                                          .areaIds = {1, 2, 3, 4},
+                                          .sampleRate = 1.234,
+                                          .resolution = 0.01,
+                                          .enableVariableUpdateRate = true};
+    auto status = mHardware->subscribe(options);
+
+    EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+    const auto& protoOptions = actualRequest.options();
+    EXPECT_EQ(protoOptions.prop_id(), 1);
+    EXPECT_THAT(protoOptions.area_ids(), RepeatedInt32Eq(std::vector<int32_t>({1, 2, 3, 4})));
+    EXPECT_FLOAT_EQ(protoOptions.sample_rate(), 1.234);
+    EXPECT_FLOAT_EQ(protoOptions.resolution(), 0.01);
+    EXPECT_EQ(protoOptions.enable_variable_update_rate(), true);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeLegacyServer) {
+    EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+            .WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
+
+    aidlvhal::SubscribeOptions options;
+    auto status = mHardware->subscribe(options);
+
+    EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeGrpcFailure) {
+    EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+            .WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
+
+    aidlvhal::SubscribeOptions options;
+    auto status = mHardware->subscribe(options);
+
+    EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeProtoFailure) {
+    proto::VehicleHalCallStatus protoStatus;
+    protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+
+    EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+            .WillOnce(DoAll(SetArgPointee<2>(protoStatus),  // Set the output status
+                            Return(::grpc::Status::OK)));
+
+    aidlvhal::SubscribeOptions options;
+    auto status = mHardware->subscribe(options);
+
+    EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, Unsubscribe) {
+    proto::VehicleHalCallStatus protoStatus;
+    protoStatus.set_status_code(proto::StatusCode::OK);
+    proto::UnsubscribeRequest actualRequest;
+
+    EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+            .WillOnce(DoAll(SaveArg<1>(&actualRequest), SetArgPointee<2>(protoStatus),
+                            Return(::grpc::Status::OK)));
+
+    int32_t propId = 1;
+    int32_t areaId = 2;
+    auto status = mHardware->unsubscribe(propId, areaId);
+
+    EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+    EXPECT_EQ(actualRequest.prop_id(), propId);
+    EXPECT_EQ(actualRequest.area_id(), areaId);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeLegacyServer) {
+    EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+            .WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
+
+    auto status = mHardware->unsubscribe(1, 2);
+
+    EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeGrpcFailure) {
+    EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+            .WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
+
+    auto status = mHardware->unsubscribe(1, 2);
+
+    EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeProtoFailure) {
+    proto::VehicleHalCallStatus protoStatus;
+    protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+
+    EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+            .WillOnce(DoAll(SetArgPointee<2>(protoStatus),  // Set the output status
+                            Return(::grpc::Status::OK)));
+
+    auto status = mHardware->unsubscribe(1, 2);
+
+    EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+}
+
 }  // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp
index 49e6fc9..ca5c2d5 100644
--- a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp
@@ -30,6 +30,13 @@
 
 namespace android::hardware::automotive::vehicle::virtualization {
 
+namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::SaveArg;
+
 const std::string kFakeServerAddr = "0.0.0.0:54321";
 
 class VehicleHardwareForTest : public IVehicleHardware {
@@ -39,38 +46,30 @@
         mOnProp = std::move(callback);
     }
 
-    void onPropertyEvent(
-            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue> values) {
+    void onPropertyEvent(std::vector<aidlvhal::VehiclePropValue> values) {
         if (mOnProp) {
             (*mOnProp)(std::move(values));
         }
     }
 
     // Functions that we do not care.
-    std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
-    getAllPropertyConfigs() const override {
-        return {};
-    }
+    std::vector<aidlvhal::VehiclePropConfig> getAllPropertyConfigs() const override { return {}; }
 
-    aidl::android::hardware::automotive::vehicle::StatusCode setValues(
+    aidlvhal::StatusCode setValues(
             std::shared_ptr<const SetValuesCallback> callback,
-            const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
-                    requests) override {
-        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+            const std::vector<aidlvhal::SetValueRequest>& requests) override {
+        return aidlvhal::StatusCode::OK;
     }
 
-    aidl::android::hardware::automotive::vehicle::StatusCode getValues(
+    aidlvhal::StatusCode getValues(
             std::shared_ptr<const GetValuesCallback> callback,
-            const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&
-                    requests) const override {
-        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+            const std::vector<aidlvhal::GetValueRequest>& requests) const override {
+        return aidlvhal::StatusCode::OK;
     }
 
     DumpResult dump(const std::vector<std::string>& options) override { return {}; }
 
-    aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() override {
-        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
-    }
+    aidlvhal::StatusCode checkHealth() override { return aidlvhal::StatusCode::OK; }
 
     void registerOnPropertySetErrorEvent(
             std::unique_ptr<const PropertySetErrorCallback> callback) override {}
@@ -79,6 +78,35 @@
     std::unique_ptr<const PropertyChangeCallback> mOnProp;
 };
 
+class MockVehicleHardware : public IVehicleHardware {
+  public:
+    // Mock methods from IVehicleHardware
+    MOCK_METHOD(std::vector<aidlvhal::VehiclePropConfig>, getAllPropertyConfigs, (),
+                (const, override));
+
+    MOCK_METHOD((aidlvhal::StatusCode), setValues,
+                (std::shared_ptr<const SetValuesCallback> callback,
+                 const std::vector<aidlvhal::SetValueRequest>& requests),
+                (override));
+
+    MOCK_METHOD((aidlvhal::StatusCode), getValues,
+                (std::shared_ptr<const GetValuesCallback> callback,
+                 const std::vector<aidlvhal::GetValueRequest>& requests),
+                (const, override));
+
+    MOCK_METHOD(DumpResult, dump, (const std::vector<std::string>& options), (override));
+    MOCK_METHOD(aidlvhal::StatusCode, checkHealth, (), (override));
+    MOCK_METHOD(void, registerOnPropertyChangeEvent,
+                (std::unique_ptr<const PropertyChangeCallback> callback), (override));
+    MOCK_METHOD(void, registerOnPropertySetErrorEvent,
+                (std::unique_ptr<const PropertySetErrorCallback> callback), (override));
+    MOCK_METHOD(std::chrono::nanoseconds, getPropertyOnChangeEventBatchingWindow, (), (override));
+    MOCK_METHOD(aidlvhal::StatusCode, subscribe, (aidlvhal::SubscribeOptions options), (override));
+    MOCK_METHOD(aidlvhal::StatusCode, unsubscribe, (int32_t propId, int32_t areaId), (override));
+    MOCK_METHOD(aidlvhal::StatusCode, updateSampleRate,
+                (int32_t propId, int32_t areaId, float sampleRate), (override));
+};
+
 TEST(GRPCVehicleProxyServerUnitTest, ClientConnectDisconnect) {
     auto testHardware = std::make_unique<VehicleHardwareForTest>();
     // HACK: manipulate the underlying hardware via raw pointer for testing.
@@ -144,4 +172,70 @@
     vehicleServer->Shutdown().Wait();
 }
 
+TEST(GRPCVehicleProxyServerUnitTest, Subscribe) {
+    auto mockHardware = std::make_unique<MockVehicleHardware>();
+    // We make sure this is alive inside the function scope.
+    MockVehicleHardware* mockHardwarePtr = mockHardware.get();
+    GrpcVehicleProxyServer server = GrpcVehicleProxyServer("", std::move(mockHardware));
+    ::grpc::ServerContext context;
+    proto::SubscribeRequest request;
+    proto::VehicleHalCallStatus returnStatus;
+    aidlvhal::SubscribeOptions aidlOptions;
+    request.mutable_options()->set_prop_id(1);
+    request.mutable_options()->add_area_ids(2);
+    request.mutable_options()->set_sample_rate(1.234);
+    request.mutable_options()->set_resolution(0.01);
+    request.mutable_options()->set_enable_variable_update_rate(true);
+
+    EXPECT_CALL(*mockHardwarePtr, subscribe(_))
+            .WillOnce(DoAll(SaveArg<0>(&aidlOptions), Return(aidlvhal::StatusCode::OK)));
+
+    auto grpcStatus = server.Subscribe(&context, &request, &returnStatus);
+
+    EXPECT_TRUE(grpcStatus.ok());
+    EXPECT_EQ(returnStatus.status_code(), proto::StatusCode::OK);
+    EXPECT_EQ(aidlOptions.propId, 1);
+    EXPECT_EQ(aidlOptions.areaIds, std::vector<int32_t>{2});
+    EXPECT_FLOAT_EQ(aidlOptions.sampleRate, 1.234);
+    EXPECT_FLOAT_EQ(aidlOptions.resolution, 0.01);
+    EXPECT_TRUE(aidlOptions.enableVariableUpdateRate);
+}
+
+TEST(GRPCVehicleProxyServerUnitTest, SubscribeNotAvailable) {
+    auto mockHardware = std::make_unique<MockVehicleHardware>();
+    // We make sure this is alive inside the function scope.
+    MockVehicleHardware* mockHardwarePtr = mockHardware.get();
+    GrpcVehicleProxyServer server = GrpcVehicleProxyServer("", std::move(mockHardware));
+    ::grpc::ServerContext context;
+    proto::SubscribeRequest request;
+    proto::VehicleHalCallStatus returnStatus;
+
+    EXPECT_CALL(*mockHardwarePtr, subscribe(_))
+            .WillOnce(Return(aidlvhal::StatusCode::NOT_AVAILABLE));
+
+    auto grpcStatus = server.Subscribe(&context, &request, &returnStatus);
+
+    EXPECT_TRUE(grpcStatus.ok());
+    EXPECT_EQ(returnStatus.status_code(), proto::StatusCode::NOT_AVAILABLE);
+}
+
+TEST(GRPCVehicleProxyServerUnitTest, Unsubscribe) {
+    auto mockHardware = std::make_unique<MockVehicleHardware>();
+    // We make sure this is alive inside the function scope.
+    MockVehicleHardware* mockHardwarePtr = mockHardware.get();
+    GrpcVehicleProxyServer server = GrpcVehicleProxyServer("", std::move(mockHardware));
+    ::grpc::ServerContext context;
+    proto::UnsubscribeRequest request;
+    proto::VehicleHalCallStatus returnStatus;
+    request.set_prop_id(1);
+    request.set_area_id(2);
+
+    EXPECT_CALL(*mockHardwarePtr, unsubscribe(1, 2)).WillOnce(Return(aidlvhal::StatusCode::OK));
+
+    auto grpcStatus = server.Unsubscribe(&context, &request, &returnStatus);
+
+    EXPECT_TRUE(grpcStatus.ok());
+    EXPECT_EQ(returnStatus.status_code(), proto::StatusCode::OK);
+}
+
 }  // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
index 52ef7be..94c09aa 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
@@ -39,25 +39,24 @@
     ],
     defaults: ["VehicleHalDefaults"],
     export_static_lib_headers: ["VehicleHalUtils"],
+    host_supported: true,
 }
 
-cc_test {
+cc_test_host {
     name: "VehicleHalProtoMessageConverterTest",
     srcs: [
         "test/*.cpp",
     ],
     vendor: true,
     defaults: ["VehicleHalDefaults"],
-    shared_libs: [
-        "libprotobuf-cpp-full",
-        "libjsoncpp",
-    ],
     static_libs: [
         "VehicleHalJsonConfigLoaderEnableTestProperties",
         "VehicleHalProtoMessageConverter",
         "VehicleHalProtos",
         "VehicleHalUtils",
         "libgtest",
+        "libprotobuf-cpp-full",
+        "libjsoncpp",
     ],
     data: [
         ":VehicleHalDefaultProperties_JSON",
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h
index 1c26fe8..25c07ef 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h
@@ -18,6 +18,7 @@
 #define android_hardware_automotive_vehicle_aidl_impl_grpc_utils_proto_message_converter_include_ProtoMessageConverter_H_
 
 #include <VehicleHalTypes.h>
+#include <android/hardware/automotive/vehicle/SubscribeOptions.pb.h>
 #include <android/hardware/automotive/vehicle/VehicleAreaConfig.pb.h>
 #include <android/hardware/automotive/vehicle/VehiclePropConfig.pb.h>
 #include <android/hardware/automotive/vehicle/VehiclePropValue.pb.h>
@@ -46,6 +47,12 @@
 void protoToAidl(
         const ::android::hardware::automotive::vehicle::proto::VehiclePropValue& inProtoVal,
         ::aidl::android::hardware::automotive::vehicle::VehiclePropValue* outAidlVal);
+// Convert AIDL SubscribeOptions to Protobuf SubscribeOptions.
+void aidlToProto(const ::aidl::android::hardware::automotive::vehicle::SubscribeOptions& in,
+                 ::android::hardware::automotive::vehicle::proto::SubscribeOptions* out);
+// Convert Protobuf SubscribeOptions to AIDL SubscribeOptions.
+void protoToAidl(const ::android::hardware::automotive::vehicle::proto::SubscribeOptions& in,
+                 ::aidl::android::hardware::automotive::vehicle::SubscribeOptions* out);
 
 }  // namespace proto_msg_converter
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
index 1ea0df4..c40004a 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
@@ -152,6 +152,24 @@
     COPY_PROTOBUF_VEC_TO_VHAL_TYPE(in, float_values, out, value.floatValues);
 }
 
+void aidlToProto(const aidl_vehicle::SubscribeOptions& in, proto::SubscribeOptions* out) {
+    out->set_prop_id(in.propId);
+    for (int areaId : in.areaIds) {
+        out->add_area_ids(areaId);
+    }
+    out->set_sample_rate(in.sampleRate);
+    out->set_resolution(in.resolution);
+    out->set_enable_variable_update_rate(in.enableVariableUpdateRate);
+}
+
+void protoToAidl(const proto::SubscribeOptions& in, aidl_vehicle::SubscribeOptions* out) {
+    out->propId = in.prop_id();
+    COPY_PROTOBUF_VEC_TO_VHAL_TYPE(in, area_ids, out, areaIds);
+    out->sampleRate = in.sample_rate();
+    out->resolution = in.resolution();
+    out->enableVariableUpdateRate = in.enable_variable_update_rate();
+}
+
 #undef COPY_PROTOBUF_VEC_TO_VHAL_TYPE
 #undef CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE
 
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
index 308be46..2efda5b 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
@@ -22,6 +22,7 @@
 
 #include <android-base/file.h>
 #include <android-base/format.h>
+#include <android/hardware/automotive/vehicle/SubscribeOptions.pb.h>
 #include <android/hardware/automotive/vehicle/VehiclePropConfig.pb.h>
 #include <android/hardware/automotive/vehicle/VehiclePropValue.pb.h>
 #include <gtest/gtest.h>
@@ -114,6 +115,21 @@
                              return ::fmt::format("property_{:d}", info.param.prop);
                          });
 
+TEST_F(PropValueConversionTest, testConvertSubscribeOption) {
+    proto::SubscribeOptions protoOptions;
+    aidl_vehicle::SubscribeOptions aidlOptions = {.propId = 1,
+                                                  .areaIds = {1, 2},
+                                                  .sampleRate = 1.234,
+                                                  .resolution = 0.01,
+                                                  .enableVariableUpdateRate = true};
+    aidl_vehicle::SubscribeOptions outputOptions;
+
+    aidlToProto(aidlOptions, &protoOptions);
+    protoToAidl(protoOptions, &outputOptions);
+
+    EXPECT_EQ(aidlOptions, outputOptions);
+}
+
 }  // namespace proto_msg_converter
 }  // namespace vehicle
 }  // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/hardware/Android.bp b/automotive/vehicle/aidl/impl/hardware/Android.bp
index edb0f29..52fd5e4 100644
--- a/automotive/vehicle/aidl/impl/hardware/Android.bp
+++ b/automotive/vehicle/aidl/impl/hardware/Android.bp
@@ -30,4 +30,5 @@
     export_header_lib_headers: [
         "VehicleHalUtilHeaders",
     ],
+    host_supported: true,
 }
diff --git a/automotive/vehicle/aidl/impl/proto/Android.bp b/automotive/vehicle/aidl/impl/proto/Android.bp
index 56fad7e..b2edf75 100644
--- a/automotive/vehicle/aidl/impl/proto/Android.bp
+++ b/automotive/vehicle/aidl/impl/proto/Android.bp
@@ -50,6 +50,9 @@
         "android/hardware/automotive/vehicle/VehiclePropertyStatus.pb.h",
         "android/hardware/automotive/vehicle/VehiclePropValue.pb.h",
         "android/hardware/automotive/vehicle/VehiclePropValueRequest.pb.h",
+        "android/hardware/automotive/vehicle/SubscribeOptions.pb.h",
+        "android/hardware/automotive/vehicle/SubscribeRequest.pb.h",
+        "android/hardware/automotive/vehicle/UnsubscribeRequest.pb.h",
     ],
 }
 
@@ -74,6 +77,9 @@
         "android/hardware/automotive/vehicle/VehiclePropertyStatus.pb.cc",
         "android/hardware/automotive/vehicle/VehiclePropValue.pb.cc",
         "android/hardware/automotive/vehicle/VehiclePropValueRequest.pb.cc",
+        "android/hardware/automotive/vehicle/SubscribeOptions.pb.cc",
+        "android/hardware/automotive/vehicle/SubscribeRequest.pb.cc",
+        "android/hardware/automotive/vehicle/UnsubscribeRequest.pb.cc",
     ],
 }
 
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeOptions.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeOptions.proto
new file mode 100644
index 0000000..3fc6581
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeOptions.proto
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.vehicle.proto;
+
+message SubscribeOptions {
+    int32 prop_id = 1;
+    repeated int32 area_ids = 2;
+    float sample_rate = 3;
+    float resolution = 4;
+    bool enable_variable_update_rate = 5;
+}
\ No newline at end of file
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeRequest.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeRequest.proto
new file mode 100644
index 0000000..4ce6335
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeRequest.proto
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.vehicle.proto;
+
+import "android/hardware/automotive/vehicle/SubscribeOptions.proto";
+
+message SubscribeRequest {
+    SubscribeOptions options = 1;
+}
\ No newline at end of file
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/UnsubscribeRequest.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/UnsubscribeRequest.proto
new file mode 100644
index 0000000..314fbf0
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/UnsubscribeRequest.proto
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.vehicle.proto;
+
+message UnsubscribeRequest {
+    int32 prop_id = 1;
+    int32 area_id = 2;
+}
\ No newline at end of file
diff --git a/automotive/vehicle/aidl/impl/utils/common/Android.bp b/automotive/vehicle/aidl/impl/utils/common/Android.bp
index e5d9346..5cd07b4 100644
--- a/automotive/vehicle/aidl/impl/utils/common/Android.bp
+++ b/automotive/vehicle/aidl/impl/utils/common/Android.bp
@@ -25,10 +25,12 @@
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
     defaults: ["VehicleHalDefaults"],
+    host_supported: true,
 }
 
 cc_library_headers {
     name: "VehicleHalUtilHeaders",
     export_include_dirs: ["include"],
     vendor: true,
+    host_supported: true,
 }
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index aca725d..f48bb2a 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -328,11 +328,15 @@
     }
 };
 
+// This is for debug purpose only.
 inline std::string propIdToString(int32_t propId) {
     return toString(
             static_cast<aidl::android::hardware::automotive::vehicle::VehicleProperty>(propId));
 }
 
+// This is for debug purpose only.
+android::base::Result<int32_t> stringToPropId(const std::string& propName);
+
 template <typename T>
 void roundToNearestResolution(std::vector<T>& arrayToSanitize, float resolution) {
     if (resolution == 0) {
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index 97efdf6..a7caeb1 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -172,9 +172,7 @@
     }
 
     if (onValuesChangeCallback == nullptr && onValueChangeCallback == nullptr) {
-        ALOGW("No callback registered, ignoring property update for propId: %" PRId32
-              ", area ID: %" PRId32,
-              propId, areaId);
+        // No callback registered.
         return {};
     }
 
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
index f85728d..4d06e4e 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
@@ -16,14 +16,18 @@
 
 #include "VehicleUtils.h"
 
+#include <unordered_map>
+
 namespace android {
 namespace hardware {
 namespace automotive {
 namespace vehicle {
 
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::toString;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
@@ -31,6 +35,39 @@
 using ::android::base::Result;
 using ::ndk::ScopedAStatus;
 
+namespace {
+
+class PropertyIdByNameSingleton {
+  public:
+    static PropertyIdByNameSingleton& getInstance() {
+        static PropertyIdByNameSingleton instance;
+        return instance;
+    }
+
+    Result<int32_t> getPropertyId(const std::string& name) {
+        auto it = mPropertyIdByName.find(name);
+        if (it == mPropertyIdByName.end()) {
+            return Error();
+        }
+        return it->second;
+    }
+
+    PropertyIdByNameSingleton(PropertyIdByNameSingleton const&) = delete;
+    void operator=(PropertyIdByNameSingleton const&) = delete;
+
+  private:
+    std::unordered_map<std::string, int32_t> mPropertyIdByName;
+
+    PropertyIdByNameSingleton() {
+        constexpr auto values = ndk::internal::enum_values<VehicleProperty>;
+        for (unsigned int i = 0; i < values.size(); i++) {
+            mPropertyIdByName.emplace(toString(values[i]), toInt(values[i]));
+        }
+    }
+};
+
+}  // namespace
+
 Result<void> checkPropValue(const VehiclePropValue& value, const VehiclePropConfig* config) {
     int32_t property = value.prop;
     VehiclePropertyType type = getPropType(property);
@@ -213,6 +250,10 @@
     return aidl::android::hardware::automotive::vehicle::toString(mCode);
 }
 
+Result<int32_t> stringToPropId(const std::string& propName) {
+    return PropertyIdByNameSingleton::getInstance().getPropertyId(propName);
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
index 9abb2a2..1048877 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
@@ -770,6 +770,23 @@
     ASSERT_EQ(result.error().message(), "error message: INVALID_ARG");
 }
 
+TEST(VehicleUtilsTest, testPropIdToString) {
+    ASSERT_EQ(propIdToString(toInt(VehicleProperty::PERF_VEHICLE_SPEED)), "PERF_VEHICLE_SPEED");
+}
+
+TEST(VehicleUtilsTest, testStringToPropId) {
+    auto result = stringToPropId("PERF_VEHICLE_SPEED");
+
+    ASSERT_TRUE(result.ok());
+    ASSERT_EQ(result.value(), toInt(VehicleProperty::PERF_VEHICLE_SPEED));
+}
+
+TEST(VehicleUtilsTest, testStringToPropId_InvalidName) {
+    auto result = stringToPropId("PERF_VEHICLE_SPEED12345");
+
+    ASSERT_FALSE(result.ok());
+}
+
 class InvalidPropValueTest : public testing::TestWithParam<InvalidPropValueTestCase> {};
 
 INSTANTIATE_TEST_SUITE_P(InvalidPropValueTests, InvalidPropValueTest,
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index 250b30c..fa2a310 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -42,10 +42,11 @@
 namespace automotive {
 namespace vehicle {
 
-class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehicle::BnVehicle {
+namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
+
+class DefaultVehicleHal final : public aidlvhal::BnVehicle {
   public:
-    using CallbackType =
-            std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
+    using CallbackType = std::shared_ptr<aidlvhal::IVehicleCallback>;
 
     explicit DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware);
 
@@ -54,26 +55,16 @@
 
     ~DefaultVehicleHal();
 
-    ndk::ScopedAStatus getAllPropConfigs(
-            aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
-            override;
-    ndk::ScopedAStatus getValues(
-            const CallbackType& callback,
-            const aidl::android::hardware::automotive::vehicle::GetValueRequests& requests)
-            override;
-    ndk::ScopedAStatus setValues(
-            const CallbackType& callback,
-            const aidl::android::hardware::automotive::vehicle::SetValueRequests& requests)
-            override;
-    ndk::ScopedAStatus getPropConfigs(
-            const std::vector<int32_t>& props,
-            aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
-            override;
-    ndk::ScopedAStatus subscribe(
-            const CallbackType& callback,
-            const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
-                    options,
-            int32_t maxSharedMemoryFileCount) override;
+    ndk::ScopedAStatus getAllPropConfigs(aidlvhal::VehiclePropConfigs* returnConfigs) override;
+    ndk::ScopedAStatus getValues(const CallbackType& callback,
+                                 const aidlvhal::GetValueRequests& requests) override;
+    ndk::ScopedAStatus setValues(const CallbackType& callback,
+                                 const aidlvhal::SetValueRequests& requests) override;
+    ndk::ScopedAStatus getPropConfigs(const std::vector<int32_t>& props,
+                                      aidlvhal::VehiclePropConfigs* returnConfigs) override;
+    ndk::ScopedAStatus subscribe(const CallbackType& callback,
+                                 const std::vector<aidlvhal::SubscribeOptions>& options,
+                                 int32_t maxSharedMemoryFileCount) override;
     ndk::ScopedAStatus unsubscribe(const CallbackType& callback,
                                    const std::vector<int32_t>& propIds) override;
     ndk::ScopedAStatus returnSharedMemory(const CallbackType& callback,
@@ -86,12 +77,8 @@
     // friend class for unit testing.
     friend class DefaultVehicleHalTest;
 
-    using GetValuesClient =
-            GetSetValuesClient<aidl::android::hardware::automotive::vehicle::GetValueResult,
-                               aidl::android::hardware::automotive::vehicle::GetValueResults>;
-    using SetValuesClient =
-            GetSetValuesClient<aidl::android::hardware::automotive::vehicle::SetValueResult,
-                               aidl::android::hardware::automotive::vehicle::SetValueResults>;
+    using GetValuesClient = GetSetValuesClient<aidlvhal::GetValueResult, aidlvhal::GetValueResults>;
+    using SetValuesClient = GetSetValuesClient<aidlvhal::SetValueResult, aidlvhal::SetValueResults>;
 
     // A wrapper for binder lifecycle operations to enable stubbing for test.
     class BinderLifecycleInterface {
@@ -137,28 +124,27 @@
     bool mShouldRefreshPropertyConfigs;
     std::unique_ptr<IVehicleHardware> mVehicleHardware;
 
-    // mConfigsByPropId and mConfigFile are only modified during initialization, so no need to
-    // lock guard them.
-    std::unordered_map<int32_t, aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
-            mConfigsByPropId;
-    // Only modified in constructor, so thread-safe.
-    std::unique_ptr<ndk::ScopedFileDescriptor> mConfigFile;
     // PendingRequestPool is thread-safe.
     std::shared_ptr<PendingRequestPool> mPendingRequestPool;
     // SubscriptionManager is thread-safe.
     std::shared_ptr<SubscriptionManager> mSubscriptionManager;
     // ConcurrentQueue is thread-safe.
-    std::shared_ptr<ConcurrentQueue<aidl::android::hardware::automotive::vehicle::VehiclePropValue>>
-            mBatchedEventQueue;
+    std::shared_ptr<ConcurrentQueue<aidlvhal::VehiclePropValue>> mBatchedEventQueue;
     // BatchingConsumer is thread-safe.
-    std::shared_ptr<
-            BatchingConsumer<aidl::android::hardware::automotive::vehicle::VehiclePropValue>>
+    std::shared_ptr<BatchingConsumer<aidlvhal::VehiclePropValue>>
             mPropertyChangeEventsBatchingConsumer;
     // Only set once during initialization.
     std::chrono::nanoseconds mEventBatchingWindow;
     // Only used for testing.
     int32_t mTestInterfaceVersion = 0;
 
+    // mConfigsByPropId and mConfigFile is lazy initialized.
+    mutable std::mutex mConfigInitLock;
+    mutable bool mConfigInit GUARDED_BY(mConfigInitLock) = false;
+    mutable std::unordered_map<int32_t, aidlvhal::VehiclePropConfig> mConfigsByPropId
+            GUARDED_BY(mConfigInitLock);
+    mutable std::unique_ptr<ndk::ScopedFileDescriptor> mConfigFile GUARDED_BY(mConfigInitLock);
+
     std::mutex mLock;
     std::unordered_map<const AIBinder*, std::unique_ptr<OnBinderDiedContext>> mOnBinderDiedContexts
             GUARDED_BY(mLock);
@@ -182,32 +168,23 @@
     // A thread to handle onBinderDied or onBinderUnlinked event.
     std::thread mOnBinderDiedUnlinkedHandlerThread;
 
-    android::base::Result<void> checkProperty(
-            const aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
+    android::base::Result<void> checkProperty(const aidlvhal::VehiclePropValue& propValue);
 
     android::base::Result<std::vector<int64_t>> checkDuplicateRequests(
-            const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&
-                    requests);
+            const std::vector<aidlvhal::GetValueRequest>& requests);
 
     android::base::Result<std::vector<int64_t>> checkDuplicateRequests(
-            const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
-                    requests);
-    VhalResult<void> checkSubscribeOptions(
-            const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
-                    options);
+            const std::vector<aidlvhal::SetValueRequest>& requests);
+    VhalResult<void> checkSubscribeOptions(const std::vector<aidlvhal::SubscribeOptions>& options);
 
-    VhalResult<void> checkPermissionHelper(
-            const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
-            aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess accessToTest) const;
+    VhalResult<void> checkPermissionHelper(const aidlvhal::VehiclePropValue& value,
+                                           aidlvhal::VehiclePropertyAccess accessToTest) const;
 
-    VhalResult<void> checkReadPermission(
-            const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+    VhalResult<void> checkReadPermission(const aidlvhal::VehiclePropValue& value) const;
 
-    VhalResult<void> checkWritePermission(
-            const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+    VhalResult<void> checkWritePermission(const aidlvhal::VehiclePropValue& value) const;
 
-    android::base::Result<const aidl::android::hardware::automotive::vehicle::VehiclePropConfig*>
-    getConfig(int32_t propId) const;
+    android::base::Result<const aidlvhal::VehiclePropConfig*> getConfig(int32_t propId) const;
 
     void onBinderDiedWithContext(const AIBinder* clientId);
 
@@ -219,7 +196,7 @@
 
     bool checkDumpPermission();
 
-    bool getAllPropConfigsFromHardware();
+    bool getAllPropConfigsFromHardwareLocked() const REQUIRES(mConfigInitLock);
 
     // The looping handler function to process all onBinderDied or onBinderUnlinked events in
     // mBinderEvents.
@@ -228,19 +205,19 @@
     size_t countSubscribeClients();
 
     // Handles the property change events in batch.
-    void handleBatchedPropertyEvents(
-            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
-                    batchedEvents);
+    void handleBatchedPropertyEvents(std::vector<aidlvhal::VehiclePropValue>&& batchedEvents);
 
-    int32_t getVhalInterfaceVersion();
+    int32_t getVhalInterfaceVersion() const;
+
+    // Gets mConfigsByPropId, lazy init it if necessary.
+    const std::unordered_map<int32_t, aidlvhal::VehiclePropConfig>& getConfigsByPropId() const;
+    // Gets mConfigFile, lazy init it if necessary.
+    const ndk::ScopedFileDescriptor* getConfigFile() const;
 
     // Puts the property change events into a queue so that they can handled in batch.
     static void batchPropertyChangeEvent(
-            const std::weak_ptr<ConcurrentQueue<
-                    aidl::android::hardware::automotive::vehicle::VehiclePropValue>>&
-                    batchedEventQueue,
-            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
-                    updatedValues);
+            const std::weak_ptr<ConcurrentQueue<aidlvhal::VehiclePropValue>>& batchedEventQueue,
+            std::vector<aidlvhal::VehiclePropValue>&& updatedValues);
 
     // Gets or creates a {@code T} object for the client to or from {@code clients}.
     template <class T>
@@ -248,10 +225,8 @@
             std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
             const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
 
-    static void onPropertyChangeEvent(
-            const std::weak_ptr<SubscriptionManager>& subscriptionManager,
-            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
-                    updatedValues);
+    static void onPropertyChangeEvent(const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+                                      std::vector<aidlvhal::VehiclePropValue>&& updatedValues);
 
     static void onPropertySetErrorEvent(
             const std::weak_ptr<SubscriptionManager>& subscriptionManager,
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index a29861f..9dc039d 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -24,6 +24,7 @@
 #include <VehicleUtils.h>
 #include <VersionForVehicleProperty.h>
 
+#include <android-base/logging.h>
 #include <android-base/result.h>
 #include <android-base/stringprintf.h>
 #include <android/binder_ibinder.h>
@@ -71,6 +72,7 @@
 
 using ::ndk::ScopedAIBinder_DeathRecipient;
 using ::ndk::ScopedAStatus;
+using ::ndk::ScopedFileDescriptor;
 
 std::string toString(const std::unordered_set<int64_t>& values) {
     std::string str = "";
@@ -103,10 +105,7 @@
     : mVehicleHardware(std::move(vehicleHardware)),
       mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)),
       mTestInterfaceVersion(testInterfaceVersion) {
-    if (!getAllPropConfigsFromHardware()) {
-        return;
-    }
-
+    ALOGD("DefaultVehicleHal init");
     IVehicleHardware* vehicleHardwarePtr = mVehicleHardware.get();
     mSubscriptionManager = std::make_shared<SubscriptionManager>(vehicleHardwarePtr);
     mEventBatchingWindow = mVehicleHardware->getPropertyOnChangeEventBatchingWindow();
@@ -319,16 +318,18 @@
     mPendingRequestPool = std::make_unique<PendingRequestPool>(timeoutInNano);
 }
 
-int32_t DefaultVehicleHal::getVhalInterfaceVersion() {
+int32_t DefaultVehicleHal::getVhalInterfaceVersion() const {
     if (mTestInterfaceVersion != 0) {
         return mTestInterfaceVersion;
     }
     int32_t myVersion = 0;
-    getInterfaceVersion(&myVersion);
+    // getInterfaceVersion is in-reality a const method.
+    const_cast<DefaultVehicleHal*>(this)->getInterfaceVersion(&myVersion);
     return myVersion;
 }
 
-bool DefaultVehicleHal::getAllPropConfigsFromHardware() {
+bool DefaultVehicleHal::getAllPropConfigsFromHardwareLocked() const {
+    ALOGD("Get all property configs from hardware");
     auto configs = mVehicleHardware->getAllPropertyConfigs();
     std::vector<VehiclePropConfig> filteredConfigs;
     int32_t myVersion = getVhalInterfaceVersion();
@@ -373,22 +374,46 @@
     return true;
 }
 
+const ScopedFileDescriptor* DefaultVehicleHal::getConfigFile() const {
+    std::scoped_lock lockGuard(mConfigInitLock);
+    if (!mConfigInit) {
+        CHECK(getAllPropConfigsFromHardwareLocked())
+                << "Failed to get property configs from hardware";
+        mConfigInit = true;
+    }
+    return mConfigFile.get();
+}
+
+const std::unordered_map<int32_t, VehiclePropConfig>& DefaultVehicleHal::getConfigsByPropId()
+        const {
+    std::scoped_lock lockGuard(mConfigInitLock);
+    if (!mConfigInit) {
+        CHECK(getAllPropConfigsFromHardwareLocked())
+                << "Failed to get property configs from hardware";
+        mConfigInit = true;
+    }
+    return mConfigsByPropId;
+}
+
 ScopedAStatus DefaultVehicleHal::getAllPropConfigs(VehiclePropConfigs* output) {
-    if (mConfigFile != nullptr) {
+    const ScopedFileDescriptor* configFile = getConfigFile();
+    const auto& configsByPropId = getConfigsByPropId();
+    if (configFile != nullptr) {
         output->payloads.clear();
-        output->sharedMemoryFd.set(dup(mConfigFile->get()));
+        output->sharedMemoryFd.set(dup(configFile->get()));
         return ScopedAStatus::ok();
     }
-    output->payloads.reserve(mConfigsByPropId.size());
-    for (const auto& [_, config] : mConfigsByPropId) {
+    output->payloads.reserve(configsByPropId.size());
+    for (const auto& [_, config] : configsByPropId) {
         output->payloads.push_back(config);
     }
     return ScopedAStatus::ok();
 }
 
 Result<const VehiclePropConfig*> DefaultVehicleHal::getConfig(int32_t propId) const {
-    auto it = mConfigsByPropId.find(propId);
-    if (it == mConfigsByPropId.end()) {
+    const auto& configsByPropId = getConfigsByPropId();
+    auto it = configsByPropId.find(propId);
+    if (it == configsByPropId.end()) {
         return Error() << "no config for property, ID: " << propId;
     }
     return &(it->second);
@@ -634,9 +659,11 @@
 ScopedAStatus DefaultVehicleHal::getPropConfigs(const std::vector<int32_t>& props,
                                                 VehiclePropConfigs* output) {
     std::vector<VehiclePropConfig> configs;
+    const auto& configsByPropId = getConfigsByPropId();
     for (int32_t prop : props) {
-        if (mConfigsByPropId.find(prop) != mConfigsByPropId.end()) {
-            configs.push_back(mConfigsByPropId[prop]);
+        auto it = configsByPropId.find(prop);
+        if (it != configsByPropId.end()) {
+            configs.push_back(it->second);
         } else {
             return ScopedAStatus::fromServiceSpecificErrorWithMessage(
                     toInt(StatusCode::INVALID_ARG),
@@ -665,13 +692,15 @@
 
 VhalResult<void> DefaultVehicleHal::checkSubscribeOptions(
         const std::vector<SubscribeOptions>& options) {
+    const auto& configsByPropId = getConfigsByPropId();
     for (const auto& option : options) {
         int32_t propId = option.propId;
-        if (mConfigsByPropId.find(propId) == mConfigsByPropId.end()) {
+        auto it = configsByPropId.find(propId);
+        if (it == configsByPropId.end()) {
             return StatusError(StatusCode::INVALID_ARG)
                    << StringPrintf("no config for property, ID: %" PRId32, propId);
         }
-        const VehiclePropConfig& config = mConfigsByPropId[propId];
+        const VehiclePropConfig& config = it->second;
         std::vector<VehicleAreaConfig> areaConfigs;
         if (option.areaIds.empty()) {
             areaConfigs = config.areaConfigs;
@@ -744,10 +773,11 @@
     }
     std::vector<SubscribeOptions> onChangeSubscriptions;
     std::vector<SubscribeOptions> continuousSubscriptions;
+    const auto& configsByPropId = getConfigsByPropId();
     for (const auto& option : options) {
         int32_t propId = option.propId;
         // We have already validate config exists.
-        const VehiclePropConfig& config = mConfigsByPropId[propId];
+        const VehiclePropConfig& config = configsByPropId.at(propId);
 
         SubscribeOptions optionCopy = option;
         // If areaIds is empty, subscribe to all areas.
@@ -871,7 +901,7 @@
         (areaConfig == nullptr || !hasRequiredAccess(areaConfig->access, accessToTest))) {
         return StatusError(StatusCode::ACCESS_DENIED)
                << StringPrintf("Property %" PRId32 " does not have the following access: %" PRId32,
-                               propId, accessToTest);
+                               propId, static_cast<int32_t>(accessToTest));
     }
     return {};
 }
@@ -936,17 +966,19 @@
     }
     DumpResult result = mVehicleHardware->dump(options);
     if (result.refreshPropertyConfigs) {
-        getAllPropConfigsFromHardware();
+        std::scoped_lock lockGuard(mConfigInitLock);
+        getAllPropConfigsFromHardwareLocked();
     }
     dprintf(fd, "%s", (result.buffer + "\n").c_str());
     if (!result.callerShouldDumpState) {
         return STATUS_OK;
     }
     dprintf(fd, "Vehicle HAL State: \n");
+    const auto& configsByPropId = getConfigsByPropId();
     {
         std::scoped_lock<std::mutex> lockGuard(mLock);
         dprintf(fd, "Interface version: %" PRId32 "\n", getVhalInterfaceVersion());
-        dprintf(fd, "Containing %zu property configs\n", mConfigsByPropId.size());
+        dprintf(fd, "Containing %zu property configs\n", configsByPropId.size());
         dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size());
         dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size());
         dprintf(fd, "Currently have %zu subscribe clients\n", countSubscribeClients());
diff --git a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
index f1106ee..14ee707 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
@@ -40,6 +40,7 @@
 using ::android::base::StringPrintf;
 using ::ndk::ScopedAStatus;
 
+constexpr float EPSILON = 0.0000001;
 constexpr float ONE_SECOND_IN_NANOS = 1'000'000'000.;
 
 SubscribeOptions newSubscribeOptions(int32_t propId, int32_t areaId, float sampleRateHz,
@@ -88,7 +89,7 @@
     }
 
     float log = std::log10(resolution);
-    return log == (int)log;
+    return std::abs(log - std::round(log)) < EPSILON;
 }
 
 void ContSubConfigs::refreshCombinedConfig() {
@@ -433,6 +434,9 @@
         }
 
         for (const auto& [client, callback] : mClientsByPropIdAreaId[propIdAreaId]) {
+            // if propId is on-change, propIdAreaId will not exist in mContSubConfigsByPropIdArea,
+            // returning an empty ContSubConfigs value for subConfigs i.e. with resolution = 0 and
+            // enableVur = false.
             auto& subConfigs = mContSubConfigsByPropIdArea[propIdAreaId];
             // Clients must be sent different VehiclePropValues with different levels of granularity
             // as requested by the client using resolution.
diff --git a/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
index f377202..440a9f9 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
@@ -521,6 +521,8 @@
 }
 
 TEST_F(SubscriptionManagerTest, testCheckResolutionValid) {
+    ASSERT_TRUE(SubscriptionManager::checkResolution(0.0));
+    ASSERT_TRUE(SubscriptionManager::checkResolution(0.1));
     ASSERT_TRUE(SubscriptionManager::checkResolution(1.0));
 }
 
diff --git a/automotive/vehicle/aidl_property/Android.bp b/automotive/vehicle/aidl_property/Android.bp
index bce2284..2aaf6b6 100644
--- a/automotive/vehicle/aidl_property/Android.bp
+++ b/automotive/vehicle/aidl_property/Android.bp
@@ -61,6 +61,7 @@
         },
 
     ],
+    host_supported: true,
 }
 
 filegroup {
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
index ab8023d..e54c179 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -1734,8 +1734,13 @@
      * change display brightness from Settings, but that must not be reflected
      * to other displays.
      *
+     * If this is writable, writing this property must cause an on property
+     * change event even if the new display brightness is the same as the
+     * current value.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @version 2
      */
     DISPLAY_BRIGHTNESS = 0x0A03 + 0x10000000 + 0x01000000
@@ -1755,6 +1760,15 @@
      * The display port uniquely identifies a physical connector on the device
      * for display output, ranging from 0 to 255.
      *
+     * Writing this property must cause an on property change event that
+     * contains the same [display port, brightness] tuple even if the new
+     * display brightness is the same as the current value.
+     *
+     * To get the display brightness for a specific display port, the
+     * GetValueRequest must contain a VehiclePropValue, which contains one
+     * int32Value: displayPort. Getting this property without specifying the
+     * the display port is undefined behavior.
+     *
      * int32Values[0] : display port
      * int32Values[1] : brightness
      *
diff --git a/automotive/vehicle/tools/translate_aidl_enums.py b/automotive/vehicle/tools/translate_aidl_enums.py
index d224f6f..a7c1808 100644
--- a/automotive/vehicle/tools/translate_aidl_enums.py
+++ b/automotive/vehicle/tools/translate_aidl_enums.py
@@ -110,7 +110,7 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -228,4 +228,4 @@
         f.write("".join(parser.outputMsgCtsTest))
 
 if __name__ == "__main__":
-    main()
\ No newline at end of file
+    main()
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index f8818fd..f273c7a 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -105,3 +105,25 @@
         latest_android_hardware_bluetooth_audio + "-ndk",
     ],
 }
+
+cc_defaults {
+    name: "latest_android_hardware_bluetooth_audio_ndk_android_shared",
+    target: {
+        android: {
+            shared_libs: [
+                latest_android_hardware_bluetooth_audio + "-ndk",
+            ],
+        },
+    },
+}
+
+cc_defaults {
+    name: "latest_android_hardware_bluetooth_audio_ndk_android_static",
+    target: {
+        android: {
+            static_libs: [
+                latest_android_hardware_bluetooth_audio + "-ndk",
+            ],
+        },
+    },
+}
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
index dc36ac0..2a2cab0 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
@@ -184,12 +184,13 @@
           SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
     std::vector<CodecInfo> db_codec_info =
         BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(session_type);
-    if (!db_codec_info.empty()) {
-      auto& provider_info = _aidl_return->emplace();
-      provider_info.name = kLeAudioOffloadProviderName;
-      provider_info.codecInfos = db_codec_info;
-      return ndk::ScopedAStatus::ok();
-    }
+    // Return provider info supports without checking db_codec_info
+    // This help with various flow implementation for multidirectional support.
+    auto& provider_info = _aidl_return->emplace();
+    provider_info.supportsMultidirectionalCapabilities = true;
+    provider_info.name = kLeAudioOffloadProviderName;
+    provider_info.codecInfos = db_codec_info;
+    return ndk::ScopedAStatus::ok();
   }
 
   if (session_type == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH) {
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index a692d84..5002a1a 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -165,8 +165,8 @@
   return cfg_codec == req_codec;
 }
 
-bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedContext(
-    AudioContext setting_context,
+bool LeAudioOffloadAudioProvider::filterCapabilitiesMatchedContext(
+    AudioContext& setting_context,
     const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
   // If has no metadata, assume match
   if (!capabilities.metadata.has_value()) return true;
@@ -178,7 +178,11 @@
       auto& context = metadata.value()
                           .get<MetadataLtv::Tag::preferredAudioContexts>()
                           .values;
-      if (setting_context.bitmask & context.bitmask) return true;
+      if (setting_context.bitmask & context.bitmask) {
+        // New mask with matched capability
+        setting_context.bitmask &= context.bitmask;
+        return true;
+      }
     }
   }
 
@@ -189,8 +193,12 @@
     CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
     CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies&
         capability_freq) {
-  for (auto [freq, bitmask] : freq_to_support_bitmask_map)
-    if (cfg_freq == freq) return (capability_freq.bitmask & bitmask);
+  auto p = freq_to_support_bitmask_map.find(cfg_freq);
+  if (p != freq_to_support_bitmask_map.end()) {
+    if (capability_freq.bitmask & p->second) {
+      return true;
+    }
+  }
   return false;
 }
 
@@ -198,9 +206,11 @@
     CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration,
     CodecSpecificCapabilitiesLtv::SupportedFrameDurations&
         capability_fduration) {
-  for (auto [fduration, bitmask] : fduration_to_support_fduration_map)
-    if (cfg_fduration == fduration)
-      return (capability_fduration.bitmask & bitmask);
+  auto p = fduration_to_support_fduration_map.find(cfg_fduration);
+  if (p != fduration_to_support_fduration_map.end())
+    if (capability_fduration.bitmask & p->second) {
+      return true;
+    }
   return false;
 }
 
@@ -240,50 +250,67 @@
 
   for (auto& codec_capability : codec_capabilities) {
     auto cfg = cfg_tag_map.find(cap_to_cfg_tag_map[codec_capability.getTag()]);
-    // Cannot find tag for the capability:
-    if (cfg == cfg_tag_map.end()) return false;
+    // If capability has this tag, but our configuration doesn't
+    // Then we will assume it is matched
+    if (cfg == cfg_tag_map.end()) {
+      continue;
+    }
 
-    // Matching logic for sampling frequency
-    if (codec_capability.getTag() ==
-        CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies) {
-      if (!isMatchedSamplingFreq(
-              cfg->second
-                  .get<CodecSpecificConfigurationLtv::Tag::samplingFrequency>(),
-              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
-                                       supportedSamplingFrequencies>()))
-        return false;
-    } else if (codec_capability.getTag() ==
-               CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations) {
-      if (!isMatchedFrameDuration(
-              cfg->second
-                  .get<CodecSpecificConfigurationLtv::Tag::frameDuration>(),
-              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
-                                       supportedFrameDurations>()))
-        return false;
-    } else if (codec_capability.getTag() ==
-               CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts) {
-      if (!isMatchedAudioChannel(
-              cfg->second.get<
-                  CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>(),
-              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
-                                       supportedAudioChannelCounts>()))
-        return false;
-    } else if (codec_capability.getTag() == CodecSpecificCapabilitiesLtv::Tag::
-                                                supportedMaxCodecFramesPerSDU) {
-      if (!isMatchedCodecFramesPerSDU(
-              cfg->second.get<
-                  CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU>(),
-              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
-                                       supportedMaxCodecFramesPerSDU>()))
-        return false;
-    } else if (codec_capability.getTag() == CodecSpecificCapabilitiesLtv::Tag::
-                                                supportedOctetsPerCodecFrame) {
-      if (!isMatchedOctetsPerCodecFrame(
-              cfg->second.get<
-                  CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(),
-              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
-                                       supportedOctetsPerCodecFrame>()))
-        return false;
+    switch (codec_capability.getTag()) {
+      case CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies: {
+        if (!isMatchedSamplingFreq(
+                cfg->second.get<
+                    CodecSpecificConfigurationLtv::Tag::samplingFrequency>(),
+                codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                         supportedSamplingFrequencies>())) {
+          return false;
+        }
+        break;
+      }
+
+      case CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations: {
+        if (!isMatchedFrameDuration(
+                cfg->second
+                    .get<CodecSpecificConfigurationLtv::Tag::frameDuration>(),
+                codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                         supportedFrameDurations>())) {
+          return false;
+        }
+        break;
+      }
+
+      case CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts: {
+        if (!isMatchedAudioChannel(
+                cfg->second.get<CodecSpecificConfigurationLtv::Tag::
+                                    audioChannelAllocation>(),
+                codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                         supportedAudioChannelCounts>())) {
+          return false;
+        }
+        break;
+      }
+
+      case CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU: {
+        if (!isMatchedCodecFramesPerSDU(
+                cfg->second.get<CodecSpecificConfigurationLtv::Tag::
+                                    codecFrameBlocksPerSDU>(),
+                codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                         supportedMaxCodecFramesPerSDU>())) {
+          return false;
+        }
+        break;
+      }
+
+      case CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame: {
+        if (!isMatchedOctetsPerCodecFrame(
+                cfg->second.get<
+                    CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(),
+                codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                         supportedOctetsPerCodecFrame>())) {
+          return false;
+        }
+        break;
+      }
     }
   }
 
@@ -298,11 +325,16 @@
   if (requirement_cfg.codecId.has_value()) {
     if (!setting_cfg.codecId.has_value()) return false;
     if (!isMatchedValidCodec(setting_cfg.codecId.value(),
-                             requirement_cfg.codecId.value()))
+                             requirement_cfg.codecId.value())) {
       return false;
+    }
   }
 
-  if (setting_cfg.targetLatency != requirement_cfg.targetLatency) return false;
+  if (requirement_cfg.targetLatency ==
+          LeAudioAseConfiguration::TargetLatency::UNDEFINED ||
+      setting_cfg.targetLatency != requirement_cfg.targetLatency) {
+    return false;
+  }
   // Ignore PHY requirement
 
   // Check all codec configuration
@@ -314,9 +346,13 @@
   for (auto requirement_cfg : requirement_cfg.codecConfiguration) {
     // Directly compare CodecSpecificConfigurationLtv
     auto cfg = cfg_tag_map.find(requirement_cfg.getTag());
-    if (cfg == cfg_tag_map.end()) return false;
+    if (cfg == cfg_tag_map.end()) {
+      return false;
+    }
 
-    if (cfg->second != requirement_cfg) return false;
+    if (cfg->second != requirement_cfg) {
+      return false;
+    }
   }
   // Ignore vendor configuration and metadata requirement
 
@@ -326,10 +362,13 @@
 bool LeAudioOffloadAudioProvider::isMatchedBISConfiguration(
     LeAudioBisConfiguration bis_cfg,
     const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
-  if (!isMatchedValidCodec(bis_cfg.codecId, capabilities.codecId)) return false;
-  if (!isCapabilitiesMatchedCodecConfiguration(
-          bis_cfg.codecConfiguration, capabilities.codecSpecificCapabilities))
+  if (!isMatchedValidCodec(bis_cfg.codecId, capabilities.codecId)) {
     return false;
+  }
+  if (!isCapabilitiesMatchedCodecConfiguration(
+          bis_cfg.codecConfiguration, capabilities.codecSpecificCapabilities)) {
+    return false;
+  }
   return true;
 }
 
@@ -357,31 +396,35 @@
 }
 
 void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration(
-    std::vector<std::optional<AseDirectionConfiguration>>&
+    std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
         direction_configurations,
-    const std::optional<std::vector<std::optional<AseDirectionRequirement>>>&
-        requirements,
-    std::vector<std::optional<AseDirectionConfiguration>>&
+    const std::vector<std::optional<AseDirectionRequirement>>& requirements,
+    std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
         valid_direction_configurations) {
-  for (auto direction_configuration : direction_configurations) {
-    if (!requirements.has_value()) {
-      // If there's no requirement, all are valid
-      valid_direction_configurations.push_back(direction_configuration);
-      continue;
-    }
-    if (!direction_configuration.has_value()) continue;
-
-    for (auto& requirement : requirements.value()) {
-      if (!requirement.has_value()) continue;
+  if (!valid_direction_configurations.has_value()) {
+    valid_direction_configurations =
+        std::vector<std::optional<AseDirectionConfiguration>>();
+  }
+  // For every requirement, find the matched ase configuration
+  if (!direction_configurations.has_value()) return;
+  for (auto& requirement : requirements) {
+    if (!requirement.has_value()) continue;
+    for (auto direction_configuration : direction_configurations.value()) {
+      if (!direction_configuration.has_value()) continue;
       if (!isMatchedAseConfiguration(
               direction_configuration.value().aseConfiguration,
               requirement.value().aseConfiguration))
         continue;
       // Valid if match any requirement.
-      valid_direction_configurations.push_back(direction_configuration);
+      valid_direction_configurations.value().push_back(direction_configuration);
       break;
     }
   }
+  // Ensure that each requirement will have one direction configurations
+  if (valid_direction_configurations.value().empty() ||
+      (valid_direction_configurations.value().size() != requirements.size())) {
+    valid_direction_configurations = std::nullopt;
+  }
 }
 
 /* Get a new LeAudioAseConfigurationSetting by matching a setting with a
@@ -392,8 +435,18 @@
     IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
     const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
     uint8_t direction) {
+  // Create a new LeAudioAseConfigurationSetting and return
+  // For other direction will contain all settings
+  LeAudioAseConfigurationSetting filtered_setting{
+      .audioContext = setting.audioContext,
+      .sinkAseConfiguration = setting.sinkAseConfiguration,
+      .sourceAseConfiguration = setting.sourceAseConfiguration,
+      .flags = setting.flags,
+      .packing = setting.packing,
+  };
   // Try to match context in metadata.
-  if (!isCapabilitiesMatchedContext(setting.audioContext, capabilities))
+  if (!filterCapabilitiesMatchedContext(filtered_setting.audioContext,
+                                        capabilities))
     return std::nullopt;
 
   // Get a list of all matched AseDirectionConfiguration
@@ -401,28 +454,30 @@
   std::vector<std::optional<AseDirectionConfiguration>>*
       direction_configuration = nullptr;
   if (direction == kLeAudioDirectionSink) {
-    if (!setting.sinkAseConfiguration.has_value()) return std::nullopt;
-    direction_configuration = &setting.sinkAseConfiguration.value();
+    if (!filtered_setting.sinkAseConfiguration.has_value()) return std::nullopt;
+    direction_configuration = &filtered_setting.sinkAseConfiguration.value();
   } else {
-    if (!setting.sourceAseConfiguration.has_value()) return std::nullopt;
-    direction_configuration = &setting.sourceAseConfiguration.value();
+    if (!filtered_setting.sourceAseConfiguration.has_value())
+      return std::nullopt;
+    direction_configuration = &filtered_setting.sourceAseConfiguration.value();
   }
   std::vector<std::optional<AseDirectionConfiguration>>
       valid_direction_configuration;
   filterCapabilitiesAseDirectionConfiguration(
       *direction_configuration, capabilities, valid_direction_configuration);
-  if (valid_direction_configuration.empty()) return std::nullopt;
+
+  // No valid configuration for this direction
+  if (valid_direction_configuration.empty()) {
+    return std::nullopt;
+  }
 
   // Create a new LeAudioAseConfigurationSetting and return
-  LeAudioAseConfigurationSetting filtered_setting;
-  filtered_setting.audioContext = setting.audioContext;
-  filtered_setting.packing = setting.packing;
+  // For other direction will contain all settings
   if (direction == kLeAudioDirectionSink) {
     filtered_setting.sinkAseConfiguration = valid_direction_configuration;
   } else {
     filtered_setting.sourceAseConfiguration = valid_direction_configuration;
   }
-  filtered_setting.flags = setting.flags;
 
   return filtered_setting;
 }
@@ -436,41 +491,49 @@
     const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
         requirement) {
   // Try to match context in metadata.
-  if (setting.audioContext != requirement.audioContext) return std::nullopt;
+  if ((setting.audioContext.bitmask & requirement.audioContext.bitmask) !=
+      requirement.audioContext.bitmask)
+    return std::nullopt;
+
+  // Further filter setting's context
+  setting.audioContext.bitmask &= requirement.audioContext.bitmask;
 
   // Check requirement for the correct direction
   const std::optional<std::vector<std::optional<AseDirectionRequirement>>>*
       direction_requirement;
   std::vector<std::optional<AseDirectionConfiguration>>*
       direction_configuration;
-  if (setting.sinkAseConfiguration.has_value()) {
-    direction_configuration = &setting.sinkAseConfiguration.value();
-    direction_requirement = &requirement.sinkAseRequirement;
-  } else {
-    direction_configuration = &setting.sourceAseConfiguration.value();
-    direction_requirement = &requirement.sourceAseRequirement;
+
+  // Create a new LeAudioAseConfigurationSetting to return
+  LeAudioAseConfigurationSetting filtered_setting{
+      .audioContext = setting.audioContext,
+      .packing = setting.packing,
+      .flags = setting.flags,
+  };
+
+  if (requirement.sinkAseRequirement.has_value()) {
+    filterRequirementAseDirectionConfiguration(
+        setting.sinkAseConfiguration, requirement.sinkAseRequirement.value(),
+        filtered_setting.sinkAseConfiguration);
+    if (!filtered_setting.sinkAseConfiguration.has_value()) return std::nullopt;
   }
 
-  std::vector<std::optional<AseDirectionConfiguration>>
-      valid_direction_configuration;
-  filterRequirementAseDirectionConfiguration(*direction_configuration,
-                                             *direction_requirement,
-                                             valid_direction_configuration);
-  if (valid_direction_configuration.empty()) return std::nullopt;
-
-  // Create a new LeAudioAseConfigurationSetting and return
-  LeAudioAseConfigurationSetting filtered_setting;
-  filtered_setting.audioContext = setting.audioContext;
-  filtered_setting.packing = setting.packing;
-  if (setting.sinkAseConfiguration.has_value())
-    filtered_setting.sinkAseConfiguration = valid_direction_configuration;
-  else
-    filtered_setting.sourceAseConfiguration = valid_direction_configuration;
-  filtered_setting.flags = setting.flags;
+  if (requirement.sourceAseRequirement.has_value()) {
+    filterRequirementAseDirectionConfiguration(
+        setting.sourceAseConfiguration,
+        requirement.sourceAseRequirement.value(),
+        filtered_setting.sourceAseConfiguration);
+    if (!filtered_setting.sourceAseConfiguration.has_value())
+      return std::nullopt;
+  }
 
   return filtered_setting;
 }
 
+// For each requirement, a valid ASE configuration will satify:
+// - matched with any sink capability (if presented)
+// - OR matched with any source capability (if presented)
+// - and the setting need to pass the requirement
 ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
     const std::optional<std::vector<
         std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
@@ -487,46 +550,81 @@
       ase_configuration_settings =
           BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
 
-  // Currently won't handle case where both sink and source capabilities
-  // are passed in. Only handle one of them.
-  const std::optional<std::vector<
-      std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>*
-      in_remoteAudioCapabilities;
-  uint8_t direction = 0;
-  if (in_remoteSinkAudioCapabilities.has_value()) {
-    direction = kLeAudioDirectionSink;
-    in_remoteAudioCapabilities = &in_remoteSinkAudioCapabilities;
-  } else {
-    direction = kLeAudioDirectionSource;
-    in_remoteAudioCapabilities = &in_remoteSourceAudioCapabilities;
+  if (!in_remoteSinkAudioCapabilities.has_value() &&
+      !in_remoteSourceAudioCapabilities.has_value()) {
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
   }
 
+  // Each setting consist of source and sink AseDirectionConfiguration vector
+  // Filter every sink capability
   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
-      capability_matched_ase_configuration_settings;
-  // Matching with remote capabilities
-  for (auto& setting : ase_configuration_settings) {
-    for (auto& capability : in_remoteAudioCapabilities->value()) {
-      if (!capability.has_value()) continue;
-      auto filtered_ase_configuration_setting =
-          getCapabilitiesMatchedAseConfigurationSettings(
-              setting, capability.value(), direction);
-      if (filtered_ase_configuration_setting.has_value()) {
-        capability_matched_ase_configuration_settings.push_back(
-            filtered_ase_configuration_setting.value());
+      matched_ase_configuration_settings;
+
+  if (in_remoteSinkAudioCapabilities.has_value()) {
+    // Matching each setting with any remote capabilities
+    for (auto& setting : ase_configuration_settings) {
+      for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
+        if (!capability.has_value()) continue;
+        auto filtered_ase_configuration_setting =
+            getCapabilitiesMatchedAseConfigurationSettings(
+                setting, capability.value(), kLeAudioDirectionSink);
+        if (filtered_ase_configuration_setting.has_value()) {
+          matched_ase_configuration_settings.push_back(
+              filtered_ase_configuration_setting.value());
+        }
       }
     }
   }
 
-  // Matching with requirements
+  // Combine filter every source capability
+  if (in_remoteSourceAudioCapabilities.has_value()) {
+    // Matching each setting with any remote capabilities
+    for (auto& setting : ase_configuration_settings) {
+      for (auto& capability : in_remoteSourceAudioCapabilities.value()) {
+        if (!capability.has_value()) continue;
+        auto filtered_ase_configuration_setting =
+            getCapabilitiesMatchedAseConfigurationSettings(
+                setting, capability.value(), kLeAudioDirectionSource);
+        if (filtered_ase_configuration_setting.has_value()) {
+          // Put into the same list
+          // possibly duplicated, filtered by requirement later
+          matched_ase_configuration_settings.push_back(
+              filtered_ase_configuration_setting.value());
+        }
+      }
+    }
+  }
+
+  if (matched_ase_configuration_settings.empty()) {
+    LOG(WARNING) << __func__ << ": No setting matched the capability";
+    return ndk::ScopedAStatus::ok();
+  }
+  // Each requirement will match with a valid setting
   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
-  for (auto& setting : capability_matched_ase_configuration_settings) {
-    for (auto& requirement : in_requirements) {
+  for (auto& requirement : in_requirements) {
+    LOG(INFO) << __func__ << ": Trying to match for the requirement "
+              << requirement.toString();
+    bool is_matched = false;
+
+    for (auto& setting : matched_ase_configuration_settings) {
       auto filtered_ase_configuration_setting =
           getRequirementMatchedAseConfigurationSettings(setting, requirement);
       if (filtered_ase_configuration_setting.has_value()) {
         result.push_back(filtered_ase_configuration_setting.value());
+        LOG(INFO) << __func__ << ": Result = "
+                  << filtered_ase_configuration_setting.value().toString();
+        // Found a matched setting, ignore other settings
+        is_matched = true;
+        break;
       }
     }
+    if (!is_matched) {
+      // If cannot satisfy this requirement, return an empty result
+      LOG(WARNING) << __func__ << ": Cannot match the requirement "
+                   << requirement.toString();
+      result.clear();
+      break;
+    }
   }
 
   *_aidl_return = result;
@@ -537,41 +635,45 @@
     LeAudioAseQosConfiguration setting_qos,
     AseQosDirectionRequirement requirement_qos) {
   if (setting_qos.retransmissionNum !=
-      requirement_qos.preferredRetransmissionNum)
+      requirement_qos.preferredRetransmissionNum) {
     return false;
-  if (setting_qos.maxTransportLatencyMs > requirement_qos.maxTransportLatencyMs)
+  }
+  if (setting_qos.maxTransportLatencyMs >
+      requirement_qos.maxTransportLatencyMs) {
     return false;
+  }
   // Ignore other parameters, as they are not populated in the setting_qos
   return true;
 }
 
-ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseQosConfiguration(
-    const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
-        in_qosRequirement,
-    IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return) {
-  IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
-  // Get all configuration settings
-  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
-      ase_configuration_settings =
-          BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
+bool isValidQosRequirement(AseQosDirectionRequirement qosRequirement) {
+  return ((qosRequirement.maxTransportLatencyMs > 0) &&
+          (qosRequirement.presentationDelayMaxUs > 0) &&
+          (qosRequirement.presentationDelayMaxUs >=
+           qosRequirement.presentationDelayMinUs));
+}
 
-  // Direction QoS matching
-  // Only handle one direction input case
-  uint8_t direction = 0;
+std::optional<LeAudioAseQosConfiguration>
+LeAudioOffloadAudioProvider::getDirectionQosConfiguration(
+    uint8_t direction,
+    const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
+        qosRequirement,
+    std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings) {
   std::optional<AseQosDirectionRequirement> direction_qos_requirement =
       std::nullopt;
-  if (in_qosRequirement.sinkAseQosRequirement.has_value()) {
-    direction_qos_requirement = in_qosRequirement.sinkAseQosRequirement.value();
-    direction = kLeAudioDirectionSink;
-  } else if (in_qosRequirement.sourceAseQosRequirement.has_value()) {
-    direction_qos_requirement =
-        in_qosRequirement.sourceAseQosRequirement.value();
-    direction = kLeAudioDirectionSource;
+
+  // Get the correct direction
+  if (direction == kLeAudioDirectionSink) {
+    direction_qos_requirement = qosRequirement.sinkAseQosRequirement.value();
+  } else {
+    direction_qos_requirement = qosRequirement.sourceAseQosRequirement.value();
   }
 
   for (auto& setting : ase_configuration_settings) {
     // Context matching
-    if (setting.audioContext != in_qosRequirement.audioContext) continue;
+    if ((setting.audioContext.bitmask & qosRequirement.audioContext.bitmask) !=
+        qosRequirement.audioContext.bitmask)
+      continue;
 
     // Match configuration flags
     // Currently configuration flags are not populated, ignore.
@@ -592,10 +694,7 @@
       if (!cfg.has_value()) continue;
       // If no requirement, return the first QoS
       if (!direction_qos_requirement.has_value()) {
-        result.sinkQosConfiguration = cfg.value().qosConfiguration;
-        result.sourceQosConfiguration = cfg.value().qosConfiguration;
-        *_aidl_return = result;
-        return ndk::ScopedAStatus::ok();
+        return cfg.value().qosConfiguration;
       }
 
       // If has requirement, return the first matched QoS
@@ -607,17 +706,41 @@
               direction_qos_requirement.value().aseConfiguration) &&
           isMatchedQosRequirement(cfg.value().qosConfiguration.value(),
                                   direction_qos_requirement.value())) {
-        if (direction == kLeAudioDirectionSink)
-          result.sinkQosConfiguration = cfg.value().qosConfiguration;
-        else
-          result.sourceQosConfiguration = cfg.value().qosConfiguration;
-        *_aidl_return = result;
-        return ndk::ScopedAStatus::ok();
+        return cfg.value().qosConfiguration;
       }
     }
   }
 
-  // No match, return empty QoS
+  return std::nullopt;
+}
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseQosConfiguration(
+    const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
+        in_qosRequirement,
+    IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return) {
+  IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+
+  // Get all configuration settings
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+      ase_configuration_settings =
+          BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
+
+  // Direction QoS matching
+  // Only handle one direction input case
+  if (in_qosRequirement.sinkAseQosRequirement.has_value()) {
+    if (!isValidQosRequirement(in_qosRequirement.sinkAseQosRequirement.value()))
+      return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    result.sinkQosConfiguration = getDirectionQosConfiguration(
+        kLeAudioDirectionSink, in_qosRequirement, ase_configuration_settings);
+  }
+  if (in_qosRequirement.sourceAseQosRequirement.has_value()) {
+    if (!isValidQosRequirement(
+            in_qosRequirement.sourceAseQosRequirement.value()))
+      return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    result.sourceQosConfiguration = getDirectionQosConfiguration(
+        kLeAudioDirectionSource, in_qosRequirement, ase_configuration_settings);
+  }
+
   *_aidl_return = result;
   return ndk::ScopedAStatus::ok();
 };
@@ -649,9 +772,13 @@
       BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(
           SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
   broadcast_settings.clear();
+
+  // Default value for unmapped fields
   CodecSpecificConfigurationLtv::AudioChannelAllocation default_allocation;
   default_allocation.bitmask =
       CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER;
+  CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU default_frame;
+  default_frame.value = 2;
 
   for (auto& codec_info : db_codec_info) {
     if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
@@ -669,15 +796,20 @@
     octets.value = transport.bitdepth[0];
 
     bis_cfg.codecConfiguration = {
-        sampling_freq_map[transport.samplingFrequencyHz[0]], octets,
-        frame_duration_map[transport.frameDurationUs[0]], default_allocation};
+        sampling_freq_map[transport.samplingFrequencyHz[0]],
+        octets,
+        frame_duration_map[transport.frameDurationUs[0]],
+        default_allocation,
+        default_frame,
+    };
 
     // Add information to structure
     IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration sub_bis_cfg;
-    sub_bis_cfg.numBis = 1;
+    sub_bis_cfg.numBis = 2;
     sub_bis_cfg.bisConfiguration = bis_cfg;
     IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration sub_cfg;
-    sub_cfg.bisConfigurations = {sub_bis_cfg};
+    // Populate the same sub config
+    sub_cfg.bisConfigurations = {sub_bis_cfg, sub_bis_cfg};
     setting.subgroupsConfigurations = {sub_cfg};
 
     broadcast_settings.push_back(setting);
@@ -721,6 +853,36 @@
   return filtered_setting;
 }
 
+bool LeAudioOffloadAudioProvider::isSubgroupConfigurationMatchedContext(
+    AudioContext setting_context,
+    LeAudioBroadcastSubgroupConfiguration configuration) {
+  // Find any valid context metadata in the bisConfigurations
+  // assuming the bis configuration in the same bis subgroup
+  // will have the same context metadata
+  std::optional<AudioContext> config_context = std::nullopt;
+
+  for (auto& p : configuration.bisConfigurations)
+    if (p.bisConfiguration.metadata.has_value()) {
+      bool is_context_found = false;
+      for (auto& metadata : p.bisConfiguration.metadata.value()) {
+        if (!metadata.has_value()) continue;
+        if (metadata.value().getTag() ==
+            MetadataLtv::Tag::preferredAudioContexts) {
+          config_context = metadata.value()
+                               .get<MetadataLtv::Tag::preferredAudioContexts>()
+                               .values;
+          is_context_found = true;
+          break;
+        }
+      }
+      if (is_context_found) break;
+    }
+
+  // Not found context metadata in any of the bis configuration, assume matched
+  if (!config_context.has_value()) return true;
+  return (setting_context.bitmask & config_context.value().bitmask);
+}
+
 ndk::ScopedAStatus
 LeAudioOffloadAudioProvider::getLeAudioBroadcastConfiguration(
     const std::optional<std::vector<
@@ -729,23 +891,28 @@
     const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement&
         in_requirement,
     LeAudioBroadcastConfigurationSetting* _aidl_return) {
-  getBroadcastSettings();
-  _aidl_return = nullptr;
+  if (in_requirement.subgroupConfigurationRequirements.empty()) {
+    LOG(WARNING) << __func__ << ": Empty requirement";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
 
-  // Match and filter capability
+  // Broadcast setting are from provider info
+  // We will allow empty capability input, match all settings with requirements.
+  getBroadcastSettings();
   std::vector<LeAudioBroadcastConfigurationSetting> filtered_settings;
   if (!in_remoteSinkAudioCapabilities.has_value()) {
-    LOG(WARNING) << __func__ << ": Empty capability";
-    return ndk::ScopedAStatus::ok();
-  }
-  for (auto& setting : broadcast_settings) {
-    for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
-      if (!capability.has_value()) continue;
-      auto filtered_setting =
-          getCapabilitiesMatchedBroadcastConfigurationSettings(
-              setting, capability.value());
-      if (filtered_setting.has_value())
-        filtered_settings.push_back(filtered_setting.value());
+    LOG(INFO) << __func__ << ": Empty capability, get all broadcast settings";
+    filtered_settings = broadcast_settings;
+  } else {
+    for (auto& setting : broadcast_settings) {
+      for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
+        if (!capability.has_value()) continue;
+        auto filtered_setting =
+            getCapabilitiesMatchedBroadcastConfigurationSettings(
+                setting, capability.value());
+        if (filtered_setting.has_value())
+          filtered_settings.push_back(filtered_setting.value());
+      }
     }
   }
 
@@ -754,36 +921,52 @@
     return ndk::ScopedAStatus::ok();
   }
 
-  // Match and return the first matched requirement
   if (in_requirement.subgroupConfigurationRequirements.empty()) {
     LOG(INFO) << __func__ << ": Empty requirement";
     *_aidl_return = filtered_settings[0];
     return ndk::ScopedAStatus::ok();
   }
 
+  // For each subgroup config requirement, find a suitable subgroup config.
+  // Gather these suitable subgroup config in an array.
+  // If the setting can satisfy all requirement, we can return the setting
+  // with the filtered array.
   for (auto& setting : filtered_settings) {
-    // Further filter out bis configuration
-    LeAudioBroadcastConfigurationSetting filtered_setting(setting);
-    filtered_setting.subgroupsConfigurations.clear();
-    for (auto& sub_cfg : setting.subgroupsConfigurations) {
-      bool isMatched = false;
-      for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
+    LeAudioBroadcastConfigurationSetting matched_setting(setting);
+    matched_setting.subgroupsConfigurations.clear();
+    auto total_num_bis = 0;
+
+    bool matched_all_requirement = true;
+
+    for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
+      bool is_matched = false;
+      for (auto& sub_cfg : setting.subgroupsConfigurations) {
+        // Match the context
+        if (!isSubgroupConfigurationMatchedContext(sub_req.audioContext,
+                                                   sub_cfg))
+          continue;
         // Matching number of BIS
         if (sub_req.bisNumPerSubgroup != sub_cfg.bisConfigurations.size())
           continue;
-        // Currently will ignore quality and context hint.
-        isMatched = true;
+        // Currently will ignore quality matching.
+        matched_setting.subgroupsConfigurations.push_back(sub_cfg);
+        total_num_bis += sub_cfg.bisConfigurations.size();
+        is_matched = true;
         break;
       }
-      if (isMatched)
-        filtered_setting.subgroupsConfigurations.push_back(sub_cfg);
+      // There is an unmatched requirement, this setting cannot be used
+      if (!is_matched) {
+        matched_all_requirement = false;
+        break;
+      }
     }
-    // Return the first match
-    if (!filtered_setting.subgroupsConfigurations.empty()) {
-      LOG(INFO) << __func__ << ": Matched requirement";
-      *_aidl_return = filtered_setting;
-      return ndk::ScopedAStatus::ok();
-    }
+
+    if (!matched_all_requirement) continue;
+
+    matched_setting.numBis = total_num_bis;
+    // Return the filtered setting if all requirement satified
+    *_aidl_return = matched_setting;
+    return ndk::ScopedAStatus::ok();
   }
 
   LOG(WARNING) << __func__ << ": Cannot match any requirement";
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
index 2785e7f..06cd405 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -96,8 +96,8 @@
 
   // Private matching function definitions
   bool isMatchedValidCodec(CodecId cfg_codec, CodecId req_codec);
-  bool isCapabilitiesMatchedContext(
-      AudioContext setting_context,
+  bool filterCapabilitiesMatchedContext(
+      AudioContext& setting_context,
       const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
   bool isMatchedSamplingFreq(
       CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
@@ -134,11 +134,10 @@
       std::vector<std::optional<AseDirectionConfiguration>>&
           valid_direction_configurations);
   void filterRequirementAseDirectionConfiguration(
-      std::vector<std::optional<AseDirectionConfiguration>>&
+      std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
           direction_configurations,
-      const std::optional<std::vector<std::optional<AseDirectionRequirement>>>&
-          requirements,
-      std::vector<std::optional<AseDirectionConfiguration>>&
+      const std::vector<std::optional<AseDirectionRequirement>>& requirements,
+      std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
           valid_direction_configurations);
   std::optional<LeAudioAseConfigurationSetting>
   getCapabilitiesMatchedAseConfigurationSettings(
@@ -157,6 +156,14 @@
       LeAudioBroadcastConfigurationSetting& setting,
       const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
   void getBroadcastSettings();
+  std::optional<LeAudioAseQosConfiguration> getDirectionQosConfiguration(
+      uint8_t direction,
+      const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
+          qosRequirement,
+      std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings);
+  bool isSubgroupConfigurationMatchedContext(
+      AudioContext requirement_context,
+      LeAudioBroadcastSubgroupConfiguration configuration);
 };
 
 class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index c313fb7..ec63831 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -58,6 +58,7 @@
 using aidl::android::hardware::bluetooth::audio::CodecSpecificCapabilitiesLtv;
 using aidl::android::hardware::bluetooth::audio::CodecSpecificConfigurationLtv;
 using aidl::android::hardware::bluetooth::audio::CodecType;
+using aidl::android::hardware::bluetooth::audio::ConfigurationFlags;
 using aidl::android::hardware::bluetooth::audio::HfpConfiguration;
 using aidl::android::hardware::bluetooth::audio::IBluetoothAudioPort;
 using aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider;
@@ -68,6 +69,7 @@
 using aidl::android::hardware::bluetooth::audio::LdacCapabilities;
 using aidl::android::hardware::bluetooth::audio::LdacConfiguration;
 using aidl::android::hardware::bluetooth::audio::LeAudioAseConfiguration;
+using aidl::android::hardware::bluetooth::audio::LeAudioBisConfiguration;
 using aidl::android::hardware::bluetooth::audio::LeAudioBroadcastConfiguration;
 using aidl::android::hardware::bluetooth::audio::
     LeAudioCodecCapabilitiesSetting;
@@ -105,12 +107,24 @@
     LeAudioAseConfigurationSetting::AseDirectionConfiguration;
 using AseQosDirectionRequirement = IBluetoothAudioProvider::
     LeAudioAseQosConfigurationRequirement::AseQosDirectionRequirement;
+using LeAudioAseQosConfigurationRequirement =
+    IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement;
 using LeAudioAseQosConfiguration =
     IBluetoothAudioProvider::LeAudioAseQosConfiguration;
 using LeAudioDeviceCapabilities =
     IBluetoothAudioProvider::LeAudioDeviceCapabilities;
 using LeAudioConfigurationRequirement =
     IBluetoothAudioProvider::LeAudioConfigurationRequirement;
+using LeAudioBroadcastConfigurationRequirement =
+    IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement;
+using LeAudioBroadcastSubgroupConfiguration =
+    IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration;
+using LeAudioBroadcastSubgroupConfigurationRequirement =
+    IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfigurationRequirement;
+using LeAudioBroadcastConfigurationSetting =
+    IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting;
+using LeAudioSubgroupBisConfiguration =
+    IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration;
 
 // Constants
 
@@ -2228,6 +2242,37 @@
     BluetoothAudioProviderFactoryAidl::TearDown();
   }
 
+  bool IsMultidirectionalCapabilitiesEnabled() {
+    if (!temp_provider_info_.has_value()) return false;
+
+    return temp_provider_info_.value().supportsMultidirectionalCapabilities;
+  }
+
+  bool IsAsymmetricConfigurationAllowed() {
+    if (!temp_provider_info_.has_value()) return false;
+    if (temp_provider_info_.value().codecInfos.empty()) return false;
+
+    for (auto& codec_info : temp_provider_info_.value().codecInfos) {
+      if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio) {
+        return false;
+      }
+
+      auto flags =
+          codec_info.transport.get<CodecInfo::Transport::leAudio>().flags;
+
+      if (!flags) {
+        continue;
+      }
+
+      if (flags->bitmask &
+          ConfigurationFlags::ALLOW_ASYMMETRIC_CONFIGURATIONS) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
   bool IsOffloadOutputSupported() {
     for (auto& capability : temp_provider_capabilities_) {
       if (capability.getTag() != AudioCapabilities::leAudioCapabilities) {
@@ -2284,27 +2329,31 @@
     return media_audio_context;
   }
 
-  LeAudioDeviceCapabilities GetDefaultRemoteCapability() {
+  LeAudioDeviceCapabilities GetDefaultRemoteSinkCapability() {
     // Create a capability
     LeAudioDeviceCapabilities capability;
 
     capability.codecId = CodecId::Core::LC3;
 
     auto pref_context_metadata = MetadataLtv::PreferredAudioContexts();
-    pref_context_metadata.values = GetAudioContext(AudioContext::MEDIA);
+    pref_context_metadata.values =
+        GetAudioContext(AudioContext::MEDIA | AudioContext::CONVERSATIONAL |
+                        AudioContext::GAME);
     capability.metadata = {pref_context_metadata};
 
     auto sampling_rate =
         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies();
     sampling_rate.bitmask =
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000 |
         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000;
     auto frame_duration =
         CodecSpecificCapabilitiesLtv::SupportedFrameDurations();
     frame_duration.bitmask =
-        CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500;
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500 |
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000;
     auto octets = CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame();
     octets.min = 0;
-    octets.max = 60;
+    octets.max = 120;
     auto frames = CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU();
     frames.value = 2;
     capability.codecSpecificCapabilities = {sampling_rate, frame_duration,
@@ -2312,29 +2361,394 @@
     return capability;
   }
 
-  LeAudioConfigurationRequirement GetDefaultRequirement(
-      bool is_source_requriement) {
+  LeAudioDeviceCapabilities GetDefaultRemoteSourceCapability() {
+    // Create a capability
+    LeAudioDeviceCapabilities capability;
+
+    capability.codecId = CodecId::Core::LC3;
+
+    auto pref_context_metadata = MetadataLtv::PreferredAudioContexts();
+    pref_context_metadata.values =
+        GetAudioContext(AudioContext::LIVE_AUDIO |
+                        AudioContext::CONVERSATIONAL | AudioContext::GAME);
+    capability.metadata = {pref_context_metadata};
+
+    auto sampling_rate =
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies();
+    sampling_rate.bitmask =
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000 |
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000;
+    auto frame_duration =
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations();
+    frame_duration.bitmask =
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500 |
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000;
+    auto octets = CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame();
+    octets.min = 0;
+    octets.max = 120;
+    auto frames = CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU();
+    frames.value = 2;
+    capability.codecSpecificCapabilities = {sampling_rate, frame_duration,
+                                            octets, frames};
+    return capability;
+  }
+
+  std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
+      const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
+      CodecSpecificConfigurationLtv::Tag tag) {
+    for (const auto ltv : configurationLtvs) {
+      if (ltv.getTag() == tag) {
+        return ltv;
+      }
+    }
+    return std::nullopt;
+  }
+
+  bool IsAseRequirementSatisfiedWithUnknownChannelCount(
+      const std::vector<std::optional<AseDirectionRequirement>>&
+          ase_requirements,
+      const std::vector<std::optional<AseDirectionConfiguration>>&
+          ase_configurations) {
+    /* This is mandatory  to match sample freq, allocation however, when in the
+     * device group there is only one device which supports left and right
+     * allocation, and channel count is hidden from the BT stack, the BT stack
+     * will send single requirement but it can receive two configurations if the
+     * channel count is 1.
+     */
+
+    int num_of_ase_requirements = 0;
+    for (const auto& ase_req : ase_requirements) {
+      auto required_allocation_ltv = GetConfigurationLtv(
+          ase_req->aseConfiguration.codecConfiguration,
+          CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+      if (required_allocation_ltv == std::nullopt) {
+        continue;
+      }
+      int required_allocation =
+          required_allocation_ltv
+              ->get<
+                  CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
+              .bitmask;
+      num_of_ase_requirements += std::bitset<32>(required_allocation).count();
+    }
+
+    int num_of_satisfied_ase_requirements = 0;
+    for (const auto& ase_req : ase_requirements) {
+      if (!ase_req) {
+        continue;
+      }
+      auto required_sample_freq_ltv = GetConfigurationLtv(
+          ase_req->aseConfiguration.codecConfiguration,
+          CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+      auto required_allocation_ltv = GetConfigurationLtv(
+          ase_req->aseConfiguration.codecConfiguration,
+          CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+
+      /* Allocation and sample freq shall be always in the requirement */
+      if (!required_sample_freq_ltv || !required_allocation_ltv) {
+        return false;
+      }
+
+      int required_allocation =
+          required_allocation_ltv
+              ->get<
+                  CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
+              .bitmask;
+
+      for (const auto& ase_conf : ase_configurations) {
+        if (!ase_conf) {
+          continue;
+        }
+        auto config_sample_freq_ltv = GetConfigurationLtv(
+            ase_conf->aseConfiguration.codecConfiguration,
+            CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+        auto config_allocation_ltv = GetConfigurationLtv(
+            ase_conf->aseConfiguration.codecConfiguration,
+            CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+        if (config_sample_freq_ltv == std::nullopt ||
+            config_allocation_ltv == std::nullopt) {
+          return false;
+        }
+
+        int configured_allocation = config_allocation_ltv
+                                        ->get<CodecSpecificConfigurationLtv::
+                                                  Tag::audioChannelAllocation>()
+                                        .bitmask;
+
+        if (config_sample_freq_ltv == required_sample_freq_ltv &&
+            (required_allocation & configured_allocation)) {
+          num_of_satisfied_ase_requirements +=
+              std::bitset<32>(configured_allocation).count();
+        }
+      }
+    }
+
+    return (num_of_satisfied_ase_requirements == num_of_ase_requirements);
+  }
+
+  bool IsAseRequirementSatisfied(
+      const std::vector<std::optional<AseDirectionRequirement>>&
+          ase_requirements,
+      const std::vector<std::optional<AseDirectionConfiguration>>&
+          ase_configurations) {
+    // This is mandatory  to match sample freq, allocation
+    int num_of_satisfied_ase_requirements = 0;
+
+    int required_allocations = 0;
+    for (const auto& ase_req : ase_requirements) {
+      auto required_allocation_ltv = GetConfigurationLtv(
+          ase_req->aseConfiguration.codecConfiguration,
+          CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+      if (required_allocation_ltv == std::nullopt) {
+        continue;
+      }
+
+      int allocations =
+          required_allocation_ltv
+              ->get<
+                  CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
+              .bitmask;
+      required_allocations += std::bitset<32>(allocations).count();
+    }
+
+    if (ase_requirements.size() != required_allocations) {
+      /* If more than one allication is requested in the requirement, then use
+       * different verifier */
+      return IsAseRequirementSatisfiedWithUnknownChannelCount(
+          ase_requirements, ase_configurations);
+    }
+
+    for (const auto& ase_req : ase_requirements) {
+      if (!ase_req) {
+        continue;
+      }
+      auto required_sample_freq_ltv = GetConfigurationLtv(
+          ase_req->aseConfiguration.codecConfiguration,
+          CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+      auto required_allocation_ltv = GetConfigurationLtv(
+          ase_req->aseConfiguration.codecConfiguration,
+          CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+
+      /* Allocation and sample freq shall be always in the requirement */
+      if (!required_sample_freq_ltv || !required_allocation_ltv) {
+        return false;
+      }
+
+      for (const auto& ase_conf : ase_configurations) {
+        if (!ase_conf) {
+          continue;
+        }
+        auto config_sample_freq_ltv = GetConfigurationLtv(
+            ase_conf->aseConfiguration.codecConfiguration,
+            CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+        auto config_allocation_ltv = GetConfigurationLtv(
+            ase_conf->aseConfiguration.codecConfiguration,
+            CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+        if (config_sample_freq_ltv == std::nullopt ||
+            config_allocation_ltv == std::nullopt) {
+          return false;
+        }
+
+        if (config_sample_freq_ltv == required_sample_freq_ltv &&
+            config_allocation_ltv == required_allocation_ltv) {
+          num_of_satisfied_ase_requirements++;
+          break;
+        }
+      }
+    }
+
+    return (num_of_satisfied_ase_requirements == ase_requirements.size());
+  }
+
+  void VerifyIfRequirementsSatisfied(
+      const std::vector<LeAudioConfigurationRequirement>& requirements,
+      const std::vector<LeAudioAseConfigurationSetting>& configurations) {
+    if (requirements.empty() && configurations.empty()) {
+      return;
+    }
+
+    /* It might happen that vendor lib will provide same configuration for
+     * multiple contexts and it should be accepted
+     */
+
+    int num_of_requirements = 0;
+    for (const auto& req : requirements) {
+      num_of_requirements += std::bitset<32>(req.audioContext.bitmask).count();
+    }
+
+    int num_of_configurations = 0;
+    for (const auto& conf : configurations) {
+      num_of_configurations +=
+          std::bitset<32>(conf.audioContext.bitmask).count();
+    }
+
+    ASSERT_EQ(num_of_requirements, num_of_configurations);
+
+    int num_of_satisfied_requirements = 0;
+    for (const auto& req : requirements) {
+      for (const auto& conf : configurations) {
+        if ((req.audioContext.bitmask & conf.audioContext.bitmask) !=
+            req.audioContext.bitmask) {
+          continue;
+        }
+
+        if (req.sinkAseRequirement && req.sourceAseRequirement) {
+          if (!conf.sinkAseConfiguration || !conf.sourceAseConfiguration) {
+            continue;
+          }
+
+          if (!IsAseRequirementSatisfied(*req.sinkAseRequirement,
+                                         *conf.sinkAseConfiguration) ||
+              !IsAseRequirementSatisfied(*req.sourceAseRequirement,
+                                         *conf.sourceAseConfiguration)) {
+            continue;
+          }
+          num_of_satisfied_requirements +=
+              std::bitset<32>(req.audioContext.bitmask).count();
+
+          break;
+        } else if (req.sinkAseRequirement) {
+          if (!IsAseRequirementSatisfied(*req.sinkAseRequirement,
+                                         *conf.sinkAseConfiguration)) {
+            continue;
+          }
+          num_of_satisfied_requirements +=
+              std::bitset<32>(req.audioContext.bitmask).count();
+          break;
+        } else if (req.sourceAseRequirement) {
+          if (!IsAseRequirementSatisfied(*req.sourceAseRequirement,
+                                         *conf.sourceAseConfiguration)) {
+            continue;
+          }
+          num_of_satisfied_requirements +=
+              std::bitset<32>(req.audioContext.bitmask).count();
+          break;
+        }
+      }
+    }
+    ASSERT_EQ(num_of_satisfied_requirements, num_of_requirements);
+  }
+
+  LeAudioConfigurationRequirement GetUnicastDefaultRequirement(
+      int32_t context_bits, bool is_sink_requirement,
+      bool is_source_requriement,
+      CodecSpecificConfigurationLtv::SamplingFrequency freq =
+          CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000) {
     // Create a requirements
     LeAudioConfigurationRequirement requirement;
-    requirement.audioContext = GetAudioContext(AudioContext::MEDIA);
+    requirement.audioContext = GetAudioContext(context_bits);
+
+    auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+    allocation.bitmask =
+        CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+        CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
 
     auto direction_ase_requriement = AseDirectionRequirement();
     direction_ase_requriement.aseConfiguration.codecId = CodecId::Core::LC3;
     direction_ase_requriement.aseConfiguration.targetLatency =
         LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY;
 
-    // Mismatch sampling frequency
     direction_ase_requriement.aseConfiguration.codecConfiguration = {
-        CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025,
-        CodecSpecificConfigurationLtv::FrameDuration::US7500,
+        freq, CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation
+
     };
+    if (is_sink_requirement)
+      requirement.sinkAseRequirement = {direction_ase_requriement};
+
     if (is_source_requriement)
       requirement.sourceAseRequirement = {direction_ase_requriement};
-    else
-      requirement.sinkAseRequirement = {direction_ase_requriement};
+
     return requirement;
   }
 
+  LeAudioConfigurationRequirement GetUnicastGameRequirement(bool asymmetric) {
+    // Create a requirements
+    LeAudioConfigurationRequirement requirement;
+    requirement.audioContext = GetAudioContext(AudioContext::GAME);
+
+    auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+    allocation.bitmask =
+        CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+        CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+    auto sink_ase_requriement = AseDirectionRequirement();
+    sink_ase_requriement.aseConfiguration.codecId = CodecId::Core::LC3;
+    sink_ase_requriement.aseConfiguration.targetLatency =
+        LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY;
+
+    sink_ase_requriement.aseConfiguration.codecConfiguration = {
+        CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+        CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation};
+
+    auto source_ase_requriement = AseDirectionRequirement();
+    source_ase_requriement.aseConfiguration.codecId = CodecId::Core::LC3;
+    source_ase_requriement.aseConfiguration.targetLatency =
+        LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY;
+
+    if (asymmetric) {
+      source_ase_requriement.aseConfiguration.codecConfiguration = {
+          CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000,
+          CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation};
+    } else {
+      source_ase_requriement.aseConfiguration.codecConfiguration = {
+          CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+          CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation};
+    }
+
+    requirement.sinkAseRequirement = {sink_ase_requriement};
+    requirement.sourceAseRequirement = {source_ase_requriement};
+
+    return requirement;
+  }
+
+  LeAudioAseQosConfigurationRequirement GetQosRequirements(
+      bool is_sink_requirement, bool is_source_requriement, bool valid = true) {
+    LeAudioAseQosConfigurationRequirement qosRequirement;
+
+    auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+    allocation.bitmask =
+        CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+        CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+    AseQosDirectionRequirement directionalRequirement = {
+        .framing = IBluetoothAudioProvider::Framing::UNFRAMED,
+        .preferredRetransmissionNum = 2,
+        .maxTransportLatencyMs = 10,
+        .presentationDelayMinUs = 40000,
+        .presentationDelayMaxUs = 40000,
+        .aseConfiguration =
+            {
+                .targetLatency = LeAudioAseConfiguration::TargetLatency::
+                    BALANCED_LATENCY_RELIABILITY,
+                .codecId = CodecId::Core::LC3,
+                .codecConfiguration =
+                    {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+                     CodecSpecificConfigurationLtv::FrameDuration::US10000,
+                     allocation},
+            },
+    };
+
+    if (!valid) {
+      // clear some required values;
+      directionalRequirement.maxTransportLatencyMs = 0;
+      directionalRequirement.presentationDelayMaxUs = 0;
+    }
+
+    qosRequirement.sinkAseQosRequirement = directionalRequirement;
+    if (is_source_requriement && is_sink_requirement) {
+      qosRequirement.sourceAseQosRequirement = directionalRequirement;
+      qosRequirement.sinkAseQosRequirement = directionalRequirement;
+    } else if (is_source_requriement) {
+      qosRequirement.sourceAseQosRequirement = directionalRequirement;
+      qosRequirement.sinkAseQosRequirement = std::nullopt;
+    } else if (is_sink_requirement) {
+      qosRequirement.sourceAseQosRequirement = std::nullopt;
+      qosRequirement.sinkAseQosRequirement = directionalRequirement;
+    }
+
+    return qosRequirement;
+  }
+
   std::vector<Lc3Configuration> GetUnicastLc3SupportedList(bool decoding,
                                                            bool supported) {
     std::vector<Lc3Configuration> le_audio_codec_configs;
@@ -2460,6 +2874,11 @@
       AudioContext::NOTIFICATIONS, AudioContext::RINGTONE_ALERTS,
       AudioContext::ALERTS,        AudioContext::EMERGENCY_ALARM,
   };
+
+  AudioContext bidirectional_contexts = {
+      .bitmask = AudioContext::CONVERSATIONAL | AudioContext::GAME |
+                 AudioContext::VOICE_ASSISTANTS | AudioContext::LIVE_AUDIO,
+  };
 };
 
 /**
@@ -2511,6 +2930,40 @@
       BluetoothAudioHalVersion::VERSION_AIDL_V4) {
     GTEST_SKIP();
   }
+
+  if (IsMultidirectionalCapabilitiesEnabled()) {
+    GTEST_SKIP();
+  }
+
+  std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+  std::vector<LeAudioConfigurationRequirement> empty_requirement;
+  std::vector<LeAudioAseConfigurationSetting> configurations;
+
+  // Check empty capability for source direction
+  auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      std::nullopt, empty_capability, empty_requirement, &configurations);
+
+  ASSERT_FALSE(aidl_retval.isOk());
+
+  // Check empty capability for sink direction
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      empty_capability, std::nullopt, empty_requirement, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_TRUE(configurations.empty());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       GetEmptyAseConfigurationEmptyCapability_Multidirectiona) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+
+  if (!IsMultidirectionalCapabilitiesEnabled()) {
+    GTEST_SKIP();
+  }
+
   std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
   std::vector<LeAudioConfigurationRequirement> empty_requirement;
   std::vector<LeAudioAseConfigurationSetting> configurations;
@@ -2536,50 +2989,388 @@
       BluetoothAudioHalVersion::VERSION_AIDL_V4) {
     GTEST_SKIP();
   }
-  std::vector<std::optional<LeAudioDeviceCapabilities>> capabilities = {
-      GetDefaultRemoteCapability()};
+  std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+      GetDefaultRemoteSinkCapability()};
+  std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+      GetDefaultRemoteSourceCapability()};
+
+  auto not_supported_sampling_rate_by_remote =
+      CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025;
 
   // Check empty capability for source direction
   std::vector<LeAudioAseConfigurationSetting> configurations;
   std::vector<LeAudioConfigurationRequirement> source_requirements = {
-      GetDefaultRequirement(true)};
+      GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /*sink */,
+                                   true /* source */,
+                                   not_supported_sampling_rate_by_remote)};
   auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
-      std::nullopt, capabilities, source_requirements, &configurations);
+      std::nullopt, source_capabilities, source_requirements, &configurations);
 
   ASSERT_TRUE(aidl_retval.isOk());
   ASSERT_TRUE(configurations.empty());
 
   // Check empty capability for sink direction
   std::vector<LeAudioConfigurationRequirement> sink_requirements = {
-      GetDefaultRequirement(false)};
+      GetUnicastDefaultRequirement(AudioContext::MEDIA, true /*sink */,
+                                   false /* source */,
+                                   not_supported_sampling_rate_by_remote)};
   aidl_retval = audio_provider_->getLeAudioAseConfiguration(
-      capabilities, std::nullopt, source_requirements, &configurations);
+      sink_capabilities, std::nullopt, sink_requirements, &configurations);
 
   ASSERT_TRUE(aidl_retval.isOk());
   ASSERT_TRUE(configurations.empty());
 }
 
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl, GetAseConfiguration) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+
+  if (IsMultidirectionalCapabilitiesEnabled()) {
+    GTEST_SKIP();
+  }
+
+  std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+      GetDefaultRemoteSinkCapability()};
+  std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+      GetDefaultRemoteSourceCapability()};
+
+  // Should not ask for Source on ENCODING session if Multidiretional not
+  // supported
+  std::vector<LeAudioAseConfigurationSetting> configurations;
+  std::vector<LeAudioConfigurationRequirement> source_requirements = {
+      GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+                                   true /* source */)};
+  auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      std::nullopt, source_capabilities, source_requirements, &configurations);
+
+  ASSERT_FALSE(aidl_retval.isOk());
+  ASSERT_TRUE(configurations.empty());
+
+  // Check capability for remote sink direction
+  std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+      GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+                                   false /* source */)};
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      sink_capabilities, std::nullopt, sink_requirements, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_FALSE(configurations.empty());
+  VerifyIfRequirementsSatisfied(sink_requirements, configurations);
+
+  // Check multiple capability for remote sink direction
+  std::vector<LeAudioConfigurationRequirement> multi_sink_requirements = {
+      GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+                                   false /* source */),
+      GetUnicastDefaultRequirement(AudioContext::CONVERSATIONAL,
+                                   true /* sink */, false /* source */)};
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      sink_capabilities, std::nullopt, multi_sink_requirements,
+      &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_FALSE(configurations.empty());
+  VerifyIfRequirementsSatisfied(multi_sink_requirements, configurations);
+
+  // Check multiple context types in a single requirement.
+  std::vector<LeAudioConfigurationRequirement> multi_context_sink_requirements =
+      {GetUnicastDefaultRequirement(
+          AudioContext::MEDIA | AudioContext::SOUND_EFFECTS, true /* sink */,
+          false /* source */)};
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      sink_capabilities, std::nullopt, multi_context_sink_requirements,
+      &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_FALSE(configurations.empty());
+  VerifyIfRequirementsSatisfied(multi_sink_requirements, configurations);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       GetAseConfiguration_Multidirectional) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+
+  if (!IsMultidirectionalCapabilitiesEnabled()) {
+    GTEST_SKIP();
+  }
+
+  std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+      GetDefaultRemoteSinkCapability()};
+  std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+      GetDefaultRemoteSourceCapability()};
+
+  // Verify source configuration is received
+  std::vector<LeAudioAseConfigurationSetting> configurations;
+  std::vector<LeAudioConfigurationRequirement> source_requirements = {
+      GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+                                   true /* source */)};
+  auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      std::nullopt, source_capabilities, source_requirements, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_FALSE(configurations.empty());
+  VerifyIfRequirementsSatisfied(source_requirements, configurations);
+
+  // Verify sink configuration is received
+  std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+      GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+                                   false /* source */)};
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      sink_capabilities, std::nullopt, sink_requirements, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_FALSE(configurations.empty());
+  VerifyIfRequirementsSatisfied(sink_requirements, configurations);
+
+  std::vector<LeAudioConfigurationRequirement> combined_requirements = {
+      GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+                                   true /* source */),
+      GetUnicastDefaultRequirement(AudioContext::CONVERSATIONAL,
+                                   true /* sink */, true /* source */),
+      GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+                                   false /* source */)};
+
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      sink_capabilities, source_capabilities, combined_requirements,
+      &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_FALSE(configurations.empty());
+  VerifyIfRequirementsSatisfied(combined_requirements, configurations);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       GetAsymmetricAseConfiguration_Multidirectional) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+
+  if (!IsMultidirectionalCapabilitiesEnabled()) {
+    GTEST_SKIP();
+  }
+
+  if (!IsAsymmetricConfigurationAllowed()) {
+    GTEST_SKIP();
+  }
+
+  std::vector<LeAudioAseConfigurationSetting> configurations;
+  std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+      GetDefaultRemoteSinkCapability()};
+  std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+      GetDefaultRemoteSourceCapability()};
+
+  std::vector<LeAudioConfigurationRequirement> asymmetric_requirements = {
+      GetUnicastGameRequirement(true /* Asymmetric */)};
+
+  auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      sink_capabilities, source_capabilities, asymmetric_requirements,
+      &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_FALSE(configurations.empty());
+  VerifyIfRequirementsSatisfied(asymmetric_requirements, configurations);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       GetQoSConfiguration_Multidirectional) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+
+  if (!IsMultidirectionalCapabilitiesEnabled()) {
+    GTEST_SKIP();
+  }
+
+  auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+  allocation.bitmask =
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+  LeAudioAseQosConfigurationRequirement requirement =
+      GetQosRequirements(true, true);
+
+  std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+      QoSConfigurations;
+  bool is_supported = false;
+  for (auto bitmask : all_context_bitmasks) {
+    requirement.audioContext = GetAudioContext(bitmask);
+    bool is_bidirectional = bidirectional_contexts.bitmask & bitmask;
+
+    if (is_bidirectional) {
+      requirement.sourceAseQosRequirement = requirement.sinkAseQosRequirement;
+    } else {
+      requirement.sourceAseQosRequirement = std::nullopt;
+    }
+
+    IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+    auto aidl_retval =
+        audio_provider_->getLeAudioAseQosConfiguration(requirement, &result);
+    if (!aidl_retval.isOk()) {
+      // If not OK, then it could be not supported, as it is an optional
+      // feature
+      ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+    }
+
+    is_supported = true;
+    if (result.sinkQosConfiguration.has_value()) {
+      if (is_bidirectional) {
+        ASSERT_TRUE(result.sourceQosConfiguration.has_value());
+      } else {
+        ASSERT_FALSE(result.sourceQosConfiguration.has_value());
+      }
+      QoSConfigurations.push_back(result.sinkQosConfiguration.value());
+    }
+  }
+  if (is_supported) {
+    // QoS Configurations should not be empty, as we searched for all contexts
+    ASSERT_FALSE(QoSConfigurations.empty());
+  }
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       GetQoSConfiguration_InvalidRequirements) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+  auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+  allocation.bitmask =
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+  LeAudioAseQosConfigurationRequirement invalid_requirement =
+      GetQosRequirements(true /* sink */, false /* source */,
+                         false /* valid */);
+
+  std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+      QoSConfigurations;
+  for (auto bitmask : all_context_bitmasks) {
+    invalid_requirement.audioContext = GetAudioContext(bitmask);
+    IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+    auto aidl_retval = audio_provider_->getLeAudioAseQosConfiguration(
+        invalid_requirement, &result);
+    ASSERT_FALSE(aidl_retval.isOk());
+  }
+}
+
 TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl, GetQoSConfiguration) {
   if (GetProviderFactoryInterfaceVersion() <
       BluetoothAudioHalVersion::VERSION_AIDL_V4) {
     GTEST_SKIP();
   }
+  auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+  allocation.bitmask =
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
   IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement requirement;
+  requirement = GetQosRequirements(true /* sink */, false /* source */);
+
   std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
       QoSConfigurations;
+  bool is_supported = false;
   for (auto bitmask : all_context_bitmasks) {
     requirement.audioContext = GetAudioContext(bitmask);
     IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
     auto aidl_retval =
         audio_provider_->getLeAudioAseQosConfiguration(requirement, &result);
-    ASSERT_TRUE(aidl_retval.isOk());
-    if (result.sinkQosConfiguration.has_value())
-      QoSConfigurations.push_back(result.sinkQosConfiguration.value());
-    if (result.sourceQosConfiguration.has_value())
-      QoSConfigurations.push_back(result.sourceQosConfiguration.value());
+    if (!aidl_retval.isOk()) {
+      // If not OK, then it could be not supported, as it is an optional
+      // feature
+      ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+    } else {
+      is_supported = true;
+      if (result.sinkQosConfiguration.has_value()) {
+        QoSConfigurations.push_back(result.sinkQosConfiguration.value());
+      }
+    }
   }
-  // QoS Configurations should not be empty, as we searched for all contexts
-  ASSERT_FALSE(QoSConfigurations.empty());
+
+  if (is_supported) {
+    // QoS Configurations should not be empty, as we searched for all contexts
+    ASSERT_FALSE(QoSConfigurations.empty());
+  }
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       GetDataPathConfiguration_Multidirectional) {
+  IBluetoothAudioProvider::StreamConfig sink_requirement;
+  IBluetoothAudioProvider::StreamConfig source_requirement;
+  std::vector<IBluetoothAudioProvider::LeAudioDataPathConfiguration>
+      DataPathConfigurations;
+
+  if (!IsMultidirectionalCapabilitiesEnabled()) {
+    GTEST_SKIP();
+  }
+
+  bool is_supported = false;
+  auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+  allocation.bitmask =
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+  auto streamMap = LeAudioConfiguration::StreamMap();
+
+  // Use some mandatory configuration
+  streamMap.streamHandle = 0x0001;
+  streamMap.audioChannelAllocation = 0x03;
+  streamMap.aseConfiguration = {
+      .targetLatency =
+          LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY,
+      .codecId = CodecId::Core::LC3,
+      .codecConfiguration =
+          {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+           CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation},
+  };
+
+  // Bidirectional
+  sink_requirement.streamMap = {streamMap};
+  source_requirement.streamMap = {streamMap};
+
+  for (auto bitmask : all_context_bitmasks) {
+    sink_requirement.audioContext = GetAudioContext(bitmask);
+    source_requirement.audioContext = sink_requirement.audioContext;
+
+    IBluetoothAudioProvider::LeAudioDataPathConfigurationPair result;
+    ::ndk::ScopedAStatus aidl_retval;
+
+    bool is_bidirectional = bidirectional_contexts.bitmask & bitmask;
+    if (is_bidirectional) {
+      aidl_retval = audio_provider_->getLeAudioAseDatapathConfiguration(
+          sink_requirement, source_requirement, &result);
+    } else {
+      aidl_retval = audio_provider_->getLeAudioAseDatapathConfiguration(
+          sink_requirement, std::nullopt, &result);
+    }
+
+    if (!aidl_retval.isOk()) {
+      // If not OK, then it could be not supported, as it is an optional
+      // feature
+      ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+    } else {
+      is_supported = true;
+      if (result.outputConfig.has_value()) {
+        if (is_bidirectional) {
+          ASSERT_TRUE(result.inputConfig.has_value());
+        } else {
+          ASSERT_TRUE(!result.inputConfig.has_value());
+        }
+        DataPathConfigurations.push_back(result.outputConfig.value());
+      }
+    }
+  }
+
+  if (is_supported) {
+    // Datapath Configurations should not be empty, as we searched for all
+    // contexts
+    ASSERT_FALSE(DataPathConfigurations.empty());
+  }
 }
 
 TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
@@ -2589,26 +3380,45 @@
     GTEST_SKIP();
   }
   IBluetoothAudioProvider::StreamConfig sink_requirement;
-  IBluetoothAudioProvider::StreamConfig source_requirement;
   std::vector<IBluetoothAudioProvider::LeAudioDataPathConfiguration>
       DataPathConfigurations;
   bool is_supported = false;
+  auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+  allocation.bitmask =
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+  auto streamMap = LeAudioConfiguration::StreamMap();
+
+  // Use some mandatory configuration
+  streamMap.streamHandle = 0x0001;
+  streamMap.audioChannelAllocation = 0x03;
+  streamMap.aseConfiguration = {
+      .targetLatency =
+          LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY,
+      .codecId = CodecId::Core::LC3,
+      .codecConfiguration =
+          {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+           CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation},
+  };
+
+  sink_requirement.streamMap = {streamMap};
 
   for (auto bitmask : all_context_bitmasks) {
     sink_requirement.audioContext = GetAudioContext(bitmask);
-    source_requirement.audioContext = GetAudioContext(bitmask);
     IBluetoothAudioProvider::LeAudioDataPathConfigurationPair result;
     auto aidl_retval = audio_provider_->getLeAudioAseDatapathConfiguration(
-        sink_requirement, source_requirement, &result);
+        sink_requirement, std::nullopt, &result);
+
     if (!aidl_retval.isOk()) {
-      // If not OK, then it could be not supported, as it is an optional feature
+      // If not OK, then it could be not supported, as it is an optional
+      // feature
       ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
     } else {
       is_supported = true;
-      if (result.inputConfig.has_value())
-        DataPathConfigurations.push_back(result.inputConfig.value());
-      if (result.inputConfig.has_value())
-        DataPathConfigurations.push_back(result.inputConfig.value());
+      if (result.outputConfig.has_value()) {
+        DataPathConfigurations.push_back(result.outputConfig.value());
+      }
     }
   }
 
@@ -2655,10 +3465,9 @@
  * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
  * stopped with Unicast hardware encoding config
  *
- * Disabled since offload codec checking is not ready
  */
 TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
-       DISABLED_StartAndEndLeAudioOutputSessionWithInvalidAudioConfiguration) {
+       StartAndEndLeAudioOutputSessionWithInvalidAudioConfiguration) {
   if (!IsOffloadOutputSupported()) {
     GTEST_SKIP();
   }
@@ -2678,8 +3487,8 @@
         audio_port_, AudioConfiguration(le_audio_config), latency_modes,
         &mq_desc);
 
-    // AIDL call should fail on invalid codec
-    ASSERT_FALSE(aidl_retval.isOk());
+    // It is OK to start session with invalid configuration
+    ASSERT_TRUE(aidl_retval.isOk());
     EXPECT_TRUE(audio_provider_->endSession().isOk());
   }
 }
@@ -2758,8 +3567,8 @@
           audio_port_, AudioConfiguration(le_audio_config), latency_modes,
           &mq_desc);
 
-      // AIDL call should fail on invalid codec
-      ASSERT_FALSE(aidl_retval.isOk());
+      // It is OK to start session with invalid configuration
+      ASSERT_TRUE(aidl_retval.isOk());
       EXPECT_TRUE(audio_provider_->endSession().isOk());
     }
   }
@@ -2879,10 +3688,9 @@
  * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH can be started and
  * stopped with Unicast hardware encoding config
  *
- * Disabled since offload codec checking is not ready
  */
 TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
-       DISABLED_StartAndEndLeAudioInputSessionWithInvalidAudioConfiguration) {
+       StartAndEndLeAudioInputSessionWithInvalidAudioConfiguration) {
   if (!IsOffloadInputSupported()) {
     GTEST_SKIP();
   }
@@ -2903,12 +3711,229 @@
         audio_port_, AudioConfiguration(le_audio_config), latency_modes,
         &mq_desc);
 
-    // AIDL call should fail on invalid codec
-    ASSERT_FALSE(aidl_retval.isOk());
+    // It is OK to start with invalid configuration as it might be unknown on
+    // start
+    ASSERT_TRUE(aidl_retval.isOk());
     EXPECT_TRUE(audio_provider_->endSession().isOk());
   }
 }
 
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+       GetEmptyAseConfigurationEmptyCapability) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+
+  if (IsMultidirectionalCapabilitiesEnabled()) {
+    GTEST_SKIP();
+  }
+
+  std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+  std::vector<LeAudioConfigurationRequirement> empty_requirement;
+  std::vector<LeAudioAseConfigurationSetting> configurations;
+
+  // Check success for source direction (Input == DecodingSession == remote
+  // source)
+  auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      std::nullopt, empty_capability, empty_requirement, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_TRUE(configurations.empty());
+
+  // Check failure for sink direction
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      empty_capability, std::nullopt, empty_requirement, &configurations);
+
+  ASSERT_FALSE(aidl_retval.isOk());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+       GetEmptyAseConfigurationEmptyCapability_Multidirectional) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+
+  if (!IsMultidirectionalCapabilitiesEnabled()) {
+    GTEST_SKIP();
+  }
+
+  std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+  std::vector<LeAudioConfigurationRequirement> empty_requirement;
+  std::vector<LeAudioAseConfigurationSetting> configurations;
+
+  // Check empty capability for source direction
+  auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      std::nullopt, empty_capability, empty_requirement, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_TRUE(configurations.empty());
+
+  // Check empty capability for sink direction
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      empty_capability, std::nullopt, empty_requirement, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_TRUE(configurations.empty());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl, GetAseConfiguration) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+
+  if (IsMultidirectionalCapabilitiesEnabled()) {
+    GTEST_SKIP();
+  }
+
+  std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+      GetDefaultRemoteSinkCapability()};
+  std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+      GetDefaultRemoteSourceCapability()};
+
+  // Check source configuration is received
+  std::vector<LeAudioAseConfigurationSetting> configurations;
+  std::vector<LeAudioConfigurationRequirement> source_requirements = {
+      GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+                                   true /* source */)};
+  auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      std::nullopt, source_capabilities, source_requirements, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_FALSE(configurations.empty());
+
+  // Check error result when requesting sink on DECODING session
+  std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+      GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+                                   false /* source */)};
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      sink_capabilities, std::nullopt, sink_requirements, &configurations);
+
+  ASSERT_FALSE(aidl_retval.isOk());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+       GetAseConfiguration_Multidirectional) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+
+  if (!IsMultidirectionalCapabilitiesEnabled()) {
+    GTEST_SKIP();
+  }
+
+  std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+      GetDefaultRemoteSinkCapability()};
+  std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+      GetDefaultRemoteSourceCapability()};
+
+  // Check source configuration is received
+  std::vector<LeAudioAseConfigurationSetting> configurations;
+  std::vector<LeAudioConfigurationRequirement> source_requirements = {
+      GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+                                   true /* source */)};
+  auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      std::nullopt, source_capabilities, source_requirements, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_FALSE(configurations.empty());
+  VerifyIfRequirementsSatisfied(source_requirements, configurations);
+
+  // Check empty capability for sink direction
+  std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+      GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+                                   false /* source */)};
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      sink_capabilities, std::nullopt, sink_requirements, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_FALSE(configurations.empty());
+  VerifyIfRequirementsSatisfied(sink_requirements, configurations);
+
+  std::vector<LeAudioConfigurationRequirement> combined_requirements = {
+      GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+                                   true /* source */),
+      GetUnicastDefaultRequirement(AudioContext::CONVERSATIONAL,
+                                   true /* sink */, true /* source */),
+      GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+                                   false /* source */)};
+
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      sink_capabilities, source_capabilities, combined_requirements,
+      &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_FALSE(configurations.empty());
+  VerifyIfRequirementsSatisfied(combined_requirements, configurations);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+       GetQoSConfiguration_InvalidRequirements) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+  auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+  allocation.bitmask =
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+  LeAudioAseQosConfigurationRequirement invalid_requirement =
+      GetQosRequirements(false /* sink */, true /* source */,
+                         false /* valid */);
+
+  std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+      QoSConfigurations;
+  for (auto bitmask : all_context_bitmasks) {
+    invalid_requirement.audioContext = GetAudioContext(bitmask);
+    IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+    auto aidl_retval = audio_provider_->getLeAudioAseQosConfiguration(
+        invalid_requirement, &result);
+    ASSERT_FALSE(aidl_retval.isOk());
+  }
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl, GetQoSConfiguration) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+  auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+  allocation.bitmask =
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+  IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement requirement;
+  requirement = GetQosRequirements(false /* sink */, true /* source */);
+
+  std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+      QoSConfigurations;
+  bool is_supported = false;
+  for (auto bitmask : all_context_bitmasks) {
+    requirement.audioContext = GetAudioContext(bitmask);
+    IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+    auto aidl_retval =
+        audio_provider_->getLeAudioAseQosConfiguration(requirement, &result);
+    if (!aidl_retval.isOk()) {
+      // If not OK, then it could be not supported, as it is an optional
+      // feature
+      ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+    } else {
+      is_supported = true;
+      if (result.sourceQosConfiguration.has_value()) {
+        QoSConfigurations.push_back(result.sourceQosConfiguration.value());
+      }
+    }
+  }
+
+  if (is_supported) {
+    // QoS Configurations should not be empty, as we searched for all contexts
+    ASSERT_FALSE(QoSConfigurations.empty());
+  }
+}
 /**
  * openProvider LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH
  */
@@ -3058,6 +4083,146 @@
     return le_audio_codec_configs;
   }
 
+  AudioContext GetAudioContext(int32_t bitmask) {
+    AudioContext media_audio_context;
+    media_audio_context.bitmask = bitmask;
+    return media_audio_context;
+  }
+
+  std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
+      const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
+      CodecSpecificConfigurationLtv::Tag tag) {
+    for (const auto ltv : configurationLtvs) {
+      if (ltv.getTag() == tag) {
+        return ltv;
+      }
+    }
+    return std::nullopt;
+  }
+
+  std::optional<CodecSpecificConfigurationLtv::SamplingFrequency>
+  GetBisSampleFreq(const LeAudioBisConfiguration& bis_conf) {
+    auto sample_freq_ltv = GetConfigurationLtv(
+        bis_conf.codecConfiguration,
+        CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+    if (!sample_freq_ltv) {
+      return std::nullopt;
+    }
+    return (*sample_freq_ltv)
+        .get<CodecSpecificConfigurationLtv::samplingFrequency>();
+  }
+
+  std::vector<CodecSpecificConfigurationLtv::SamplingFrequency>
+  GetSubgroupSampleFreqs(
+      const LeAudioBroadcastSubgroupConfiguration& subgroup_conf) {
+    std::vector<CodecSpecificConfigurationLtv::SamplingFrequency> result = {};
+
+    for (const auto& bis_conf : subgroup_conf.bisConfigurations) {
+      auto sample_freq = GetBisSampleFreq(bis_conf.bisConfiguration);
+      if (sample_freq) {
+        result.push_back(*sample_freq);
+      }
+    }
+    return result;
+  }
+
+  void VerifyBroadcastConfiguration(
+      const LeAudioBroadcastConfigurationRequirement& requirements,
+      const LeAudioBroadcastConfigurationSetting& configuration,
+      std::vector<CodecSpecificConfigurationLtv::SamplingFrequency>
+          expectedSampleFreqs = {}) {
+    std::vector<CodecSpecificConfigurationLtv::SamplingFrequency> sampleFreqs =
+        {};
+
+    int number_of_requested_bises = 0;
+    for (const auto& subgroup_req :
+         requirements.subgroupConfigurationRequirements) {
+      number_of_requested_bises += subgroup_req.bisNumPerSubgroup;
+    }
+
+    if (!expectedSampleFreqs.empty()) {
+      for (const auto& subgroup_conf : configuration.subgroupsConfigurations) {
+        auto result = GetSubgroupSampleFreqs(subgroup_conf);
+        sampleFreqs.insert(sampleFreqs.end(), result.begin(), result.end());
+      }
+    }
+
+    ASSERT_EQ(number_of_requested_bises, configuration.numBis);
+    ASSERT_EQ(requirements.subgroupConfigurationRequirements.size(),
+              configuration.subgroupsConfigurations.size());
+
+    if (expectedSampleFreqs.empty()) {
+      return;
+    }
+
+    std::sort(sampleFreqs.begin(), sampleFreqs.end());
+    std::sort(expectedSampleFreqs.begin(), expectedSampleFreqs.end());
+
+    ASSERT_EQ(sampleFreqs, expectedSampleFreqs);
+  }
+
+  LeAudioDeviceCapabilities GetDefaultBroadcastSinkCapability() {
+    // Create a capability
+    LeAudioDeviceCapabilities capability;
+
+    capability.codecId = CodecId::Core::LC3;
+
+    auto pref_context_metadata = MetadataLtv::PreferredAudioContexts();
+    pref_context_metadata.values =
+        GetAudioContext(AudioContext::MEDIA | AudioContext::CONVERSATIONAL |
+                        AudioContext::GAME);
+    capability.metadata = {pref_context_metadata};
+
+    auto sampling_rate =
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies();
+    sampling_rate.bitmask =
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ48000 |
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000;
+    auto frame_duration =
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations();
+    frame_duration.bitmask =
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500 |
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000;
+    auto octets = CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame();
+    octets.min = 0;
+    octets.max = 120;
+    auto frames = CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU();
+    frames.value = 2;
+    capability.codecSpecificCapabilities = {sampling_rate, frame_duration,
+                                            octets, frames};
+    return capability;
+  }
+
+  LeAudioBroadcastConfigurationRequirement GetBroadcastRequirement(
+      bool standard_quality, bool high_quality) {
+    LeAudioBroadcastConfigurationRequirement requirement;
+
+    AudioContext media_audio_context;
+    media_audio_context.bitmask = AudioContext::MEDIA;
+
+    LeAudioBroadcastSubgroupConfigurationRequirement
+        standard_quality_requirement = {
+            .audioContext = media_audio_context,
+            .quality = IBluetoothAudioProvider::BroadcastQuality::STANDARD,
+            .bisNumPerSubgroup = 2};
+
+    LeAudioBroadcastSubgroupConfigurationRequirement high_quality_requirement =
+        {.audioContext = media_audio_context,
+         .quality = IBluetoothAudioProvider::BroadcastQuality::HIGH,
+         .bisNumPerSubgroup = 2};
+
+    if (standard_quality) {
+      requirement.subgroupConfigurationRequirements.push_back(
+          standard_quality_requirement);
+    }
+
+    if (high_quality) {
+      requirement.subgroupConfigurationRequirements.push_back(
+          high_quality_requirement);
+    }
+    return requirement;
+  }
+
   std::vector<Lc3Configuration> GetBroadcastLc3SupportedList(bool supported) {
     std::vector<Lc3Configuration> le_audio_codec_configs;
     if (!supported) {
@@ -3164,18 +4329,93 @@
       BluetoothAudioHalVersion::VERSION_AIDL_V4) {
     GTEST_SKIP();
   }
+
+  if (!IsBroadcastOffloadSupported()) {
+    GTEST_SKIP();
+  }
+
   std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
   IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement
       empty_requirement;
 
-  IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting* configuration =
-      new IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting();
+  IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting configuration;
 
   // Check empty capability for source direction
   auto aidl_retval = audio_provider_->getLeAudioBroadcastConfiguration(
-      empty_capability, empty_requirement, configuration);
+      empty_capability, empty_requirement, &configuration);
+
+  ASSERT_FALSE(aidl_retval.isOk());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
+       GetBroadcastConfigurationEmptyCapability) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+
+  if (!IsBroadcastOffloadSupported()) {
+    GTEST_SKIP();
+  }
+
+  std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+  IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting configuration;
+
+  IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement
+      one_subgroup_requirement =
+          GetBroadcastRequirement(true /* standard*/, false /* high */);
+
+  // Check empty capability for source direction
+  auto aidl_retval = audio_provider_->getLeAudioBroadcastConfiguration(
+      empty_capability, one_subgroup_requirement, &configuration);
 
   ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_NE(configuration.numBis, 0);
+  ASSERT_FALSE(configuration.subgroupsConfigurations.empty());
+  VerifyBroadcastConfiguration(one_subgroup_requirement, configuration);
+
+  IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement
+      two_subgroup_requirement =
+          GetBroadcastRequirement(true /* standard*/, true /* high */);
+
+  // Check empty capability for source direction
+  aidl_retval = audio_provider_->getLeAudioBroadcastConfiguration(
+      empty_capability, two_subgroup_requirement, &configuration);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_NE(configuration.numBis, 0);
+  ASSERT_FALSE(configuration.subgroupsConfigurations.empty());
+  VerifyBroadcastConfiguration(two_subgroup_requirement, configuration);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
+       GetBroadcastConfigurationNonEmptyCapability) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+
+  if (!IsBroadcastOffloadSupported()) {
+    GTEST_SKIP();
+  }
+
+  std::vector<std::optional<LeAudioDeviceCapabilities>> capability = {
+      GetDefaultBroadcastSinkCapability()};
+
+  IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement
+      requirement =
+          GetBroadcastRequirement(true /* standard*/, true /* high */);
+
+  IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting configuration;
+
+  // Check empty capability for source direction
+  auto aidl_retval = audio_provider_->getLeAudioBroadcastConfiguration(
+      capability, requirement, &configuration);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_NE(configuration.numBis, 0);
+  ASSERT_FALSE(configuration.subgroupsConfigurations.empty());
+  VerifyBroadcastConfiguration(requirement, configuration);
 }
 
 /**
@@ -3186,7 +4426,7 @@
 TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
        StartAndEndLeAudioBroadcastSessionWithPossibleBroadcastConfig) {
   if (!IsBroadcastOffloadSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   auto lc3_codec_configs = GetBroadcastLc3SupportedList(true /* supported */);
@@ -3225,7 +4465,7 @@
     BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
     DISABLED_StartAndEndLeAudioBroadcastSessionWithInvalidAudioConfiguration) {
   if (!IsBroadcastOffloadSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   auto lc3_codec_configs = GetBroadcastLc3SupportedList(false /* supported */);
diff --git a/bluetooth/audio/flags/btaudiohal.aconfig b/bluetooth/audio/flags/btaudiohal.aconfig
index 4c1500a..13e2116 100644
--- a/bluetooth/audio/flags/btaudiohal.aconfig
+++ b/bluetooth/audio/flags/btaudiohal.aconfig
@@ -7,3 +7,10 @@
     description: "Flag for DSA Over LEA"
     bug: "270987427"
 }
+
+flag {
+    name: "leaudio_report_broadcast_ac_to_hal"
+    namespace: "pixel_bluetooth"
+    description: "Flag for reporting lea broadcast audio config to HAL"
+    bug: "321168976"
+}
\ No newline at end of file
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 779a90f..1661362 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -90,6 +90,9 @@
 
 cc_test {
     name: "BluetoothLeAudioCodecsProviderTest",
+    defaults: [
+        "latest_android_hardware_bluetooth_audio_ndk_shared",
+    ],
     srcs: [
         "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
         "aidl_session/BluetoothLeAudioCodecsProviderTest.cpp",
@@ -100,7 +103,6 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.bluetooth.audio-V4-ndk",
         "libxml2",
     ],
     test_suites: [
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 67ba93c..d0f2a26 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -121,18 +121,41 @@
 
 void BluetoothAudioSession::ReportAudioConfigChanged(
     const AudioConfiguration& audio_config) {
-  if (session_type_ !=
-          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
-      session_type_ !=
-          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-    return;
-  }
-
   std::lock_guard<std::recursive_mutex> guard(mutex_);
-  if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
-    LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
-               << toString(session_type_);
-    return;
+  if (com::android::btaudio::hal::flags::leaudio_report_broadcast_ac_to_hal()) {
+    if (session_type_ ==
+            SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+        session_type_ ==
+            SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+      if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
+        LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+                  << toString(session_type_);
+        return;
+      }
+    } else if (session_type_ ==
+            SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+      if (audio_config.getTag() != AudioConfiguration::leAudioBroadcastConfig) {
+        LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+                  << toString(session_type_);
+        return;
+      }
+    } else {
+      LOG(ERROR) << __func__ << " invalid SessionType ="
+                 << toString(session_type_);
+      return;
+    }
+  } else {
+    if (session_type_ !=
+            SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+        session_type_ !=
+            SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+      return;
+    }
+    if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
+      LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+                 << toString(session_type_);
+      return;
+    }
   }
 
   audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index 31e8014..ad8d4c8 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -32,6 +32,7 @@
 #include <torch_provider_cb.h>
 #include <com_android_internal_camera_flags.h>
 #include <list>
+#include <nativebase/nativebase.h>
 
 using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
 using ::aidl::android::hardware::camera::common::CameraResourceCost;
@@ -299,6 +300,15 @@
             ASSERT_TRUE(ret.isOk());
             ASSERT_NE(device, nullptr);
 
+            int32_t interfaceVersion = -1;
+            ret = device->getInterfaceVersion(&interfaceVersion);
+            ASSERT_TRUE(ret.isOk());
+            bool supportSessionCharacteristics =
+                    (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3);
+            if (!supportSessionCharacteristics) {
+                continue;
+            }
+
             CameraMetadata meta;
             openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
                                    &device /*out*/);
@@ -1675,9 +1685,9 @@
                                     BufferStatus::OK, NativeHandle(), NativeHandle()};
             } else {
                 allocateGraphicBuffer(previewStream.width, previewStream.height,
-                                      android_convertGralloc1To0Usage(
+                                      ANDROID_NATIVE_UNSIGNED_CAST(android_convertGralloc1To0Usage(
                                               static_cast<uint64_t>(halStream.producerUsage),
-                                              static_cast<uint64_t>(halStream.consumerUsage)),
+                                              static_cast<uint64_t>(halStream.consumerUsage))),
                                       halStream.overrideFormat, &buffer_handle);
                 graphicBuffers.push_back(buffer_handle);
                 outputBuffers[k] = {
@@ -1896,9 +1906,9 @@
                                         NativeHandle(), NativeHandle()};
                 } else {
                     allocateGraphicBuffer(previewStream.width, previewStream.height,
-                                          android_convertGralloc1To0Usage(
+                                          ANDROID_NATIVE_UNSIGNED_CAST(android_convertGralloc1To0Usage(
                                                   static_cast<uint64_t>(halStream.producerUsage),
-                                                  static_cast<uint64_t>(halStream.consumerUsage)),
+                                                  static_cast<uint64_t>(halStream.consumerUsage))),
                                           halStream.overrideFormat, &buffer_handle);
                     graphicBuffers.push_back(buffer_handle);
                     outputBuffers[k] = {
@@ -2064,9 +2074,9 @@
                                             NativeHandle(), BufferStatus::OK,
                                             NativeHandle(), NativeHandle()};
                     } else {
-                        auto usage = android_convertGralloc1To0Usage(
+                        auto usage = ANDROID_NATIVE_UNSIGNED_CAST(android_convertGralloc1To0Usage(
                                 static_cast<uint64_t>(halStream.producerUsage),
-                                static_cast<uint64_t>(halStream.consumerUsage));
+                                static_cast<uint64_t>(halStream.consumerUsage)));
                         allocateGraphicBuffer(previewStream.width, previewStream.height, usage,
                                               halStream.overrideFormat, &buffer_handle);
 
@@ -2285,9 +2295,9 @@
                                 NativeHandle(),   NativeHandle()};
             } else {
                 allocateGraphicBuffer(previewStream.width, previewStream.height,
-                                      android_convertGralloc1To0Usage(
+                                      ANDROID_NATIVE_UNSIGNED_CAST(android_convertGralloc1To0Usage(
                                               static_cast<uint64_t>(halStreams[0].producerUsage),
-                                              static_cast<uint64_t>(halStreams[0].consumerUsage)),
+                                              static_cast<uint64_t>(halStreams[0].consumerUsage))),
                                       halStreams[0].overrideFormat, &buffers[i]);
                 outputBuffer = {halStreams[0].id, bufferId + i,   ::android::makeToAidl(buffers[i]),
                                 BufferStatus::OK, NativeHandle(), NativeHandle()};
@@ -2385,9 +2395,9 @@
             bufferId = 0;
         } else {
             allocateGraphicBuffer(previewStream.width, previewStream.height,
-                                  android_convertGralloc1To0Usage(
+                                  ANDROID_NATIVE_UNSIGNED_CAST(android_convertGralloc1To0Usage(
                                           static_cast<uint64_t>(halStreams[0].producerUsage),
-                                          static_cast<uint64_t>(halStreams[0].consumerUsage)),
+                                          static_cast<uint64_t>(halStreams[0].consumerUsage))),
                                   halStreams[0].overrideFormat, &buffer_handle);
         }
 
@@ -2508,9 +2518,9 @@
             } else {
                 // jpeg buffer (w,h) = (blobLen, 1)
                 allocateGraphicBuffer(jpegBufferSize, /*height*/ 1,
-                                      android_convertGralloc1To0Usage(
+                                      ANDROID_NATIVE_UNSIGNED_CAST(android_convertGralloc1To0Usage(
                                               static_cast<uint64_t>(halStream.producerUsage),
-                                              static_cast<uint64_t>(halStream.consumerUsage)),
+                                              static_cast<uint64_t>(halStream.consumerUsage))),
                                       halStream.overrideFormat, &buffers[i]);
                 outputBuffer = {halStream.id,     bufferId + i,   ::android::makeToAidl(buffers[i]),
                                 BufferStatus::OK, NativeHandle(), NativeHandle()};
@@ -2734,9 +2744,9 @@
                             BufferStatus::OK, NativeHandle(), NativeHandle()};
         } else {
             allocateGraphicBuffer(previewStream.width, previewStream.height,
-                                  android_convertGralloc1To0Usage(
+                                  ANDROID_NATIVE_UNSIGNED_CAST(android_convertGralloc1To0Usage(
                                           static_cast<uint64_t>(halStreams[0].producerUsage),
-                                          static_cast<uint64_t>(halStreams[0].consumerUsage)),
+                                          static_cast<uint64_t>(halStreams[0].consumerUsage))),
                                   halStreams[0].overrideFormat, &buffer_handle);
             outputBuffer = {halStreams[0].id, bufferId,       ::android::makeToAidl(buffer_handle),
                             BufferStatus::OK, NativeHandle(), NativeHandle()};
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index a01fb04..1ad5af9 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -41,6 +41,7 @@
 #include <regex>
 #include <typeinfo>
 #include "utils/Errors.h"
+#include <nativebase/nativebase.h>
 
 using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
 using ::aidl::android::hardware::camera::common::TorchModeStatus;
@@ -2340,8 +2341,8 @@
                     /* We don't look at halStreamConfig.streams[0].consumerUsage
                      * since that is 0 for output streams
                      */
-                    android_convertGralloc1To0Usage(
-                            static_cast<uint64_t>(halStreams[0].producerUsage), bufferUsage),
+                    ANDROID_NATIVE_UNSIGNED_CAST(android_convertGralloc1To0Usage(
+                            static_cast<uint64_t>(halStreams[0].producerUsage), bufferUsage)),
                     halStreams[0].overrideFormat, &handle);
 
             outputBuffer = {halStreams[0].id, bufferId,       ::android::makeToAidl(handle),
@@ -2868,9 +2869,9 @@
                                   /* We don't look at halStreamConfig.streams[0].consumerUsage
                                    * since that is 0 for output streams
                                    */
-                                  android_convertGralloc1To0Usage(
+                                  ANDROID_NATIVE_UNSIGNED_CAST(android_convertGralloc1To0Usage(
                                           static_cast<uint64_t>(halStreams[0].producerUsage),
-                                          GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                                          GRALLOC1_CONSUMER_USAGE_HWCOMPOSER)),
                                   halStreams[0].overrideFormat, &buffer_handle);
             outputBuffer = {halStreams[0].id, bufferId,       ::android::makeToAidl(buffer_handle),
                             BufferStatus::OK, NativeHandle(), NativeHandle()};
@@ -3851,9 +3852,9 @@
                                         NativeHandle(), BufferStatus::OK,
                                         NativeHandle(), NativeHandle()};
                 } else {
-                    auto usage = android_convertGralloc1To0Usage(
+                    auto usage = ANDROID_NATIVE_UNSIGNED_CAST(android_convertGralloc1To0Usage(
                             static_cast<uint64_t>(halStream.producerUsage),
-                            static_cast<uint64_t>(halStream.consumerUsage));
+                            static_cast<uint64_t>(halStream.consumerUsage)));
                     allocateGraphicBuffer(previewStream.width, previewStream.height, usage,
                                             halStream.overrideFormat, &buffer_handle);
 
@@ -4009,9 +4010,9 @@
                                 NativeHandle(),   NativeHandle()};
             } else {
                 allocateGraphicBuffer(previewStream.width, previewStream.height,
-                                      android_convertGralloc1To0Usage(
+                                      ANDROID_NATIVE_UNSIGNED_CAST(android_convertGralloc1To0Usage(
                                               static_cast<uint64_t>(halStreams[0].producerUsage),
-                                              static_cast<uint64_t>(halStreams[0].consumerUsage)),
+                                              static_cast<uint64_t>(halStreams[0].consumerUsage))),
                                       halStreams[0].overrideFormat, &buffers[i]);
                 outputBuffer = {halStreams[0].id, bufferId + i,   ::android::makeToAidl(buffers[i]),
                                 BufferStatus::OK, NativeHandle(), NativeHandle()};
diff --git a/camera/provider/aidl/vts/device_cb.cpp b/camera/provider/aidl/vts/device_cb.cpp
index 2c11d3f..8a8b925 100644
--- a/camera/provider/aidl/vts/device_cb.cpp
+++ b/camera/provider/aidl/vts/device_cb.cpp
@@ -20,6 +20,7 @@
 #include <aidlcommonsupport/NativeHandle.h>
 #include <grallocusage/GrallocUsageConversion.h>
 #include <cinttypes>
+#include <nativebase/nativebase.h>
 
 using ::aidl::android::hardware::camera::device::BufferStatus;
 using ::aidl::android::hardware::camera::device::ErrorMsg;
@@ -143,8 +144,8 @@
 
             CameraAidlTest::allocateGraphicBuffer(
                     w, h,
-                    android_convertGralloc1To0Usage(static_cast<uint64_t>(halStream.producerUsage),
-                                                    static_cast<uint64_t>(halStream.consumerUsage)),
+                    ANDROID_NATIVE_UNSIGNED_CAST(android_convertGralloc1To0Usage(static_cast<uint64_t>(halStream.producerUsage),
+                                                    static_cast<uint64_t>(halStream.consumerUsage))),
                     halStream.overrideFormat, &handle);
 
             StreamBuffer streamBuffer = StreamBuffer();
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 11de087..431059b 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -11,6 +11,7 @@
     name: "android.hardware.common",
     host_supported: true,
     vendor_available: true,
+    product_available: true,
     double_loadable: true,
     vndk_use_version: "2",
     srcs: [
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index 17c11ab..9c1b45d 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -11,6 +11,7 @@
     name: "android.hardware.common.fmq",
     host_supported: true,
     vendor_available: true,
+    product_available: true,
     double_loadable: true,
     srcs: [
         "android/hardware/common/fmq/*.aidl",
diff --git a/common/support/Android.bp b/common/support/Android.bp
index 12ab1f7..56700fa 100644
--- a/common/support/Android.bp
+++ b/common/support/Android.bp
@@ -10,6 +10,7 @@
 cc_library_static {
     name: "libaidlcommonsupport",
     vendor_available: true,
+    product_available: true,
     host_supported: true,
     target: {
         darwin: {
diff --git a/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl
index 92328a8..dcce7ef 100644
--- a/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl
+++ b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl
@@ -38,15 +38,15 @@
      * prevented the TUI from being shut down gracefully.
      *
      * @param formattedMessage holds the prompt text and extra data.
-     *                         The message is CBOR (RFC 7049) encoded and has the following format:
-     *                         CBOR_MAP{ "prompt", <promptText>, "extra", <extraData> }
-     *                         The message is a CBOR encoded map (type 5) with the keys
-     *                         "prompt" and "extra". The keys are encoded as CBOR text string
-     *                         (type 3). The value <promptText> is encoded as CBOR text string
-     *                         (type 3), and the value <extraData> is encoded as CBOR byte string
-     *                         (type 2). The map must have exactly one key value pair for each of
-     *                         the keys "prompt" and "extra". Other keys are not allowed.
-     *                         The value of "prompt" is given by the proptText argument to
+     *                         The message is CBOR (RFC 7049) encoded and has the exact format
+     *                         given by the following CDDL:
+     *
+     *                         formattedMessage = {
+     *                             "prompt" : tstr,
+     *                             "extra" : bstr,
+     *                         }
+     *
+     *                         The value of "prompt" is given by the promptText argument to
      *                         IConfirmationUI::promptUserConfirmation and must not be modified
      *                         by the implementation.
      *                         The value of "extra" is given by the extraData argument to
@@ -59,8 +59,7 @@
      *                          the "", concatenated with the formatted message as returned in the
      *                          formattedMessage argument. The HMAC is keyed with a 256-bit secret
      *                          which is shared with Keymaster. In test mode the test key MUST be
-     *                          used (see TestModeCommands.aidl and
-     * IConfirmationUI::TEST_KEY_BYTE).
+     *                          used (see TestModeCommands.aidl and IConfirmationUI::TEST_KEY_BYTE)
      */
     void result(in int error, in byte[] formattedMessage, in byte[] confirmationToken);
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
index 2985212..1117504 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
@@ -161,8 +161,7 @@
      *
      * The allocator should examine the usage bits passed in when allocating a
      * buffer with this format, and it should derive the pixel format from
-     * those usage flags. This format must never be used with any of the
-     * BufferUsage::CPU_* usage flags.
+     * those usage flags.
      *
      * Even when the internally chosen format has an alpha component, the
      * clients must assume the alpha vlaue to be 1.0.
diff --git a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
index 336d15d..6a45987 100644
--- a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
+++ b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
@@ -33,6 +33,7 @@
 #include <string.h>
 
 #include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <android/hardware/graphics/composer/2.1/IComposerClient.h>
 #include <fmq/MessageQueue.h>
 #include <log/log.h>
 #include <sync/sync.h>
@@ -649,7 +650,8 @@
         *outLength = static_cast<uint16_t>(val & length_mask);
 
         if (mDataRead + *outLength > mDataSize) {
-            ALOGE("command 0x%x has invalid command length %" PRIu16, *outCommand, *outLength);
+            ALOGE("command %s has invalid command length %" PRIu16,
+                  toString(*outCommand).c_str(), *outLength);
             // undo the read() above
             mDataRead--;
             return false;
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
index d3842c5..da6116f 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -288,6 +288,20 @@
         return false;
     }
 
+    std::string printConfig(int config) {
+        const auto displayConfig = getDisplayConfig(config);
+        const auto vrrConfigOpt = displayConfig.vrrConfigOpt;
+        std::stringstream ss;
+        if (displayConfig.vrrConfigOpt) {
+            ss << "{Config " << config << ": vsyncPeriod " << displayConfig.vsyncPeriod
+                << ", minFrameIntervalNs " << vrrConfigOpt->minFrameIntervalNs << "}";
+        }
+        else {
+            ss << "{Config " << config << ": vsyncPeriod " << displayConfig.vsyncPeriod << "}";
+        }
+        return ss.str();
+    }
+
     std::unordered_map<int32_t, DisplayConfig> getDisplayConfigs() { return mDisplayConfigs; }
 
   private:
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index d4ce3ba..3d9253f 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -59,10 +59,12 @@
 
         EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk());
 
+        const auto format = getHasReadbackBuffer() ? mPixelFormat : common::PixelFormat::RGBA_8888;
+
         ASSERT_NO_FATAL_FAILURE(
                 mTestRenderEngine = std::unique_ptr<TestRenderEngine>(new TestRenderEngine(
                         ::android::renderengine::RenderEngineCreationArgs::Builder()
-                                .setPixelFormat(static_cast<int>(common::PixelFormat::RGBA_8888))
+                                .setPixelFormat(static_cast<int>(format))
                                 .setImageCacheSize(TestRenderEngine::sMaxFrameBufferAcquireBuffers)
                                 .setEnableProtectedContext(false)
                                 .setPrecacheToneMapperShaderOnly(false)
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index 0227e39..ba15421 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -2877,8 +2877,9 @@
             } while (--retryCount > 0);
 
             if (retryCount == 0) {
-                GTEST_FAIL() << "failed to get a callback for the display " << displayId
-                             << " with config " << config2;
+                GTEST_FAIL() << "Failed to get a callback for Display " << displayId
+                             << " switching from " << display.printConfig(config1)
+                             << " to " << display.printConfig(config2);
             }
         });
 
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/ProtectCallback.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/ProtectCallback.h
index 92ed1cd..9a7fe5e 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/ProtectCallback.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/ProtectCallback.h
@@ -56,6 +56,8 @@
 // Thread safe class
 class DeathMonitor final {
   public:
+    explicit DeathMonitor(uintptr_t cookieKey) : kCookieKey(cookieKey) {}
+
     static void serviceDied(void* cookie);
     void serviceDied();
     // Precondition: `killable` must be non-null.
@@ -63,9 +65,18 @@
     // Precondition: `killable` must be non-null.
     void remove(IProtectedCallback* killable) const;
 
+    uintptr_t getCookieKey() const { return kCookieKey; }
+
+    ~DeathMonitor();
+    DeathMonitor(const DeathMonitor&) = delete;
+    DeathMonitor(DeathMonitor&&) noexcept = delete;
+    DeathMonitor& operator=(const DeathMonitor&) = delete;
+    DeathMonitor& operator=(DeathMonitor&&) noexcept = delete;
+
   private:
     mutable std::mutex mMutex;
     mutable std::vector<IProtectedCallback*> mObjects GUARDED_BY(mMutex);
+    const uintptr_t kCookieKey;
 };
 
 class DeathHandler final {
diff --git a/neuralnetworks/aidl/utils/src/ProtectCallback.cpp b/neuralnetworks/aidl/utils/src/ProtectCallback.cpp
index 54a673c..4a7ac08 100644
--- a/neuralnetworks/aidl/utils/src/ProtectCallback.cpp
+++ b/neuralnetworks/aidl/utils/src/ProtectCallback.cpp
@@ -25,6 +25,7 @@
 
 #include <algorithm>
 #include <functional>
+#include <map>
 #include <memory>
 #include <mutex>
 #include <vector>
@@ -33,6 +34,16 @@
 
 namespace aidl::android::hardware::neuralnetworks::utils {
 
+namespace {
+
+// Only dereference the cookie if it's valid (if it's in this set)
+// Only used with ndk
+std::mutex sCookiesMutex;
+uintptr_t sCookieKeyCounter GUARDED_BY(sCookiesMutex) = 0;
+std::map<uintptr_t, std::weak_ptr<DeathMonitor>> sCookies GUARDED_BY(sCookiesMutex);
+
+}  // namespace
+
 void DeathMonitor::serviceDied() {
     std::lock_guard guard(mMutex);
     std::for_each(mObjects.begin(), mObjects.end(),
@@ -40,8 +51,24 @@
 }
 
 void DeathMonitor::serviceDied(void* cookie) {
-    auto deathMonitor = static_cast<DeathMonitor*>(cookie);
-    deathMonitor->serviceDied();
+    std::shared_ptr<DeathMonitor> monitor;
+    {
+        std::lock_guard<std::mutex> guard(sCookiesMutex);
+        if (auto it = sCookies.find(reinterpret_cast<uintptr_t>(cookie)); it != sCookies.end()) {
+            monitor = it->second.lock();
+            sCookies.erase(it);
+        } else {
+            LOG(INFO)
+                    << "Service died, but cookie is no longer valid so there is nothing to notify.";
+            return;
+        }
+    }
+    if (monitor) {
+        LOG(INFO) << "Notifying DeathMonitor from serviceDied.";
+        monitor->serviceDied();
+    } else {
+        LOG(INFO) << "Tried to notify DeathMonitor from serviceDied but could not promote.";
+    }
 }
 
 void DeathMonitor::add(IProtectedCallback* killable) const {
@@ -57,12 +84,25 @@
     mObjects.erase(removedIter);
 }
 
+DeathMonitor::~DeathMonitor() {
+    // lock must be taken so object is not used in OnBinderDied"
+    std::lock_guard<std::mutex> guard(sCookiesMutex);
+    sCookies.erase(kCookieKey);
+}
+
 nn::GeneralResult<DeathHandler> DeathHandler::create(std::shared_ptr<ndk::ICInterface> object) {
     if (object == nullptr) {
         return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
                << "utils::DeathHandler::create must have non-null object";
     }
-    auto deathMonitor = std::make_shared<DeathMonitor>();
+
+    std::shared_ptr<DeathMonitor> deathMonitor;
+    {
+        std::lock_guard<std::mutex> guard(sCookiesMutex);
+        deathMonitor = std::make_shared<DeathMonitor>(sCookieKeyCounter++);
+        sCookies[deathMonitor->getCookieKey()] = deathMonitor;
+    }
+
     auto deathRecipient = ndk::ScopedAIBinder_DeathRecipient(
             AIBinder_DeathRecipient_new(DeathMonitor::serviceDied));
 
@@ -70,8 +110,9 @@
     // STATUS_INVALID_OPERATION. We ignore this case because we only use local binders in tests
     // where this is not an error.
     if (object->isRemote()) {
-        const auto ret = ndk::ScopedAStatus::fromStatus(AIBinder_linkToDeath(
-                object->asBinder().get(), deathRecipient.get(), deathMonitor.get()));
+        const auto ret = ndk::ScopedAStatus::fromStatus(
+                AIBinder_linkToDeath(object->asBinder().get(), deathRecipient.get(),
+                                     reinterpret_cast<void*>(deathMonitor->getCookieKey())));
         HANDLE_ASTATUS(ret) << "AIBinder_linkToDeath failed";
     }
 
@@ -91,8 +132,9 @@
 
 DeathHandler::~DeathHandler() {
     if (kObject != nullptr && kDeathRecipient.get() != nullptr && kDeathMonitor != nullptr) {
-        const auto ret = ndk::ScopedAStatus::fromStatus(AIBinder_unlinkToDeath(
-                kObject->asBinder().get(), kDeathRecipient.get(), kDeathMonitor.get()));
+        const auto ret = ndk::ScopedAStatus::fromStatus(
+                AIBinder_unlinkToDeath(kObject->asBinder().get(), kDeathRecipient.get(),
+                                       reinterpret_cast<void*>(kDeathMonitor->getCookieKey())));
         const auto maybeSuccess = handleTransportError(ret);
         if (!maybeSuccess.ok()) {
             LOG(ERROR) << maybeSuccess.error().message;
diff --git a/neuralnetworks/aidl/utils/test/DeviceTest.cpp b/neuralnetworks/aidl/utils/test/DeviceTest.cpp
index 73727b3..ffd3b8e 100644
--- a/neuralnetworks/aidl/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/aidl/utils/test/DeviceTest.cpp
@@ -697,7 +697,8 @@
     const auto mockDevice = createMockDevice();
     const auto device = Device::create(kName, mockDevice, kVersion).value();
     const auto ret = [&device]() {
-        DeathMonitor::serviceDied(device->getDeathMonitor());
+        DeathMonitor::serviceDied(
+                reinterpret_cast<void*>(device->getDeathMonitor()->getCookieKey()));
         return ndk::ScopedAStatus::ok();
     };
     EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _))
@@ -846,7 +847,8 @@
     const auto mockDevice = createMockDevice();
     const auto device = Device::create(kName, mockDevice, kVersion).value();
     const auto ret = [&device]() {
-        DeathMonitor::serviceDied(device->getDeathMonitor());
+        DeathMonitor::serviceDied(
+                reinterpret_cast<void*>(device->getDeathMonitor()->getCookieKey()));
         return ndk::ScopedAStatus::ok();
     };
     EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
@@ -970,7 +972,8 @@
     const auto mockDevice = createMockDevice();
     const auto device = Device::create(kName, mockDevice, kVersion).value();
     const auto ret = [&device]() {
-        DeathMonitor::serviceDied(device->getDeathMonitor());
+        DeathMonitor::serviceDied(
+                reinterpret_cast<void*>(device->getDeathMonitor()->getCookieKey()));
         return ndk::ScopedAStatus::ok();
     };
     EXPECT_CALL(*mockDevice, prepareModelFromCache(_, _, _, _, _))
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index 3d3abe4..e4db40c 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -519,26 +519,38 @@
 TEST_P(RadioHidlTest_v1_5, setSystemSelectionChannels_1_5) {
     serial = GetRandomSerialNumber();
 
-    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands bandP900;
-    bandP900.geranBands() = {GeranBands::BAND_P900};
-    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands band850;
-    band850.geranBands() = {GeranBands::BAND_850};
-    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifierP900 = {
-            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN,
-            .bands = bandP900,
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands band3;
+    band3.eutranBands({::android::hardware::radio::V1_5::EutranBands::BAND_3});
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands band17;
+    band17.eutranBands({::android::hardware::radio::V1_5::EutranBands::BAND_17});
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands band20;
+    band20.eutranBands({::android::hardware::radio::V1_5::EutranBands::BAND_20});
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands band40;
+    band40.eutranBands({::android::hardware::radio::V1_5::EutranBands::BAND_40});
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier3 = {
+            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::EUTRAN,
+            .bands = band3,
             .channels = {1, 2}};
-    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier850 = {
-            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN,
-            .bands = band850,
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier17 = {
+            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::EUTRAN,
+            .bands = band17,
+            .channels = {1, 2}};
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier20 = {
+            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::EUTRAN,
+            .bands = band20,
+            .channels = {128, 129}};
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier40 = {
+            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::EUTRAN,
+            .bands = band40,
             .channels = {128, 129}};
 
-    Return<void> res =
-            radio_v1_5->setSystemSelectionChannels_1_5(serial, true, {specifierP900, specifier850});
+    Return<void> res = radio_v1_5->setSystemSelectionChannels_1_5(
+            serial, true, {specifier3, specifier17, specifier20, specifier40});
     ASSERT_OK(res);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
-    ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n",
+    ALOGI("setSystemSelectionChannels_1_5, rspInfo.error = %s\n",
           toString(radioRsp_v1_5->rspInfo.error).c_str());
     ASSERT_TRUE(CheckAnyOfErrors(
             radioRsp_v1_5->rspInfo.error,
@@ -547,12 +559,12 @@
     if (radioRsp_v1_5->rspInfo.error == RadioError::NONE) {
         serial = GetRandomSerialNumber();
         Return<void> res = radio_v1_5->setSystemSelectionChannels_1_5(
-                serial, false, {specifierP900, specifier850});
+                serial, false, {specifier3, specifier17, specifier20, specifier40});
         ASSERT_OK(res);
         EXPECT_EQ(std::cv_status::no_timeout, wait());
         EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
         EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
-        ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n",
+        ALOGI("setSystemSelectionChannels_1_5, rspInfo.error = %s\n",
               toString(radioRsp_v1_5->rspInfo.error).c_str());
         EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
     }
@@ -1190,11 +1202,12 @@
 
     // can't camp on nonexistent MCCMNC, so we expect this to fail.
     Return<void> res = radio_v1_5->setNetworkSelectionModeManual_1_5(
-            serial, "123456", android::hardware::radio::V1_5::RadioAccessNetworks::GERAN);
+            serial, "123456", android::hardware::radio::V1_5::RadioAccessNetworks::EUTRAN);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
-
+    ALOGI("setNetworkSelectionModeManual_1_5, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
     if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME,
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
index d9eea03..b67e8e0 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -747,6 +747,7 @@
 
     /**
      * Response of isCellularIdentifierTransparencyEnabled.
+     * This is an optional API.
      *
      * @param info Response info struct containing response type, serial no. and error.
      * @param isEnabled Indicates whether cellular identifier transparency is enabled or not.
@@ -757,12 +758,14 @@
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
+     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void isCellularIdentifierTransparencyEnabledResponse(
             in RadioResponseInfo info, boolean isEnabled);
 
     /**
      * Response of setCellularIdentifierTransparencyEnabled.
+     * This is an optional API.
      *
      * @param info Response info struct containing response type, serial no. and error.
      *
@@ -773,11 +776,13 @@
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
      *   RadioError:INVALID_STATE
+     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void setCellularIdentifierTransparencyEnabledResponse(in RadioResponseInfo info);
 
     /**
      * Response of setSecurityAlgorithmsUpdatedEnabled.
+     * This is an optional API.
      *
      * @param info Response info struct containing response type, serial no. and error.
      *
@@ -788,11 +793,13 @@
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
      *   RadioError:INVALID_STATE
+     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void setSecurityAlgorithmsUpdatedEnabledResponse(in RadioResponseInfo info);
 
     /**
      * Response of isSecurityAlgorithmsUpdatedEnabled.
+     * This is an optional API.
      *
      * @param info Response info struct containing response type, serial no. and error.
      * @param isEnabled Indicates whether cellular ciphering transparency is enabled or not.
@@ -803,6 +810,7 @@
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
+     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void isSecurityAlgorithmsUpdatedEnabledResponse(
             in RadioResponseInfo info, in boolean isEnabled);
diff --git a/radio/aidl/vts/radio_config_test.cpp b/radio/aidl/vts/radio_config_test.cpp
index 6f18d18..e7214e5 100644
--- a/radio/aidl/vts/radio_config_test.cpp
+++ b/radio/aidl/vts/radio_config_test.cpp
@@ -278,7 +278,14 @@
                     EXPECT_LT(logicalSlotId, slotPortMappingList.size());
                     if (logicalSlotId >= 0 && logicalSlotId < slotPortMappingList.size()) {
                         slotPortMappingList[logicalSlotId].physicalSlotId = i;
-                        slotPortMappingList[logicalSlotId].portId = j;
+                        if (radioRsp_config->simSlotStatus[i].supportedMepMode ==
+                                    MultipleEnabledProfilesMode::MEP_A1 ||
+                            radioRsp_config->simSlotStatus[i].supportedMepMode ==
+                                    MultipleEnabledProfilesMode::MEP_A2) {
+                            slotPortMappingList[logicalSlotId].portId = j + 1;
+                        } else {
+                            slotPortMappingList[logicalSlotId].portId = j;
+                        }
                     }
                 }
             }
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index fd8512f..b214401 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -2195,6 +2195,18 @@
 
     serial = GetRandomSerialNumber();
 
+    radio_network->setEmergencyMode(serial, EmergencyMode::EMERGENCY_WWAN);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_network->rspInfo.error,
+            {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED, RadioError::RADIO_NOT_AVAILABLE,
+             RadioError::MODEM_ERR, RadioError::INVALID_ARGUMENTS}));
+
+    serial = GetRandomSerialNumber();
+
     EmergencyNetworkScanTrigger scanRequest;
     scanRequest.accessNetwork = {AccessNetwork::EUTRAN};
     scanRequest.scanType = EmergencyScanType::NO_PREFERENCE;
@@ -2208,6 +2220,19 @@
             radioRsp_network->rspInfo.error,
             {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED, RadioError::RADIO_NOT_AVAILABLE,
              RadioError::MODEM_ERR, RadioError::INVALID_ARGUMENTS}));
+
+    // exit emergency mode for other tests
+    serial = GetRandomSerialNumber();
+
+    radio_network->exitEmergencyMode(serial);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                 {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED,
+                                  RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
 }
 
 /*
@@ -2434,9 +2459,9 @@
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
 
-    ASSERT_TRUE(CheckAnyOfErrors(
-            radioRsp_network->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                  RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
 }
 
 TEST_P(RadioNetworkTest, setCellularIdentifierTransparencyEnabled) {
@@ -2465,9 +2490,9 @@
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
 
-    ASSERT_TRUE(CheckAnyOfErrors(
-            radioRsp_network->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                  RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
 
     // Assert the value has changed
     serial = GetRandomSerialNumber();
@@ -2477,9 +2502,9 @@
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
-    ASSERT_TRUE(CheckAnyOfErrors(
-            radioRsp_network->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                  RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
     EXPECT_EQ(valueToSet, radioRsp_network->isCellularIdentifierTransparencyEnabled);
 
     // Reset original state
@@ -2518,9 +2543,9 @@
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
 
-    ASSERT_TRUE(CheckAnyOfErrors(
-            radioRsp_network->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                  RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
 
     // Assert the value has changed
     serial = GetRandomSerialNumber();
@@ -2530,9 +2555,9 @@
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
-    ASSERT_TRUE(CheckAnyOfErrors(
-            radioRsp_network->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                  RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
     EXPECT_EQ(valueToSet, radioRsp_network->isSecurityAlgorithmsUpdatedEnabled);
 
     // Reset original state
@@ -2564,7 +2589,7 @@
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
 
-    ASSERT_TRUE(CheckAnyOfErrors(
-            radioRsp_network->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                  RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
 }
diff --git a/security/keymint/aidl/default/main.rs b/security/keymint/aidl/default/main.rs
index 47143f4..007aded 100644
--- a/security/keymint/aidl/default/main.rs
+++ b/security/keymint/aidl/default/main.rs
@@ -74,6 +74,35 @@
     // Create a TA in-process, which acts as a local channel for communication.
     let channel = Arc::new(Mutex::new(LocalTa::new()));
 
+    // Let the TA know information about the boot environment. In a real device this
+    // is communicated directly from the bootloader to the TA, but here we retrieve
+    // the information from system properties and send from the HAL service.
+    let boot_req = get_boot_info();
+    debug!("boot/HAL->TA: boot info is {:?}", boot_req);
+    kmr_hal::send_boot_info(channel.lock().unwrap().deref_mut(), boot_req)
+        .map_err(|e| HalServiceError(format!("Failed to send boot info: {:?}", e)))?;
+
+    // Let the TA know information about the userspace environment.
+    if let Err(e) = kmr_hal::send_hal_info(channel.lock().unwrap().deref_mut()) {
+        error!("Failed to send HAL info: {:?}", e);
+    }
+
+    // Let the TA know about attestation IDs. (In a real device these would be pre-provisioned into
+    // the TA.)
+    let attest_ids = attestation_id_info();
+    if let Err(e) = kmr_hal::send_attest_ids(channel.lock().unwrap().deref_mut(), attest_ids) {
+        error!("Failed to send attestation ID info: {:?}", e);
+    }
+
+    let secret_service = kmr_hal::sharedsecret::Device::new_as_binder(channel.clone());
+    let service_name = format!("{}/{}", SECRET_SERVICE_NAME, SERVICE_INSTANCE);
+    binder::add_service(&service_name, secret_service.as_binder()).map_err(|e| {
+        HalServiceError(format!(
+            "Failed to register service {} because of {:?}.",
+            service_name, e
+        ))
+    })?;
+
     let km_service = kmr_hal::keymint::Device::new_as_binder(channel.clone());
     let service_name = format!("{}/{}", KM_SERVICE_NAME, SERVICE_INSTANCE);
     binder::add_service(&service_name, km_service.as_binder()).map_err(|e| {
@@ -101,37 +130,6 @@
         ))
     })?;
 
-    let secret_service = kmr_hal::sharedsecret::Device::new_as_binder(channel.clone());
-    let service_name = format!("{}/{}", SECRET_SERVICE_NAME, SERVICE_INSTANCE);
-    binder::add_service(&service_name, secret_service.as_binder()).map_err(|e| {
-        HalServiceError(format!(
-            "Failed to register service {} because of {:?}.",
-            service_name, e
-        ))
-    })?;
-
-    info!("Successfully registered KeyMint HAL services.");
-
-    // Let the TA know information about the boot environment. In a real device this
-    // is communicated directly from the bootloader to the TA, but here we retrieve
-    // the information from system properties and send from the HAL service.
-    let boot_req = get_boot_info();
-    debug!("boot/HAL->TA: boot info is {:?}", boot_req);
-    kmr_hal::send_boot_info(channel.lock().unwrap().deref_mut(), boot_req)
-        .map_err(|e| HalServiceError(format!("Failed to send boot info: {:?}", e)))?;
-
-    // Let the TA know information about the userspace environment.
-    if let Err(e) = kmr_hal::send_hal_info(channel.lock().unwrap().deref_mut()) {
-        error!("Failed to send HAL info: {:?}", e);
-    }
-
-    // Let the TA know about attestation IDs. (In a real device these would be pre-provisioned into
-    // the TA.)
-    let attest_ids = attestation_id_info();
-    if let Err(e) = kmr_hal::send_attest_ids(channel.lock().unwrap().deref_mut(), attest_ids) {
-        error!("Failed to send attestation ID info: {:?}", e);
-    }
-
     info!("Successfully registered KeyMint HAL services.");
     binder::ProcessState::join_thread_pool();
     info!("KeyMint HAL service is terminating."); // should not reach here
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 65a4645..35e5e84 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -8917,13 +8917,6 @@
 using aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase;
 
 int main(int argc, char** argv) {
-    std::cout << "Testing ";
-    auto halInstances = KeyMintAidlTestBase::build_params();
-    std::cout << "HAL instances:\n";
-    for (auto& entry : halInstances) {
-        std::cout << "    " << entry << '\n';
-    }
-
     ::testing::InitGoogleTest(&argc, argv);
     for (int i = 1; i < argc; ++i) {
         if (argv[i][0] == '-') {
diff --git a/security/keymint/support/fuzzer/Android.bp b/security/keymint/support/fuzzer/Android.bp
new file mode 100644
index 0000000..1b1a580
--- /dev/null
+++ b/security/keymint/support/fuzzer/Android.bp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2024 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.
+ *
+ */
+
+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"],
+    default_team: "trendy_team_android_hardware_backed_security",
+}
+
+cc_defaults {
+    name: "keymint_fuzzer_defaults",
+    static_libs: [
+        "libhidlbase",
+        "libkeymint_support",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcrypto",
+        "libutils",
+        "libhardware",
+        "libbinder_ndk",
+        "liblog",
+    ],
+    defaults: [
+        "keymint_use_latest_hal_aidl_ndk_shared",
+    ],
+    include_dirs: [
+        "hardware/interfaces/security/keymint/support/include",
+        "frameworks/native/libs/binder/ndk/include_platform",
+    ],
+}
+
+cc_fuzz {
+    name: "keymint_attestation_fuzzer",
+    srcs: [
+        "keymint_attestation_fuzzer.cpp",
+    ],
+    defaults: [
+        "keymint_fuzzer_defaults",
+    ],
+}
+
+cc_fuzz {
+    name: "keymint_authSet_fuzzer",
+    srcs: [
+        "keymint_authSet_fuzzer.cpp",
+    ],
+    defaults: [
+        "keymint_fuzzer_defaults",
+    ],
+}
diff --git a/security/keymint/support/fuzzer/README.md b/security/keymint/support/fuzzer/README.md
new file mode 100644
index 0000000..d41af08
--- /dev/null
+++ b/security/keymint/support/fuzzer/README.md
@@ -0,0 +1,79 @@
+# Fuzzers for libkeymint_support
+
+## Plugin Design Considerations
+The fuzzer plugins for libkeymint_support are designed based on the understanding of the source code and try to achieve the following:
+
+#### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on incoming data. This ensures more code paths are reached by the fuzzers.
+
+#### Maximize utilization of input data
+The plugins feed the entire input data to the module. This ensures that the plugins tolerate any kind of input (empty, huge, malformed, etc) and dont `exit()` on any input and thereby increasing the chance of identifying vulnerabilities.
+
+## Table of contents
++ [keymint_attestation_fuzzer](#KeyMintAttestation)
++ [keymint_authSet_fuzzer](#KeyMintAuthSet)
+
+# <a name="KeyMintAttestation"></a> Fuzzer for KeyMintAttestation
+KeyMintAttestation supports the following parameters:
+1. PaddingMode(parameter name: "padding")
+2. Digest(parameter name: "digest")
+3. Index(parameter name: "idx")
+4. Timestamp(parameter name: "timestamp")
+5. AuthSet(parameter name: "authSet")
+6. IssuerSubjectName(parameter name: "issuerSubjectName")
+7. AttestationChallenge(parameter name: "challenge")
+8. AttestationApplicationId(parameter name: "id")
+9. EcCurve(parameter name: "ecCurve")
+10. BlockMode(parameter name: "blockmode")
+11. minMacLength(parameter name: "minMacLength")
+12. macLength(parameter name: "macLength")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |--------------| -------------------- |
+|`padding`| `PaddingMode` |Value obtained from FuzzedDataProvider|
+|`digest`| `Digest` |Value obtained from FuzzedDataProvider|
+|`idx`| `size_t` |Value obtained from FuzzedDataProvider|
+|`timestamp`| `uint64_t` |Value obtained from FuzzedDataProvider|
+|`authSet`| `uint32_t` |Value obtained from FuzzedDataProvider|
+|`issuerSubjectName`| `uint8_t` |Value obtained from FuzzedDataProvider|
+|`AttestationChallenge`| `string` |Value obtained from FuzzedDataProvider|
+|`AttestationApplicationId`| `string` |Value obtained from FuzzedDataProvider|
+|`blockmode`| `BlockMode` |Value obtained from FuzzedDataProvider|
+|`minMacLength`| `uint32_t` |Value obtained from FuzzedDataProvider|
+|`macLength`| `uint32_t` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) keymint_attestation_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/keymint_attestation_fuzzer/keymint_attestation_fuzzer
+```
+
+# <a name="KeyMintAuthSet"></a> Fuzzer for KeyMintAuthSet
+KeyMintAuthSet supports the following parameters:
+1. AuthorizationSet(parameter name: "authSet")
+2. AuthorizationSet(parameter name: "params")
+3. KeyParameters(parameter name: "numKeyParam")
+4. Tag(parameter name: "tag")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |--------------| -------------------- |
+|`authSet`| `AuthorizationSet` |Value obtained from FuzzedDataProvider|
+|`params`| `AuthorizationSet` |Value obtained from FuzzedDataProvider|
+|`numKeyParam`| `size_t` |Value obtained from FuzzedDataProvider|
+|`tag`| `Tag` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) keymint_authSet_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/keymint_authSet_fuzzer/keymint_authSet_fuzzer
+```
diff --git a/security/keymint/support/fuzzer/keymint_attestation_fuzzer.cpp b/security/keymint/support/fuzzer/keymint_attestation_fuzzer.cpp
new file mode 100644
index 0000000..bd781ac
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_attestation_fuzzer.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2024 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.
+ *
+ */
+
+#include <aidl/android/hardware/security/keymint/AttestationKey.h>
+#include <aidl/android/hardware/security/keymint/KeyCreationResult.h>
+#include <android/binder_manager.h>
+#include <keymint_common.h>
+#include <keymint_support/attestation_record.h>
+#include <keymint_support/openssl_utils.h>
+#include <utils/Log.h>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+using namespace android;
+using AStatus = ::ndk::ScopedAStatus;
+std::shared_ptr<IKeyMintDevice> gKeyMint = nullptr;
+
+constexpr size_t kMaxBytes = 256;
+const std::string kServiceName = "android.hardware.security.keymint.IKeyMintDevice/default";
+
+class KeyMintAttestationFuzzer {
+  public:
+    KeyMintAttestationFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void process();
+
+  private:
+    KeyCreationResult generateKey(const AuthorizationSet& keyDesc,
+                                  const std::optional<AttestationKey>& attestKey,
+                                  vector<uint8_t>* keyBlob,
+                                  vector<KeyCharacteristics>* keyCharacteristics,
+                                  vector<Certificate>* certChain);
+    X509_Ptr parseCertificateBlob(const vector<uint8_t>& blob);
+    ASN1_OCTET_STRING* getAttestationRecord(const X509* certificate);
+    bool verifyAttestationRecord(const vector<uint8_t>& attestationCert);
+    FuzzedDataProvider mFdp;
+};
+
+KeyCreationResult KeyMintAttestationFuzzer::generateKey(
+        const AuthorizationSet& keyDesc, const std::optional<AttestationKey>& attestKey,
+        vector<uint8_t>* keyBlob, vector<KeyCharacteristics>* keyCharacteristics,
+        vector<Certificate>* certChain) {
+    KeyCreationResult creationResult;
+    AStatus result = gKeyMint->generateKey(keyDesc.vector_data(), attestKey, &creationResult);
+    if (result.isOk() && creationResult.keyBlob.size() > 0) {
+        *keyBlob = std::move(creationResult.keyBlob);
+        *keyCharacteristics = std::move(creationResult.keyCharacteristics);
+        *certChain = std::move(creationResult.certificateChain);
+    }
+    return creationResult;
+}
+
+X509_Ptr KeyMintAttestationFuzzer::parseCertificateBlob(const vector<uint8_t>& blob) {
+    const uint8_t* data = blob.data();
+    return X509_Ptr(d2i_X509(nullptr, &data, blob.size()));
+}
+
+ASN1_OCTET_STRING* KeyMintAttestationFuzzer::getAttestationRecord(const X509* certificate) {
+    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+    if (!oid.get()) {
+        return nullptr;
+    }
+
+    int32_t location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+    if (location == -1) {
+        return nullptr;
+    }
+
+    X509_EXTENSION* attestRecordExt = X509_get_ext(certificate, location);
+    if (!attestRecordExt) {
+        return nullptr;
+    }
+
+    ASN1_OCTET_STRING* attestRecord = X509_EXTENSION_get_data(attestRecordExt);
+    return attestRecord;
+}
+
+bool KeyMintAttestationFuzzer::verifyAttestationRecord(const vector<uint8_t>& attestationCert) {
+    X509_Ptr cert(parseCertificateBlob(attestationCert));
+    if (!cert.get()) {
+        return false;
+    }
+
+    ASN1_OCTET_STRING* attestRecord = getAttestationRecord(cert.get());
+    if (!attestRecord) {
+        return false;
+    }
+
+    AuthorizationSet attestationSwEnforced;
+    AuthorizationSet attestationHwEnforced;
+    SecurityLevel attestationSecurityLevel;
+    SecurityLevel keymintSecurityLevel;
+    vector<uint8_t> attestationChallenge;
+    vector<uint8_t> attestationUniqueId;
+    uint32_t attestationVersion;
+    uint32_t keymintVersion;
+
+    auto error = parse_attestation_record(attestRecord->data, attestRecord->length,
+                                          &attestationVersion, &attestationSecurityLevel,
+                                          &keymintVersion, &keymintSecurityLevel,
+                                          &attestationChallenge, &attestationSwEnforced,
+                                          &attestationHwEnforced, &attestationUniqueId);
+    if (error != ErrorCode::OK) {
+        return false;
+    }
+
+    VerifiedBoot verifiedBootState;
+    vector<uint8_t> verifiedBootKey;
+    vector<uint8_t> verifiedBootHash;
+    bool device_locked;
+
+    error = parse_root_of_trust(attestRecord->data, attestRecord->length, &verifiedBootKey,
+                                &verifiedBootState, &device_locked, &verifiedBootHash);
+    if (error != ErrorCode::OK) {
+        return false;
+    }
+    return true;
+}
+
+void KeyMintAttestationFuzzer::process() {
+    AttestationKey attestKey;
+    vector<Certificate> attestKeyCertChain;
+    vector<KeyCharacteristics> attestKeyCharacteristics;
+    generateKey(createAuthSetForAttestKey(&mFdp), {}, &attestKey.keyBlob, &attestKeyCharacteristics,
+                &attestKeyCertChain);
+
+    vector<Certificate> attestedKeyCertChain;
+    vector<KeyCharacteristics> attestedKeyCharacteristics;
+    vector<uint8_t> attestedKeyBlob;
+    attestKey.issuerSubjectName = mFdp.ConsumeBytes<uint8_t>(kMaxBytes);
+    generateKey(createAuthorizationSet(&mFdp), attestKey, &attestedKeyBlob,
+                &attestedKeyCharacteristics, &attestedKeyCertChain);
+
+    if (attestedKeyCertChain.size() > 0) {
+        size_t leafCert = attestedKeyCertChain.size() - 1;
+        verifyAttestationRecord(attestedKeyCertChain[leafCert].encodedCertificate);
+    }
+}
+
+extern "C" int LLVMFuzzerInitialize(int /* *argc */, char /* ***argv */) {
+    ::ndk::SpAIBinder binder(AServiceManager_waitForService(kServiceName.c_str()));
+    gKeyMint = std::move(IKeyMintDevice::fromBinder(binder));
+    LOG_ALWAYS_FATAL_IF(!gKeyMint, "Failed to get IKeyMintDevice instance.");
+    return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    KeyMintAttestationFuzzer kmAttestationFuzzer(data, size);
+    kmAttestationFuzzer.process();
+    return 0;
+}
+
+}  // namespace android::hardware::security::keymint_support::fuzzer
diff --git a/security/keymint/support/fuzzer/keymint_authSet_fuzzer.cpp b/security/keymint/support/fuzzer/keymint_authSet_fuzzer.cpp
new file mode 100644
index 0000000..fcc3d91
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_authSet_fuzzer.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2024 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.
+ *
+ */
+#include <keymint_common.h>
+#include <fstream>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+
+constexpr size_t kMinAction = 0;
+constexpr size_t kMaxAction = 10;
+constexpr size_t kMinKeyParameter = 1;
+constexpr size_t kMaxKeyParameter = 10;
+
+constexpr Tag kTagArray[] = {Tag::INVALID,
+                             Tag::PURPOSE,
+                             Tag::ALGORITHM,
+                             Tag::KEY_SIZE,
+                             Tag::BLOCK_MODE,
+                             Tag::DIGEST,
+                             Tag::PADDING,
+                             Tag::CALLER_NONCE,
+                             Tag::MIN_MAC_LENGTH,
+                             Tag::EC_CURVE,
+                             Tag::RSA_PUBLIC_EXPONENT,
+                             Tag::INCLUDE_UNIQUE_ID,
+                             Tag::RSA_OAEP_MGF_DIGEST,
+                             Tag::BOOTLOADER_ONLY,
+                             Tag::ROLLBACK_RESISTANCE,
+                             Tag::HARDWARE_TYPE,
+                             Tag::EARLY_BOOT_ONLY,
+                             Tag::ACTIVE_DATETIME,
+                             Tag::ORIGINATION_EXPIRE_DATETIME,
+                             Tag::USAGE_EXPIRE_DATETIME,
+                             Tag::MIN_SECONDS_BETWEEN_OPS,
+                             Tag::MAX_USES_PER_BOOT,
+                             Tag::USAGE_COUNT_LIMIT,
+                             Tag::USER_ID,
+                             Tag::USER_SECURE_ID,
+                             Tag::NO_AUTH_REQUIRED,
+                             Tag::USER_AUTH_TYPE,
+                             Tag::AUTH_TIMEOUT,
+                             Tag::ALLOW_WHILE_ON_BODY,
+                             Tag::TRUSTED_USER_PRESENCE_REQUIRED,
+                             Tag::TRUSTED_CONFIRMATION_REQUIRED,
+                             Tag::UNLOCKED_DEVICE_REQUIRED,
+                             Tag::APPLICATION_ID,
+                             Tag::APPLICATION_DATA,
+                             Tag::CREATION_DATETIME,
+                             Tag::ORIGIN,
+                             Tag::ROOT_OF_TRUST,
+                             Tag::OS_VERSION,
+                             Tag::OS_PATCHLEVEL,
+                             Tag::UNIQUE_ID,
+                             Tag::ATTESTATION_CHALLENGE,
+                             Tag::ATTESTATION_APPLICATION_ID,
+                             Tag::ATTESTATION_ID_BRAND,
+                             Tag::ATTESTATION_ID_DEVICE,
+                             Tag::ATTESTATION_ID_PRODUCT,
+                             Tag::ATTESTATION_ID_SERIAL,
+                             Tag::ATTESTATION_ID_IMEI,
+                             Tag::ATTESTATION_ID_MEID,
+                             Tag::ATTESTATION_ID_MANUFACTURER,
+                             Tag::ATTESTATION_ID_MODEL,
+                             Tag::VENDOR_PATCHLEVEL,
+                             Tag::BOOT_PATCHLEVEL,
+                             Tag::DEVICE_UNIQUE_ATTESTATION,
+                             Tag::IDENTITY_CREDENTIAL_KEY,
+                             Tag::STORAGE_KEY,
+                             Tag::ASSOCIATED_DATA,
+                             Tag::NONCE,
+                             Tag::MAC_LENGTH,
+                             Tag::RESET_SINCE_ID_ROTATION,
+                             Tag::CONFIRMATION_TOKEN,
+                             Tag::CERTIFICATE_SERIAL,
+                             Tag::CERTIFICATE_SUBJECT,
+                             Tag::CERTIFICATE_NOT_BEFORE,
+                             Tag::CERTIFICATE_NOT_AFTER,
+                             Tag::MAX_BOOT_LEVEL};
+
+class KeyMintAuthSetFuzzer {
+  public:
+    KeyMintAuthSetFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void process();
+
+  private:
+    FuzzedDataProvider mFdp;
+};
+
+void KeyMintAuthSetFuzzer::process() {
+    AuthorizationSet authSet = createAuthorizationSet(&mFdp);
+    while (mFdp.remaining_bytes()) {
+        auto invokeAuthSetAPI = mFdp.PickValueInArray<const std::function<void()>>({
+                [&]() { authSet.Sort(); },
+                [&]() { authSet.Deduplicate(); },
+                [&]() { authSet.Union(createAuthorizationSet(&mFdp)); },
+                [&]() { authSet.Subtract(createAuthorizationSet(&mFdp)); },
+                [&]() {  // invoke push_back()
+                    AuthorizationSetBuilder builder = AuthorizationSetBuilder();
+                    for (const KeyParameter& tag : authSet) {
+                        builder.push_back(tag);
+                    }
+                    AuthorizationSet params = createAuthorizationSet(&mFdp);
+                    authSet.push_back(params);
+                },
+                [&]() {  // invoke copy constructor
+                    auto params = AuthorizationSetBuilder().Authorizations(authSet);
+                    authSet = params;
+                },
+                [&]() {  // invoke move constructor
+                    auto params = AuthorizationSetBuilder().Authorizations(authSet);
+                    authSet = std::move(params);
+                },
+                [&]() {  // invoke Constructor from vector<KeyParameter>
+                    vector<KeyParameter> keyParam;
+                    size_t numKeyParam =
+                            mFdp.ConsumeIntegralInRange<size_t>(kMinKeyParameter, kMaxKeyParameter);
+                    keyParam.resize(numKeyParam);
+                    for (size_t idx = 0; idx < numKeyParam - 1; ++idx) {
+                        keyParam[idx].tag = mFdp.PickValueInArray(kTagArray);
+                    }
+                    if (mFdp.ConsumeBool()) {
+                        AuthorizationSet auths(keyParam);
+                        auths.push_back(AuthorizationSet(keyParam));
+                    } else {  // invoke operator=
+                        AuthorizationSet auths = keyParam;
+                    }
+                },
+                [&]() {  // invoke 'Contains()'
+                    Tag tag = Tag::INVALID;
+                    if (authSet.size() > 0) {
+                        tag = authSet[mFdp.ConsumeIntegralInRange<size_t>(0, authSet.size() - 1)]
+                                      .tag;
+                    }
+                    authSet.Contains(mFdp.ConsumeBool() ? tag : mFdp.PickValueInArray(kTagArray));
+                },
+                [&]() {  // invoke 'GetTagCount()'
+                    Tag tag = Tag::INVALID;
+                    if (authSet.size() > 0) {
+                        tag = authSet[mFdp.ConsumeIntegralInRange<size_t>(0, authSet.size() - 1)]
+                                      .tag;
+                    }
+                    authSet.GetTagCount(mFdp.ConsumeBool() ? tag
+                                                           : mFdp.PickValueInArray(kTagArray));
+                },
+                [&]() {  // invoke 'erase()'
+                    if (authSet.size() > 0) {
+                        authSet.erase(mFdp.ConsumeIntegralInRange<size_t>(0, authSet.size() - 1));
+                    }
+                },
+        });
+        invokeAuthSetAPI();
+    }
+    authSet.Clear();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    KeyMintAuthSetFuzzer kmAuthSetFuzzer(data, size);
+    kmAuthSetFuzzer.process();
+    return 0;
+}
+
+}  // namespace android::hardware::security::keymint_support::fuzzer
diff --git a/security/keymint/support/fuzzer/keymint_common.h b/security/keymint/support/fuzzer/keymint_common.h
new file mode 100644
index 0000000..5c30e38
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_common.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2024 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.
+ *
+ */
+#ifndef __KEYMINT_COMMON_H__
+#define __KEYMINT_COMMON_H__
+
+#include <aidl/android/hardware/security/keymint/BlockMode.h>
+#include <aidl/android/hardware/security/keymint/Digest.h>
+#include <aidl/android/hardware/security/keymint/EcCurve.h>
+#include <aidl/android/hardware/security/keymint/PaddingMode.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <keymint_support/authorization_set.h>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+
+using namespace aidl::android::hardware::security::keymint;
+
+constexpr uint32_t kStringSize = 64;
+constexpr uint32_t k3DesKeySize = 168;
+constexpr uint32_t kSymmKeySize = 256;
+constexpr uint32_t kRsaKeySize = 2048;
+constexpr uint32_t kPublicExponent = 65537;
+
+constexpr EcCurve kCurve[] = {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521,
+                              EcCurve::CURVE_25519};
+
+constexpr PaddingMode kPaddingMode[] = {
+        PaddingMode::NONE,
+        PaddingMode::RSA_OAEP,
+        PaddingMode::RSA_PSS,
+        PaddingMode::RSA_PKCS1_1_5_ENCRYPT,
+        PaddingMode::RSA_PKCS1_1_5_SIGN,
+        PaddingMode::PKCS7,
+};
+
+constexpr Digest kDigest[] = {
+        Digest::NONE,      Digest::MD5,       Digest::SHA1,      Digest::SHA_2_224,
+        Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512,
+};
+
+constexpr BlockMode kBlockMode[] = {
+        BlockMode::ECB,
+        BlockMode::CBC,
+        BlockMode::CTR,
+        BlockMode::GCM,
+};
+
+enum AttestAuthSet : uint32_t {
+    RSA_ATTEST_KEY = 0u,
+    ECDSA_ATTEST_KEY,
+};
+
+enum AuthSet : uint32_t {
+    RSA_KEY = 0u,
+    RSA_SIGNING_KEY,
+    RSA_ENCRYPTION_KEY,
+    ECDSA_SIGNING_CURVE,
+    AES_ENCRYPTION_KEY,
+    TRIPLE_DES,
+    HMAC,
+    NO_DIGEST,
+    ECB_MODE,
+    GSM_MODE_MIN_MAC,
+    GSM_MODE_MAC,
+    BLOCK_MODE,
+};
+
+AuthorizationSet createAuthSetForAttestKey(FuzzedDataProvider* dataProvider) {
+    uint32_t attestAuthSet = dataProvider->ConsumeBool() ? AttestAuthSet::RSA_ATTEST_KEY
+                                                         : AttestAuthSet::ECDSA_ATTEST_KEY;
+    uint64_t timestamp = dataProvider->ConsumeIntegral<uint64_t>();
+    Digest digest = dataProvider->PickValueInArray(kDigest);
+    PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+    std::string challenge = dataProvider->ConsumeRandomLengthString(kStringSize);
+    std::string id = dataProvider->ConsumeRandomLengthString(kStringSize);
+    switch (attestAuthSet) {
+        case RSA_ATTEST_KEY: {
+            return AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .RsaKey(kRsaKeySize, kPublicExponent)
+                    .Digest(digest)
+                    .Padding(padding)
+                    .AttestKey()
+                    .AttestationChallenge(challenge)
+                    .AttestationApplicationId(id)
+                    .SetDefaultValidity()
+                    .Authorization(TAG_CREATION_DATETIME, timestamp)
+                    .Authorization(TAG_INCLUDE_UNIQUE_ID)
+                    .Authorization(TAG_PURPOSE, KeyPurpose::ATTEST_KEY);
+        } break;
+        case ECDSA_ATTEST_KEY: {
+            EcCurve ecCurve = dataProvider->PickValueInArray(kCurve);
+            return AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .EcdsaKey(ecCurve)
+                    .AttestKey()
+                    .Digest(digest)
+                    .AttestationChallenge(challenge)
+                    .AttestationApplicationId(id)
+                    .SetDefaultValidity()
+                    .Authorization(TAG_CREATION_DATETIME, timestamp)
+                    .Authorization(TAG_INCLUDE_UNIQUE_ID)
+                    .Authorization(TAG_PURPOSE, KeyPurpose::ATTEST_KEY);
+        } break;
+        default:
+            break;
+    };
+    return AuthorizationSetBuilder();
+}
+
+AuthorizationSet createAuthorizationSet(FuzzedDataProvider* dataProvider) {
+    uint32_t authSet =
+            dataProvider->ConsumeIntegralInRange<uint32_t>(AuthSet::RSA_KEY, AuthSet::BLOCK_MODE);
+    uint64_t timestamp = dataProvider->ConsumeIntegral<uint64_t>();
+    Digest digest = dataProvider->PickValueInArray(kDigest);
+    PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+    std::string challenge = dataProvider->ConsumeRandomLengthString(kStringSize);
+    std::string id = dataProvider->ConsumeRandomLengthString(kStringSize);
+    switch (authSet) {
+        case RSA_KEY: {
+            return AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .RsaKey(kRsaKeySize, kPublicExponent)
+                    .Digest(digest)
+                    .Padding(padding)
+                    .AttestKey()
+                    .AttestationChallenge(challenge)
+                    .AttestationApplicationId(id)
+                    .SetDefaultValidity()
+                    .Authorization(TAG_CREATION_DATETIME, timestamp)
+                    .Authorization(TAG_INCLUDE_UNIQUE_ID);
+        } break;
+        case RSA_SIGNING_KEY: {
+            return AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .RsaSigningKey(kRsaKeySize, kPublicExponent)
+                    .Digest(digest)
+                    .Padding(padding)
+                    .AttestationChallenge(challenge)
+                    .AttestationApplicationId(id)
+                    .SetDefaultValidity()
+                    .Authorization(TAG_CREATION_DATETIME, timestamp)
+                    .Authorization(TAG_INCLUDE_UNIQUE_ID);
+        } break;
+        case RSA_ENCRYPTION_KEY: {
+            return AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .RsaEncryptionKey(kRsaKeySize, kPublicExponent)
+                    .Digest(digest)
+                    .Padding(padding)
+                    .AttestationChallenge(challenge)
+                    .AttestationApplicationId(id)
+                    .SetDefaultValidity()
+                    .Authorization(TAG_CREATION_DATETIME, timestamp)
+                    .Authorization(TAG_INCLUDE_UNIQUE_ID);
+        } break;
+        case ECDSA_SIGNING_CURVE: {
+            EcCurve ecCurve = dataProvider->PickValueInArray(kCurve);
+            return AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .EcdsaSigningKey(ecCurve)
+                    .Digest(digest)
+                    .AttestationChallenge(challenge)
+                    .AttestationApplicationId(id)
+                    .SetDefaultValidity()
+                    .Authorization(TAG_CREATION_DATETIME, timestamp)
+                    .Authorization(TAG_INCLUDE_UNIQUE_ID);
+        } break;
+        case AES_ENCRYPTION_KEY: {
+            BlockMode blockmode = dataProvider->PickValueInArray(kBlockMode);
+            return AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .AesEncryptionKey(kSymmKeySize)
+                    .BlockMode(blockmode)
+                    .Digest(digest)
+                    .Padding(padding);
+        } break;
+        case TRIPLE_DES: {
+            BlockMode blockmode = dataProvider->PickValueInArray(kBlockMode);
+            return AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .TripleDesEncryptionKey(k3DesKeySize)
+                    .BlockMode(blockmode)
+                    .Digest(digest)
+                    .Padding(padding)
+                    .EcbMode()
+                    .SetDefaultValidity();
+        } break;
+        case HMAC: {
+            return AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .HmacKey(kSymmKeySize)
+                    .Digest(digest)
+                    .Padding(padding);
+        } break;
+        case NO_DIGEST: {
+            return AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .AesEncryptionKey(kSymmKeySize)
+                    .NoDigestOrPadding()
+                    .Digest(digest)
+                    .Padding(padding);
+        } break;
+        case ECB_MODE: {
+            return AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .AesEncryptionKey(kSymmKeySize)
+                    .EcbMode()
+                    .Digest(digest)
+                    .Padding(padding);
+        } break;
+        case GSM_MODE_MIN_MAC: {
+            uint32_t minMacLength = dataProvider->ConsumeIntegral<uint32_t>();
+            return AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .AesEncryptionKey(kSymmKeySize)
+                    .GcmModeMinMacLen(minMacLength)
+                    .Digest(digest)
+                    .Padding(padding);
+        } break;
+        case GSM_MODE_MAC: {
+            uint32_t macLength = dataProvider->ConsumeIntegral<uint32_t>();
+            return AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .AesEncryptionKey(kSymmKeySize)
+                    .GcmModeMacLen(macLength)
+                    .Digest(digest)
+                    .Padding(padding);
+        } break;
+        case BLOCK_MODE: {
+            BlockMode blockmode = dataProvider->PickValueInArray(kBlockMode);
+            return AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .AesEncryptionKey(kSymmKeySize)
+                    .BlockMode(blockmode)
+                    .Digest(digest)
+                    .Padding(padding);
+        } break;
+        default:
+            break;
+    };
+    return AuthorizationSetBuilder();
+}
+
+}  // namespace android::hardware::security::keymint_support::fuzzer
+
+#endif  // __KEYMINT_COMMON_H__
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 2a8fd96..2dbc73f 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -188,9 +188,15 @@
         }
         ASSERT_NE(provisionable_, nullptr);
         auto status = provisionable_->getHardwareInfo(&rpcHardwareInfo);
-        if (GetParam() == RKP_VM_INSTANCE_NAME &&
-            status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
-            GTEST_SKIP() << "The RKP VM is not supported on this system.";
+        if (GetParam() == RKP_VM_INSTANCE_NAME) {
+            if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+                GTEST_SKIP() << "The RKP VM is not supported on this system.";
+            }
+            int apiLevel = get_vsr_api_level();
+            if (apiLevel < __ANDROID_API_V__) {
+                GTEST_SKIP() << "The RKP VM is supported only on V+ devices. Vendor API level: "
+                             << apiLevel;
+            }
         }
         ASSERT_TRUE(status.isOk());
     }
diff --git a/threadnetwork/aidl/default/main.cpp b/threadnetwork/aidl/default/main.cpp
index 26683bf..6514184 100644
--- a/threadnetwork/aidl/default/main.cpp
+++ b/threadnetwork/aidl/default/main.cpp
@@ -18,7 +18,11 @@
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
+#include <netinet/in.h>
+#include <net/if.h>
 #include <utils/Log.h>
+#include <cutils/properties.h>
+#include <sys/stat.h>
 
 #include "service.hpp"
 #include "thread_chip.hpp"
@@ -26,6 +30,8 @@
 using aidl::android::hardware::threadnetwork::IThreadChip;
 using aidl::android::hardware::threadnetwork::ThreadChip;
 
+#define THREADNETWORK_COPROCESSOR_SIMULATION_PATH "/apex/com.android.hardware.threadnetwork/bin/ot-rcp"
+
 namespace {
 void addThreadChip(int id, const char* url) {
     binder_status_t status;
@@ -41,14 +47,36 @@
     status = AServiceManager_addService(threadChip->asBinder().get(), serviceName.c_str());
     CHECK_EQ(status, STATUS_OK);
 }
+
+void addSimulatedThreadChip() {
+    char local_interface[PROP_VALUE_MAX];
+
+    CHECK_GT(property_get("persist.vendor.otsim.local_interface",
+                local_interface, "eth1"), 0);
+
+    int node_id = property_get_int32("ro.boot.openthread_node_id", 0);
+    CHECK_GT(node_id,0);
+
+    std::string url = std::string("spinel+hdlc+forkpty://" \
+            THREADNETWORK_COPROCESSOR_SIMULATION_PATH "?forkpty-arg=-L") \
+                      + local_interface + "&forkpty-arg=" + std::to_string(node_id);
+    addThreadChip(0, url.c_str());
+}
 }
 
 int main(int argc, char* argv[]) {
-    CHECK_GT(argc, 1);
     aidl::android::hardware::threadnetwork::Service service;
 
-    for (int id = 0; id < argc - 1; id++) {
-        addThreadChip(id, argv[id + 1]);
+    if (argc > 1) {
+        for (int id = 0; id < argc - 1; id++) {
+            addThreadChip(id, argv[id + 1]);
+        }
+    } else {
+        struct stat sb;
+
+        CHECK_EQ(stat(THREADNETWORK_COPROCESSOR_SIMULATION_PATH, &sb), 0);
+        CHECK(sb.st_mode & S_IXUSR);
+        addSimulatedThreadChip();
     }
 
     ALOGI("Thread Network HAL is running");
diff --git a/threadnetwork/aidl/default/threadnetwork-service.rc b/threadnetwork/aidl/default/threadnetwork-service.rc
index 3b889eb..a2ac0f7 100644
--- a/threadnetwork/aidl/default/threadnetwork-service.rc
+++ b/threadnetwork/aidl/default/threadnetwork-service.rc
@@ -1,3 +1,3 @@
-service vendor.threadnetwork_hal /apex/com.android.hardware.threadnetwork/bin/hw/android.hardware.threadnetwork-service spinel+hdlc+forkpty:///apex/com.android.hardware.threadnetwork/bin/ot-rcp?forkpty-arg=1
+service vendor.threadnetwork_hal /apex/com.android.hardware.threadnetwork/bin/hw/android.hardware.threadnetwork-service
     class hal
     user thread_network
diff --git a/threadnetwork/aidl/vts/Android.bp b/threadnetwork/aidl/vts/Android.bp
index 864e885..931081b 100644
--- a/threadnetwork/aidl/vts/Android.bp
+++ b/threadnetwork/aidl/vts/Android.bp
@@ -31,6 +31,7 @@
     static_libs: [
         "android.hardware.threadnetwork-V1-ndk",
     ],
+    test_config: "VtsHalThreadNetworkTargetTest.xml",
     test_suites: [
         "general-tests",
         "vts",
diff --git a/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.xml b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.xml
new file mode 100644
index 0000000..0525876
--- /dev/null
+++ b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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 VtsHalThreadNetworkTargetTest.">
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="cmd thread_network force-stop-ot-daemon enabled" />
+        <option name="run-command" value="cmd bluetooth_manager enable" />
+        <option name="teardown-command" value="cmd thread_network force-stop-ot-daemon disabled" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalThreadNetworkTargetTest->/data/local/tmp/VtsHalThreadNetworkTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalThreadNetworkTargetTest" />
+    </test>
+</configuration>
diff --git a/tv/Android.mk b/tv/Android.mk
deleted file mode 100644
index d78614a..0000000
--- a/tv/Android.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-$(eval $(call declare-1p-copy-files,hardware/interfaces/tv,tuner_vts_config_1_0.xml))
-$(eval $(call declare-1p-copy-files,hardware/interfaces/tv,tuner_vts_config_1_1.xml))
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
index 491a79b..6cabb3d 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
@@ -31,11 +31,7 @@
 
 bool initConfiguration() {
     std::array<char, PROPERTY_VALUE_MAX> variant;
-    auto res = property_get("ro.vendor.vts_tuner_configuration_variant", variant.data(), "");
-    if (res <= 0) {
-        ALOGE("[vts] failed to read system property ro.vendor.vts_tuner_configuration_variant");
-        return false;
-    }
+    property_get("ro.vendor.vts_tuner_configuration_variant", variant.data(), "");
     string configFilePath = "/vendor/etc/tuner_vts_config_aidl_V1";
     if (variant.size() != 0) {
         configFilePath = configFilePath + "."  + variant.data();