Merge "EnvironmentalReverbTest: Add Tests to Validate Environmental Reverb Effect" 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/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
index 03de74f..7192d97 100644
--- a/audio/aidl/default/EffectImpl.cpp
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -23,6 +23,9 @@
 #include "include/effect-impl/EffectTypes.h"
 
 using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kEventFlagDataMqNotEmpty;
+using aidl::android::hardware::audio::effect::kEventFlagNotEmpty;
+using aidl::android::hardware::audio::effect::kReopenSupportedVersion;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::media::audio::common::PcmType;
 using ::android::hardware::EventFlag;
@@ -43,7 +46,6 @@
 ndk::ScopedAStatus EffectImpl::open(const Parameter::Common& common,
                                     const std::optional<Parameter::Specific>& specific,
                                     OpenEffectReturn* ret) {
-    LOG(DEBUG) << getEffectName() << __func__;
     // effect only support 32bits float
     RETURN_IF(common.input.base.format.pcm != common.output.base.format.pcm ||
                       common.input.base.format.pcm != PcmType::FLOAT_32_BIT,
@@ -54,11 +56,12 @@
     mImplContext = createContext(common);
     RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
 
-    int version = 0;
-    RETURN_IF(!getInterfaceVersion(&version).isOk(), EX_UNSUPPORTED_OPERATION,
+    RETURN_IF(!getInterfaceVersion(&mVersion).isOk(), EX_UNSUPPORTED_OPERATION,
               "FailedToGetInterfaceVersion");
-    mImplContext->setVersion(version);
+    mImplContext->setVersion(mVersion);
     mEventFlag = mImplContext->getStatusEventFlag();
+    mDataMqNotEmptyEf =
+            mVersion >= kReopenSupportedVersion ? kEventFlagDataMqNotEmpty : kEventFlagNotEmpty;
 
     if (specific.has_value()) {
         RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
@@ -66,8 +69,9 @@
 
     mState = State::IDLE;
     mImplContext->dupeFmq(ret);
-    RETURN_IF(createThread(getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
-              "FailedToCreateWorker");
+    RETURN_IF(createThread(getEffectNameWithVersion()) != RetCode::SUCCESS,
+              EX_UNSUPPORTED_OPERATION, "FailedToCreateWorker");
+    LOG(INFO) << getEffectNameWithVersion() << __func__;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -89,7 +93,7 @@
         mState = State::INIT;
     }
 
-    RETURN_IF(notifyEventFlag(kEventFlagNotEmpty) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+    RETURN_IF(notifyEventFlag(mDataMqNotEmptyEf) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
               "notifyEventFlagNotEmptyFailed");
     // stop the worker thread, ignore the return code
     RETURN_IF(destroyThread() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
@@ -101,13 +105,13 @@
         mImplContext.reset();
     }
 
-    LOG(DEBUG) << getEffectName() << __func__;
+    LOG(INFO) << getEffectNameWithVersion() << __func__;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus EffectImpl::setParameter(const Parameter& param) {
     std::lock_guard lg(mImplMutex);
-    LOG(VERBOSE) << getEffectName() << __func__ << " with: " << param.toString();
+    LOG(VERBOSE) << getEffectNameWithVersion() << __func__ << " with: " << param.toString();
 
     const auto& tag = param.getTag();
     switch (tag) {
@@ -122,7 +126,7 @@
             return setParameterSpecific(param.get<Parameter::specific>());
         }
         default: {
-            LOG(ERROR) << getEffectName() << __func__ << " unsupportedParameterTag "
+            LOG(ERROR) << getEffectNameWithVersion() << __func__ << " unsupportedParameterTag "
                        << toString(tag);
             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
                                                                     "ParameterNotSupported");
@@ -147,7 +151,7 @@
             break;
         }
     }
-    LOG(VERBOSE) << getEffectName() << __func__ << id.toString() << param->toString();
+    LOG(VERBOSE) << getEffectNameWithVersion() << __func__ << id.toString() << param->toString();
     return ndk::ScopedAStatus::ok();
 }
 
@@ -180,7 +184,7 @@
                       EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
             break;
         default: {
-            LOG(ERROR) << getEffectName() << __func__ << " unsupportedParameterTag "
+            LOG(ERROR) << getEffectNameWithVersion() << __func__ << " unsupportedParameterTag "
                        << toString(tag);
             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
                                                                     "commonParamNotSupported");
@@ -214,7 +218,8 @@
             break;
         }
         default: {
-            LOG(DEBUG) << getEffectName() << __func__ << " unsupported tag " << toString(tag);
+            LOG(DEBUG) << getEffectNameWithVersion() << __func__ << " unsupported tag "
+                       << toString(tag);
             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
                                                                     "tagNotSupported");
         }
@@ -236,7 +241,7 @@
             RETURN_OK_IF(mState == State::PROCESSING);
             RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
             mState = State::PROCESSING;
-            RETURN_IF(notifyEventFlag(kEventFlagNotEmpty) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+            RETURN_IF(notifyEventFlag(mDataMqNotEmptyEf) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
                       "notifyEventFlagNotEmptyFailed");
             startThread();
             break;
@@ -244,17 +249,18 @@
         case CommandId::RESET:
             RETURN_OK_IF(mState == State::IDLE);
             mState = State::IDLE;
-            RETURN_IF(notifyEventFlag(kEventFlagNotEmpty) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+            RETURN_IF(notifyEventFlag(mDataMqNotEmptyEf) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
                       "notifyEventFlagNotEmptyFailed");
             stopThread();
             RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
             break;
         default:
-            LOG(ERROR) << getEffectName() << __func__ << " instance still processing";
+            LOG(ERROR) << getEffectNameWithVersion() << __func__ << " instance still processing";
             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
                                                                     "CommandIdNotSupported");
     }
-    LOG(VERBOSE) << getEffectName() << __func__ << " transfer to state: " << toString(mState);
+    LOG(VERBOSE) << getEffectNameWithVersion() << __func__
+                 << " transfer to state: " << toString(mState);
     return ndk::ScopedAStatus::ok();
 }
 
@@ -284,14 +290,14 @@
 
 RetCode EffectImpl::notifyEventFlag(uint32_t flag) {
     if (!mEventFlag) {
-        LOG(ERROR) << getEffectName() << __func__ << ": StatusEventFlag invalid";
+        LOG(ERROR) << getEffectNameWithVersion() << __func__ << ": StatusEventFlag invalid";
         return RetCode::ERROR_EVENT_FLAG_ERROR;
     }
     if (const auto ret = mEventFlag->wake(flag); ret != ::android::OK) {
-        LOG(ERROR) << getEffectName() << __func__ << ": wake failure with ret " << ret;
+        LOG(ERROR) << getEffectNameWithVersion() << __func__ << ": wake failure with ret " << ret;
         return RetCode::ERROR_EVENT_FLAG_ERROR;
     }
-    LOG(VERBOSE) << getEffectName() << __func__ << ": " << std::hex << mEventFlag;
+    LOG(VERBOSE) << getEffectNameWithVersion() << __func__ << ": " << std::hex << mEventFlag;
     return RetCode::SUCCESS;
 }
 
@@ -304,17 +310,17 @@
 }
 
 void EffectImpl::process() {
-    ATRACE_NAME(getEffectName().c_str());
+    ATRACE_NAME(getEffectNameWithVersion().c_str());
     /**
      * wait for the EventFlag without lock, it's ok because the mEfGroup pointer will not change
      * in the life cycle of workerThread (threadLoop).
      */
     uint32_t efState = 0;
     if (!mEventFlag ||
-        ::android::OK != mEventFlag->wait(kEventFlagNotEmpty, &efState, 0 /* no timeout */,
+        ::android::OK != mEventFlag->wait(mDataMqNotEmptyEf, &efState, 0 /* no timeout */,
                                           true /* retry */) ||
-        !(efState & kEventFlagNotEmpty)) {
-        LOG(ERROR) << getEffectName() << __func__ << ": StatusEventFlag - " << mEventFlag
+        !(efState & mDataMqNotEmptyEf)) {
+        LOG(ERROR) << getEffectNameWithVersion() << __func__ << ": StatusEventFlag - " << mEventFlag
                    << " efState - " << std::hex << efState;
         return;
     }
@@ -322,7 +328,8 @@
     {
         std::lock_guard lg(mImplMutex);
         if (mState != State::PROCESSING) {
-            LOG(DEBUG) << getEffectName() << " skip process in state: " << toString(mState);
+            LOG(DEBUG) << getEffectNameWithVersion()
+                       << " skip process in state: " << toString(mState);
             return;
         }
         RETURN_VALUE_IF(!mImplContext, void(), "nullContext");
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/include/effect-impl/EffectImpl.h b/audio/aidl/default/include/effect-impl/EffectImpl.h
index 21f6502..d3bb7f4 100644
--- a/audio/aidl/default/include/effect-impl/EffectImpl.h
+++ b/audio/aidl/default/include/effect-impl/EffectImpl.h
@@ -89,6 +89,11 @@
     void process() override;
 
   protected:
+    // current Hal version
+    int mVersion = 0;
+    // Use kEventFlagNotEmpty for V1 HAL, kEventFlagDataMqNotEmpty for V2 and above
+    int mDataMqNotEmptyEf = aidl::android::hardware::audio::effect::kEventFlagDataMqNotEmpty;
+
     State mState GUARDED_BY(mImplMutex) = State::INIT;
 
     IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
@@ -107,6 +112,11 @@
     virtual ndk::ScopedAStatus commandImpl(CommandId id) REQUIRES(mImplMutex);
 
     RetCode notifyEventFlag(uint32_t flag);
+
+    std::string getEffectNameWithVersion() {
+        return getEffectName() + "V" + std::to_string(mVersion);
+    }
+
     ::android::hardware::EventFlag* mEventFlag;
 };
 }  // namespace aidl::android::hardware::audio::effect
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/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index 0d1e0dc..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,11 +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;
@@ -77,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,
@@ -108,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));
     }
@@ -160,7 +169,7 @@
         std::fill(buffer.begin(), buffer.end(), 0x5a);
     }
     static void writeToFmq(std::unique_ptr<StatusMQ>& statusMq, std::unique_ptr<DataMQ>& dataMq,
-                           const std::vector<float>& buffer) {
+                           const std::vector<float>& buffer, int version) {
         const size_t available = dataMq->availableToWrite();
         ASSERT_NE(0Ul, available);
         auto bufferFloats = buffer.size();
@@ -171,7 +180,8 @@
         ASSERT_EQ(::android::OK,
                   EventFlag::createEventFlag(statusMq->getEventFlagWord(), &efGroup));
         ASSERT_NE(nullptr, efGroup);
-        efGroup->wake(kEventFlagNotEmpty);
+        efGroup->wake(version >= kReopenSupportedVersion ? kEventFlagDataMqNotEmpty
+                                                         : kEventFlagNotEmpty);
         ASSERT_EQ(::android::OK, EventFlag::deleteEventFlag(&efGroup));
     }
     static void readFromFmq(std::unique_ptr<StatusMQ>& statusMq, size_t statusNum,
@@ -204,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;
@@ -322,7 +348,10 @@
         ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
         // Write from buffer to message queues and calling process
-        EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, inputBuffer));
+        EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, inputBuffer, [&]() {
+            int version = 0;
+            return (mEffect && mEffect->getInterfaceVersion(&version).isOk()) ? version : 0;
+        }()));
 
         // Read the updated message queues into buffer
         EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 1, outputMQ,
@@ -373,4 +402,7 @@
 
         return bufferMag;
     }
+
+    bool mIsSpatializer;
+    Descriptor mDescriptor;
 };
diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h
index 0a5addc..3a6c137 100644
--- a/audio/aidl/vts/TestUtils.h
+++ b/audio/aidl/vts/TestUtils.h
@@ -108,7 +108,7 @@
     ({                                                                                            \
         if ((flags).hwAcceleratorMode ==                                                          \
                     aidl::android::hardware::audio::effect::Flags::HardwareAccelerator::TUNNEL || \
-            (flags).bypass) {                                                                     \
+            (flags).bypass || (flags).offloadIndication) {                                        \
             GTEST_SKIP() << "Skip data path for offload";                                         \
         }                                                                                         \
     })
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 4693f10..2f47d07 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -42,7 +42,6 @@
 using aidl::android::hardware::audio::effect::Flags;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::IFactory;
-using aidl::android::hardware::audio::effect::kReopenSupportedVersion;
 using aidl::android::hardware::audio::effect::Parameter;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::media::audio::common::AudioDeviceDescription;
@@ -58,6 +57,7 @@
   public:
     AudioEffectTest() {
         std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+        mVersion = EffectFactoryHelper::getHalVersion(mFactory);
     }
 
     void SetUp() override {}
@@ -76,6 +76,7 @@
     std::shared_ptr<IFactory> mFactory;
     std::shared_ptr<IEffect> mEffect;
     Descriptor mDescriptor;
+    int mVersion = 0;
 
     void setAndGetParameter(Parameter::Id id, const Parameter& set) {
         Parameter get;
@@ -395,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));
 
@@ -415,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)));
 
@@ -431,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)));
 
@@ -450,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)));
 
@@ -466,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)));
 
@@ -485,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)));
 
@@ -620,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;
@@ -665,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;
@@ -682,7 +683,7 @@
 
     std::vector<float> buffer;
     EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
     EXPECT_NO_FATAL_FAILURE(
             EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
 
@@ -699,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;
@@ -722,7 +723,7 @@
     ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
     EXPECT_NO_FATAL_FAILURE(
             EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
 
@@ -743,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;
@@ -759,7 +760,7 @@
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
     ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
     EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
     EXPECT_NO_FATAL_FAILURE(
             EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
 
@@ -779,7 +780,7 @@
 
     // verify data consume again
     EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
     EXPECT_NO_FATAL_FAILURE(
             EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
 
@@ -796,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;
@@ -810,7 +811,7 @@
 
     std::vector<float> buffer;
     EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
     ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
@@ -830,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;
@@ -844,7 +845,7 @@
 
     std::vector<float> buffer;
     EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
     EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
@@ -853,7 +854,7 @@
     EXPECT_NO_FATAL_FAILURE(
             EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
 
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
     EXPECT_NO_FATAL_FAILURE(
             EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
 
@@ -870,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;
@@ -886,13 +887,13 @@
     ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
     std::vector<float> buffer;
     EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
     EXPECT_NO_FATAL_FAILURE(
             EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
     ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
     EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
@@ -912,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;
@@ -928,7 +929,7 @@
 
     std::vector<float> buffer;
     EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
     EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
 
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
@@ -941,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;
@@ -964,7 +965,7 @@
 
     std::vector<float> buffer1, buffer2;
     EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common1, inputMQ1, buffer1));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ1, inputMQ1, buffer1));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ1, inputMQ1, buffer1, mVersion));
     EXPECT_NO_FATAL_FAILURE(
             EffectHelper::readFromFmq(statusMQ1, 1, outputMQ1, buffer1.size(), buffer1));
 
@@ -975,7 +976,7 @@
     auto outputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.outputDataMQ);
     ASSERT_TRUE(outputMQ2->isValid());
     EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common2, inputMQ2, buffer2));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ2, inputMQ2, buffer2));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ2, inputMQ2, buffer2, mVersion));
     EXPECT_NO_FATAL_FAILURE(
             EffectHelper::readFromFmq(statusMQ2, 1, outputMQ2, buffer2.size(), buffer2));
 
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 3ed9ed2..b023df1 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 39cfa8d..c7c6505 100644
--- a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -153,7 +153,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 */,
                 mFrameCount /* iFrameCount */, mFrameCount /* oFrameCount */);
         ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
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 a075423..3c72dfa 100644
--- a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -48,11 +48,12 @@
         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));
         ASSERT_NE(nullptr, mEffect);
+        mVersion = EffectFactoryHelper::getHalVersion(mFactory);
     }
 
     void TearDownLoudnessEnhancer() {
@@ -114,6 +115,7 @@
     std::shared_ptr<IFactory> mFactory;
     std::shared_ptr<IEffect> mEffect;
     Descriptor mDescriptor;
+    int mVersion = 0;
 };
 
 /**
@@ -190,7 +192,8 @@
         ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
         // Write from buffer to message queues and calling process
-        EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(mStatusMQ, mInputMQ, mInputBuffer));
+        EXPECT_NO_FATAL_FAILURE(
+                EffectHelper::writeToFmq(mStatusMQ, mInputMQ, mInputBuffer, mVersion));
 
         // Read the updated message queues into buffer
         EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(mStatusMQ, 1, mOutputMQ,
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 1c1489d..db2f4a9 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/vehicle/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index e1a90cb..117c872 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 5ca1fc8..ff0635a 100644
--- a/automotive/vehicle/aidl/Android.bp
+++ b/automotive/vehicle/aidl/Android.bp
@@ -56,5 +56,5 @@
         },
 
     ],
-
+    host_supported: true,
 }
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/Android.bp b/automotive/vehicle/aidl/generated_lib/cpp/Android.bp
index 11d3693..d14cbc2 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/Android.bp
+++ b/automotive/vehicle/aidl/generated_lib/cpp/Android.bp
@@ -24,4 +24,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 75a3541..d1974ac 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 e75f648..33b403f 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
@@ -32,6 +32,7 @@
         "VehicleHalDefaults",
         "FakeVehicleHardwareDefaults",
     ],
+    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 8cd92b3..1b6f576 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -182,7 +182,7 @@
     std::unordered_set<int32_t> hvacPowerDependentProps;
 
     const bool mForceOverride;
-    bool mAddExtraTestVendorConfigs;
+    bool mAddExtraTestVendorConfigs = false;
 
     // Only used during initialization.
     JsonConfigLoader mLoader;
@@ -200,7 +200,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.
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 dced624..2b20f38 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -329,7 +329,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);
     }
@@ -2258,30 +2263,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 9819f3c..a335eea 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -54,6 +54,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/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/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index 6a2a695..3d0a524 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -173,9 +173,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_property/Android.bp b/automotive/vehicle/aidl_property/Android.bp
index 5db39d8..6a49792 100644
--- a/automotive/vehicle/aidl_property/Android.bp
+++ b/automotive/vehicle/aidl_property/Android.bp
@@ -56,6 +56,7 @@
             imports: [],
         },
     ],
+    host_supported: true,
 }
 
 filegroup {
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index feed6f5..995426c 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -97,3 +97,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 e335853..c1bffb4 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;
@@ -1622,9 +1623,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] = {
@@ -1838,9 +1839,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] = {
@@ -2004,9 +2005,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);
 
@@ -2223,9 +2224,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()};
@@ -2323,9 +2324,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);
         }
 
@@ -2446,9 +2447,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()};
@@ -2672,9 +2673,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 f70e93c..ed34b19 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;
@@ -2263,8 +2264,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),
@@ -2775,9 +2776,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()};
@@ -3757,9 +3758,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);
 
@@ -3913,9 +3914,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/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_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index 093105b..49c1e7c 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -2193,6 +2193,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;
@@ -2206,6 +2218,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}));
 }
 
 /*
@@ -2446,9 +2471,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) {
@@ -2477,9 +2502,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();
@@ -2489,9 +2514,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
@@ -2530,9 +2555,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();
@@ -2542,9 +2567,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
@@ -2576,7 +2601,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();