Merge "Document error for IStorageSession::renameFile" into main
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 0f2fe99..97577d1 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -60,7 +60,7 @@
         ndk: {
             apex_available: [
                 "//apex_available:platform",
-                "com.android.btservices",
+                "com.android.bt",
             ],
             min_sdk_version: "31",
         },
diff --git a/audio/aidl/android/hardware/audio/effect/IFactory.aidl b/audio/aidl/android/hardware/audio/effect/IFactory.aidl
index b80e6ac..75d4d9e 100644
--- a/audio/aidl/android/hardware/audio/effect/IFactory.aidl
+++ b/audio/aidl/android/hardware/audio/effect/IFactory.aidl
@@ -74,13 +74,18 @@
 
     /**
      * Called by the framework to destroy the effect and free up all currently allocated resources.
-     * It is recommended to destroy the effect from the client side as soon as it is becomes unused.
+     * This method can be called at any time to destroy an effect instance. It is recommended to
+     * destroy the effect from the client side as soon as it becomes unused to free up resources.
      *
-     * The client must ensure effect instance is closed before destroy.
+     * The effect instance must handle any necessary cleanup and resource deallocation.
+     * If the effect is in the **PROCESSING** or **DRAINING** state, it must gracefully stop
+     * processing before destruction.
+     * The effect must ensure that all internal states are properly cleaned up to prevent resource
+     * leaks.
      *
      * @param handle The handle of effect instance to be destroyed.
      * @throws EX_ILLEGAL_ARGUMENT if the effect handle is not valid.
-     * @throws EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
+     * @throws EX_ILLEGAL_STATE if the effect instance can not be destroyed.
      */
     void destroyEffect(in IEffect handle);
 }
diff --git a/audio/aidl/android/hardware/audio/effect/State.aidl b/audio/aidl/android/hardware/audio/effect/State.aidl
index 1b698d7..ecd1bbe 100644
--- a/audio/aidl/android/hardware/audio/effect/State.aidl
+++ b/audio/aidl/android/hardware/audio/effect/State.aidl
@@ -24,6 +24,8 @@
  * it should transfer to IDLE state after handle the command successfully. Effect instance should
  * consume minimal resource and transfer to INIT state after it was close().
  *
+ * An effect instance can be destroyed from any state using `IFactory.destroyEffect()`.
+ *
  * Refer to the state machine diagram `state.gv` for a detailed state diagram.
  */
 @VintfStability
@@ -66,6 +68,7 @@
      * - Transitions to **INIT** on `IEffect.close()`.
      * - Remains in **IDLE** on `IEffect.getParameter()`, `IEffect.setParameter()`,
      *   `IEffect.getDescriptor()`, `IEffect.command(CommandId.RESET)`, and `IEffect.reopen()`.
+     * - Transitions to the final state on `IFactory.destroyEffect()`.
      */
     IDLE,
 
@@ -98,6 +101,7 @@
      *   stop processing with `CommandId.STOP` before closing.
      * - If `IEffect.close()` is called in this state, the effect instance should stop processing,
      *   transition to **IDLE**, and then close.
+     * - Transitions to the final state on `IFactory.destroyEffect()`.
      */
     PROCESSING,
 
@@ -123,6 +127,7 @@
      * - If not implemented, the effect instance may transition directly from **PROCESSING** to
      *   **IDLE** without this intermediate state.
      * - Any `CommandId.STOP` commands received during **DRAINING** should be ignored.
+     * - Transitions to the final state on `IFactory.destroyEffect()`.
      */
     DRAINING,
 }
diff --git a/audio/aidl/android/hardware/audio/effect/state.gv b/audio/aidl/android/hardware/audio/effect/state.gv
index 2a8194e..8590296 100644
--- a/audio/aidl/android/hardware/audio/effect/state.gv
+++ b/audio/aidl/android/hardware/audio/effect/state.gv
@@ -13,8 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-// To render: "dot -Tpng state.gv -o state.png"
 
+// To render: "dot -Tpng state.gv -o state.png"
 digraph effect_state_machine {
 
     rankdir=LR; // Left to Right layout
@@ -29,40 +29,30 @@
     I [shape=point, fillcolor=black, width=0.2];
 
     // Final state node
-    F [shape=doublecircle, fillcolor=white, width=0.2];
+    F [shape=doublecircle, label="Destroyed"];
 
     // Define other nodes with colors
-    INIT [shape=ellipse, fillcolor=lightgreen];
-    IDLE [shape=ellipse, fillcolor=lightblue];
-    PROCESSING [shape=ellipse, fillcolor=lightyellow];
-    DRAINING [shape=ellipse, fillcolor=lightgrey];
+    INIT [shape=ellipse, fillcolor=lightgreen, label="INIT"];
+    IDLE [shape=ellipse, fillcolor=lightblue, label="IDLE"];
+    PROCESSING [shape=ellipse, fillcolor=lightyellow, label="PROCESSING"];
+    DRAINING [shape=ellipse, fillcolor=lightgrey, label="DRAINING"];
+    ANY_STATE [shape=ellipse, style=dashed, label="Any State", fillcolor=white];
 
-    // Transitions
+    // Main transitions
     I -> INIT [label="IFactory.createEffect", fontcolor="navy"];
-
-    INIT -> F [label="IFactory.destroyEffect"];
-
     INIT -> IDLE [label="IEffect.open()", fontcolor="lime"];
-
     IDLE -> PROCESSING [label="IEffect.command(START)"];
-
-    PROCESSING -> IDLE [label="IEffect.command(STOP)\nIEffect.command(RESET)"];
-
-    PROCESSING -> DRAINING [label="IEffect.command(STOP)", fontcolor="orange"];
-
-    DRAINING -> IDLE [label="Draining complete\n(IEffect.command(RESET)\nautomatic)"];
-
-    DRAINING -> PROCESSING [label="IEffect.command(START)\n(Interrupt draining)"];
-
+    PROCESSING -> IDLE [label="IEffect.command(STOP) (if draining not required)\nIEffect.command(RESET)"];
+    PROCESSING -> DRAINING [label="IEffect.command(STOP) (if draining required)", fontcolor="orange"];
+    DRAINING -> IDLE [label="IEffect.command(RESET)\nDraining complete (automatic transition)"];
+    DRAINING -> PROCESSING [label="IEffect.command(START) (Interrupt draining)"];
     IDLE -> INIT [label="IEffect.close()"];
 
-    // Self-loops
-    INIT -> INIT [label="IEffect.getState\nIEffect.getDescriptor"];
-
-    IDLE -> IDLE [label="IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.command(RESET)\nIEffect.reopen"];
-
-    PROCESSING -> PROCESSING [label="IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.reopen"];
-
-    DRAINING -> DRAINING [label="IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.reopen\nFading"];
-
+    // Global transitions
+    subgraph cluster_global_transitions {
+        label="Global Transitions (Any State)";
+        style=dashed;
+        ANY_STATE -> F [label="IFactory.destroyEffect", style="bold"];
+        ANY_STATE -> ANY_STATE [label="IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.getState\nIEffect.reopen", fontsize=10];
+    }
 }
diff --git a/audio/aidl/common/tests/utils_tests.cpp b/audio/aidl/common/tests/utils_tests.cpp
index 1b8b8df..1522d7e 100644
--- a/audio/aidl/common/tests/utils_tests.cpp
+++ b/audio/aidl/common/tests/utils_tests.cpp
@@ -86,7 +86,7 @@
             std::make_pair(6UL, AudioChannelLayout::LAYOUT_5POINT1),
             std::make_pair(8UL, AudioChannelLayout::LAYOUT_7POINT1),
             std::make_pair(16UL, AudioChannelLayout::LAYOUT_9POINT1POINT6),
-            std::make_pair(13UL, AudioChannelLayout::LAYOUT_13POINT_360RA),
+            std::make_pair(13UL, AudioChannelLayout::LAYOUT_13POINT0),
             std::make_pair(24UL, AudioChannelLayout::LAYOUT_22POINT2),
             std::make_pair(3UL, AudioChannelLayout::LAYOUT_STEREO_HAPTIC_A),
             std::make_pair(4UL, AudioChannelLayout::LAYOUT_STEREO_HAPTIC_AB)};
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
index 7857f53..97f7286 100644
--- a/audio/aidl/default/EffectImpl.cpp
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -22,7 +22,10 @@
 #include "effect-impl/EffectTypes.h"
 #include "include/effect-impl/EffectTypes.h"
 
+using aidl::android::hardware::audio::effect::CommandId;
+using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kDestroyAnyStateSupportedVersion;
 using aidl::android::hardware::audio::effect::kEventFlagDataMqNotEmpty;
 using aidl::android::hardware::audio::effect::kEventFlagNotEmpty;
 using aidl::android::hardware::audio::effect::kReopenSupportedVersion;
@@ -31,13 +34,45 @@
 using ::android::hardware::EventFlag;
 
 extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
-    State state;
-    ndk::ScopedAStatus status = instanceSp->getState(&state);
-    if (!status.isOk() || State::INIT != state) {
+    if (!instanceSp) {
+        LOG(ERROR) << __func__ << " nullptr";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+
+    Descriptor desc;
+    ndk::ScopedAStatus status = instanceSp->getDescriptor(&desc);
+    if (!status.isOk()) {
         LOG(ERROR) << __func__ << " instance " << instanceSp.get()
+                   << " failed to get descriptor, status: " << status.getDescription();
+        return EX_ILLEGAL_STATE;
+    }
+
+    State state;
+    status = instanceSp->getState(&state);
+    if (!status.isOk()) {
+        LOG(ERROR) << __func__ << " " << desc.common.name << " instance " << instanceSp.get()
                    << " in state: " << toString(state) << ", status: " << status.getDescription();
         return EX_ILLEGAL_STATE;
     }
+
+    int effectVersion = 0;
+    if (!instanceSp->getInterfaceVersion(&effectVersion).isOk()) {
+        LOG(WARNING) << __func__ << " " << desc.common.name << " failed to get interface version";
+    }
+
+    if (effectVersion < kDestroyAnyStateSupportedVersion) {
+        if (State::INIT != state) {
+            LOG(ERROR) << __func__ << " " << desc.common.name << " can not destroy instance "
+                       << instanceSp.get() << " in state: " << toString(state);
+            return EX_ILLEGAL_STATE;
+        }
+    } else {
+        instanceSp->command(CommandId::RESET);
+        instanceSp->close();
+    }
+
+    LOG(DEBUG) << __func__ << " " << desc.common.name << " instance " << instanceSp.get()
+               << " destroyed";
     return EX_NONE;
 }
 
diff --git a/audio/aidl/default/EngineConfigXmlConverter.cpp b/audio/aidl/default/EngineConfigXmlConverter.cpp
index 5a8b0a3..d945b17 100644
--- a/audio/aidl/default/EngineConfigXmlConverter.cpp
+++ b/audio/aidl/default/EngineConfigXmlConverter.cpp
@@ -179,8 +179,13 @@
         const eng_xsd::ProductStrategies::ProductStrategy& xsdcProductStrategy) {
     AudioHalProductStrategy aidlProductStrategy;
 
-    aidlProductStrategy.id =
-            VALUE_OR_FATAL(convertProductStrategyIdToAidl(xsdcProductStrategy.getId()));
+    if (xsdcProductStrategy.hasId()) {
+        aidlProductStrategy.id =
+                VALUE_OR_FATAL(convertProductStrategyIdToAidl(xsdcProductStrategy.getId()));
+    } else {
+        aidlProductStrategy.id =
+                VALUE_OR_FATAL(convertProductStrategyNameToAidl(xsdcProductStrategy.getName()));
+    }
     aidlProductStrategy.name = xsdcProductStrategy.getName();
 
     if (xsdcProductStrategy.hasAttributesGroup()) {
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index e96cf81..f9fa799 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -184,8 +184,12 @@
     const int32_t nominalLatencyMs = getNominalLatencyMs(*portConfigIt);
     // Since this is a private method, it is assumed that
     // validity of the portConfigId has already been checked.
-    const int32_t minimumStreamBufferSizeFrames =
-            calculateBufferSizeFrames(nominalLatencyMs, portConfigIt->sampleRate.value().value);
+    int32_t minimumStreamBufferSizeFrames = 0;
+    if (!calculateBufferSizeFrames(
+                portConfigIt->format.value(), nominalLatencyMs,
+                portConfigIt->sampleRate.value().value, &minimumStreamBufferSizeFrames).isOk()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     if (in_bufferSizeFrames < minimumStreamBufferSizeFrames) {
         LOG(ERROR) << __func__ << ": " << mType << ": insufficient buffer size "
                    << in_bufferSizeFrames << ", must be at least " << minimumStreamBufferSizeFrames;
@@ -378,6 +382,18 @@
     return kLatencyMs;
 }
 
+ndk::ScopedAStatus Module::calculateBufferSizeFrames(
+        const ::aidl::android::media::audio::common::AudioFormatDescription &format,
+        int32_t latencyMs, int32_t sampleRateHz, int32_t *bufferSizeFrames) {
+    if (format.type == AudioFormatType::PCM) {
+        *bufferSizeFrames = calculateBufferSizeFramesForPcm(latencyMs, sampleRateHz);
+        return ndk::ScopedAStatus::ok();
+    }
+    LOG(ERROR) << __func__ << ": " << mType << ": format " << format.toString()
+        << " is not supported";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
 ndk::ScopedAStatus Module::createMmapBuffer(
         const ::aidl::android::hardware::audio::core::StreamContext& context __unused,
         ::aidl::android::hardware::audio::core::StreamDescriptor* desc __unused) {
@@ -1123,8 +1139,14 @@
     *_aidl_return = in_requested;
     auto maxSampleRateIt = std::max_element(sampleRates.begin(), sampleRates.end());
     const int32_t latencyMs = getNominalLatencyMs(*(maxSampleRateIt->second));
-    _aidl_return->minimumStreamBufferSizeFrames =
-            calculateBufferSizeFrames(latencyMs, maxSampleRateIt->first);
+    if (!calculateBufferSizeFrames(
+                maxSampleRateIt->second->format.value(), latencyMs, maxSampleRateIt->first,
+                &_aidl_return->minimumStreamBufferSizeFrames).isOk()) {
+        if (patchesBackup.has_value()) {
+            mPatches = std::move(*patchesBackup);
+        }
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     _aidl_return->latenciesMs.clear();
     _aidl_return->latenciesMs.insert(_aidl_return->latenciesMs.end(),
                                      _aidl_return->sinkPortConfigIds.size(), latencyMs);
diff --git a/audio/aidl/default/config/audioPolicy/api/current.txt b/audio/aidl/default/config/audioPolicy/api/current.txt
index e57c108..3814fe6 100644
--- a/audio/aidl/default/config/audioPolicy/api/current.txt
+++ b/audio/aidl/default/config/audioPolicy/api/current.txt
@@ -50,7 +50,7 @@
     enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO;
     enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO;
     enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_NONE;
-    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_13POINT_360RA;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_13POINT0;
     enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_22POINT2;
     enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT0POINT2;
     enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1;
diff --git a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
index 108a6a3..cfe0a6e 100644
--- a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
+++ b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
@@ -463,7 +463,7 @@
             <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT4"/>
             <xs:enumeration value="AUDIO_CHANNEL_OUT_9POINT1POINT4"/>
             <xs:enumeration value="AUDIO_CHANNEL_OUT_9POINT1POINT6"/>
-            <xs:enumeration value="AUDIO_CHANNEL_OUT_13POINT_360RA"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_13POINT0"/>
             <xs:enumeration value="AUDIO_CHANNEL_OUT_22POINT2"/>
             <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO_HAPTIC_A"/>
             <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A"/>
diff --git a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
index c16e366..cfd99eb 100644
--- a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
+++ b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
@@ -105,7 +105,8 @@
                         <xs:element name="AttributesGroup" type="AttributesGroup" minOccurs="1" maxOccurs="unbounded"/>
                     </xs:sequence>
                     <xs:attribute name="name" type="xs:string" use="required"/>
-                    <xs:attribute name="id" type="xs:int" use="required"/>
+                    <!-- Only needs to be specified for vendor strategies. -->
+                    <xs:attribute name="id" type="xs:int" use="optional"/>
                 </xs:complexType>
             </xs:element>
         </xs:sequence>
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index d03598a..cbc13d1 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -207,12 +207,15 @@
     virtual std::unique_ptr<Configuration> initializeConfig();
     virtual int32_t getNominalLatencyMs(
             const ::aidl::android::media::audio::common::AudioPortConfig& portConfig);
+    virtual ndk::ScopedAStatus calculateBufferSizeFrames(
+            const ::aidl::android::media::audio::common::AudioFormatDescription &format,
+            int32_t latencyMs, int32_t sampleRateHz, int32_t *bufferSizeFrames);
     virtual ndk::ScopedAStatus createMmapBuffer(
             const ::aidl::android::hardware::audio::core::StreamContext& context,
             ::aidl::android::hardware::audio::core::StreamDescriptor* desc);
 
     // Utility and helper functions accessible to subclasses.
-    static int32_t calculateBufferSizeFrames(int32_t latencyMs, int32_t sampleRateHz) {
+    static int32_t calculateBufferSizeFramesForPcm(int32_t latencyMs, int32_t sampleRateHz) {
         const int32_t rawSizeFrames =
                 aidl::android::hardware::audio::common::frameCountFromDurationMs(latencyMs,
                                                                                  sampleRateHz);
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index ea59771..cef0ea6 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -77,17 +77,15 @@
 }
 
 ::android::status_t StreamRemoteSubmix::drain(StreamDescriptor::DrainMode) {
-    usleep(1000);
     return ::android::OK;
 }
 
 ::android::status_t StreamRemoteSubmix::flush() {
-    usleep(1000);
-    return ::android::OK;
+    // TODO(b/372951987): consider if this needs to be done from 'StreamInWorkerLogic::cycle'.
+    return mIsInput ? standby() : ::android::OK;
 }
 
 ::android::status_t StreamRemoteSubmix::pause() {
-    usleep(1000);
     return ::android::OK;
 }
 
diff --git a/audio/aidl/default/r_submix/SubmixRoute.cpp b/audio/aidl/default/r_submix/SubmixRoute.cpp
index 325a012..445b1d3 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.cpp
+++ b/audio/aidl/default/r_submix/SubmixRoute.cpp
@@ -134,10 +134,10 @@
 // - the peer input is in standby AFTER having been active.
 // We DO block if:
 // - the input was never activated to avoid discarding first frames in the pipe in case capture
-// start was delayed
+//   start was delayed
 bool SubmixRoute::shouldBlockWrite() {
     std::lock_guard guard(mLock);
-    return (mStreamInOpen || (mStreamInStandby && (mReadCounterFrames != 0)));
+    return mStreamInOpen && (!mStreamInStandby || mReadCounterFrames == 0);
 }
 
 long SubmixRoute::updateReadCounterFrames(size_t frameCount) {
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index eedac3d..8ceb56b 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -47,6 +47,7 @@
 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::kDrainSupportedVersion;
 using aidl::android::hardware::audio::effect::kEffectTypeUuidSpatializer;
 using aidl::android::hardware::audio::effect::kEventFlagDataMqNotEmpty;
 using aidl::android::hardware::audio::effect::kEventFlagDataMqUpdate;
@@ -195,8 +196,11 @@
                 ASSERT_TRUE(expectState(effect, State::PROCESSING));
                 break;
             case CommandId::STOP:
-                ASSERT_TRUE(expectState(effect, State::IDLE) ||
-                            expectState(effect, State::DRAINING));
+                // Enforce the state checking after kDrainSupportedVersion
+                if (getHalVersion(effect) >= kDrainSupportedVersion) {
+                    ASSERT_TRUE(expectState(effect, State::IDLE) ||
+                                expectState(effect, State::DRAINING));
+                }
                 break;
             case CommandId::RESET:
                 ASSERT_TRUE(expectState(effect, State::IDLE));
@@ -518,6 +522,11 @@
         }
     }
 
+    static int getHalVersion(const std::shared_ptr<IEffect>& effect) {
+        int version = 0;
+        return (effect && effect->getInterfaceVersion(&version).isOk()) ? version : 0;
+    }
+
     bool mIsSpatializer;
     Descriptor mDescriptor;
     size_t mInputFrameSize, mOutputFrameSize;
diff --git a/audio/aidl/vts/VtsHalAECTargetTest.cpp b/audio/aidl/vts/VtsHalAECTargetTest.cpp
index 53b6757..c007f18 100644
--- a/audio/aidl/vts/VtsHalAECTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp
@@ -139,12 +139,12 @@
 };
 
 TEST_P(AECParamTest, SetAndGetEchoDelay) {
-    EXPECT_NO_FATAL_FAILURE(addEchoDelayParam(mEchoDelay));
+    addEchoDelayParam(mEchoDelay);
     SetAndGetParameters();
 }
 
 TEST_P(AECParamTest, SetAndGetMobileMode) {
-    EXPECT_NO_FATAL_FAILURE(addMobileModeParam(mMobileMode));
+    addMobileModeParam(mMobileMode);
     SetAndGetParameters();
 }
 
diff --git a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
index f14afbc..72a2d5e 100644
--- a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
@@ -139,17 +139,17 @@
 };
 
 TEST_P(AGC1ParamTest, SetAndGetTargetPeakLevelParam) {
-    EXPECT_NO_FATAL_FAILURE(addTargetPeakLevelParam(mTargetPeakLevel));
+    addTargetPeakLevelParam(mTargetPeakLevel);
     SetAndGetParameters();
 }
 
 TEST_P(AGC1ParamTest, SetAndGetMaxCompressionGain) {
-    EXPECT_NO_FATAL_FAILURE(addMaxCompressionGainParam(mMaxCompressionGain));
+    addMaxCompressionGainParam(mMaxCompressionGain);
     SetAndGetParameters();
 }
 
 TEST_P(AGC1ParamTest, SetAndGetEnableLimiter) {
-    EXPECT_NO_FATAL_FAILURE(addEnableLimiterParam(mEnableLimiter));
+    addEnableLimiterParam(mEnableLimiter);
     SetAndGetParameters();
 }
 
diff --git a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
index 048d540..ccac8c5 100644
--- a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
@@ -145,17 +145,17 @@
 };
 
 TEST_P(AGC2ParamTest, SetAndGetDigitalGainParam) {
-    EXPECT_NO_FATAL_FAILURE(addDigitalGainParam(mGain));
+    addDigitalGainParam(mGain);
     SetAndGetParameters();
 }
 
 TEST_P(AGC2ParamTest, SetAndGetSaturationMargin) {
-    EXPECT_NO_FATAL_FAILURE(addSaturationMarginParam(mMargin));
+    addSaturationMarginParam(mMargin);
     SetAndGetParameters();
 }
 
 TEST_P(AGC2ParamTest, SetAndGetLevelEstimator) {
-    EXPECT_NO_FATAL_FAILURE(addLevelEstimatorParam(mLevelEstimator));
+    addLevelEstimatorParam(mLevelEstimator);
     SetAndGetParameters();
 }
 
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index 93c2a61..750e54d 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -938,6 +938,8 @@
         LOG(DEBUG) << __func__;
         return "";
     }
+    const std::vector<int8_t>& getData() const { return mData; }
+    void fillData(int8_t filler) { std::fill(mData.begin(), mData.end(), filler); }
     std::optional<StreamDescriptor::Command> maybeGetNextCommand(int* actualSize = nullptr) {
         TransitionTrigger trigger = mDriver->getNextTrigger(mData.size(), actualSize);
         if (StreamEventReceiver::Event* expEvent =
@@ -1007,6 +1009,8 @@
     StreamReaderLogic(const StreamContext& context, StreamLogicDriver* driver,
                       StreamEventReceiver* eventReceiver)
         : StreamCommonLogic(context, driver, eventReceiver) {}
+    // Should only be called after the worker has joined.
+    const std::vector<int8_t>& getData() const { return StreamCommonLogic::getData(); }
 
   protected:
     Status cycle() override {
@@ -1072,6 +1076,7 @@
         if (const size_t readCount =
                     !isMmapped() ? getDataMQ()->availableToRead() : reply.fmqByteCount;
             readCount > 0) {
+            fillData(-1);
             if (isMmapped() ? readDataFromMmap(readCount) : readDataFromMQ(readCount)) {
                 goto checkAcceptedReply;
             }
@@ -1093,6 +1098,8 @@
     StreamWriterLogic(const StreamContext& context, StreamLogicDriver* driver,
                       StreamEventReceiver* eventReceiver)
         : StreamCommonLogic(context, driver, eventReceiver) {}
+    // Should only be called after the worker has joined.
+    const std::vector<int8_t>& getData() const { return StreamCommonLogic::getData(); }
 
   protected:
     Status cycle() override {
@@ -1109,6 +1116,14 @@
             return Status::ABORT;
         }
         if (actualSize != 0) {
+            if (command.getTag() == StreamDescriptor::Command::burst) {
+                fillData(mBurstIteration);
+                if (mBurstIteration < std::numeric_limits<int8_t>::max()) {
+                    mBurstIteration++;
+                } else {
+                    mBurstIteration = 0;
+                }
+            }
             if (isMmapped() ? !writeDataToMmap() : !writeDataToMQ()) {
                 return Status::ABORT;
             }
@@ -1167,6 +1182,9 @@
         LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
         return Status::ABORT;
     }
+
+  private:
+    int8_t mBurstIteration = 1;
 };
 using StreamWriter = StreamWorker<StreamWriterLogic>;
 
@@ -2859,10 +2877,12 @@
         ASSERT_NO_FATAL_FAILURE(mStream->SetUpStream(module, getMinimumStreamBufferSizeFrames()));
     }
 
-    void SetUpStreamForDevicePort(IModule* module, ModuleConfig* moduleConfig,
-                                  const AudioPort& devicePort, bool connectedOnly = false) {
-        ASSERT_NO_FATAL_FAILURE(
-                SetUpPortConfigForDevicePort(module, moduleConfig, devicePort, connectedOnly));
+    void SetUpStreamForDevicePort(
+            IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort,
+            bool connectedOnly = false,
+            const std::optional<AudioDeviceAddress>& connectionAddress = std::nullopt) {
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConfigForDevicePort(module, moduleConfig, devicePort,
+                                                             connectedOnly, connectionAddress));
         if (!mSkipTestReason.empty()) return;
         ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
     }
@@ -2898,6 +2918,23 @@
         if (!mSkipTestReason.empty()) return;
         ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
     }
+    void SetUpStreamForNewMixPortConfig(IModule* module, ModuleConfig*,
+                                        const AudioPortConfig& existingMixPortConfig,
+                                        const AudioPortConfig& existingDevicePortConfig) {
+        auto mixPortConfig = existingMixPortConfig;
+        mixPortConfig.id = 0;
+        mMixPortConfig = std::make_unique<WithAudioPortConfig>(mixPortConfig);
+        ASSERT_NO_FATAL_FAILURE(mMixPortConfig->SetUp(module));
+        mDevicePortConfig = std::make_unique<WithAudioPortConfig>(existingDevicePortConfig);
+        ASSERT_NO_FATAL_FAILURE(mDevicePortConfig->SetUp(module));
+        mDevice = existingDevicePortConfig.ext.get<AudioPortExt::device>().device;
+        mPatch = std::make_unique<WithAudioPatch>(mIsInput, mMixPortConfig->get(),
+                                                  mDevicePortConfig->get());
+        ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(module));
+        mStream = std::make_unique<WithStream<Stream>>(mMixPortConfig->get());
+        ASSERT_NO_FATAL_FAILURE(mStream->SetUpPortConfig(module));
+        ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
+    }
     void SetUpPatchForMixPortConfig(IModule* module, ModuleConfig* moduleConfig,
                                     const AudioPortConfig& mixPortConfig) {
         constexpr bool connectedOnly = true;
@@ -2929,6 +2966,7 @@
     }
 
     const AudioDevice& getDevice() const { return mDevice; }
+    const AudioPortConfig& getDevicePortConfig() const { return mDevicePortConfig->get(); }
     int32_t getMinimumStreamBufferSizeFrames() const {
         return mPatch->getMinimumStreamBufferSizeFrames();
     }
@@ -2944,7 +2982,8 @@
   private:
     void SetUpDevicePort(IModule* module, ModuleConfig* moduleConfig,
                          const std::set<int32_t>& devicePortIds, bool connectedOnly,
-                         std::optional<AudioPort>* connectedDevicePort) {
+                         std::optional<AudioPort>* connectedDevicePort,
+                         const std::optional<AudioDeviceAddress>& connectionAddress) {
         const auto attachedDevicePorts = moduleConfig->getAttachedDevicePorts();
         if (auto it = findAny<AudioPort>(attachedDevicePorts, devicePortIds);
             it != attachedDevicePorts.end()) {
@@ -2961,7 +3000,12 @@
             const auto externalDevicePorts = moduleConfig->getExternalDevicePorts();
             if (auto it = findAny<AudioPort>(externalDevicePorts, devicePortIds);
                 it != externalDevicePorts.end()) {
-                AudioPort portWithData = GenerateUniqueDeviceAddress(*it);
+                AudioPort portWithData = *it;
+                if (connectionAddress.has_value()) {
+                    portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+                            *connectionAddress;
+                }
+                portWithData = GenerateUniqueDeviceAddress(portWithData);
                 mPortConnected = std::make_unique<WithDevicePortConnectedState>(portWithData);
                 ASSERT_NO_FATAL_FAILURE(mPortConnected->SetUp(module, moduleConfig));
                 *connectedDevicePort = mPortConnected->get();
@@ -2980,9 +3024,9 @@
             LOG(DEBUG) << __func__ << ": " << mSkipTestReason;
             return;
         };
-        ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(module, moduleConfig,
-                                                extractIds<AudioPort>(devicePorts), connectedOnly,
-                                                connectedDevicePort));
+        ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(
+                module, moduleConfig, extractIds<AudioPort>(devicePorts), connectedOnly,
+                connectedDevicePort, std::nullopt /*connectionAddress*/));
         if (!connectedDevicePort->has_value()) {
             mSkipTestReason = std::string("Unable to find a device port pair for mix port id ")
                                       .append(std::to_string(mixPort.id));
@@ -2990,11 +3034,14 @@
             return;
         }
     }
-    void SetUpPortConfigForDevicePort(IModule* module, ModuleConfig* moduleConfig,
-                                      const AudioPort& devicePort, bool connectedOnly) {
+    void SetUpPortConfigForDevicePort(
+            IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort,
+            bool connectedOnly,
+            const std::optional<AudioDeviceAddress>& connectionAddress = std::nullopt) {
         std::optional<AudioPort> connectedDevicePort;
         ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(module, moduleConfig, {devicePort.id},
-                                                connectedOnly, &connectedDevicePort));
+                                                connectedOnly, &connectedDevicePort,
+                                                connectionAddress));
         if (!connectedDevicePort.has_value()) {
             mSkipTestReason = std::string("Device port id ")
                                       .append(std::to_string(devicePort.id))
@@ -3135,7 +3182,8 @@
 };
 
 // Defined later together with state transition sequences.
-std::shared_ptr<StateSequence> makeBurstCommands(bool isSync);
+std::shared_ptr<StateSequence> makeBurstCommands(bool isSync, size_t burstCount = 10,
+                                                 bool standbyInputWhenDone = false);
 
 // Certain types of ports can not be used without special preconditions.
 static bool skipStreamIoTestForMixPortConfig(const AudioPortConfig& portConfig) {
@@ -3160,10 +3208,11 @@
   public:
     explicit StreamFixtureWithWorker(bool isSync) : mIsSync(isSync) {}
 
-    void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort) {
+    void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort,
+               const std::optional<AudioDeviceAddress>& connectionAddress = std::nullopt) {
         mStream = std::make_unique<StreamFixture<Stream>>();
-        ASSERT_NO_FATAL_FAILURE(
-                mStream->SetUpStreamForDevicePort(module, moduleConfig, devicePort));
+        ASSERT_NO_FATAL_FAILURE(mStream->SetUpStreamForDevicePort(
+                module, moduleConfig, devicePort, false /*connectedOnly*/, connectionAddress));
         MaybeSetSkipTestReason();
     }
 
@@ -3175,26 +3224,42 @@
         MaybeSetSkipTestReason();
     }
 
-    void SendBurstCommands(bool validatePosition = true) {
-        ASSERT_NO_FATAL_FAILURE(StartWorkerToSendBurstCommands());
+    void SetUp(IModule* module, ModuleConfig* moduleConfig,
+               const AudioPortConfig& existingMixPortConfig,
+               const AudioPortConfig& existingDevicePortConfig) {
+        mStream = std::make_unique<StreamFixture<Stream>>();
+        ASSERT_NO_FATAL_FAILURE(mStream->SetUpStreamForNewMixPortConfig(
+                module, moduleConfig, existingMixPortConfig, existingDevicePortConfig));
+        MaybeSetSkipTestReason();
+    }
+
+    void SendBurstCommands(bool validatePosition = true, size_t burstCount = 10,
+                           bool standbyInputWhenDone = false) {
+        ASSERT_NO_FATAL_FAILURE(StartWorkerToSendBurstCommands(burstCount, standbyInputWhenDone));
         ASSERT_NO_FATAL_FAILURE(JoinWorkerAfterBurstCommands(validatePosition));
     }
 
-    void StartWorkerToSendBurstCommands() {
+    void StartWorkerToSendBurstCommands(size_t burstCount = 10, bool standbyInputWhenDone = false) {
+        if (!IOTraits<Stream>::is_input) {
+            ASSERT_FALSE(standbyInputWhenDone) << "Only supported for input";
+        }
         const StreamContext* context = mStream->getStreamContext();
         mWorkerDriver = std::make_unique<StreamLogicDefaultDriver>(
-                makeBurstCommands(mIsSync), context->getFrameSizeBytes(), context->isMmapped());
+                makeBurstCommands(mIsSync, burstCount, standbyInputWhenDone),
+                context->getFrameSizeBytes(), context->isMmapped());
         mWorker = std::make_unique<typename IOTraits<Stream>::Worker>(
                 *context, mWorkerDriver.get(), mStream->getStreamEventReceiver());
         LOG(DEBUG) << __func__ << ": starting " << IOTraits<Stream>::directionStr << " worker...";
         ASSERT_TRUE(mWorker->start());
     }
 
-    void JoinWorkerAfterBurstCommands(bool validatePosition = true) {
-        // Must call 'prepareToClose' before attempting to join because the stream may be stuck.
-        std::shared_ptr<IStreamCommon> common;
-        ASSERT_IS_OK(mStream->getStream()->getStreamCommon(&common));
-        ASSERT_IS_OK(common->prepareToClose());
+    void JoinWorkerAfterBurstCommands(bool validatePosition = true,
+                                      bool callPrepareToClose = true) {
+        if (callPrepareToClose) {
+            std::shared_ptr<IStreamCommon> common;
+            ASSERT_IS_OK(mStream->getStream()->getStreamCommon(&common));
+            ASSERT_IS_OK(common->prepareToClose());
+        }
         LOG(DEBUG) << __func__ << ": joining " << IOTraits<Stream>::directionStr << " worker...";
         mWorker->join();
         EXPECT_FALSE(mWorker->hasError()) << mWorker->getError();
@@ -3205,6 +3270,7 @@
             EXPECT_FALSE(mWorkerDriver->hasObservableRetrogradePosition());
             EXPECT_FALSE(mWorkerDriver->hasHardwareRetrogradePosition());
         }
+        mLastData = mWorker->getData();
         mWorker.reset();
         mWorkerDriver.reset();
     }
@@ -3212,6 +3278,9 @@
     void TeardownPatch() { mStream->TeardownPatch(); }
 
     const AudioDevice& getDevice() const { return mStream->getDevice(); }
+    const AudioPortConfig& getDevicePortConfig() const { return mStream->getDevicePortConfig(); }
+    const std::vector<int8_t>& getLastData() const { return mLastData; }
+    const AudioPortConfig& getPortConfig() const { return mStream->getPortConfig(); }
     Stream* getStream() const { return mStream->getStream(); }
     std::string skipTestReason() const {
         return !mSkipTestReason.empty() ? mSkipTestReason : mStream->skipTestReason();
@@ -3229,6 +3298,7 @@
     std::unique_ptr<StreamFixture<Stream>> mStream;
     std::unique_ptr<StreamLogicDefaultDriver> mWorkerDriver;
     std::unique_ptr<typename IOTraits<Stream>::Worker> mWorker;
+    std::vector<int8_t> mLastData;
 };
 
 template <typename Stream>
@@ -4576,15 +4646,20 @@
 
 // TODO: Add async test cases for input once it is implemented.
 
-std::shared_ptr<StateSequence> makeBurstCommands(bool isSync) {
+std::shared_ptr<StateSequence> makeBurstCommands(bool isSync, size_t burstCount,
+                                                 bool standbyInputWhenDone) {
     using State = StreamDescriptor::State;
     auto d = std::make_unique<StateDag>();
-    StateDag::Node last = d->makeFinalNode(State::ACTIVE);
+    StateDag::Node active = d->makeFinalNode(State::ACTIVE);
+    StateDag::Node paused = d->makeNodes({std::make_pair(State::ACTIVE, kPauseCommand),
+                                          std::make_pair(State::PAUSED, kFlushCommand)},
+                                         State::STANDBY);
+    StateDag::Node& last = standbyInputWhenDone ? paused : active;
     if (isSync) {
         StateDag::Node idle = d->makeNode(
                 State::IDLE, kBurstCommand,
                 // Use several bursts to ensure that the driver starts reporting the position.
-                d->makeNodes(State::ACTIVE, kBurstCommand, 10, last));
+                d->makeNodes(State::ACTIVE, kBurstCommand, burstCount, last));
         d->makeNode(State::STANDBY, kStartCommand, idle);
     } else {
         StateDag::Node active2 = d->makeNode(State::ACTIVE, kBurstCommand, last);
@@ -4949,49 +5024,69 @@
   public:
     WithRemoteSubmix() : mStream(true /*isSync*/) {}
     explicit WithRemoteSubmix(AudioDeviceAddress address)
-        : mStream(true /*isSync*/), mAddress(address) {}
+        : mStream(true /*isSync*/), mAddress(address) {
+        LOG(DEBUG) << __func__ << ": Creating " << IOTraits<Stream>::directionStr
+                   << " stream for: " << mAddress.value_or(AudioDeviceAddress{}).toString();
+    }
     WithRemoteSubmix(const WithRemoteSubmix&) = delete;
     WithRemoteSubmix& operator=(const WithRemoteSubmix&) = delete;
+    ~WithRemoteSubmix() {
+        LOG(DEBUG) << __func__ << ": Deleting " << IOTraits<Stream>::directionStr
+                   << " stream for: " << mAddress.value_or(AudioDeviceAddress{}).toString();
+    }
 
-    static std::optional<AudioPort> getRemoteSubmixAudioPort(
-            ModuleConfig* moduleConfig,
-            const std::optional<AudioDeviceAddress>& address = std::nullopt) {
+    static std::optional<AudioPort> getRemoteSubmixAudioPort(ModuleConfig* moduleConfig) {
         auto ports =
                 moduleConfig->getRemoteSubmixPorts(IOTraits<Stream>::is_input, true /*singlePort*/);
         if (ports.empty()) return {};
-        AudioPort port = ports.front();
-        if (address) {
-            port.ext.template get<AudioPortExt::Tag::device>().device.address = address.value();
-        }
-        return port;
+        return ports.front();
     }
 
     void SetUp(IModule* module, ModuleConfig* moduleConfig) {
-        auto devicePort = getRemoteSubmixAudioPort(moduleConfig, mAddress);
+        auto devicePort = getRemoteSubmixAudioPort(moduleConfig);
         ASSERT_TRUE(devicePort.has_value()) << "Device port for remote submix device not found";
-        ASSERT_NO_FATAL_FAILURE(mStream.SetUp(module, moduleConfig, *devicePort));
+        ASSERT_NO_FATAL_FAILURE(mStream.SetUp(module, moduleConfig, *devicePort, mAddress));
         mAddress = mStream.getDevice().address;
     }
-
-    void StartWorkerToSendBurstCommands() {
-        ASSERT_NO_FATAL_FAILURE(mStream.StartWorkerToSendBurstCommands());
+    void SetUp(IModule* module, ModuleConfig* moduleConfig,
+               const AudioPortConfig& existingMixPortConfig,
+               const AudioPortConfig& existingDevicePortConfig) {
+        ASSERT_NO_FATAL_FAILURE(mStream.SetUp(module, moduleConfig, existingMixPortConfig,
+                                              existingDevicePortConfig));
+        mAddress = mStream.getDevice().address;
+    }
+    void StartWorkerToSendBurstCommands(size_t burstCount = 10, bool standbyInputWhenDone = false) {
+        ASSERT_NO_FATAL_FAILURE(
+                mStream.StartWorkerToSendBurstCommands(burstCount, standbyInputWhenDone));
     }
 
-    void JoinWorkerAfterBurstCommands() {
-        ASSERT_NO_FATAL_FAILURE(mStream.JoinWorkerAfterBurstCommands());
+    void JoinWorkerAfterBurstCommands(bool callPrepareToCloseBeforeJoin) {
+        ASSERT_NO_FATAL_FAILURE(mStream.JoinWorkerAfterBurstCommands(
+                true /*validatePositionIncrease*/, callPrepareToCloseBeforeJoin));
     }
 
-    void SendBurstCommands() {
-        ASSERT_NO_FATAL_FAILURE(mStream.StartWorkerToSendBurstCommands());
-        ASSERT_NO_FATAL_FAILURE(mStream.JoinWorkerAfterBurstCommands());
+    void JoinWorkerAfterBurstCommands(bool validatePositionIncrease,
+                                      bool callPrepareToCloseBeforeJoin) {
+        ASSERT_NO_FATAL_FAILURE(mStream.JoinWorkerAfterBurstCommands(validatePositionIncrease,
+                                                                     callPrepareToCloseBeforeJoin));
+    }
+
+    void SendBurstCommands(bool callPrepareToCloseBeforeJoin, size_t burstCount = 10,
+                           bool standbyInputWhenDone = false) {
+        ASSERT_NO_FATAL_FAILURE(StartWorkerToSendBurstCommands(burstCount, standbyInputWhenDone));
+        // When 'burstCount == 0', there is no "previous" frame count, thus the check for
+        // the position increase fails.
+        ASSERT_NO_FATAL_FAILURE(JoinWorkerAfterBurstCommands(
+                burstCount > 0 /*validatePositionIncrease*/, callPrepareToCloseBeforeJoin));
     }
 
     std::optional<AudioDeviceAddress> getAudioDeviceAddress() const { return mAddress; }
+    const AudioPortConfig& getDevicePortConfig() const { return mStream.getDevicePortConfig(); }
+    int8_t getLastBurstIteration() const { return mStream.getLastData()[0]; }
+    const AudioPortConfig& getPortConfig() const { return mStream.getPortConfig(); }
     std::string skipTestReason() const { return mStream.skipTestReason(); }
 
   private:
-    void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort) {}
-
     StreamFixtureWithWorker<Stream> mStream;
     std::optional<AudioDeviceAddress> mAddress;
 };
@@ -5007,77 +5102,130 @@
         }
         ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
     }
+
+    void TearDown() override {
+        streamIn.reset();
+        streamOut.reset();
+    }
+
+    void CreateOutputStream() {
+        streamOut = std::make_unique<WithRemoteSubmix<IStreamOut>>();
+        ASSERT_NO_FATAL_FAILURE(streamOut->SetUp(module.get(), moduleConfig.get()));
+        // Note: any issue with connection attempts is considered as a problem.
+        ASSERT_EQ("", streamOut->skipTestReason());
+        ASSERT_TRUE(streamOut->getAudioDeviceAddress().has_value());
+    }
+
+    void CreateInputStream(const std::optional<AudioDeviceAddress>& address = std::nullopt) {
+        if (address.has_value()) {
+            streamIn = std::make_unique<WithRemoteSubmix<IStreamIn>>(address.value());
+        } else {
+            ASSERT_TRUE(streamOut->getAudioDeviceAddress().has_value());
+            streamIn = std::make_unique<WithRemoteSubmix<IStreamIn>>(
+                    streamOut->getAudioDeviceAddress().value());
+        }
+        ASSERT_NO_FATAL_FAILURE(streamIn->SetUp(module.get(), moduleConfig.get()));
+        ASSERT_EQ("", streamIn->skipTestReason());
+        auto inAddress = streamIn->getAudioDeviceAddress();
+        ASSERT_TRUE(inAddress.has_value());
+        if (address.has_value()) {
+            if (address.value() != AudioDeviceAddress{}) {
+                ASSERT_EQ(address.value(), inAddress.value());
+            }
+        } else {
+            ASSERT_EQ(streamOut->getAudioDeviceAddress().value(), inAddress.value());
+        }
+    }
+
+    std::unique_ptr<WithRemoteSubmix<IStreamOut>> streamOut;
+    std::unique_ptr<WithRemoteSubmix<IStreamIn>> streamIn;
 };
 
 TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenNoInput) {
-    WithRemoteSubmix<IStreamOut> streamOut;
-    ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    // Note: here and in other tests any issue with connection attempts is considered as a problem.
-    ASSERT_EQ("", streamOut.skipTestReason());
-    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommands());
+    ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+    ASSERT_NO_FATAL_FAILURE(streamOut->SendBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
 }
 
-TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenInputStuck) {
-    WithRemoteSubmix<IStreamOut> streamOut;
-    ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    ASSERT_EQ("", streamOut.skipTestReason());
-    auto address = streamOut.getAudioDeviceAddress();
-    ASSERT_TRUE(address.has_value());
+TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenInputInStandby) {
+    if (int32_t version; module->getInterfaceVersion(&version).isOk() && version < 3) {
+        GTEST_SKIP() << "Default remote submix implementation <V3 could not pass this test";
+    }
+    ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+    ASSERT_NO_FATAL_FAILURE(CreateInputStream());
+    ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
+    // Send just 1 burst command. This triggers the condition "input is in standby after
+    // being active." The output must flush the fifo before writing to avoid being blocked.
+    ASSERT_NO_FATAL_FAILURE(
+            streamIn->StartWorkerToSendBurstCommands(1, true /*stanbyInputWhenDone*/));
+    // The output must be able to close without shutting down the pipe first (due to a call
+    // to 'prepareToClose').
+    ASSERT_NO_FATAL_FAILURE(
+            streamOut->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
+    ASSERT_NO_FATAL_FAILURE(
+            streamIn->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
+}
 
-    WithRemoteSubmix<IStreamIn> streamIn(address.value());
-    ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
-    ASSERT_EQ("", streamIn.skipTestReason());
+TEST_P(AudioModuleRemoteSubmix, BlockedOutputUnblocksOnClose) {
+    ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+    ASSERT_NO_FATAL_FAILURE(CreateInputStream());
+    ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
+    // Send just 3 burst command, but do not enter standby. This is a stalled input.
+    ASSERT_NO_FATAL_FAILURE(streamIn->StartWorkerToSendBurstCommands(3));
+    ASSERT_NO_FATAL_FAILURE(
+            streamOut->JoinWorkerAfterBurstCommands(true /*callPrepareToCloseBeforeJoin*/));
+    ASSERT_NO_FATAL_FAILURE(
+            streamIn->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
+}
 
-    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommands());
+TEST_P(AudioModuleRemoteSubmix, OutputBlocksUntilInputStarts) {
+    ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+    ASSERT_NO_FATAL_FAILURE(CreateInputStream());
+    ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
+    // Read the head of the pipe and check that it starts with the first output burst, that is,
+    // the contents of the very first write has not been superseded due to pipe overflow.
+    // The burstCount is '0' because the very first burst is used to exit from the 'IDLE' state,
+    // see 'makeBurstCommands'.
+    ASSERT_NO_FATAL_FAILURE(streamIn->SendBurstCommands(false /*callPrepareToCloseBeforeJoin*/, 0,
+                                                        true /*standbyInputWhenDone*/));
+    EXPECT_EQ(1, streamIn->getLastBurstIteration());
+    ASSERT_NO_FATAL_FAILURE(
+            streamOut->JoinWorkerAfterBurstCommands(true /*callPrepareToCloseBeforeJoin*/));
 }
 
 TEST_P(AudioModuleRemoteSubmix, OutputAndInput) {
-    WithRemoteSubmix<IStreamOut> streamOut;
-    ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    ASSERT_EQ("", streamOut.skipTestReason());
-    auto address = streamOut.getAudioDeviceAddress();
-    ASSERT_TRUE(address.has_value());
-
-    WithRemoteSubmix<IStreamIn> streamIn(address.value());
-    ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
-    ASSERT_EQ("", streamIn.skipTestReason());
-
+    ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+    ASSERT_NO_FATAL_FAILURE(CreateInputStream());
     // Start writing into the output stream.
-    ASSERT_NO_FATAL_FAILURE(streamOut.StartWorkerToSendBurstCommands());
+    ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
     // Simultaneously, read from the input stream.
-    ASSERT_NO_FATAL_FAILURE(streamIn.SendBurstCommands());
-    ASSERT_NO_FATAL_FAILURE(streamOut.JoinWorkerAfterBurstCommands());
+    ASSERT_NO_FATAL_FAILURE(streamIn->SendBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
+    ASSERT_NO_FATAL_FAILURE(
+            streamOut->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
 }
 
 TEST_P(AudioModuleRemoteSubmix, OpenInputMultipleTimes) {
-    WithRemoteSubmix<IStreamOut> streamOut;
-    ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    ASSERT_EQ("", streamOut.skipTestReason());
-    auto address = streamOut.getAudioDeviceAddress();
-    ASSERT_TRUE(address.has_value());
-
-    const size_t streamInCount = 3;
-    std::vector<std::unique_ptr<WithRemoteSubmix<IStreamIn>>> streamIns(streamInCount);
-    for (size_t i = 0; i < streamInCount; i++) {
-        streamIns[i] = std::make_unique<WithRemoteSubmix<IStreamIn>>(address.value());
-        ASSERT_NO_FATAL_FAILURE(streamIns[i]->SetUp(module.get(), moduleConfig.get()));
+    ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+    ASSERT_NO_FATAL_FAILURE(CreateInputStream());
+    ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
+    ASSERT_NO_FATAL_FAILURE(streamIn->SendBurstCommands(false /*callPrepareToCloseBeforeJoin*/, 1,
+                                                        true /*standbyInputWhenDone*/));
+    // For the new stream, only create a new mix port config and a new patch.
+    const size_t extraStreamInCount = 2;
+    std::vector<std::unique_ptr<WithRemoteSubmix<IStreamIn>>> streamIns(extraStreamInCount);
+    for (size_t i = 0; i < extraStreamInCount; i++) {
+        streamIns[i] = std::make_unique<WithRemoteSubmix<IStreamIn>>();
+        ASSERT_NO_FATAL_FAILURE(streamIns[i]->SetUp(module.get(), moduleConfig.get(),
+                                                    streamIn->getPortConfig(),
+                                                    streamIn->getDevicePortConfig()));
         ASSERT_EQ("", streamIns[i]->skipTestReason());
+        const auto inAddress = streamIns[i]->getAudioDeviceAddress();
+        ASSERT_TRUE(inAddress.has_value());
+        ASSERT_EQ(streamOut->getAudioDeviceAddress().value(), inAddress.value());
+        ASSERT_NO_FATAL_FAILURE(streamIns[i]->SendBurstCommands(
+                false /*callPrepareToCloseBeforeJoin*/, 1, true /*standbyInputWhenDone*/));
     }
-    // Start writing into the output stream.
-    ASSERT_NO_FATAL_FAILURE(streamOut.StartWorkerToSendBurstCommands());
-    // Simultaneously, read from input streams.
-    for (size_t i = 0; i < streamInCount; i++) {
-        ASSERT_NO_FATAL_FAILURE(streamIns[i]->StartWorkerToSendBurstCommands());
-    }
-    for (size_t i = 0; i < streamInCount; i++) {
-        ASSERT_NO_FATAL_FAILURE(streamIns[i]->JoinWorkerAfterBurstCommands());
-    }
-    ASSERT_NO_FATAL_FAILURE(streamOut.JoinWorkerAfterBurstCommands());
-    // Clean up input streams in the reverse order because the device connection is owned
-    // by the first one.
-    for (size_t i = streamInCount; i != 0; --i) {
-        streamIns[i - 1].reset();
-    }
+    ASSERT_NO_FATAL_FAILURE(
+            streamOut->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
 }
 
 INSTANTIATE_TEST_SUITE_P(AudioModuleRemoteSubmixTest, AudioModuleRemoteSubmix,
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index d23bdc9..5b78981 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -42,6 +42,7 @@
 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::kDestroyAnyStateSupportedVersion;
 using aidl::android::hardware::audio::effect::Parameter;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::media::audio::common::AudioDeviceDescription;
@@ -316,28 +317,39 @@
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
-// Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
+// Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed before
+// `kDestroyAnyStateSupportedVersion`.
+// For any version after `kDestroyAnyStateSupportedVersion`, expect `destroy` to always success.
 TEST_P(AudioEffectTest, DestroyOpenEffects) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect, EX_ILLEGAL_STATE));
-
-    // cleanup
-    ASSERT_NO_FATAL_FAILURE(close(mEffect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    if (mVersion < kDestroyAnyStateSupportedVersion) {
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect, EX_ILLEGAL_STATE));
+        // cleanup
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    } else {
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
 }
 
-// Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
+// Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed before
+// `kDestroyAnyStateSupportedVersion`.
+// For any version after `kDestroyAnyStateSupportedVersion`, expect `destroy` to always success.
 TEST_P(AudioEffectTest, DestroyProcessingEffects) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect, EX_ILLEGAL_STATE));
 
-    // cleanup
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(close(mEffect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    if (mVersion < kDestroyAnyStateSupportedVersion) {
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect, EX_ILLEGAL_STATE));
+        // cleanup
+        ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    } else {
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
 }
 
 TEST_P(AudioEffectTest, NormalSequenceStates) {
diff --git a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
index bf22839..322fdc0 100644
--- a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
@@ -52,7 +52,7 @@
         AudioChannelLayout::LAYOUT_5POINT1POINT4, AudioChannelLayout::LAYOUT_6POINT1,
         AudioChannelLayout::LAYOUT_7POINT1,       AudioChannelLayout::LAYOUT_7POINT1POINT2,
         AudioChannelLayout::LAYOUT_7POINT1POINT4, AudioChannelLayout::LAYOUT_9POINT1POINT4,
-        AudioChannelLayout::LAYOUT_9POINT1POINT6, AudioChannelLayout::LAYOUT_13POINT_360RA,
+        AudioChannelLayout::LAYOUT_9POINT1POINT6, AudioChannelLayout::LAYOUT_13POINT0,
         AudioChannelLayout::LAYOUT_22POINT2};
 
 static const std::vector<int32_t> kChannels = {
diff --git a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
index 3b1f3d9..37441f0 100644
--- a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
+++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
@@ -542,7 +542,7 @@
 };
 
 TEST_P(DynamicsProcessingTestEngineArchitecture, SetAndGetEngineArch) {
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mCfg));
+    addEngineConfig(mCfg);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
@@ -594,7 +594,7 @@
 };
 
 TEST_P(DynamicsProcessingTestInputGain, SetAndGetInputGain) {
-    EXPECT_NO_FATAL_FAILURE(addInputGain(mInputGain));
+    addInputGain(mInputGain);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
@@ -652,7 +652,7 @@
             mInputGain.push_back(DynamicsProcessing::InputGain(i, gainDb));
         }
         std::vector<float> output(mInput.size());
-        EXPECT_NO_FATAL_FAILURE(addInputGain(mInputGain));
+        addInputGain(mInputGain);
         EXPECT_NO_FATAL_FAILURE(setParamsAndProcess(mInput, output));
         if (!isAllParamsValid()) {
             continue;
@@ -719,8 +719,8 @@
 };
 
 TEST_P(DynamicsProcessingTestLimiterConfig, SetAndGetLimiterConfig) {
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
-    EXPECT_NO_FATAL_FAILURE(addLimiterConfig(mLimiterConfigList));
+    addEngineConfig(mEngineConfigPreset);
+    addLimiterConfig(mLimiterConfigList);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
@@ -782,8 +782,8 @@
     }
 
     void setLimiterParamsAndProcess(std::vector<float>& input, std::vector<float>& output) {
-        EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
-        EXPECT_NO_FATAL_FAILURE(addLimiterConfig(mLimiterConfigList));
+        addEngineConfig(mEngineConfigPreset);
+        addLimiterConfig(mLimiterConfigList);
         EXPECT_NO_FATAL_FAILURE(setParamsAndProcess(input, output));
     }
 
@@ -937,20 +937,20 @@
 };
 
 TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPreEqChannelConfig) {
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
-    EXPECT_NO_FATAL_FAILURE(addPreEqChannelConfig(mCfg));
+    addEngineConfig(mEngineConfigPreset);
+    addPreEqChannelConfig(mCfg);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
 TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPostEqChannelConfig) {
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
-    EXPECT_NO_FATAL_FAILURE(addPostEqChannelConfig(mCfg));
+    addEngineConfig(mEngineConfigPreset);
+    addPostEqChannelConfig(mCfg);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
 TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetMbcChannelConfig) {
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
-    EXPECT_NO_FATAL_FAILURE(addMbcChannelConfig(mCfg));
+    addEngineConfig(mEngineConfigPreset);
+    addMbcChannelConfig(mCfg);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
@@ -1018,27 +1018,27 @@
 
 TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPreEqBandConfig) {
     mEngineConfigPreset.preEqStage.bandCount = mCfgs.size();
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+    addEngineConfig(mEngineConfigPreset);
     std::vector<DynamicsProcessing::ChannelConfig> cfgs(mChannelCount);
     for (int i = 0; i < mChannelCount; i++) {
         cfgs[i].channel = i;
         cfgs[i].enable = true;
     }
-    EXPECT_NO_FATAL_FAILURE(addPreEqChannelConfig(cfgs));
-    EXPECT_NO_FATAL_FAILURE(addPreEqBandConfigs(mCfgs));
+    addPreEqChannelConfig(cfgs);
+    addPreEqBandConfigs(mCfgs);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
 TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPostEqBandConfig) {
     mEngineConfigPreset.postEqStage.bandCount = mCfgs.size();
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+    addEngineConfig(mEngineConfigPreset);
     std::vector<DynamicsProcessing::ChannelConfig> cfgs(mChannelCount);
     for (int i = 0; i < mChannelCount; i++) {
         cfgs[i].channel = i;
         cfgs[i].enable = true;
     }
-    EXPECT_NO_FATAL_FAILURE(addPostEqChannelConfig(cfgs));
-    EXPECT_NO_FATAL_FAILURE(addPostEqBandConfigs(mCfgs));
+    addPostEqChannelConfig(cfgs);
+    addPostEqBandConfigs(mCfgs);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
@@ -1185,14 +1185,14 @@
 
 TEST_P(DynamicsProcessingTestMbcBandConfig, SetAndGetMbcBandConfig) {
     mEngineConfigPreset.mbcStage.bandCount = mCfgs.size();
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+    addEngineConfig(mEngineConfigPreset);
     std::vector<DynamicsProcessing::ChannelConfig> cfgs(mChannelCount);
     for (int i = 0; i < mChannelCount; i++) {
         cfgs[i].channel = i;
         cfgs[i].enable = true;
     }
-    EXPECT_NO_FATAL_FAILURE(addMbcChannelConfig(cfgs));
-    EXPECT_NO_FATAL_FAILURE(addMbcBandConfigs(mCfgs));
+    addMbcChannelConfig(cfgs);
+    addMbcBandConfigs(mCfgs);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
index a29920e..bf48a87 100644
--- a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -43,13 +43,13 @@
 static const std::vector<TagVectorPair> kParamsIncreasingVector = {
         {EnvironmentalReverb::roomLevelMb, {-3500, -2800, -2100, -1400, -700, 0}},
         {EnvironmentalReverb::roomHfLevelMb, {-4000, -3200, -2400, -1600, -800, 0}},
-        {EnvironmentalReverb::decayTimeMs, {800, 1600, 2400, 3200, 4000}},
-        {EnvironmentalReverb::decayHfRatioPm, {100, 600, 1100, 1600, 2000}},
+        {EnvironmentalReverb::decayTimeMs, {400, 800, 1200, 1600, 2000}},
+        {EnvironmentalReverb::decayHfRatioPm, {1000, 900, 800, 700}},
         {EnvironmentalReverb::levelMb, {-3500, -2800, -2100, -1400, -700, 0}},
 };
 
 static const TagVectorPair kDiffusionParam = {EnvironmentalReverb::diffusionPm,
-                                              {200, 400, 600, 800, 1000}};
+                                              {100, 300, 500, 700, 900}};
 static const TagVectorPair kDensityParam = {EnvironmentalReverb::densityPm,
                                             {0, 200, 400, 600, 800, 1000}};
 
@@ -281,7 +281,7 @@
 
     static constexpr int kDurationMilliSec = 500;
     static constexpr int kBufferSize = kSamplingFrequency * kDurationMilliSec / 1000;
-    static constexpr int kInputFrequency = 1000;
+    static constexpr int kInputFrequency = 2000;
 
     int mStereoChannelCount =
             getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp
index a50e1b4..c5a9bad 100644
--- a/audio/aidl/vts/VtsHalNSTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp
@@ -140,12 +140,12 @@
 };
 
 TEST_P(NSParamTest, SetAndGetLevel) {
-    EXPECT_NO_FATAL_FAILURE(addLevelParam(mLevel));
+    addLevelParam(mLevel);
     SetAndGetParameters();
 }
 
 TEST_P(NSParamTest, SetAndGetType) {
-    EXPECT_NO_FATAL_FAILURE(addLevelParam(mLevel));
+    addLevelParam(mLevel);
     SetAndGetParameters();
 }
 
diff --git a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
index a942521..3b07809 100644
--- a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
@@ -189,22 +189,22 @@
 };
 
 TEST_P(VisualizerParamTest, SetAndGetCaptureSize) {
-    ASSERT_NO_FATAL_FAILURE(addCaptureSizeParam(mCaptureSize));
+    addCaptureSizeParam(mCaptureSize);
     ASSERT_NO_FATAL_FAILURE(SetAndGetParameters());
 }
 
 TEST_P(VisualizerParamTest, SetAndGetScalingMode) {
-    ASSERT_NO_FATAL_FAILURE(addScalingModeParam(mScalingMode));
+    addScalingModeParam(mScalingMode);
     ASSERT_NO_FATAL_FAILURE(SetAndGetParameters());
 }
 
 TEST_P(VisualizerParamTest, SetAndGetMeasurementMode) {
-    ASSERT_NO_FATAL_FAILURE(addMeasurementModeParam(mMeasurementMode));
+    addMeasurementModeParam(mMeasurementMode);
     ASSERT_NO_FATAL_FAILURE(SetAndGetParameters());
 }
 
 TEST_P(VisualizerParamTest, SetAndGetLatency) {
-    ASSERT_NO_FATAL_FAILURE(addLatencyParam(mLatency));
+    addLatencyParam(mLatency);
     ASSERT_NO_FATAL_FAILURE(SetAndGetParameters());
 }
 
@@ -212,10 +212,10 @@
     SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
 
     bool allParamsValid = true;
-    ASSERT_NO_FATAL_FAILURE(addCaptureSizeParam(mCaptureSize));
-    ASSERT_NO_FATAL_FAILURE(addScalingModeParam(mScalingMode));
-    ASSERT_NO_FATAL_FAILURE(addMeasurementModeParam(mMeasurementMode));
-    ASSERT_NO_FATAL_FAILURE(addLatencyParam(mLatency));
+    addCaptureSizeParam(mCaptureSize);
+    addScalingModeParam(mScalingMode);
+    addMeasurementModeParam(mMeasurementMode);
+    addLatencyParam(mLatency);
     ASSERT_NO_FATAL_FAILURE(SetAndGetParameters(&allParamsValid));
 
     Parameter getParam;
@@ -276,9 +276,9 @@
 
     for (float maxAudioSampleValue : testMaxAudioSampleValueList) {
         bool allParamsValid = true;
-        ASSERT_NO_FATAL_FAILURE(addCaptureSizeParam(mCaptureSize));
-        ASSERT_NO_FATAL_FAILURE(addScalingModeParam(mScalingMode));
-        ASSERT_NO_FATAL_FAILURE(addLatencyParam(mLatency));
+        addCaptureSizeParam(mCaptureSize);
+        addScalingModeParam(mScalingMode);
+        addLatencyParam(mLatency);
         ASSERT_NO_FATAL_FAILURE(SetAndGetParameters(&allParamsValid));
 
         generateSineWave(std::vector<int>{1000}, mInputBuffer, maxAudioSampleValue,
diff --git a/audio/common/5.0/Android.bp b/audio/common/5.0/Android.bp
index 02f66a3..d9c4f58 100644
--- a/audio/common/5.0/Android.bp
+++ b/audio/common/5.0/Android.bp
@@ -23,6 +23,6 @@
     gen_java_constants: true,
     apex_available: [
         "//apex_available:platform",
-        "com.android.btservices",
+        "com.android.bt",
     ],
 }
diff --git a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
index 02e593a..2b86049 100644
--- a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
+++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
@@ -105,7 +105,7 @@
                         <xs:element name="AttributesGroup" type="AttributesGroup" minOccurs="1" maxOccurs="unbounded"/>
                     </xs:sequence>
                     <xs:attribute name="name" type="xs:string" use="required"/>
-                    <xs:attribute name="id" type="xs:int" use="required"/>
+                    <xs:attribute name="id" type="xs:int" use="optional"/>
                 </xs:complexType>
             </xs:element>
         </xs:sequence>
diff --git a/automotive/can/aidl/default/CanController.cpp b/automotive/can/aidl/default/CanController.cpp
index 1435a02..40332d5 100644
--- a/automotive/can/aidl/default/CanController.cpp
+++ b/automotive/can/aidl/default/CanController.cpp
@@ -20,10 +20,10 @@
 #include "CanBusSlcan.h"
 #include "CanBusVirtual.h"
 
-#include <android-base/format.h>
 #include <android-base/logging.h>
 
 #include <filesystem>
+#include <format>
 #include <fstream>
 #include <regex>
 
@@ -235,7 +235,7 @@
                                                    std::string* ifaceName) {
     *ifaceName = {};
     if (mBusesByName.find(busName) == mBusesByName.end()) {
-        return resultToStatus(Result::BAD_BUS_NAME, fmt::format("{} doesn't exist", busName));
+        return resultToStatus(Result::BAD_BUS_NAME, std::format("{} doesn't exist", busName));
     }
     *ifaceName = std::string(mBusesByName[busName]->getIfaceName());
     return ok();
@@ -245,11 +245,11 @@
     if (!isValidName(config.name)) {
         LOG(ERROR) << "Bus name " << config.name << " is invalid";
         return resultToStatus(Result::BAD_BUS_NAME,
-                              fmt::format("{} is not a valid bus name", config.name));
+                              std::format("{} is not a valid bus name", config.name));
     } else if (mBusesByName.find(config.name) != mBusesByName.end()) {
         LOG(ERROR) << "A bus named " << config.name << " already exists!";
         return resultToStatus(Result::INVALID_STATE,
-                              fmt::format("A bus named {} already exists", config.name));
+                              std::format("A bus named {} already exists", config.name));
     }
 
     if (config.interfaceId.getTag() == BusConfig::InterfaceId::Tag::virtualif) {
@@ -310,7 +310,7 @@
     if (result != Result::OK) {
         // the bus failed to come up, don't leave a broken entry in the map.
         mBusesByName.erase(config.name);
-        return resultToStatus(result, fmt::format("CanBus::up failed for {}", config.name));
+        return resultToStatus(result, std::format("CanBus::up failed for {}", config.name));
     }
 
     *ifaceName = mBusesByName[config.name]->getIfaceName();
@@ -321,11 +321,11 @@
     if (mBusesByName.find(busName) == mBusesByName.end()) {
         return resultToStatus(
                 Result::UNKNOWN_ERROR,
-                fmt::format("Couldn't bring down {}, because it doesn't exist", busName));
+                std::format("Couldn't bring down {}, because it doesn't exist", busName));
     }
     Result result = mBusesByName[busName]->down();
     if (result != Result::OK) {
-        return resultToStatus(result, fmt::format("Couldn't bring down {}!", busName));
+        return resultToStatus(result, std::format("Couldn't bring down {}!", busName));
     }
     mBusesByName.erase(busName);
     return ok();
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp
index 86fc70a..6c83339 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp
@@ -16,10 +16,10 @@
 
 #define LOG_TAG "DefaultVehicleHalServer"
 
+#include <format>
 #include <fstream>
 #include <regex>
 
-#include <android-base/format.h>
 #include <android-base/logging.h>
 #include <android-base/parsedouble.h>
 #include <android-base/parseint.h>
@@ -237,7 +237,7 @@
         auto values = mServerSidePropStore.readAllValues();
         size_t i = 0;
         for (const auto& value : values) {
-            result.buffer += fmt::format("[{}]: {}\n", i, toString(value));
+            result.buffer += std::format("[{}]: {}\n", i, toString(value));
             i++;
         }
         return result;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/userhal/FakeUserHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/userhal/FakeUserHal.cpp
index e9ebcc6..c735b05 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/userhal/FakeUserHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/userhal/FakeUserHal.cpp
@@ -15,6 +15,8 @@
  */
 #define LOG_TAG "FakeUserHal"
 
+#include <format>
+
 #include <cutils/log.h>
 #include <utils/SystemClock.h>
 
@@ -312,34 +314,34 @@
 }
 
 std::string FakeUserHal::showDumpHelp() {
-    return fmt::format("{}: dumps state used for user management\n", kUserHalDumpOption);
+    return std::format("{}: dumps state used for user management\n", kUserHalDumpOption);
 }
 
 std::string FakeUserHal::dump(std::string indent) {
     std::string info;
     if (mInitialUserResponseFromCmd != nullptr) {
-        info += fmt::format("{}InitialUserInfo response: {}\n", indent.c_str(),
+        info += std::format("{}InitialUserInfo response: {}\n", indent.c_str(),
                             toString(*mInitialUserResponseFromCmd).c_str());
     } else {
-        info += fmt::format("{}No InitialUserInfo response\n", indent.c_str());
+        info += std::format("{}No InitialUserInfo response\n", indent.c_str());
     }
     if (mSwitchUserResponseFromCmd != nullptr) {
-        info += fmt::format("{}SwitchUser response: {}\n", indent.c_str(),
+        info += std::format("{}SwitchUser response: {}\n", indent.c_str(),
                             toString(*mSwitchUserResponseFromCmd).c_str());
     } else {
-        info += fmt::format("{}No SwitchUser response\n", indent.c_str());
+        info += std::format("{}No SwitchUser response\n", indent.c_str());
     }
     if (mCreateUserResponseFromCmd != nullptr) {
-        info += fmt::format("{}CreateUser response: {}\n", indent.c_str(),
+        info += std::format("{}CreateUser response: {}\n", indent.c_str(),
                             toString(*mCreateUserResponseFromCmd).c_str());
     } else {
-        info += fmt::format("{}No CreateUser response\n", indent.c_str());
+        info += std::format("{}No CreateUser response\n", indent.c_str());
     }
     if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
-        info += fmt::format("{}SetUserIdentificationAssociation response: {}\n", indent.c_str(),
+        info += std::format("{}SetUserIdentificationAssociation response: {}\n", indent.c_str(),
                             toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str());
     } else {
-        info += fmt::format("{}No SetUserIdentificationAssociation response\n", indent.c_str());
+        info += std::format("{}No SetUserIdentificationAssociation response\n", indent.c_str());
     }
     return info;
 }
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/userhal/include/FakeUserHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/userhal/include/FakeUserHal.h
index 122aee8..33cef54 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/userhal/include/FakeUserHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/userhal/include/FakeUserHal.h
@@ -17,7 +17,6 @@
 #ifndef android_hardware_automotive_vehicle_V2_0_impl_FakeUserHal_H_
 #define android_hardware_automotive_vehicle_V2_0_impl_FakeUserHal_H_
 
-#include <android-base/format.h>
 #include <android-base/result.h>
 
 #include <android/hardware/automotive/vehicle/2.0/types.h>
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h b/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
index fcbe8fd..1bf5ce1 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
@@ -17,7 +17,6 @@
 #ifndef android_hardware_automotive_vehicle_aidl_impl_fake_impl_userhal_include_FakeUserHal_H_
 #define android_hardware_automotive_vehicle_aidl_impl_fake_impl_userhal_include_FakeUserHal_H_
 
-#include <android-base/format.h>
 #include <android-base/result.h>
 #include <android-base/thread_annotations.h>
 
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp b/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
index 878c2e7..309dd5f 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
@@ -19,6 +19,8 @@
 
 #include "UserHalHelper.h"
 
+#include <format>
+
 #include <VehicleUtils.h>
 #include <utils/Log.h>
 #include <utils/SystemClock.h>
@@ -336,7 +338,7 @@
 }
 
 std::string FakeUserHal::showDumpHelp() const {
-    return fmt::format("{}: dumps state used for user management\n", kUserHalDumpOption);
+    return std::format("{}: dumps state used for user management\n", kUserHalDumpOption);
 }
 
 std::string FakeUserHal::dump() const {
@@ -344,23 +346,23 @@
 
     std::string info;
     if (mInitialUserResponseFromCmd != nullptr) {
-        info += fmt::format("InitialUserInfo response: {}\n",
+        info += std::format("InitialUserInfo response: {}\n",
                             mInitialUserResponseFromCmd->toString());
     } else {
         info += "No InitialUserInfo response\n";
     }
     if (mSwitchUserResponseFromCmd != nullptr) {
-        info += fmt::format("SwitchUser response: {}\n", mSwitchUserResponseFromCmd->toString());
+        info += std::format("SwitchUser response: {}\n", mSwitchUserResponseFromCmd->toString());
     } else {
         info += "No SwitchUser response\n";
     }
     if (mCreateUserResponseFromCmd != nullptr) {
-        info += fmt::format("CreateUser response: {}\n", mCreateUserResponseFromCmd->toString());
+        info += std::format("CreateUser response: {}\n", mCreateUserResponseFromCmd->toString());
     } else {
         info += "No CreateUser response\n";
     }
     if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
-        info += fmt::format("SetUserIdentificationAssociation response: {}\n",
+        info += std::format("SetUserIdentificationAssociation response: {}\n",
                             mSetUserIdentificationAssociationResponseFromCmd->toString());
     } else {
         info += "No SetUserIdentificationAssociation response\n";
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 2efda5b..6fe40a6 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
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <format>
 #include <vector>
 
 #include <JsonConfigLoader.h>
@@ -21,7 +22,6 @@
 #include <VehicleHalTypes.h>
 
 #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>
@@ -106,13 +106,13 @@
 INSTANTIATE_TEST_SUITE_P(DefaultConfigs, PropConfigConversionTest,
                          ::testing::ValuesIn(prepareTestConfigs()),
                          [](const ::testing::TestParamInfo<aidl_vehicle::VehiclePropConfig>& info) {
-                             return ::fmt::format("property_{:d}", info.param.prop);
+                             return ::std::format("property_{:d}", info.param.prop);
                          });
 
 INSTANTIATE_TEST_SUITE_P(TestValues, PropValueConversionTest,
                          ::testing::ValuesIn(prepareTestValues()),
                          [](const ::testing::TestParamInfo<aidl_vehicle::VehiclePropValue>& info) {
-                             return ::fmt::format("property_{:d}", info.param.prop);
+                             return ::std::format("property_{:d}", info.param.prop);
                          });
 
 TEST_F(PropValueConversionTest, testConvertSubscribeOption) {
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index 90a7c46..2bb4ba8 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -17,9 +17,10 @@
 #ifndef android_hardware_automotive_vehicle_aidl_impl_utils_common_include_VehicleUtils_H_
 #define android_hardware_automotive_vehicle_aidl_impl_utils_common_include_VehicleUtils_H_
 
+#include <format>
+
 #include <VehicleHalTypes.h>
 
-#include <android-base/format.h>
 #include <android-base/result.h>
 #include <math/HashCombine.h>
 #include <utils/Log.h>
@@ -289,7 +290,7 @@
     }
     return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
             toInt(status),
-            fmt::format("{}, error: {}", additionalErrorMsg, getErrorMsg(result)).c_str());
+            std::format("{}, error: {}", additionalErrorMsg, getErrorMsg(result)).c_str());
 }
 
 template <class T, class E>
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/PendingRequestPoolTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/PendingRequestPoolTest.cpp
index 734c739..cc690d7 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/PendingRequestPoolTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/PendingRequestPoolTest.cpp
@@ -57,7 +57,7 @@
 
   private:
     // Test timeout is 0.1s.
-    static const int64_t TEST_TIMEOUT = 100000000;
+    static constexpr int64_t TEST_TIMEOUT = 100000000;
 
     std::unique_ptr<PendingRequestPool> mPool;
 };
diff --git a/biometrics/face/aidl/default/apex/Android.bp b/biometrics/face/aidl/default/apex/Android.bp
index c4632d4..0561145 100644
--- a/biometrics/face/aidl/default/apex/Android.bp
+++ b/biometrics/face/aidl/default/apex/Android.bp
@@ -19,7 +19,7 @@
 apex {
     name: "com.android.hardware.biometrics.face.virtual",
     manifest: "manifest.json",
-    file_contexts: "file_contexts",
+    file_contexts: ":com.android.biometrics.virtual.face-file_contexts",
     key: "com.android.hardware.key",
     certificate: ":com.android.hardware.certificate",
     updatable: false,
diff --git a/biometrics/face/aidl/default/apex/file_contexts b/biometrics/face/aidl/default/apex/file_contexts
deleted file mode 100644
index 4f935c1..0000000
--- a/biometrics/face/aidl/default/apex/file_contexts
+++ /dev/null
@@ -1,3 +0,0 @@
-(/.*)?                                          u:object_r:vendor_file:s0
-/etc(/.*)?                                      u:object_r:vendor_configs_file:s0
-/bin/hw/android\.hardware\.biometrics\.face-service\.example u:object_r:hal_face_default_exec:s0
\ No newline at end of file
diff --git a/bluetooth/1.0/Android.bp b/bluetooth/1.0/Android.bp
index bd1ca69..3ffc203 100644
--- a/bluetooth/1.0/Android.bp
+++ b/bluetooth/1.0/Android.bp
@@ -23,6 +23,6 @@
     gen_java: true,
     apex_available: [
         "//apex_available:platform",
-        "com.android.btservices",
+        "com.android.bt",
     ],
 }
diff --git a/bluetooth/1.1/Android.bp b/bluetooth/1.1/Android.bp
index f8a05f1..9c65b62 100644
--- a/bluetooth/1.1/Android.bp
+++ b/bluetooth/1.1/Android.bp
@@ -23,6 +23,6 @@
     gen_java: true,
     apex_available: [
         "//apex_available:platform",
-        "com.android.btservices",
+        "com.android.bt",
     ],
 }
diff --git a/bluetooth/OWNERS b/bluetooth/OWNERS
index f401b8c..df250c8 100644
--- a/bluetooth/OWNERS
+++ b/bluetooth/OWNERS
@@ -1,5 +1,5 @@
 # Bug component: 27441
 
+asoulier@google.com
 henrichataing@google.com
-mylesgw@google.com
 siyuanh@google.com
diff --git a/bluetooth/aidl/Android.bp b/bluetooth/aidl/Android.bp
index c6a592f..0daecf7 100644
--- a/bluetooth/aidl/Android.bp
+++ b/bluetooth/aidl/Android.bp
@@ -23,13 +23,16 @@
             // translate code.
             enabled: true,
         },
+        rust: {
+            enabled: true,
+        },
         java: {
             sdk_version: "module_current",
         },
         ndk: {
             apex_available: [
                 "//apex_available:platform",
-                "com.android.btservices",
+                "com.android.bt",
             ],
             min_sdk_version: "33",
         },
diff --git a/bluetooth/audio/2.0/Android.bp b/bluetooth/audio/2.0/Android.bp
index 725ec11..61f9a35 100644
--- a/bluetooth/audio/2.0/Android.bp
+++ b/bluetooth/audio/2.0/Android.bp
@@ -26,6 +26,6 @@
     gen_java: false,
     apex_available: [
         "//apex_available:platform",
-        "com.android.btservices",
+        "com.android.bt",
     ],
 }
diff --git a/bluetooth/audio/2.1/Android.bp b/bluetooth/audio/2.1/Android.bp
index 4ca0bef..4d01a00 100644
--- a/bluetooth/audio/2.1/Android.bp
+++ b/bluetooth/audio/2.1/Android.bp
@@ -25,7 +25,7 @@
     ],
     apex_available: [
         "//apex_available:platform",
-        "com.android.btservices",
+        "com.android.bt",
     ],
     gen_java: false,
 }
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index ae55fa9..6d4edb1 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -38,6 +38,9 @@
         cpp: {
             enabled: false,
         },
+        rust: {
+            enabled: true,
+        },
         java: {
             sdk_version: "module_current",
             enabled: false,
@@ -45,7 +48,7 @@
         ndk: {
             apex_available: [
                 "//apex_available:platform",
-                "com.android.btservices",
+                "com.android.bt",
             ],
             min_sdk_version: "31",
         },
@@ -86,7 +89,6 @@
 
     ],
     frozen: false,
-
 }
 
 // Note: This should always be one version ahead of the last frozen version
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index 18fc4b2..3f1f5f6 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -489,11 +489,11 @@
 std::vector<AseDirectionConfiguration> getValidConfigurationsFromAllocation(
     int req_allocation_bitmask,
     std::vector<AseDirectionConfiguration>& valid_direction_configurations,
-    bool is_exact) {
+    bool isExact) {
   // Prefer the same allocation_bitmask
   int channel_count = getCountFromBitmask(req_allocation_bitmask);
 
-  if (is_exact) {
+  if (isExact) {
     for (auto& cfg : valid_direction_configurations) {
       int cfg_bitmask =
           getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
@@ -747,12 +747,19 @@
     std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
         matched_ase_configuration_settings,
     const IBluetoothAudioProvider::LeAudioConfigurationRequirement& requirement,
-    bool isMatchContext, bool isExact) {
+    bool isMatchContext, bool isExact, bool isMatchFlags) {
   LOG(INFO) << __func__ << ": Trying to match for the requirement "
             << requirement.toString() << ", match context = " << isMatchContext
-            << ", match exact = " << isExact;
+            << ", match exact = " << isExact
+            << ", match flags = " << isMatchFlags;
+  // Don't have to match with flag if requirements don't have flags.
+  auto requirement_flags_bitmask = 0;
+  if (isMatchFlags) {
+    if (!requirement.flags.has_value()) return std::nullopt;
+    requirement_flags_bitmask = requirement.flags.value().bitmask;
+  }
   for (auto& setting : matched_ase_configuration_settings) {
-    // Try to match context in metadata.
+    // Try to match context.
     if (isMatchContext) {
       if ((setting.audioContext.bitmask & requirement.audioContext.bitmask) !=
           requirement.audioContext.bitmask)
@@ -761,6 +768,16 @@
                  << getSettingOutputString(setting);
     }
 
+    // Try to match configuration flags
+    if (isMatchFlags) {
+      if (!setting.flags.has_value()) continue;
+      if ((setting.flags.value().bitmask & requirement_flags_bitmask) !=
+          requirement_flags_bitmask)
+        continue;
+      LOG(DEBUG) << __func__ << ": Setting with matched flags: "
+                 << getSettingOutputString(setting);
+    }
+
     auto filtered_ase_configuration_setting =
         getRequirementMatchedAseConfigurationSettings(setting, requirement,
                                                       isExact);
@@ -853,21 +870,25 @@
     // If we cannot match, return an empty result.
 
     // Matching priority list:
+    // Matched configuration flags, i.e. for asymmetric requirement.
     // Preferred context - exact match with allocation
     // Preferred context - loose match with allocation
     // Any context - exact match with allocation
     // Any context - loose match with allocation
     bool found = false;
-    for (bool match_context : {true, false}) {
-      for (bool match_exact : {true, false}) {
-        auto matched_setting =
-            matchWithRequirement(matched_ase_configuration_settings,
-                                 requirement, match_context, match_exact);
-        if (matched_setting.has_value()) {
-          result.push_back(matched_setting.value());
-          found = true;
-          break;
+    for (bool match_flag : {true, false}) {
+      for (bool match_context : {true, false}) {
+        for (bool match_exact : {true, false}) {
+          auto matched_setting = matchWithRequirement(
+              matched_ase_configuration_settings, requirement, match_context,
+              match_exact, match_flag);
+          if (matched_setting.has_value()) {
+            result.push_back(matched_setting.value());
+            found = true;
+            break;
+          }
         }
+        if (found) break;
       }
       if (found) break;
     }
@@ -881,7 +902,11 @@
     }
   }
 
-  LOG(INFO) << __func__ << ": Found matches for all requirements!";
+  LOG(INFO) << __func__
+            << ": Found matches for all requirements, chosen settings:";
+  for (auto& setting : result) {
+    LOG(INFO) << __func__ << ": " << getSettingOutputString(setting);
+  }
   *_aidl_return = result;
   return ndk::ScopedAStatus::ok();
 };
@@ -913,7 +938,13 @@
     const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
         qosRequirement,
     std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings,
-    bool is_exact) {
+    bool isExact, bool isMatchFlags) {
+  auto requirement_flags_bitmask = 0;
+  if (isMatchFlags) {
+    if (!qosRequirement.flags.has_value()) return std::nullopt;
+    requirement_flags_bitmask = qosRequirement.flags.value().bitmask;
+  }
+
   std::optional<AseQosDirectionRequirement> direction_qos_requirement =
       std::nullopt;
 
@@ -929,9 +960,18 @@
     if ((setting.audioContext.bitmask & qosRequirement.audioContext.bitmask) !=
         qosRequirement.audioContext.bitmask)
       continue;
+    LOG(DEBUG) << __func__ << ": Setting with matched context: "
+               << getSettingOutputString(setting);
 
     // Match configuration flags
-    // Currently configuration flags are not populated, ignore.
+    if (isMatchFlags) {
+      if (!setting.flags.has_value()) continue;
+      if ((setting.flags.value().bitmask & requirement_flags_bitmask) !=
+          requirement_flags_bitmask)
+        continue;
+      LOG(DEBUG) << __func__ << ": Setting with matched flags: "
+                 << getSettingOutputString(setting);
+    }
 
     // Get a list of all matched AseDirectionConfiguration
     // for the input direction
@@ -980,7 +1020,7 @@
         direction_qos_requirement.value().aseConfiguration);
     // Get the best matching config based on channel allocation
     auto req_valid_configs = getValidConfigurationsFromAllocation(
-        qos_allocation_bitmask, temp, is_exact);
+        qos_allocation_bitmask, temp, isExact);
     if (req_valid_configs.empty()) {
       LOG(WARNING) << __func__
                    << ": Cannot find matching allocation for bitmask "
@@ -1010,29 +1050,38 @@
   if (in_qosRequirement.sinkAseQosRequirement.has_value()) {
     if (!isValidQosRequirement(in_qosRequirement.sinkAseQosRequirement.value()))
       return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
-    {
-      // Try exact match first
-      result.sinkQosConfiguration =
-          getDirectionQosConfiguration(kLeAudioDirectionSink, in_qosRequirement,
-                                       ase_configuration_settings, true);
-      if (!result.sinkQosConfiguration.has_value()) {
-        result.sinkQosConfiguration = getDirectionQosConfiguration(
+    bool found = false;
+    for (bool match_flag : {true, false}) {
+      for (bool match_exact : {true, false}) {
+        auto setting = getDirectionQosConfiguration(
             kLeAudioDirectionSink, in_qosRequirement,
-            ase_configuration_settings, false);
+            ase_configuration_settings, match_exact, match_flag);
+        if (setting.has_value()) {
+          found = true;
+          result.sinkQosConfiguration = setting;
+          break;
+        }
       }
+      if (found) break;
     }
   }
   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, true);
-    if (!result.sourceQosConfiguration.has_value()) {
-      result.sourceQosConfiguration = getDirectionQosConfiguration(
-          kLeAudioDirectionSource, in_qosRequirement,
-          ase_configuration_settings, false);
+    bool found = false;
+    for (bool match_flag : {true, false}) {
+      for (bool match_exact : {true, false}) {
+        auto setting = getDirectionQosConfiguration(
+            kLeAudioDirectionSource, in_qosRequirement,
+            ase_configuration_settings, match_exact, match_flag);
+        if (setting.has_value()) {
+          found = true;
+          result.sourceQosConfiguration = setting;
+          break;
+        }
+      }
+      if (found) break;
     }
   }
 
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
index 3a82b73..8c4f543 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -164,7 +164,7 @@
       const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
           qosRequirement,
       std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings,
-      bool is_exact);
+      bool isExact, bool isMatchedFlag);
   bool isSubgroupConfigurationMatchedContext(
       AudioContext requirement_context,
       IBluetoothAudioProvider::BroadcastQuality quality,
@@ -175,7 +175,7 @@
           matched_ase_configuration_settings,
       const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
           requirements,
-      bool isMatchContext, bool isExact);
+      bool isMatchContext, bool isExact, bool isMatchFlags);
 };
 
 class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index d4968a8..6d1da63 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -90,15 +90,15 @@
 
 cc_test {
     name: "BluetoothLeAudioCodecsProviderTest",
-    srcs: [
-        "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
-        "aidl_session/BluetoothLeAudioCodecsProviderTest.cpp",
-    ],
     defaults: [
         "latest_android_hardware_audio_common_ndk_static",
         "latest_android_hardware_bluetooth_audio_ndk_static",
         "latest_android_media_audio_common_types_ndk_static",
     ],
+    srcs: [
+        "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
+        "aidl_session/BluetoothLeAudioCodecsProviderTest.cpp",
+    ],
     header_libs: [
         "libxsdc-utils",
     ],
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
index 07e4997..5909c92 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
@@ -47,6 +47,8 @@
 #include <aidl/android/hardware/bluetooth/audio/Phy.h>
 #include <android-base/logging.h>
 
+#include <optional>
+
 #include "flatbuffers/idl.h"
 #include "flatbuffers/util.h"
 
@@ -561,6 +563,17 @@
   if (ase_cnt == 2) directionAseConfiguration.push_back(config);
 }
 
+// Comparing if 2 AseDirectionConfiguration is equal.
+// Configuration are copied in, so we can remove some fields for comparison
+// without affecting the result.
+bool isAseConfigurationEqual(AseDirectionConfiguration cfg_a,
+                             AseDirectionConfiguration cfg_b) {
+  // Remove unneeded fields when comparing.
+  cfg_a.aseConfiguration.metadata = std::nullopt;
+  cfg_b.aseConfiguration.metadata = std::nullopt;
+  return cfg_a == cfg_b;
+}
+
 void AudioSetConfigurationProviderJson::PopulateAseConfigurationFromFlat(
     const le_audio::AudioSetConfiguration* flat_cfg,
     std::vector<const le_audio::CodecConfiguration*>* codec_cfgs,
@@ -569,7 +582,7 @@
     std::vector<std::optional<AseDirectionConfiguration>>&
         sourceAseConfiguration,
     std::vector<std::optional<AseDirectionConfiguration>>& sinkAseConfiguration,
-    ConfigurationFlags& /*configurationFlags*/) {
+    ConfigurationFlags& configurationFlags) {
   if (flat_cfg == nullptr) {
     LOG(ERROR) << "flat_cfg cannot be null";
     return;
@@ -636,17 +649,41 @@
                          sourceAseConfiguration, location);
       }
     }
-  } else {
-    if (codec_cfg == nullptr) {
-      LOG(ERROR) << "No codec config matching key " << codec_config_key.c_str()
-                 << " found";
+
+    // After putting all subconfig, check if it's an asymmetric configuration
+    // and populate information for ConfigurationFlags
+    if (!sinkAseConfiguration.empty() && !sourceAseConfiguration.empty()) {
+      if (sinkAseConfiguration.size() == sourceAseConfiguration.size()) {
+        for (int i = 0; i < sinkAseConfiguration.size(); ++i) {
+          if (sinkAseConfiguration[i].has_value() !=
+              sourceAseConfiguration[i].has_value()) {
+            // Different configuration: one is not empty and other is.
+            configurationFlags.bitmask |=
+                ConfigurationFlags::ALLOW_ASYMMETRIC_CONFIGURATIONS;
+          } else if (sinkAseConfiguration[i].has_value()) {
+            // Both is not empty, comparing inner fields:
+            if (!isAseConfigurationEqual(sinkAseConfiguration[i].value(),
+                                         sourceAseConfiguration[i].value())) {
+              configurationFlags.bitmask |=
+                  ConfigurationFlags::ALLOW_ASYMMETRIC_CONFIGURATIONS;
+            }
+          }
+        }
+      } else {
+        // Different number of ASE, is a different configuration.
+        configurationFlags.bitmask |=
+            ConfigurationFlags::ALLOW_ASYMMETRIC_CONFIGURATIONS;
+      }
     } else {
-      LOG(ERROR) << "Configuration '" << flat_cfg->name()->c_str()
-                 << "' has no valid subconfigurations.";
+      if (codec_cfg == nullptr) {
+        LOG(ERROR) << "No codec config matching key "
+                   << codec_config_key.c_str() << " found";
+      } else {
+        LOG(ERROR) << "Configuration '" << flat_cfg->name()->c_str()
+                   << "' has no valid subconfigurations.";
+      }
     }
   }
-
-  // TODO: Populate information for ConfigurationFlags
 }
 
 bool AudioSetConfigurationProviderJson::LoadConfigurationsFromFiles(
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
index 59c43a4..a96df52 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
+#include <optional>
 #include <set>
 
 #include "aidl/android/hardware/bluetooth/audio/ChannelMode.h"
 #include "aidl/android/hardware/bluetooth/audio/CodecId.h"
+#include "aidl/android/hardware/bluetooth/audio/CodecInfo.h"
+#include "aidl/android/hardware/bluetooth/audio/ConfigurationFlags.h"
 #include "aidl_android_hardware_bluetooth_audio_setting_enums.h"
 #define LOG_TAG "BTAudioCodecsProviderAidl"
 
@@ -52,6 +55,26 @@
   return le_audio_offload_setting;
 }
 
+void add_flag(CodecInfo& codec_info, int32_t bitmask) {
+  auto& transport =
+      codec_info.transport.get<CodecInfo::Transport::Tag::leAudio>();
+  if (!transport.flags.has_value()) transport.flags = ConfigurationFlags();
+  transport.flags->bitmask |= bitmask;
+}
+
+// Compare 2 codec info to see if they are equal.
+// Currently only compare bitdepth, frameDurationUs and samplingFrequencyHz
+bool is_equal(CodecInfo& codec_info_a, CodecInfo& codec_info_b) {
+  auto& transport_a =
+      codec_info_a.transport.get<CodecInfo::Transport::Tag::leAudio>();
+  auto& transport_b =
+      codec_info_b.transport.get<CodecInfo::Transport::Tag::leAudio>();
+  return codec_info_a.name == codec_info_b.name &&
+         transport_a.bitdepth == transport_b.bitdepth &&
+         transport_a.frameDurationUs == transport_b.frameDurationUs &&
+         transport_a.samplingFrequencyHz == transport_b.samplingFrequencyHz;
+}
+
 std::unordered_map<SessionType, std::vector<CodecInfo>>
 BluetoothLeAudioCodecsProvider::GetLeAudioCodecInfo(
     const std::optional<setting::LeAudioOffloadSetting>&
@@ -111,6 +134,9 @@
     codec_info.transport =
         CodecInfo::Transport::make<CodecInfo::Transport::Tag::leAudio>();
 
+    // Add low latency support by default
+    add_flag(codec_info, ConfigurationFlags::LOW_LATENCY);
+
     // Mapping codec configuration information
     auto& transport =
         codec_info.transport.get<CodecInfo::Transport::Tag::leAudio>();
@@ -152,6 +178,25 @@
     }
   }
 
+  // Goes through a list of scenarios and detect asymmetrical config using
+  // codecConfiguration name.
+  for (auto& s : supported_scenarios_) {
+    if (s.hasEncode() && s.hasDecode() &&
+        config_codec_info_map_.count(s.getEncode()) &&
+        config_codec_info_map_.count(s.getDecode())) {
+      // Check if it's actually using the different codec
+      auto& encode_codec_info = config_codec_info_map_[s.getEncode()];
+      auto& decode_codec_info = config_codec_info_map_[s.getDecode()];
+      if (!is_equal(encode_codec_info, decode_codec_info)) {
+        // Change both x and y to become asymmetrical
+        add_flag(encode_codec_info,
+                 ConfigurationFlags::ALLOW_ASYMMETRIC_CONFIGURATIONS);
+        add_flag(decode_codec_info,
+                 ConfigurationFlags::ALLOW_ASYMMETRIC_CONFIGURATIONS);
+      }
+    }
+  }
+
   // Goes through every scenario, deduplicate configuration, skip the invalid
   // config references (e.g. the "invalid" entries in the xml file).
   std::set<std::string> encoding_config, decoding_config, broadcast_config;
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
index c47f7d5..6338e11 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
@@ -20,10 +20,16 @@
 #include <tuple>
 
 #include "BluetoothLeAudioCodecsProvider.h"
+#include "aidl/android/hardware/bluetooth/audio/CodecInfo.h"
+#include "aidl/android/hardware/bluetooth/audio/ConfigurationFlags.h"
+#include "aidl/android/hardware/bluetooth/audio/SessionType.h"
 
 using aidl::android::hardware::bluetooth::audio::BluetoothLeAudioCodecsProvider;
+using aidl::android::hardware::bluetooth::audio::CodecInfo;
+using aidl::android::hardware::bluetooth::audio::ConfigurationFlags;
 using aidl::android::hardware::bluetooth::audio::
     LeAudioCodecCapabilitiesSetting;
+using aidl::android::hardware::bluetooth::audio::SessionType;
 using aidl::android::hardware::bluetooth::audio::setting::AudioLocation;
 using aidl::android::hardware::bluetooth::audio::setting::CodecConfiguration;
 using aidl::android::hardware::bluetooth::audio::setting::
@@ -51,15 +57,30 @@
 static const Scenario kValidBroadcastScenario(
     std::nullopt, std::nullopt, std::make_optional("BcastStereo_16_2"));
 
+static const Scenario kValidAsymmetricScenario(
+    std::make_optional("OneChanStereo_32_1"),
+    std::make_optional("OneChanStereo_16_1"), std::nullopt);
+
 // Configuration
 static const Configuration kValidConfigOneChanStereo_16_1(
     std::make_optional("OneChanStereo_16_1"), std::make_optional("LC3_16k_1"),
     std::make_optional("STEREO_ONE_CIS_PER_DEVICE"));
+
+static const Configuration kValidConfigOneChanStereo_32_1(
+    std::make_optional("OneChanStereo_32_1"), std::make_optional("LC3_32k_1"),
+    std::make_optional("STEREO_ONE_CIS_PER_DEVICE"));
+
 // CodecConfiguration
 static const CodecConfiguration kValidCodecLC3_16k_1(
     std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
     std::nullopt, std::make_optional(16000), std::make_optional(7500),
     std::make_optional(30), std::nullopt);
+
+static const CodecConfiguration kValidCodecLC3_32k_1(
+    std::make_optional("LC3_32k_1"), std::make_optional(CodecType::LC3),
+    std::nullopt, std::make_optional(32000), std::make_optional(7500),
+    std::make_optional(30), std::nullopt);
+
 // StrategyConfiguration
 static const StrategyConfiguration kValidStrategyStereoOneCis(
     std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
@@ -181,6 +202,17 @@
             kValidStrategyStereoOneCisBoth, kValidStrategyStereoTwoCisBoth,
             kValidStrategyMonoOneCisBoth, kValidStrategyBroadcastStereoBoth})};
 
+// Define some valid asymmetric scenario list
+static const std::vector<ScenarioList> kValidAsymmetricScenarioList = {
+    ScenarioList(std::vector<Scenario>{kValidAsymmetricScenario})};
+static const std::vector<ConfigurationList> kValidAsymmetricConfigurationList =
+    {ConfigurationList(std::vector<Configuration>{
+        kValidConfigOneChanStereo_16_1, kValidConfigOneChanStereo_32_1})};
+static const std::vector<CodecConfigurationList>
+    kValidAsymmetricCodecConfigurationList = {
+        CodecConfigurationList(std::vector<CodecConfiguration>{
+            kValidCodecLC3_16k_1, kValidCodecLC3_32k_1})};
+
 class BluetoothLeAudioCodecsProviderTest
     : public ::testing::TestWithParam<OffloadSetting> {
  public:
@@ -227,6 +259,19 @@
     return le_audio_codec_capabilities;
   }
 
+  std::unordered_map<SessionType, std::vector<CodecInfo>>
+  RunCodecInfoTestCase() {
+    auto& [scenario_lists, configuration_lists, codec_configuration_lists,
+           strategy_configuration_lists] = GetParam();
+    LeAudioOffloadSetting le_audio_offload_setting(
+        scenario_lists, configuration_lists, codec_configuration_lists,
+        strategy_configuration_lists);
+    auto le_audio_codec_capabilities =
+        BluetoothLeAudioCodecsProvider::GetLeAudioCodecInfo(
+            std::make_optional(le_audio_offload_setting));
+    return le_audio_codec_capabilities;
+  }
+
  private:
   static inline OffloadSetting CreateTestCase(
       const ScenarioList& scenario_list,
@@ -392,6 +437,39 @@
   ASSERT_TRUE(!le_audio_codec_capabilities.empty());
 }
 
+class ComposeLeAudioAymmetricCodecInfoTest
+    : public BluetoothLeAudioCodecsProviderTest {
+ public:
+};
+
+TEST_P(ComposeLeAudioAymmetricCodecInfoTest, AsymmetricCodecInfoNotEmpty) {
+  Initialize();
+  auto le_audio_codec_info_map = RunCodecInfoTestCase();
+  ASSERT_TRUE(!le_audio_codec_info_map.empty());
+  // Check true asymmetric codec info
+  ASSERT_TRUE(!le_audio_codec_info_map
+                   [SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH]
+                       .empty());
+  ASSERT_TRUE(!le_audio_codec_info_map
+                   [SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH]
+                       .empty());
+  auto required_flag = ConfigurationFlags();
+  required_flag.bitmask |= ConfigurationFlags::ALLOW_ASYMMETRIC_CONFIGURATIONS;
+
+  auto codec_info = le_audio_codec_info_map
+      [SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH][0];
+  ASSERT_EQ(codec_info.transport.getTag(), CodecInfo::Transport::Tag::leAudio);
+  auto& transport =
+      codec_info.transport.get<CodecInfo::Transport::Tag::leAudio>();
+  ASSERT_EQ(transport.flags, std::make_optional(required_flag));
+
+  codec_info = le_audio_codec_info_map
+      [SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH][0];
+  ASSERT_EQ(codec_info.transport.getTag(), CodecInfo::Transport::Tag::leAudio);
+  transport = codec_info.transport.get<CodecInfo::Transport::Tag::leAudio>();
+  ASSERT_EQ(transport.flags, std::make_optional(required_flag));
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GetScenariosTest);
 INSTANTIATE_TEST_SUITE_P(
     BluetoothLeAudioCodecsProviderTest, GetScenariosTest,
@@ -434,6 +512,15 @@
         kValidScenarioList, kValidConfigurationList,
         kValidCodecConfigurationList, kValidStrategyConfigurationList)));
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    ComposeLeAudioAymmetricCodecInfoTest);
+INSTANTIATE_TEST_SUITE_P(
+    BluetoothLeAudioCodecsProviderTest, ComposeLeAudioAymmetricCodecInfoTest,
+    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+        kValidAsymmetricScenarioList, kValidAsymmetricConfigurationList,
+        kValidAsymmetricCodecConfigurationList,
+        kValidStrategyConfigurationList)));
+
 int main(int argc, char** argv) {
   ::testing::InitGoogleTest(&argc, argv);
   return RUN_ALL_TESTS();
diff --git a/bluetooth/ranging/aidl/Android.bp b/bluetooth/ranging/aidl/Android.bp
index 4096669..b5ae205 100644
--- a/bluetooth/ranging/aidl/Android.bp
+++ b/bluetooth/ranging/aidl/Android.bp
@@ -31,7 +31,7 @@
         ndk: {
             apex_available: [
                 "//apex_available:platform",
-                "com.android.btservices",
+                "com.android.bt",
             ],
             min_sdk_version: "33",
         },
diff --git a/bluetooth/socket/aidl/Android.bp b/bluetooth/socket/aidl/Android.bp
index 77679f8..7c03677 100644
--- a/bluetooth/socket/aidl/Android.bp
+++ b/bluetooth/socket/aidl/Android.bp
@@ -37,7 +37,7 @@
         ndk: {
             apex_available: [
                 "//apex_available:platform",
-                "com.android.btservices",
+                "com.android.bt",
             ],
             min_sdk_version: "33",
         },
diff --git a/boot/aidl/default/Android.bp b/boot/aidl/default/Android.bp
index c1d3c57..2fd2dad 100644
--- a/boot/aidl/default/Android.bp
+++ b/boot/aidl/default/Android.bp
@@ -57,7 +57,7 @@
     name: "android.hardware.boot-service.default_recovery",
     defaults: ["android.hardware.boot-service_common"],
     init_rc: ["android.hardware.boot-service.default_recovery.rc"],
-    vintf_fragments: ["android.hardware.boot-service.default.xml"],
+    vintf_fragment_modules: ["android.hardware.boot-service.default.xml.recovery"],
     recovery: true,
 
     shared_libs: [
@@ -77,11 +77,16 @@
     installable: false,
 }
 
-prebuilt_etc {
+vintf_fragment {
+    name: "android.hardware.boot-service.default.xml.recovery",
+    src: "android.hardware.boot-service.default.xml",
+    recovery: true,
+}
+
+vintf_fragment {
     name: "android.hardware.boot-service.default.xml",
     src: "android.hardware.boot-service.default.xml",
-    sub_dir: "vintf",
-    installable: false,
+    vendor: true,
 }
 
 apex {
@@ -98,6 +103,8 @@
     ],
     prebuilts: [
         "android.hardware.boot-service.default.rc",
+    ],
+    vintf_fragment_modules: [
         "android.hardware.boot-service.default.xml",
     ],
 }
diff --git a/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp b/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp
index 93c8376..228e2af 100644
--- a/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp
+++ b/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp
@@ -84,20 +84,20 @@
 
     for (int s = 0; s < 2; s++) {
         const auto result = boot->setActiveBootSlot(s);
-        ASSERT_TRUE(result.isOk());
+        ASSERT_TRUE(result.isOk()) << result;
     }
     {
         // Restore original flags to avoid problems on reboot
         auto result = boot->setActiveBootSlot(curSlot);
-        ASSERT_TRUE(result.isOk());
+        ASSERT_TRUE(result.isOk()) << result;
 
         if (!otherBootable) {
             const auto result = boot->setSlotAsUnbootable(otherSlot);
-            ASSERT_TRUE(result.isOk());
+            ASSERT_TRUE(result.isOk()) << result;
         }
 
         result = boot->markBootSuccessful();
-        ASSERT_TRUE(result.isOk());
+        ASSERT_TRUE(result.isOk()) << result;
     }
     {
         int slots = 0;
@@ -116,19 +116,19 @@
     boot->isSlotBootable(otherSlot, &otherBootable);
     {
         auto result = boot->setSlotAsUnbootable(otherSlot);
-        ASSERT_TRUE(result.isOk());
+        ASSERT_TRUE(result.isOk()) << result;
         boot->isSlotBootable(otherSlot, &otherBootable);
         ASSERT_FALSE(otherBootable);
 
         // Restore original flags to avoid problems on reboot
         if (otherBootable) {
             result = boot->setActiveBootSlot(otherSlot);
-            ASSERT_TRUE(result.isOk());
+            ASSERT_TRUE(result.isOk()) << result;
         }
         result = boot->setActiveBootSlot(curSlot);
-        ASSERT_TRUE(result.isOk());
+        ASSERT_TRUE(result.isOk()) << result;
         result = boot->markBootSuccessful();
-        ASSERT_TRUE(result.isOk());
+        ASSERT_TRUE(result.isOk()) << result;
     }
     {
         int32_t slots = 0;
@@ -143,7 +143,7 @@
     for (int s = 0; s < 2; s++) {
         bool bootable = false;
         const auto res = boot->isSlotBootable(s, &bootable);
-        ASSERT_TRUE(res.isOk()) << res.getMessage();
+        ASSERT_TRUE(res.isOk()) << res;
     }
     int32_t slots = 0;
     boot->getNumberSlots(&slots);
@@ -184,7 +184,7 @@
     {
         const string emptySuffix = "";
         const auto result = boot->getSuffix(numSlots, &suffixStr);
-        ASSERT_TRUE(result.isOk());
+        ASSERT_TRUE(result.isOk()) << result;
         ASSERT_EQ(suffixStr, emptySuffix);
     }
 }
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 825c931..19f4839 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -147,6 +147,6 @@
     stem: "compatibility_matrix.202504.xml",
     srcs: ["compatibility_matrix.202504.xml"],
     kernel_configs: [
-        "kernel_config_w_6.12",
+        "kernel_config_b_6.12",
     ],
 }
diff --git a/compatibility_matrices/bump.py b/compatibility_matrices/bump.py
index ee2fa88..bcb0fa6 100755
--- a/compatibility_matrices/bump.py
+++ b/compatibility_matrices/bump.py
@@ -181,14 +181,14 @@
                         help="VINTF level of the next version (e.g. 202504)")
     parser.add_argument("current_letter",
                         type=str,
-                        help="Letter of the API level of the current version (e.g. v)")
+                        help="Letter of the API level of the current version (e.g. b)")
     parser.add_argument("next_letter",
                         type=str,
-                        help="Letter of the API level of the next version (e.g. w)")
+                        help="Letter of the API level of the next version (e.g. c)")
     parser.add_argument("platform_version",
                         type=str,
                         nargs="?",
-                        help="Android release version number number (e.g. 15)")
+                        help="Android release version number number (e.g. 16)")
     cmdline_args = parser.parse_args()
 
     Bump(cmdline_args).run()
diff --git a/contexthub/aidl/Android.bp b/contexthub/aidl/Android.bp
index 674f8af..b56537a 100644
--- a/contexthub/aidl/Android.bp
+++ b/contexthub/aidl/Android.bp
@@ -35,7 +35,7 @@
         ndk: {
             apex_available: [
                 "//apex_available:platform",
-                "com.android.btservices",
+                "com.android.bt",
             ],
             min_sdk_version: "33",
             apps_enabled: true,
diff --git a/graphics/bufferqueue/1.0/Android.bp b/graphics/bufferqueue/1.0/Android.bp
index c7c6453..87c3892 100644
--- a/graphics/bufferqueue/1.0/Android.bp
+++ b/graphics/bufferqueue/1.0/Android.bp
@@ -25,7 +25,7 @@
     gen_java: true,
     apex_available: [
         "//apex_available:platform",
-        "com.android.btservices",
+        "com.android.bt",
         "com.android.media",
         "com.android.media.swcodec",
     ],
diff --git a/graphics/bufferqueue/2.0/Android.bp b/graphics/bufferqueue/2.0/Android.bp
index e9f75c1..54f68c6 100644
--- a/graphics/bufferqueue/2.0/Android.bp
+++ b/graphics/bufferqueue/2.0/Android.bp
@@ -27,7 +27,7 @@
     gen_java: true,
     apex_available: [
         "//apex_available:platform",
-        "com.android.btservices",
+        "com.android.bt",
         "com.android.media",
         "com.android.media.swcodec",
     ],
diff --git a/graphics/common/1.0/Android.bp b/graphics/common/1.0/Android.bp
index b876bf3..1683c22 100644
--- a/graphics/common/1.0/Android.bp
+++ b/graphics/common/1.0/Android.bp
@@ -20,7 +20,7 @@
     gen_java_constants: true,
     apex_available: [
         "//apex_available:platform",
-        "com.android.btservices",
+        "com.android.bt",
         "com.android.media.swcodec",
         "test_com.android.media.swcodec",
     ],
diff --git a/graphics/common/1.1/Android.bp b/graphics/common/1.1/Android.bp
index ff6c9b7..81df887 100644
--- a/graphics/common/1.1/Android.bp
+++ b/graphics/common/1.1/Android.bp
@@ -23,7 +23,7 @@
     gen_java_constants: true,
     apex_available: [
         "//apex_available:platform",
-        "com.android.btservices",
+        "com.android.bt",
         "com.android.media.swcodec",
         "test_com.android.media.swcodec",
     ],
diff --git a/graphics/common/1.2/Android.bp b/graphics/common/1.2/Android.bp
index b4663e5..e1f4fe0 100644
--- a/graphics/common/1.2/Android.bp
+++ b/graphics/common/1.2/Android.bp
@@ -24,7 +24,7 @@
     gen_java_constants: true,
     apex_available: [
         "//apex_available:platform",
-        "com.android.btservices",
+        "com.android.bt",
         "com.android.media.swcodec",
         "test_com.android.media.swcodec",
     ],
diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
index 5de5f1c..cfd3173 100644
--- a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
+++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
@@ -753,7 +753,7 @@
  * Test IMapper::lock and IMapper::unlock with no CPU usage requested.
  */
 TEST_P(GraphicsMapperStableCTests, LockUnlockNoCPUUsage) {
-    constexpr auto usage = BufferUsage::CPU_READ_NEVER | BufferUsage::CPU_WRITE_NEVER;
+    constexpr auto usage = BufferUsage::CPU_READ_RARELY | BufferUsage::CPU_WRITE_NEVER;
     auto buffer = allocate({
             .name = {"VTS_TEMP"},
             .width = 64,
@@ -771,15 +771,12 @@
     auto handle = buffer->import();
     uint8_t* data = nullptr;
 
-    EXPECT_EQ(AIMAPPER_ERROR_BAD_VALUE,
-              mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
-                                region, -1,(void**)&data))
-              << "Locking with 0 access succeeded";
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_VALUE, mapper()->v5.lock(*handle, 0, region, -1, (void**)&data))
+            << "Locking with 0 access succeeded";
 
     int releaseFence = -1;
-    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER,
-              mapper()->v5.unlock(*handle, &releaseFence))
-              << "Unlocking not locked buffer succeeded";
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(*handle, &releaseFence))
+            << "Unlocking not locked buffer succeeded";
     if (releaseFence != -1) {
         close(releaseFence);
     }
diff --git a/macsec/aidl/default/MacsecPskPlugin.cpp b/macsec/aidl/default/MacsecPskPlugin.cpp
index 82d2545..8cb5283 100644
--- a/macsec/aidl/default/MacsecPskPlugin.cpp
+++ b/macsec/aidl/default/MacsecPskPlugin.cpp
@@ -18,7 +18,6 @@
 #include <openssl/cipher.h>
 #include <openssl/mem.h>
 
-#include <android-base/format.h>
 #include <android-base/logging.h>
 
 namespace aidl::android::hardware::macsec {
diff --git a/nfc/aidl/vts/functional/Android.bp b/nfc/aidl/vts/functional/Android.bp
index f97405e..8852f6c 100644
--- a/nfc/aidl/vts/functional/Android.bp
+++ b/nfc/aidl/vts/functional/Android.bp
@@ -58,12 +58,12 @@
         "CondVar.cpp",
     ],
     include_dirs: [
-        "system/nfc/src/gki/common",
-        "system/nfc/src/gki/ulinux",
-        "system/nfc/src/include",
-        "system/nfc/src/nfa/include",
-        "system/nfc/src/nfc/include",
-        "system/nfc/utils/include",
+        "packages/modules/Nfc/libnfc-nci/src/gki/common",
+        "packages/modules/Nfc/libnfc-nci/src/gki/ulinux",
+        "packages/modules/Nfc/libnfc-nci/src/include",
+        "packages/modules/Nfc/libnfc-nci/src/nfa/include",
+        "packages/modules/Nfc/libnfc-nci/src/nfc/include",
+        "packages/modules/Nfc/libnfc-nci/utils/include",
     ],
     shared_libs: [
         "liblog",
diff --git a/nfc/aidl/vts/functional/VtsNfcBehaviorChangesTest.cpp b/nfc/aidl/vts/functional/VtsNfcBehaviorChangesTest.cpp
index ff2522c..e93de95 100644
--- a/nfc/aidl/vts/functional/VtsNfcBehaviorChangesTest.cpp
+++ b/nfc/aidl/vts/functional/VtsNfcBehaviorChangesTest.cpp
@@ -119,6 +119,7 @@
         case NCI_MSG_PROP_ANDROID: {
             uint8_t android_sub_opcode = p_param[3];
             switch (android_sub_opcode) {
+                case NCI_ANDROID_SET_PASSIVE_OBSERVER_TECH:
                 case NCI_ANDROID_PASSIVE_OBSERVE: {
                     sVSCmdStatus = p_param[4];
                     LOG(INFO) << StringPrintf("Observe mode RSP: status: %x", sVSCmdStatus);
@@ -157,7 +158,7 @@
                      static_cast<uint8_t>(enable ? NCI_ANDROID_PASSIVE_OBSERVE_PARAM_ENABLE
                                                  : NCI_ANDROID_PASSIVE_OBSERVE_PARAM_DISABLE)};
 
-    status = NFA_SendRawVsCommand(sizeof(cmd), cmd, nfaVSCallback);
+    status = NFA_SendVsCommand(NCI_MSG_PROP_ANDROID, sizeof(cmd), cmd, nfaVSCallback);
 
     if (status == NFA_STATUS_OK) {
         if (!sNfaVsCommand.wait(1000)) {
diff --git a/radio/1.0/Android.bp b/radio/1.0/Android.bp
index e49a50d..09cf9aa 100644
--- a/radio/1.0/Android.bp
+++ b/radio/1.0/Android.bp
@@ -25,7 +25,7 @@
     ],
     apex_available: [
         "//apex_available:platform",
-        "com.android.btservices",
+        "com.android.bt",
     ],
     gen_java: true,
 }
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
index 9f530b3..f909676 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -239,18 +239,13 @@
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
-    if (getRadioHalCapabilities()) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_v1_6->rspInfo.error,
-                {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
-    } else {
-        ASSERT_TRUE(
-                CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
-                                 {::android::hardware::radio::V1_6::RadioError::NONE,
-                                  ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
-                                  ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
-                                  ::android::hardware::radio::V1_6::RadioError::MODEM_ERR}));
-    }
+    ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_v1_6->rspInfo.error,
+            {::android::hardware::radio::V1_6::RadioError::NONE,
+             ::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED,
+             ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+             ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+             ::android::hardware::radio::V1_6::RadioError::MODEM_ERR}));
 }
 
 /*
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index 01c09d8..53ef145 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -227,7 +227,7 @@
         java: {
             apex_available: [
                 "//apex_available:platform",
-                "com.android.btservices",
+                "com.android.bt",
             ],
             sdk_version: "module_current",
             min_sdk_version: "Tiramisu",
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
index 2945dab..e6d2fdf 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -45,6 +45,9 @@
   void deleteAllKeys();
   void destroyAttestationIds();
   android.hardware.security.keymint.BeginResult begin(in android.hardware.security.keymint.KeyPurpose purpose, in byte[] keyBlob, in android.hardware.security.keymint.KeyParameter[] params, in @nullable android.hardware.security.keymint.HardwareAuthToken authToken);
+  /**
+   * @deprecated Method has never been used due to design limitations
+   */
   void deviceLocked(in boolean passwordOnly, in @nullable android.hardware.security.secureclock.TimeStampToken timestampToken);
   void earlyBootEnded();
   byte[] convertStorageKeyToEphemeral(in byte[] storageKeyBlob);
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index b57dd8a..cafec70 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -826,6 +826,7 @@
      *
      * @param passwordOnly N/A due to the deprecation
      * @param timestampToken N/A due to the deprecation
+     * @deprecated Method has never been used due to design limitations
      */
     void deviceLocked(in boolean passwordOnly, in @nullable TimeStampToken timestampToken);
 
@@ -964,10 +965,11 @@
      * IKeyMintDevice must ignore KeyParameters with tags not included in the following list:
      *
      * o Tag::MODULE_HASH: holds a hash that must be included in attestations in the moduleHash
-     *   field of the software enforced authorization list. If Tag::MODULE_HASH is included in more
-     *   than one setAdditionalAttestationInfo call, the implementation should compare the initial
-     *   KeyParamValue with the more recent one. If they differ, the implementation should fail with
-     *   ErrorCode::MODULE_HASH_ALREADY_SET. If they are the same, no action needs to be taken.
+     *   field of the software enforced authorization list.
+     *
+     * @return error ErrorCode::MODULE_HASH_ALREADY_SET if this is not the first time
+     *         setAdditionalAttestationInfo is called with Tag::MODULE_HASH, and the associated
+     *         KeyParamValue of the current call doesn't match the KeyParamValue of the first call.
      */
     void setAdditionalAttestationInfo(in KeyParameter[] info);
 }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index e56c193..7ea5f5d 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -904,6 +904,9 @@
      * Tag::MODULE_HASH specifies the SHA-256 hash of the DER-encoded module information (see
      * KeyCreationResult.aidl for the ASN.1 schema).
      *
+     * KeyStore clients can retrieve the unhashed DER-encoded module information from Android
+     * via KeyStoreManager.getSupplementaryAttestationInfo.
+     *
      * This tag is never provided or returned from KeyMint in the key characteristics. It exists
      * only to define the tag for use in the attestation record.
      *
diff --git a/security/keymint/aidl/default/hal/lib.rs b/security/keymint/aidl/default/hal/lib.rs
index fad807f..196cf17 100644
--- a/security/keymint/aidl/default/hal/lib.rs
+++ b/security/keymint/aidl/default/hal/lib.rs
@@ -20,6 +20,19 @@
 use kmr_hal::env::get_property;
 use log::error;
 
+/// Retrieve the most significant attestation property for `name`.
+fn attestation_property(name: &str) -> Vec<u8> {
+    let prop_val = get_property(&format!("ro.product.vendor.{}", name)).unwrap_or_default();
+    if !prop_val.is_empty() {
+        prop_val
+    } else {
+        get_property(&format!("ro.product.{}", name))
+            .unwrap_or_else(|prop_name| format!("{} unavailable", prop_name))
+    }
+    .as_bytes()
+    .to_vec()
+}
+
 /// Populate attestation ID information based on properties (where available).
 /// Retrieving the serial number requires SELinux permission.
 pub fn attestation_id_info() -> kmr_wire::AttestationIdInfo {
@@ -30,12 +43,12 @@
             .to_vec()
     };
     kmr_wire::AttestationIdInfo {
-        brand: prop("ro.product.brand"),
-        device: prop("ro.product.device"),
-        product: prop("ro.product.name"),
+        brand: attestation_property("brand"),
+        device: attestation_property("device"),
+        product: attestation_property("name"),
         serial: prop("ro.serialno"),
-        manufacturer: prop("ro.product.manufacturer"),
-        model: prop("ro.product.model"),
+        manufacturer: attestation_property("manufacturer"),
+        model: attestation_property("model"),
         // Currently modem_simulator always returns one fixed value. See `handleGetIMEI` in
         // device/google/cuttlefish/host/commands/modem_simulator/misc_service.cpp for more details.
         // TODO(b/263188546): Use device-specific IMEI values when available.
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index eaeec32..dcf8674 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <format>
 #include <iomanip>
 #include <iterator>
 #include <memory>
@@ -535,7 +536,7 @@
     switch (rpcHardwareInfo.versionNumber) {
         case 3:
             if (isTeeDeviceInfo(*parsed) && parsed->size() != kNumTeeDeviceInfoEntries) {
-                error += fmt::format(
+                error += std::format(
                         "Err: Incorrect number of device info entries. Expected {} but got "
                         "{}\n",
                         kNumTeeDeviceInfoEntries, parsed->size());
@@ -544,7 +545,7 @@
             // may omit `os_version`
             if (!isTeeDeviceInfo(*parsed) && (parsed->size() != kNumTeeDeviceInfoEntries &&
                                               parsed->size() != kNumTeeDeviceInfoEntries - 1)) {
-                error += fmt::format(
+                error += std::format(
                         "Err: Incorrect number of device info entries. Expected {} or {} but got "
                         "{}\n",
                         kNumTeeDeviceInfoEntries - 1, kNumTeeDeviceInfoEntries, parsed->size());
@@ -870,7 +871,7 @@
     }
 
     auto csr = hwtrust::Csr::validate(encodedCsr, *diceChainKind, false /*isFactory*/,
-                                      false /*allowAnyMode*/, deviceSuffix(instanceName));
+                                      true /*allowAnyMode*/, deviceSuffix(instanceName));
     if (!csr.ok()) {
         return csr.error().message();
     }
@@ -904,7 +905,7 @@
     }
 
     auto csr1 = hwtrust::Csr::validate(encodedCsr1, *diceChainKind, false /*isFactory*/,
-                                       false /*allowAnyMode*/, deviceSuffix(instanceName1));
+                                       true /*allowAnyMode*/, deviceSuffix(instanceName1));
     if (!csr1.ok()) {
         return csr1.error().message();
     }
@@ -921,7 +922,7 @@
     }
 
     auto csr2 = hwtrust::Csr::validate(encodedCsr2, *diceChainKind, false /*isFactory*/,
-                                       false /*allowAnyMode*/, deviceSuffix(instanceName2));
+                                       true /*allowAnyMode*/, deviceSuffix(instanceName2));
     if (!csr2.ok()) {
         return csr2.error().message();
     }
@@ -952,7 +953,7 @@
     }
 
     auto csr = hwtrust::Csr::validate(encodedCsr, *diceChainKind, false /*isFactory*/,
-                                      false /*allowAnyMode*/, deviceSuffix(DEFAULT_INSTANCE_NAME));
+                                      true /*allowAnyMode*/, deviceSuffix(DEFAULT_INSTANCE_NAME));
     if (!csr.ok()) {
         return csr.error().message();
     }
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 810cc38..66f7539 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -853,7 +853,7 @@
  * is not "green" if and only if the mode on at least one certificate in the DICE chain
  * is non-normal.
  */
-TEST_P(CertificateRequestV2Test, unlockedBootloaderStatesImpliesNonnormalDiceChain) {
+TEST_P(CertificateRequestV2Test, DISABLED_unlockedBootloaderStatesImpliesNonnormalDiceChain) {
     auto challenge = randomBytes(MAX_CHALLENGE_SIZE);
     bytevec csr;
     auto status =
diff --git a/security/secretkeeper/aidl/vts/dice_sample.rs b/security/secretkeeper/aidl/vts/dice_sample.rs
index 4ef396a..d6379e5 100644
--- a/security/secretkeeper/aidl/vts/dice_sample.rs
+++ b/security/secretkeeper/aidl/vts/dice_sample.rs
@@ -283,7 +283,7 @@
             SUBCOMPONENT_AUTHORITY_HASH => hex::decode("ed255ae9ea98826f3f3a966849f0aaaf356d140c766a869048016e0ba10141af039fec5c53658ddebdad9c2339587c5ef5487bde89237ca79802238d91aebba8").unwrap(),
         },
         {
-            SUBCOMPONENT_NAME => "apex:com.android.btservices",
+            SUBCOMPONENT_NAME => "apex:com.android.bt",
             SUBCOMPONENT_SECURITY_VERSION => 990090000,
             SUBCOMPONENT_CODE_HASH => hex::decode("d7aa86dfdf92e662d2210cd2b3ad4e4522c917e9e287268363aa90e20f9ae16c").unwrap(),
             SUBCOMPONENT_AUTHORITY_HASH => hex::decode("a0d577d4a56cfad09aaa7abcd2355cd78872df85672f2faf9ac2fdf15c06147394e704c7473f28bed737803581a3d097275cc26d8095a4a896ee76167f9ee40e").unwrap(),
diff --git a/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
index b31a06c..99eb761 100644
--- a/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
@@ -64,7 +64,7 @@
     int keySizeBytes;
   }
   union DerivedKeyPolicy {
-    android.hardware.security.see.hwcrypto.IHwCryptoKey.ClearKeyPolicy clearKey;
+    android.hardware.security.see.hwcrypto.IHwCryptoKey.ClearKeyPolicy clearKeyPolicy;
     byte[] opaqueKey;
   }
   parcelable DerivedKeyParameters {
diff --git a/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
index 7c87dd3..3adb2f9 100644
--- a/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
@@ -34,5 +34,5 @@
 package android.hardware.security.see.hwcrypto;
 @VintfStability
 interface IHwCryptoOperations {
-  android.hardware.security.see.hwcrypto.CryptoOperationResult[] processCommandList(inout android.hardware.security.see.hwcrypto.CryptoOperationSet[] operations, out android.hardware.security.see.hwcrypto.CryptoOperationErrorAdditionalInfo additionalErrorInfo);
+  android.hardware.security.see.hwcrypto.CryptoOperationResult[] processCommandList(inout android.hardware.security.see.hwcrypto.CryptoOperationSet[] operations);
 }
diff --git a/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
index 97a4c37..93d6cbc 100644
--- a/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
@@ -107,10 +107,12 @@
          * If used we will derive a clear key and pass it back as an array of bytes on
          * <code>HwCryptoKeyMaterial::explicitKey</code>.
          */
-        ClearKeyPolicy clearKey;
+        ClearKeyPolicy clearKeyPolicy;
 
         /*
          * Policy for the newly derived opaque key. Defines how the key can be used and its type.
+         * Its definition can be found in <code>KeyPolicy.cddl</code>, which is basically a CBOR
+         * serialization of the file <code>KeyPolicy.aidl</code>.
          */
         byte[] opaqueKey;
     }
@@ -154,11 +156,14 @@
      *     Key to be used to derive the new key using HKDF.
      *
      * @return:
-     *     A DiceCurrentBoundKeyResult containint the versioned key tied the current client version
+     *     A DiceCurrentBoundKeyResult containing the versioned key tied the current client version
      *     on success.
      *
      * @throws:
-     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs,
+     *      in particular:
+     *          - BAD_PARAMETER if an invalid DeviceKeyId is requested.
+     *          - INVALID_KEY if an opaque key is provided that is not suitable for key derivation.
      */
     DiceCurrentBoundKeyResult deriveCurrentDicePolicyBoundKey(
             in DiceBoundDerivationKey derivationKey);
@@ -184,7 +189,11 @@
      *      success.
      *
      * @throws:
-     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs,
+     *      in particular:
+     *          - BAD_PARAMETER if an invalid DeviceKeyId is requested or if dicePolicyForKeyVersion
+     *            is not a valid encrypted DICE policy.
+     *          - INVALID_KEY if an opaque key is provided that is not suitable for key derivation.
      */
     DiceBoundKeyResult deriveDicePolicyBoundKey(
             in DiceBoundDerivationKey derivationKey, in byte[] dicePolicyForKeyVersion);
@@ -197,10 +206,15 @@
      *      file for more information.
      *
      * @return:
-     *      A HwCryptoKeyMaterial containing the derived key on success.
+     *      A <code>DerivedKey</code> containing the derived key on success.
      *
      * @throws:
-     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs,
+     *      in particular:
+     *          - BAD_PARAMETER if an invalid key policy is provided or if the key policy conflicts
+     *            with the requested key.
+     *          - SERIALIZATION_ERROR if the provided key policy is not a valid CBOR key policy.
+     *          - INVALID_KEY if an opaque key is provided that is not suitable for key derivation.
      */
     DerivedKey deriveKey(in DerivedKeyParameters parameters);
 
@@ -233,7 +247,11 @@
      *      IOpaqueKey on success.
      *
      * @throws:
-     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs,
+     *      in particular:
+     *          - BAD_PARAMETER if an invalid Key policy is provided or if the key policy conflicts
+     *            with provided key material.
+     *          - ALLOCATION_ERROR if the system runs out of memory while carring out the operation.
      */
     IOpaqueKey importClearKey(in ExplicitKeyMaterial keyMaterial, in KeyPolicy newKeyPolicy);
 
@@ -248,7 +266,9 @@
      * passing the receiver DICE policy to insure that only that receiver can import the key.
      *
      * @return:
-     *      byte[] on success, which is the caller encrypted DICE policy.
+     *      byte[] on success, which is the caller encrypted DICE policy. The DICE policy follows
+     *      the structure defined on DicePolicy.cddl, located under
+     *      hardware/interfaces/security/authgraph/aidl/android/hardware/security/authgraph/
      */
     byte[] getCurrentDicePolicy();
 
@@ -266,10 +286,14 @@
      *      DICE policy used to seal the exported key.
      *
      * @return:
-     *      An IOpaqueKey that can be directly be used on the local HWCrypto service on success.
+     *      An IOpaqueKey that can be directly used on the local HWCrypto service on success.
      *
      * @throws:
-     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs,
+     *      in particular:
+     *          - BAD_PARAMETER if an invalid encrypted sealing DICE policy is provided.
+     *          - ALLOCATION_ERROR if the system runs out of memory while carring out the operation.
+     *          - UNAUTHORIZED if the sealingDicePolicy do not match the caller.
      */
     IOpaqueKey keyTokenImport(in OpaqueKeyToken requestedKey, in byte[] sealingDicePolicy);
 
@@ -287,8 +311,9 @@
      *      An IOpaqueKey corresponding to the requested key slot on success.
      *
      * @throws:
-     *      ServiceSpecificException <code>UNAUTHORIZED</code> if the caller cannot access the
-     *      requested key, another specific error based on <code>HalErrorCode</code> otherwise.
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs,
+     *      in particular:
+     *          - UNAUTHORIZED if the caller cannot access the requested key.
      */
     IOpaqueKey getKeyslotData(KeySlot slotId);
 }
diff --git a/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
index 9df6d67..dbe4d80 100644
--- a/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
@@ -31,19 +31,21 @@
      *
      * @param operations:
      *      Parameter containing 1 or more set of commands to execute. Additionally, each set can
-     *      also contain a context on which the commands will be executed.
-     *
-     * @param additionalErrorInfo:
-     *      Structure containing additional info when errors are encountered. Only valid if the
-     *      function failed its execution.
+     *      also contain a context on which the commands will be executed. The parameter has type
+     *      inout because it can contain buffers used to write the output of the operation.
      *
      * @return:
      *      CryptoOperationResult[] on success, which can contain a context to continue executing
      *      each of the provided operations sets.
      *
      * @throws:
-     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs,
+     *      in particular:
+     *          - INVALID_KEY if the provided key is not compatible with the operation requested.
+     *          - BAD_STATE if the provided <code>CryptoOperationSet</code> contains operations that
+     *            cannot be carried out in the current server state.
+     *          - UNSUPPORTED if the requested operation is not supported by the server.
+     *          - ALLOCATION_ERROR if the system runs out of memory while carring out the operation.
      */
-    CryptoOperationResult[] processCommandList(inout CryptoOperationSet[] operations,
-            out CryptoOperationErrorAdditionalInfo additionalErrorInfo);
+    CryptoOperationResult[] processCommandList(inout CryptoOperationSet[] operations);
 }
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
index 2b39bc6..59d9593 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -100,7 +100,9 @@
     ASSERT_TRUE(mFilterTests.configFilter(filterReconf.settings, filterId));
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
     ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
-    ASSERT_TRUE(mFilterTests.startIdTest(filterId));
+    if (!isPassthroughFilter(filterReconf)) {
+        ASSERT_TRUE(mFilterTests.startIdTest(filterId));
+    }
     ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
     ASSERT_TRUE(mFilterTests.closeFilter(filterId));
@@ -152,7 +154,9 @@
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
     // tune test
     ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
-    ASSERT_TRUE(filterDataOutputTest());
+    if (!isPassthroughFilter(filterConf)) {
+        ASSERT_TRUE(filterDataOutputTest());
+    }
     ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
     ASSERT_TRUE(mFilterTests.closeFilter(filterId));
@@ -1377,6 +1381,10 @@
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
         live = configuration;
+        // shared memory handle is not used by a passthrough filter at all
+        if (isPassthroughFilter(filterMap[live.videoFilterId])) {
+            continue;
+        }
         mediaFilterUsingSharedMemoryTest(filterMap[live.videoFilterId],
                                          frontendMap[live.frontendId]);
     }
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
index be9b996..5fdc3dc 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
@@ -89,6 +89,28 @@
     sectionFilterIds.clear();
 }
 
+bool isPassthroughFilter(FilterConfig filterConfig) {
+    auto type = filterConfig.type;
+    if (type.mainType == DemuxFilterMainType::TS) {
+        auto subType = type.subType.get<DemuxFilterSubType::Tag::tsFilterType>();
+        if (subType == DemuxTsFilterType::AUDIO || subType == DemuxTsFilterType::VIDEO) {
+            auto tsFilterSettings = filterConfig.settings.get<DemuxFilterSettings::Tag::ts>();
+            auto avSettings = tsFilterSettings.filterSettings
+                    .get<DemuxTsFilterSettingsFilterSettings::Tag::av>();
+            return avSettings.isPassthrough;
+        }
+    } else if (filterConfig.type.mainType != DemuxFilterMainType::MMTP) {
+        auto subType = type.subType.get<DemuxFilterSubType::Tag::mmtpFilterType>();
+        if (subType == DemuxMmtpFilterType::AUDIO || subType == DemuxMmtpFilterType::VIDEO) {
+            auto mmtpFilterSettings = filterConfig.settings.get<DemuxFilterSettings::Tag::mmtp>();
+            auto avSettings = mmtpFilterSettings.filterSettings
+                    .get<DemuxMmtpFilterSettingsFilterSettings::Tag::av>();
+            return avSettings.isPassthrough;
+        }
+    }
+    return false;
+}
+
 enum class Dataflow_Context { LNBRECORD, RECORD, DESCRAMBLING, LNBDESCRAMBLING };
 
 class TunerLnbAidlTest : public testing::TestWithParam<std::string> {
diff --git a/virtualization/OWNERS b/virtualization/OWNERS
new file mode 100644
index 0000000..316145b
--- /dev/null
+++ b/virtualization/OWNERS
@@ -0,0 +1 @@
+include platform/packages/modules/Virtualization:/OWNERS
diff --git a/virtualization/capabilities_service/README.md b/virtualization/capabilities_service/README.md
new file mode 100644
index 0000000..7dc141e
--- /dev/null
+++ b/virtualization/capabilities_service/README.md
@@ -0,0 +1,9 @@
+The IVmCapabilitiesService HAL is used in a flow to grant a pVM a capability to
+issue vendor-specific SMCs. For more information see: TODO(ioffe): link the docs
+
+Here is a brief overview of the subdirectories structure:
+
+* default/ - a reference implementation of the HAL that partners can integrate
+    in their products.
+* noop/ - a no-op implementation is used in cuttlefish for mixed build testing.
+* vts/ - VTS tests for this HAL.
diff --git a/virtualization/capabilities_service/noop/Android.bp b/virtualization/capabilities_service/noop/Android.bp
new file mode 100644
index 0000000..37dc1a7
--- /dev/null
+++ b/virtualization/capabilities_service/noop/Android.bp
@@ -0,0 +1,34 @@
+package {
+    default_team: "trendy_team_virtualization",
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_binary {
+    name: "android.hardware.virtualization.capabilities.capabilities_service-noop",
+    relative_install_path: "hw",
+    vendor: true,
+    installable: true,
+    prefer_rlib: true,
+    rustlibs: [
+        "android.hardware.virtualization.capabilities.capabilities_service-V1-rust",
+        "libanyhow",
+        "libandroid_logger",
+        "libbinder_rs",
+        "liblog_rust",
+    ],
+    srcs: [
+        "src/main.rs",
+    ],
+    init_rc: [
+        "android.hardware.virtualization.capabilities.no_op_vm_capabilities_service.rc",
+    ],
+    vintf_fragment_modules: [
+        "android.hardware.virtualization.capabilities.no_op_vm_capabilities_service.xml",
+    ],
+}
+
+vintf_fragment {
+    name: "android.hardware.virtualization.capabilities.no_op_vm_capabilities_service.xml",
+    src: "android.hardware.virtualization.capabilities.no_op_vm_capabilities_service.xml",
+    vendor: true,
+}
diff --git a/virtualization/capabilities_service/noop/android.hardware.virtualization.capabilities.no_op_vm_capabilities_service.rc b/virtualization/capabilities_service/noop/android.hardware.virtualization.capabilities.no_op_vm_capabilities_service.rc
new file mode 100644
index 0000000..58c554a
--- /dev/null
+++ b/virtualization/capabilities_service/noop/android.hardware.virtualization.capabilities.no_op_vm_capabilities_service.rc
@@ -0,0 +1,6 @@
+service vendor.vm_capabilities_service /vendor/bin/hw/android.hardware.virtualization.capabilities.capabilities_service-noop
+  interface aidl android.hardware.virtualization.capabilities.IVmCapabilitiesService/noop
+  class hal
+  disabled
+  user nobody
+  group nobody
diff --git a/virtualization/capabilities_service/noop/android.hardware.virtualization.capabilities.no_op_vm_capabilities_service.xml b/virtualization/capabilities_service/noop/android.hardware.virtualization.capabilities.no_op_vm_capabilities_service.xml
new file mode 100644
index 0000000..8ecb9e5
--- /dev/null
+++ b/virtualization/capabilities_service/noop/android.hardware.virtualization.capabilities.no_op_vm_capabilities_service.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.virtualization.capabilities</name>
+        <version>1</version>
+        <interface>
+            <name>IVmCapabilitiesService</name>
+            <instance>noop</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/virtualization/capabilities_service/noop/src/aidl.rs b/virtualization/capabilities_service/noop/src/aidl.rs
new file mode 100644
index 0000000..8d85e49
--- /dev/null
+++ b/virtualization/capabilities_service/noop/src/aidl.rs
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2025 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.
+ */
+
+//! No-op implementation of the IVmCapabilitiesService AIDL interface.
+
+use android_hardware_virtualization_capabilities_capabilities_service::aidl::android::hardware::virtualization::capabilities::IVmCapabilitiesService::IVmCapabilitiesService;
+use binder::{Interface, ParcelFileDescriptor};
+use log::info;
+
+/// No-op implementation of IVmCapabilitiesService
+pub struct NoOpVmCapabilitiesService {}
+
+impl NoOpVmCapabilitiesService {
+    pub fn init() -> NoOpVmCapabilitiesService {
+        let service = NoOpVmCapabilitiesService {};
+        service
+    }
+}
+
+impl Interface for NoOpVmCapabilitiesService {}
+
+impl IVmCapabilitiesService for NoOpVmCapabilitiesService {
+
+    fn grantAccessToVendorTeeServices(&self,
+        vm_fd: &ParcelFileDescriptor, tee_services: &[String]) -> binder::Result<()> {
+        info!("received {vm_fd:?} {tee_services:?}");
+        Ok(())
+    }
+}
diff --git a/virtualization/capabilities_service/noop/src/main.rs b/virtualization/capabilities_service/noop/src/main.rs
new file mode 100644
index 0000000..9440996
--- /dev/null
+++ b/virtualization/capabilities_service/noop/src/main.rs
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2025 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.
+ */
+
+//! No-op implementation of the IVmCapabilitiesService.
+
+mod aidl;
+
+use crate::aidl::NoOpVmCapabilitiesService;
+use anyhow::{bail, Context, Result};
+use log::{error, info, LevelFilter};
+use binder::{register_lazy_service, BinderFeatures, ProcessState};
+use android_hardware_virtualization_capabilities_capabilities_service::aidl::android::hardware::virtualization::capabilities::IVmCapabilitiesService::BnVmCapabilitiesService;
+
+const SERVICE_NAME: &str = "android.hardware.virtualization.capabilities.IVmCapabilitiesService/noop";
+
+fn try_main() -> Result<()> {
+    // Initialize Android logging.
+    android_logger::init_once(
+        android_logger::Config::default()
+            .with_tag("NoOpIVmCapabilitiesService")
+            .with_max_level(LevelFilter::Info)
+            .with_log_buffer(android_logger::LogId::System),
+    );
+
+    ProcessState::start_thread_pool();
+    let service_impl = NoOpVmCapabilitiesService::init();
+    let service = BnVmCapabilitiesService::new_binder(service_impl, BinderFeatures::default());
+    register_lazy_service(SERVICE_NAME, service.as_binder())
+        .with_context(|| format!("failed to register {SERVICE_NAME}"))?;
+    info!("Registered Binder service, joining threadpool.");
+    ProcessState::join_thread_pool();
+    bail!("thread pool unexpectedly ended");
+}
+
+fn main() {
+    if let Err(e) = try_main() {
+        error!("failed with {e:?}");
+        std::process::exit(1);
+    }
+}
diff --git a/virtualization/capabilities_service/vts/Android.bp b/virtualization/capabilities_service/vts/Android.bp
new file mode 100644
index 0000000..1aa21c9
--- /dev/null
+++ b/virtualization/capabilities_service/vts/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2025 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 {
+    default_team: "trendy_team_virtualization",
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_test {
+    name: "VtsVmCapabilitiesServiceTest",
+    srcs: ["tests.rs"],
+    defaults: [
+        "rdroidtest.defaults",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    test_config: "AndroidTest.xml",
+    rustlibs: [
+        "android.hardware.virtualization.capabilities.capabilities_service-V1-rust",
+        "libbinder_rs",
+    ],
+    require_root: true,
+}
diff --git a/virtualization/capabilities_service/vts/AndroidTest.xml b/virtualization/capabilities_service/vts/AndroidTest.xml
new file mode 100644
index 0000000..2c3dadb
--- /dev/null
+++ b/virtualization/capabilities_service/vts/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2025 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for VmCapabilitiesService VTS tests.">
+  <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <option name="push-file" key="VtsVmCapabilitiesServiceTest"
+      value="/data/local/tmp/VtsVmCapabilitiesServiceTest" />
+  </target_preparer>
+
+  <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+    <option name="test-device-path" value="/data/local/tmp" />
+    <option name="module-name" value="VtsVmCapabilitiesServiceTest" />
+  </test>
+</configuration>
diff --git a/virtualization/capabilities_service/vts/tests.rs b/virtualization/capabilities_service/vts/tests.rs
new file mode 100644
index 0000000..9f0b7fd
--- /dev/null
+++ b/virtualization/capabilities_service/vts/tests.rs
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use android_hardware_virtualization_capabilities_capabilities_service::aidl::android::hardware::virtualization::capabilities::IVmCapabilitiesService::IVmCapabilitiesService;
+use rdroidtest::rdroidtest;
+use std::fs::File;
+
+const VM_CAPABILITIES_SERVICE: &str =
+    "android.hardware.virtualization.capabilities.IVmCapabilitiesService";
+
+/// Returns all available instances of VmCapabilitiesService.
+/// Note: it actually returns a pair of (<instance_name>, <instance_name)). This is a requirement
+/// of the rdroidtest framework for parameterized tests. See
+/// platform_testing/libraries/rdroidtest/README.md for more information.
+fn get_instances() -> Vec<(String, String)> {
+    binder::get_declared_instances(VM_CAPABILITIES_SERVICE)
+        .unwrap_or_default()
+        .into_iter()
+        .map(|v| (v.clone(), v))
+        .collect()
+}
+
+fn connect(instance: &str) -> binder::Strong<dyn IVmCapabilitiesService> {
+    let name = format!("{VM_CAPABILITIES_SERVICE}/{instance}");
+    binder::wait_for_interface(&name).unwrap()
+}
+
+/// A very basic test that simply connects to the service and send bogus data.
+#[rdroidtest(get_instances())]
+fn connect_to_service(instance: String) {
+    let service = connect(&instance);
+    let dev_null = File::open("/dev/null").expect("failed to open /dev/null");
+    let fd = binder::ParcelFileDescriptor::new(dev_null);
+    // In this test we don't care what service returns.
+    let _ = service.grantAccessToVendorTeeServices(&fd, &[]);
+}
+
+rdroidtest::test_main!();