Merge "Import contexthub v4 from bluetooth socket hal" into main
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
index 17f9814..873fb43 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
@@ -37,4 +37,5 @@
   INIT,
   IDLE,
   PROCESSING,
+  DRAINING,
 }
diff --git a/audio/aidl/android/hardware/audio/effect/CommandId.aidl b/audio/aidl/android/hardware/audio/effect/CommandId.aidl
index d940b42..de573bf 100644
--- a/audio/aidl/android/hardware/audio/effect/CommandId.aidl
+++ b/audio/aidl/android/hardware/audio/effect/CommandId.aidl
@@ -33,25 +33,39 @@
     /**
      * Start effect engine processing.
      * An effect instance must start processing data and transfer to PROCESSING state if it is in
-     * IDLE state and have all necessary information. Otherwise it must:
-     * 1. Throw a EX_ILLEGAL_STATE exception if effect is not in IDLE state, or
-     * 2. Throw a EX_TRANSACTION_FAILED for all other errors.
+     * IDLE or DRAINING state and has all necessary information. Otherwise, it must:
+     * 1. Throw an EX_ILLEGAL_STATE exception if the effect is not in IDLE or DRAINING state, or
+     * 2. Throw an EX_TRANSACTION_FAILED for all other errors.
      *
-     * Depending on parameters set to the effect instance, effect may do process or reverse
-     * process after START command.
+     * If an effect instance in DRAINING state receives a START command, it must transit back to
+     * PROCESSING state.
      */
     START = 0,
     /**
-     * Stop effect engine processing with all resource kept.
-     * The currently processed audio data will be discarded if the effect engine is in PROCESSING
-     * state.
-     * Effect instance must do nothing and return ok when it receive STOP command in IDLE state.
+     * Stop effect engine processing with all resources kept.
+     * If the effect is in **PROCESSING** state:
+     *   - It must transition to **IDLE** state if no intermediate operations are required.
+     *   - It must transition to **DRAINING** state if draining (e.g., fading) is required.
+     *     - The instance must automatically transition to **IDLE** after draining.
+     *     - It must ignore any new `STOP` commands during **DRAINING**.
+     *     - `START` commands during **DRAINING** must transition the instance back to
+     *       **PROCESSING**.
+     * If the effect instance is already in **IDLE** state, it must do nothing and return success.
+     *
+     * If the effect instance transitions to DRAINING state:
+     * 1. It must automatically transition to IDLE after completing draining tasks.
+     * 2. It must ignore any new STOP commands received during the DRAINING state.
+     * 3. START commands during DRAINING must immediately transfer the instance back to PROCESSING.
+     *
      */
     STOP = 1,
     /**
      * Keep all parameter settings but reset the buffer content, stop engine processing, and transit
-     * instance state to IDLE if its in PROCESSING state.
+     * the instance state to IDLE if it is in PROCESSING state.
      * Effect instance must be able to handle RESET command at IDLE and PROCESSING states.
+     *
+     * If the implementation includes intermediate operations such as draining, the RESET command
+     * must bypass DRAINING and immediately transition the state to IDLE.
      */
     RESET = 2,
 
diff --git a/audio/aidl/android/hardware/audio/effect/State.aidl b/audio/aidl/android/hardware/audio/effect/State.aidl
index 85a4afc..1b698d7 100644
--- a/audio/aidl/android/hardware/audio/effect/State.aidl
+++ b/audio/aidl/android/hardware/audio/effect/State.aidl
@@ -24,18 +24,18 @@
  * 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().
  *
- * Refer to State.gv for detailed state diagram.
+ * Refer to the state machine diagram `state.gv` for a detailed state diagram.
  */
 @VintfStability
 @Backing(type="byte")
 enum State {
-
     /**
      * An effect instance is in INIT state by default after it was created with
      * IFactory.createEffect(). When an effect instance is in INIT state, it should have instance
      * context initialized, and ready to handle IEffect.setParameter(), IEffect.open() as well as
      * all getter interfaces.
      *
+     * **Requirements in INIT state:**
      * In INIT state, effect instance must:
      * 1. Not handle any IEffect.command() and return EX_ILLEGAL_STATE with any Command.Id.
      * 2. Be able to handle all parameter setting with IEffect.setParameter().
@@ -43,28 +43,32 @@
      * IEffect.getState().
      * 4. Be able to handle IEffect.open() successfully after configuration.
      *
-     * Client is expected to do necessary configuration with IEffect.setParameter(), get all
-     * resource ready with IEffect.open(), and make sure effect instance transfer to IDLE state
-     * before sending commands with IEffect.command() interface. Effect instance must transfer
-     * from INIT to IDLE state after handle IEffect.open() call successfully.
+     * **State Transitions:**
+     * - Transitions to **IDLE** after successful `IEffect.open()`.
+     * - Remains in **INIT** on `IEffect.getState()` and `IEffect.getDescriptor()`.
+     * - Transitions to the final state on `IFactory.destroyEffect()`.
      */
     INIT,
+
     /**
      * An effect instance transfer to IDLE state after it was open successfully with IEffect.open()
      * in INIT state, or after it was stop/reset with Command.Id.STOP/RESET in PROCESSING state.
      *
-     * In IDLE state, effect instance must:
+     * **Requirements in IDLE state:**
      * 1. Be able to start effect processing engine with IEffect.command(Command.Id.START) call.
      * 2. Be able to handle all parameter setting with IEffect.setParameter().
      * 3. Be able to handle all getter interface calls like IEffect.getParameter() and
      * IEffect.getState().
      *
-     * The following state transfer can happen in IDLE state:
-     * 1. Transfer to PROCESSING if instance receive an START command and start processing data
-     * successfully.
-     * 2. Transfer to INIT if instance receive a close() call.
+     * **State Transitions:**
+     * - Transitions to **PROCESSING** on `IEffect.command(CommandId.START)` after starting
+     *   processing data successfully.
+     * - Transitions to **INIT** on `IEffect.close()`.
+     * - Remains in **IDLE** on `IEffect.getParameter()`, `IEffect.setParameter()`,
+     *   `IEffect.getDescriptor()`, `IEffect.command(CommandId.RESET)`, and `IEffect.reopen()`.
      */
     IDLE,
+
     /**
      * An effect instance is in PROCESSING state after it receive an START command and start
      * processing data successfully. Effect instance will transfer from PROCESSING to IDLE state if
@@ -75,12 +79,50 @@
      * the case of a close() call received when instance in PROCESSING state, it should try to stop
      * processing and transfer to IDLE first before close().
      *
-     * In PROCESSING state, effect instance must:
+     * **Requirements in PROCESSING state:**
      * 1. Return EX_ILLEGAL_STATE if it's not able to handle any parameter settings at runtime.
      * 2. Be able to handle STOP and RESET for IEffect.command() interface, and return
      * EX_ILLEGAL_STATE for all other commands.
      * 3. Must be able to handle all get* interface calls like IEffect.getParameter() and
      * IEffect.getState().
+     *
+     * **State Transitions:**
+     * - Transitions to **IDLE** on `IEffect.command(CommandId.STOP)` ( if no draining is required
+     *   or implemented) or `IEffect.command(CommandId.RESET)`.
+     * - Transitions to **DRAINING** on `IEffect.command(CommandId.STOP)` if draining is required.
+     * - Remains in **PROCESSING** on `IEffect.getParameter()`, `IEffect.setParameter()`,
+     *   `IEffect.getDescriptor()`, and `IEffect.reopen()`.
+     *
+     * **Notes:**
+     * - Clients should avoid calling `IEffect.close()` directly in this state; instead, they should
+     *   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.
      */
     PROCESSING,
+
+    /**
+     * DRAINING is an optional transitional state where the effect instance completes processing
+     * remaining input buffers or finalizes operations (e.g., fading) before stopping completely.
+     * This state is typically entered after a `CommandId.STOP` command in the PROCESSING state when
+     * draining is required.
+     *
+     * **Requirements in DRAINING state:**
+     * 1. Must handle `CommandId.START` and transition back to **PROCESSING**.
+     * 2. Must handle getter interface calls like `IEffect.getParameter()` and `IEffect.getState()`.
+     * 3. Must automatically transition to **IDLE** after draining is complete.
+     *
+     * **State Transitions:**
+     * - Transitions to **PROCESSING** on `IEffect.command(CommandId.START)`.
+     * - Transitions to **IDLE** on `IEffect.command(CommandId.RESET)`.
+     * - Transitions to **IDLE** automatically after draining is complete.
+     * - Remains in **DRAINING** on `IEffect.getParameter()`, `IEffect.setParameter()`,
+     *   `IEffect.getDescriptor()`, and `IEffect.reopen()`.
+     *
+     * **Notes:**
+     * - 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.
+     */
+    DRAINING,
 }
diff --git a/audio/aidl/android/hardware/audio/effect/state.gv b/audio/aidl/android/hardware/audio/effect/state.gv
index 22c70c8..2a8194e 100644
--- a/audio/aidl/android/hardware/audio/effect/state.gv
+++ b/audio/aidl/android/hardware/audio/effect/state.gv
@@ -13,26 +13,56 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 // To render: "dot -Tpng state.gv -o state.png"
+
 digraph effect_state_machine {
-    node[shape = point style = filled fillcolor = black width = 0.5] I;
-    node[shape = doublecircle] F;
-    node[shape = oval width = 1];
-    node[fillcolor = lightgreen] INIT;
-    node[fillcolor = lightblue] IDLE;
-    node[fillcolor = lightyellow] PROCESSING;
 
-    I -> INIT[label = "IFactory.createEffect" labelfontcolor = "navy"];
-    INIT -> F[label = "IFactory.destroyEffect"];
-    INIT -> IDLE[label = "IEffect.open()" labelfontcolor = "lime"];
-    IDLE -> PROCESSING[label = "IEffect.command(START"];
-    PROCESSING -> IDLE[label = "IEffect.command(STOP)\nIEffect.command(RESET)"];
-    IDLE -> INIT[label = "IEffect.close()"];
+    rankdir=LR; // Left to Right layout
 
-    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"];
+    label="Effect State Machine";
+    fontsize=20;
+    labelloc=top;
+
+    node [fontname="Helvetica", fontsize=12, style=filled];
+
+    // Initial state node
+    I [shape=point, fillcolor=black, width=0.2];
+
+    // Final state node
+    F [shape=doublecircle, fillcolor=white, width=0.2];
+
+    // 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];
+
+    // 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)"];
+
+    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"];
+
 }
diff --git a/audio/aidl/default/EffectContext.cpp b/audio/aidl/default/EffectContext.cpp
index 26c88b2..b354dd1 100644
--- a/audio/aidl/default/EffectContext.cpp
+++ b/audio/aidl/default/EffectContext.cpp
@@ -258,4 +258,18 @@
     return RetCode::SUCCESS;
 }
 
+RetCode EffectContext::startDraining() {
+    mIsDraining = true;
+    return RetCode::SUCCESS;
+}
+
+RetCode EffectContext::finishDraining() {
+    mIsDraining = false;
+    return RetCode::SUCCESS;
+}
+
+bool EffectContext::isDraining() {
+    return mIsDraining;
+}
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
index 3e61335..7857f53 100644
--- a/audio/aidl/default/EffectImpl.cpp
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -79,7 +79,6 @@
     std::lock_guard lg(mImplMutex);
     RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "alreadyClosed");
 
-    // TODO: b/302036943 add reopen implementation
     RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
     mImplContext->dupeFmqWithReopen(ret);
     return ndk::ScopedAStatus::ok();
@@ -347,7 +346,7 @@
 
     {
         std::lock_guard lg(mImplMutex);
-        if (mState != State::PROCESSING) {
+        if (mState != State::PROCESSING && mState != State::DRAINING) {
             LOG(DEBUG) << getEffectNameWithVersion()
                        << " skip process in state: " << toString(mState);
             return;
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
index b515385..1a52c13 100644
--- a/audio/aidl/default/EffectThread.cpp
+++ b/audio/aidl/default/EffectThread.cpp
@@ -68,7 +68,11 @@
 RetCode EffectThread::startThread() {
     {
         std::lock_guard lg(mThreadMutex);
-        mStop = false;
+        if (mDraining) {
+            mDraining = false;
+        } else {
+            mStop = false;
+        }
         mCv.notify_one();
     }
 
@@ -87,6 +91,25 @@
     return RetCode::SUCCESS;
 }
 
+RetCode EffectThread::startDraining() {
+    std::lock_guard lg(mThreadMutex);
+    mDraining = true;
+    mCv.notify_one();
+
+    LOG(VERBOSE) << mName << __func__;
+    return RetCode::SUCCESS;
+}
+
+RetCode EffectThread::finishDraining() {
+    std::lock_guard lg(mThreadMutex);
+    mDraining = false;
+    mStop = true;
+    mCv.notify_one();
+
+    LOG(VERBOSE) << mName << __func__;
+    return RetCode::SUCCESS;
+}
+
 void EffectThread::threadLoop() {
     pthread_setname_np(pthread_self(), mName.substr(0, kMaxTaskNameLen - 1).c_str());
     setpriority(PRIO_PROCESS, 0, mPriority);
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index 2cef9eb..2e860d8 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -76,6 +76,7 @@
         <effect name="bassboost" library="bundle" uuid="8631f300-72e2-11df-b57e-0002a5d5c51b"/>
         <effect name="downmix" library="downmix" uuid="93f04452-e4fe-41cc-91f9-e475b6d1d69f"/>
         <effect name="dynamics_processing" library="dynamics_processing" uuid="e0e6539b-1781-7261-676f-6d7573696340"/>
+        <effect name="eraser" library="erasersw" uuid="fa81ab46-588b-11ed-9b6a-0242ac120002"/>
         <effect name="haptic_generator" library="haptic_generator" uuid="97c4acd1-8b82-4f2f-832e-c2fe5d7a9931"/>
         <effect name="loudness_enhancer" library="loudness_enhancer" uuid="fa415329-2034-4bea-b5dc-5b381c8d1e2c"/>
         <effect name="reverb_env_aux" library="reverb" uuid="4a387fc0-8ab3-11df-8bad-0002a5d5c51b"/>
diff --git a/audio/aidl/default/eraser/Eraser.cpp b/audio/aidl/default/eraser/Eraser.cpp
index 157ec79..59cc9a2 100644
--- a/audio/aidl/default/eraser/Eraser.cpp
+++ b/audio/aidl/default/eraser/Eraser.cpp
@@ -133,10 +133,70 @@
     LOG(DEBUG) << __func__;
 }
 
+ndk::ScopedAStatus EraserSw::command(CommandId command) {
+    std::lock_guard lg(mImplMutex);
+    RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "instanceNotOpen");
+
+    switch (command) {
+        case CommandId::START:
+            RETURN_OK_IF(mState == State::PROCESSING);
+            mState = State::PROCESSING;
+            mContext->enable();
+            startThread();
+            RETURN_IF(notifyEventFlag(mDataMqNotEmptyEf) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+                      "notifyEventFlagNotEmptyFailed");
+            break;
+        case CommandId::STOP:
+            RETURN_OK_IF(mState == State::IDLE || mState == State::DRAINING);
+            if (mVersion < kDrainSupportedVersion) {
+                mState = State::IDLE;
+                stopThread();
+                mContext->disable();
+            } else {
+                mState = State::DRAINING;
+                startDraining();
+                mContext->startDraining();
+            }
+            RETURN_IF(notifyEventFlag(mDataMqNotEmptyEf) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+                      "notifyEventFlagNotEmptyFailed");
+            break;
+        case CommandId::RESET:
+            mState = State::IDLE;
+            RETURN_IF(notifyEventFlag(mDataMqNotEmptyEf) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+                      "notifyEventFlagNotEmptyFailed");
+            stopThread();
+            mImplContext->disable();
+            mImplContext->reset();
+            mImplContext->resetBuffer();
+            break;
+        default:
+            LOG(ERROR) << getEffectNameWithVersion() << __func__ << " instance still processing";
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "CommandIdNotSupported");
+    }
+    LOG(VERBOSE) << getEffectNameWithVersion() << __func__
+                 << " transfer to state: " << toString(mState);
+    return ndk::ScopedAStatus::ok();
+}
+
 // Processing method running in EffectWorker thread.
 IEffect::Status EraserSw::effectProcessImpl(float* in, float* out, int samples) {
     RETURN_VALUE_IF(!mContext, (IEffect::Status{EX_NULL_POINTER, 0, 0}), "nullContext");
-    return mContext->process(in, out, samples);
+    IEffect::Status procStatus{STATUS_NOT_ENOUGH_DATA, 0, 0};
+    procStatus = mContext->process(in, out, samples);
+    if (mState == State::DRAINING && procStatus.status == STATUS_NOT_ENOUGH_DATA) {
+        drainingComplete_l();
+    }
+
+    return procStatus;
+}
+
+void EraserSw::drainingComplete_l() {
+    if (mState != State::DRAINING) return;
+
+    LOG(DEBUG) << getEffectNameWithVersion() << __func__;
+    finishDraining();
+    mState = State::IDLE;
 }
 
 EraserSwContext::EraserSwContext(int statusDepth, const Parameter::Common& common)
@@ -164,24 +224,47 @@
 
 IEffect::Status EraserSwContext::process(float* in, float* out, int samples) {
     LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
-    IEffect::Status status = {EX_ILLEGAL_ARGUMENT, 0, 0};
-
+    IEffect::Status procStatus = {EX_ILLEGAL_ARGUMENT, 0, 0};
     const auto inputChannelCount = getChannelCount(mCommon.input.base.channelMask);
     const auto outputChannelCount = getChannelCount(mCommon.output.base.channelMask);
     if (inputChannelCount < outputChannelCount) {
         LOG(ERROR) << __func__ << " invalid channel count, in: " << inputChannelCount
                    << " out: " << outputChannelCount;
-        return status;
+        return procStatus;
     }
 
-    int iFrames = samples / inputChannelCount;
+    if (samples <= 0 || 0 != samples % inputChannelCount) {
+        LOG(ERROR) << __func__ << " invalid samples: " << samples;
+        return procStatus;
+    }
+
+    const int iFrames = samples / inputChannelCount;
+    const float gainPerSample = 1.f / iFrames;
     for (int i = 0; i < iFrames; i++) {
-        std::memcpy(out, in, outputChannelCount);
+        if (isDraining()) {
+            const float gain = (iFrames - i - 1) * gainPerSample;
+            for (size_t c = 0; c < outputChannelCount; c++) {
+                out[c] = in[c] * gain;
+            }
+        } else {
+            std::memcpy(out, in, outputChannelCount * sizeof(float));
+        }
+
         in += inputChannelCount;
         out += outputChannelCount;
     }
-    return {STATUS_OK, static_cast<int32_t>(iFrames * inputChannelCount),
-            static_cast<int32_t>(iFrames * outputChannelCount)};
+
+    // drain for one cycle
+    if (isDraining()) {
+        procStatus.status = STATUS_NOT_ENOUGH_DATA;
+        finishDraining();
+    } else {
+        procStatus.status = STATUS_OK;
+    }
+    procStatus.fmqConsumed = static_cast<int32_t>(iFrames * inputChannelCount);
+    procStatus.fmqProduced = static_cast<int32_t>(iFrames * outputChannelCount);
+
+    return procStatus;
 }
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/eraser/Eraser.h b/audio/aidl/default/eraser/Eraser.h
index 0d4eb8f..7bf2f57 100644
--- a/audio/aidl/default/eraser/Eraser.h
+++ b/audio/aidl/default/eraser/Eraser.h
@@ -63,6 +63,9 @@
     IEffect::Status effectProcessImpl(float* in, float* out, int samples)
             REQUIRES(mImplMutex) final;
 
+    ndk::ScopedAStatus command(CommandId command) final;
+    void drainingComplete_l() REQUIRES(mImplMutex);
+
   private:
     static const std::vector<Range::SpatializerRange> kRanges;
     std::shared_ptr<EraserSwContext> mContext GUARDED_BY(mImplMutex);
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index 02a4caa..9e44349 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -86,7 +86,12 @@
     virtual RetCode disable();
     virtual RetCode reset();
 
+    virtual RetCode startDraining();
+    virtual RetCode finishDraining();
+    virtual bool isDraining();
+
   protected:
+    bool mIsDraining = false;
     int mVersion = 0;
     size_t mInputFrameSize = 0;
     size_t mOutputFrameSize = 0;
diff --git a/audio/aidl/default/include/effect-impl/EffectThread.h b/audio/aidl/default/include/effect-impl/EffectThread.h
index ec2a658..9abcdb8 100644
--- a/audio/aidl/default/include/effect-impl/EffectThread.h
+++ b/audio/aidl/default/include/effect-impl/EffectThread.h
@@ -38,6 +38,8 @@
     RetCode destroyThread();
     RetCode startThread();
     RetCode stopThread();
+    RetCode startDraining();
+    RetCode finishDraining();
 
     // Will call process() in a loop if the thread is running.
     void threadLoop();
@@ -49,6 +51,9 @@
      */
     virtual void process() = 0;
 
+  protected:
+    bool mDraining GUARDED_BY(mThreadMutex) = false;
+
   private:
     static constexpr int kMaxTaskNameLen = 15;
 
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index 570ecef..787bd12 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -124,7 +124,7 @@
             return;
         }
 
-        ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+        ASSERT_TRUE(expectState(effect, State::IDLE));
         updateFrameSize(common);
     }
 
@@ -155,7 +155,7 @@
         if (effect) {
             ASSERT_STATUS(status, effect->close());
             if (status == EX_NONE) {
-                ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
+                ASSERT_TRUE(expectState(effect, State::INIT));
             }
         }
     }
@@ -166,12 +166,14 @@
         ASSERT_STATUS(status, effect->getDescriptor(&desc));
     }
 
-    static void expectState(std::shared_ptr<IEffect> effect, State expectState,
-                            binder_status_t status = EX_NONE) {
-        ASSERT_NE(effect, nullptr);
-        State state;
-        ASSERT_STATUS(status, effect->getState(&state));
-        ASSERT_EQ(expectState, state);
+    static bool expectState(std::shared_ptr<IEffect> effect, State expectState) {
+        if (effect == nullptr) return false;
+
+        if (State state; EX_NONE != effect->getState(&state).getStatus() || expectState != state) {
+            return false;
+        }
+
+        return true;
     }
 
     static void commandIgnoreRet(std::shared_ptr<IEffect> effect, CommandId command) {
@@ -190,12 +192,14 @@
 
         switch (command) {
             case CommandId::START:
-                ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+                ASSERT_TRUE(expectState(effect, State::PROCESSING));
                 break;
             case CommandId::STOP:
-                FALLTHROUGH_INTENDED;
+                ASSERT_TRUE(expectState(effect, State::IDLE) ||
+                            expectState(effect, State::DRAINING));
+                break;
             case CommandId::RESET:
-                ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+                ASSERT_TRUE(expectState(effect, State::IDLE));
                 break;
             default:
                 return;
@@ -371,6 +375,24 @@
         return functor(result);
     }
 
+    // keep writing data to the FMQ until effect transit from DRAINING to IDLE
+    static void waitForDrain(std::vector<float>& inputBuffer, std::vector<float>& outputBuffer,
+                             const std::shared_ptr<IEffect>& effect,
+                             std::unique_ptr<EffectHelper::StatusMQ>& statusMQ,
+                             std::unique_ptr<EffectHelper::DataMQ>& inputMQ,
+                             std::unique_ptr<EffectHelper::DataMQ>& outputMQ, int version) {
+        State state;
+        while (effect->getState(&state).getStatus() == EX_NONE && state == State::DRAINING) {
+            EXPECT_NO_FATAL_FAILURE(
+                    EffectHelper::writeToFmq(statusMQ, inputMQ, inputBuffer, version));
+            EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(
+                    statusMQ, 1, outputMQ, outputBuffer.size(), outputBuffer, std::nullopt));
+        }
+        ASSERT_TRUE(State::IDLE == state);
+        EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, outputBuffer));
+        return;
+    }
+
     static void processAndWriteToOutput(std::vector<float>& inputBuffer,
                                         std::vector<float>& outputBuffer,
                                         const std::shared_ptr<IEffect>& effect,
@@ -404,8 +426,9 @@
         // Disable the process
         if (callStopReset) {
             ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+            EXPECT_NO_FATAL_FAILURE(waitForDrain(inputBuffer, outputBuffer, effect, statusMQ,
+                                                 inputMQ, outputMQ, version));
         }
-        EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, outputBuffer));
 
         if (callStopReset) {
             ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
diff --git a/automotive/vehicle/aidl/impl/vhal/src/fuzzer.cpp b/automotive/vehicle/aidl/impl/vhal/src/fuzzer.cpp
index ac1e3b1..6d994bb 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/fuzzer.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/fuzzer.cpp
@@ -25,6 +25,8 @@
 using ::ndk::SharedRefBase;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    // TODO(b/183141167): need to rewrite 'dump' to avoid SIGPIPE.
+    signal(SIGPIPE, SIG_IGN);
     std::unique_ptr<FakeVehicleHardware> hardware = std::make_unique<FakeVehicleHardware>();
     std::shared_ptr<DefaultVehicleHal> vhal =
             ::ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BroadcastCapability.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BroadcastCapability.aidl
index 58710ef..2872362 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BroadcastCapability.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BroadcastCapability.aidl
@@ -38,6 +38,7 @@
   android.hardware.bluetooth.audio.AudioLocation supportedChannel;
   int channelCountPerStream;
   android.hardware.bluetooth.audio.BroadcastCapability.LeAudioCodecCapabilities leAudioCodecCapabilities;
+  @nullable android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.AudioChannelAllocation audioLocation;
   @VintfStability
   parcelable VendorCapabilities {
     ParcelableHolder extension;
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
index be79b0d..97fcd1f 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
@@ -92,6 +92,7 @@
     const int FRONT_RIGHT_WIDE = 0x02000000;
     const int LEFT_SURROUND = 0x04000000;
     const int RIGHT_SURROUND = 0x08000000;
+    const int MONO = 0x00000000;
   }
   parcelable OctetsPerCodecFrame {
     int value;
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/UnicastCapability.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/UnicastCapability.aidl
index 481e2ac..6ed0e56 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/UnicastCapability.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/UnicastCapability.aidl
@@ -39,6 +39,7 @@
   int deviceCount;
   int channelCountPerDevice;
   android.hardware.bluetooth.audio.UnicastCapability.LeAudioCodecCapabilities leAudioCodecCapabilities;
+  @nullable android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.AudioChannelAllocation audioLocation;
   @VintfStability
   parcelable VendorCapabilities {
     ParcelableHolder extension;
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BroadcastCapability.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BroadcastCapability.aidl
index f1301fb..db3c10e 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BroadcastCapability.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BroadcastCapability.aidl
@@ -17,6 +17,7 @@
 package android.hardware.bluetooth.audio;
 
 import android.hardware.bluetooth.audio.AudioLocation;
+import android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.AudioChannelAllocation;
 import android.hardware.bluetooth.audio.CodecType;
 import android.hardware.bluetooth.audio.Lc3Capabilities;
 
@@ -35,8 +36,11 @@
         @nullable VendorCapabilities[] vendorCapabillities;
     }
     CodecType codecType;
+    // @deprecated use audioLocation if present.
     AudioLocation supportedChannel;
     // Supported channel count for each stream
     int channelCountPerStream;
     LeAudioCodecCapabilities leAudioCodecCapabilities;
+    // The new audio location type, replacing supportedChannel
+    @nullable AudioChannelAllocation audioLocation;
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
index 5e32e5e..2835325 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
@@ -47,6 +47,7 @@
     }
 
     parcelable AudioChannelAllocation {
+        // @deprecated use MONO instead.
         const int NOT_ALLOWED = 0x00000000;
         const int FRONT_LEFT = 0x00000001;
         const int FRONT_RIGHT = 0x00000002;
@@ -76,6 +77,7 @@
         const int FRONT_RIGHT_WIDE = 0x02000000;
         const int LEFT_SURROUND = 0x04000000;
         const int RIGHT_SURROUND = 0x08000000;
+        const int MONO = 0x00000000;
 
         // Bit mask of Audio Locations
         int bitmask;
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/UnicastCapability.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/UnicastCapability.aidl
index 8583221..9f33672 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/UnicastCapability.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/UnicastCapability.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.bluetooth.audio.AptxAdaptiveLeCapabilities;
 import android.hardware.bluetooth.audio.AudioLocation;
+import android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.AudioChannelAllocation;
 import android.hardware.bluetooth.audio.CodecType;
 import android.hardware.bluetooth.audio.Lc3Capabilities;
 import android.hardware.bluetooth.audio.OpusCapabilities;
@@ -39,10 +40,13 @@
         OpusCapabilities opusCapabilities;
     }
     CodecType codecType;
+    // @deprecated use audioLocation if present.
     AudioLocation supportedChannel;
     // The number of connected device
     int deviceCount;
     // Supported channel count for each device
     int channelCountPerDevice;
     LeAudioCodecCapabilities leAudioCodecCapabilities;
+    // The new audio location type, replacing supportedChannel
+    @nullable AudioChannelAllocation audioLocation;
 }
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index a10e0a6..18fc4b2 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -534,7 +534,8 @@
         direction_configurations,
     const std::vector<std::optional<AseDirectionRequirement>>& requirements,
     std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
-        valid_direction_configurations) {
+        valid_direction_configurations,
+    bool isExact) {
   if (!direction_configurations.has_value()) return;
 
   if (!valid_direction_configurations.has_value()) {
@@ -542,55 +543,93 @@
         std::vector<std::optional<AseDirectionConfiguration>>();
   }
 
-  // Exact matching process
-  // Need to respect the number of device
-  for (int i = 0; i < requirements.size(); ++i) {
-    auto requirement = requirements[i];
-    auto direction_configuration = direction_configurations.value()[i];
-    if (!direction_configuration.has_value()) {
-      valid_direction_configurations = std::nullopt;
-      return;
-    }
-    auto cfg = direction_configuration.value();
-    if (!filterMatchedAseConfiguration(cfg.aseConfiguration,
-                                       requirement.value().aseConfiguration)) {
-      valid_direction_configurations = std::nullopt;
-      return;  // No way to match
-    }
-    // For exact match, we require this direction to have the same allocation.
-    // If stereo, need stereo.
-    // If mono, need mono (modified to the correct required allocation)
-    auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
-        requirement.value().aseConfiguration);
-    int req_channel_count = getCountFromBitmask(req_allocation_bitmask);
-    int cfg_bitmask =
-        getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
-    int cfg_channel_count = getCountFromBitmask(cfg_bitmask);
-    if (req_channel_count <= 1) {
-      // MONO case, is a match if also mono, modify to the same allocation
-      if (cfg_channel_count > 1) {
+  if (isExact) {
+    // Exact matching process
+    // Need to respect the number of device
+    for (int i = 0; i < requirements.size(); ++i) {
+      auto requirement = requirements[i];
+      auto direction_configuration = direction_configurations.value()[i];
+      if (!direction_configuration.has_value()) {
         valid_direction_configurations = std::nullopt;
-        return;  // Not a match
+        return;
       }
-      // Modify the bitmask to be the same as the requirement
-      for (auto& codec_cfg : cfg.aseConfiguration.codecConfiguration) {
-        if (codec_cfg.getTag() ==
-            CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
-          codec_cfg
-              .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
-              .bitmask = req_allocation_bitmask;
-          break;
+      auto cfg = direction_configuration.value();
+      if (!filterMatchedAseConfiguration(
+              cfg.aseConfiguration, requirement.value().aseConfiguration)) {
+        valid_direction_configurations = std::nullopt;
+        return;  // No way to match
+      }
+      // For exact match, we require this direction to have the same allocation.
+      // If stereo, need stereo.
+      // If mono, need mono (modified to the correct required allocation)
+      auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
+          requirement.value().aseConfiguration);
+      int req_channel_count = getCountFromBitmask(req_allocation_bitmask);
+      int cfg_bitmask =
+          getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
+      int cfg_channel_count = getCountFromBitmask(cfg_bitmask);
+      if (req_channel_count <= 1) {
+        // MONO case, is a match if also mono, modify to the same allocation
+        if (cfg_channel_count > 1) {
+          valid_direction_configurations = std::nullopt;
+          return;  // Not a match
+        }
+        // Modify the bitmask to be the same as the requirement
+        for (auto& codec_cfg : cfg.aseConfiguration.codecConfiguration) {
+          if (codec_cfg.getTag() ==
+              CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
+            codec_cfg
+                .get<CodecSpecificConfigurationLtv::Tag::
+                         audioChannelAllocation>()
+                .bitmask = req_allocation_bitmask;
+            break;
+          }
+        }
+      } else {
+        // STEREO case, is a match if same allocation
+        if (req_allocation_bitmask != cfg_bitmask) {
+          valid_direction_configurations = std::nullopt;
+          return;  // Not a match
         }
       }
-    } else {
-      // STEREO case, is a match if same allocation
-      if (req_allocation_bitmask != cfg_bitmask) {
+      // Push to list if valid
+      valid_direction_configurations.value().push_back(cfg);
+    }
+  } else {
+    // Loose matching process
+    for (auto& requirement : requirements) {
+      if (!requirement.has_value()) continue;
+      auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
+          requirement.value().aseConfiguration);
+      auto req_channel_count = getCountFromBitmask(req_allocation_bitmask);
+
+      auto temp = std::vector<AseDirectionConfiguration>();
+
+      for (auto direction_configuration : direction_configurations.value()) {
+        if (!direction_configuration.has_value()) continue;
+        if (!filterMatchedAseConfiguration(
+                direction_configuration.value().aseConfiguration,
+                requirement.value().aseConfiguration))
+          continue;
+        // Valid if match any requirement.
+        temp.push_back(direction_configuration.value());
+      }
+
+      // Get the best matching config based on channel allocation
+      auto total_cfg_channel_count = 0;
+      auto req_valid_configs = getValidConfigurationsFromAllocation(
+          req_allocation_bitmask, temp, isExact);
+      // Count and check required channel counts
+      for (auto& cfg : req_valid_configs) {
+        total_cfg_channel_count += getCountFromBitmask(
+            getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration));
+        valid_direction_configurations.value().push_back(cfg);
+      }
+      if (total_cfg_channel_count != req_channel_count) {
         valid_direction_configurations = std::nullopt;
-        return;  // Not a match
+        return;
       }
     }
-    // Push to list if valid
-    valid_direction_configurations.value().push_back(cfg);
   }
 }
 
@@ -650,8 +689,8 @@
 std::optional<LeAudioAseConfigurationSetting>
 LeAudioOffloadAudioProvider::getRequirementMatchedAseConfigurationSettings(
     IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
-    const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
-        requirement) {
+    const IBluetoothAudioProvider::LeAudioConfigurationRequirement& requirement,
+    bool isExact) {
   // Create a new LeAudioAseConfigurationSetting to return
   // Make context the same as the requirement
   LeAudioAseConfigurationSetting filtered_setting{
@@ -664,25 +703,27 @@
   // is the number of device.
 
   // The exact matching process is as follow:
-  // 1. Setting direction has the same number of cfg (ignore when null require)
+  // 1. Setting direction has the same number of cfg (ignore when null
+  // require)
   // 2. For each index, it's a 1-1 filter / mapping.
+  if (isExact) {
+    if (requirement.sinkAseRequirement.has_value() &&
+        requirement.sinkAseRequirement.value().size() !=
+            setting.sinkAseConfiguration.value().size()) {
+      return std::nullopt;
+    }
 
-  if (requirement.sinkAseRequirement.has_value() &&
-      requirement.sinkAseRequirement.value().size() !=
-          setting.sinkAseConfiguration.value().size()) {
-    return std::nullopt;
-  }
-
-  if (requirement.sourceAseRequirement.has_value() &&
-      requirement.sourceAseRequirement.value().size() !=
-          setting.sourceAseConfiguration.value().size()) {
-    return std::nullopt;
+    if (requirement.sourceAseRequirement.has_value() &&
+        requirement.sourceAseRequirement.value().size() !=
+            setting.sourceAseConfiguration.value().size()) {
+      return std::nullopt;
+    }
   }
 
   if (requirement.sinkAseRequirement.has_value()) {
     filterRequirementAseDirectionConfiguration(
         setting.sinkAseConfiguration, requirement.sinkAseRequirement.value(),
-        filtered_setting.sinkAseConfiguration);
+        filtered_setting.sinkAseConfiguration, isExact);
     if (!filtered_setting.sinkAseConfiguration.has_value()) {
       return std::nullopt;
     }
@@ -692,7 +733,7 @@
     filterRequirementAseDirectionConfiguration(
         setting.sourceAseConfiguration,
         requirement.sourceAseRequirement.value(),
-        filtered_setting.sourceAseConfiguration);
+        filtered_setting.sourceAseConfiguration, isExact);
     if (!filtered_setting.sourceAseConfiguration.has_value()) {
       return std::nullopt;
     }
@@ -706,9 +747,10 @@
     std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
         matched_ase_configuration_settings,
     const IBluetoothAudioProvider::LeAudioConfigurationRequirement& requirement,
-    bool isMatchContext) {
+    bool isMatchContext, bool isExact) {
   LOG(INFO) << __func__ << ": Trying to match for the requirement "
-            << requirement.toString() << ", match context = " << isMatchContext;
+            << requirement.toString() << ", match context = " << isMatchContext
+            << ", match exact = " << isExact;
   for (auto& setting : matched_ase_configuration_settings) {
     // Try to match context in metadata.
     if (isMatchContext) {
@@ -720,7 +762,8 @@
     }
 
     auto filtered_ase_configuration_setting =
-        getRequirementMatchedAseConfigurationSettings(setting, requirement);
+        getRequirementMatchedAseConfigurationSettings(setting, requirement,
+                                                      isExact);
     if (filtered_ase_configuration_setting.has_value()) {
       LOG(INFO) << __func__ << ": Result found: "
                 << getSettingOutputString(
@@ -811,26 +854,30 @@
 
     // Matching priority list:
     // Preferred context - exact match with allocation
+    // Preferred context - loose match with allocation
     // Any context - exact match with allocation
-    auto matched_setting_with_context = matchWithRequirement(
-        matched_ase_configuration_settings, requirement, true);
-    if (matched_setting_with_context.has_value()) {
-      result.push_back(matched_setting_with_context.value());
-    } else {
-      auto matched_setting = matchWithRequirement(
-          matched_ase_configuration_settings, requirement, false);
-      if (matched_setting.has_value()) {
-        result.push_back(matched_setting.value());
-      } else {
-        // Cannot find a match for this requirement
-        // Immediately return
-        LOG(ERROR)
-            << __func__
-            << ": Cannot find any match for this requirement, exitting...";
-        result.clear();
-        *_aidl_return = result;
-        return ndk::ScopedAStatus::ok();
+    // 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;
+        }
       }
+      if (found) break;
+    }
+
+    if (!found) {
+      LOG(ERROR) << __func__
+                 << ": Cannot find any match for this requirement, exitting...";
+      result.clear();
+      *_aidl_return = result;
+      return ndk::ScopedAStatus::ok();
     }
   }
 
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
index 798f183..3a82b73 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -139,7 +139,8 @@
           direction_configurations,
       const std::vector<std::optional<AseDirectionRequirement>>& requirements,
       std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
-          valid_direction_configurations);
+          valid_direction_configurations,
+      bool isExact);
   std::optional<LeAudioAseConfigurationSetting>
   getCapabilitiesMatchedAseConfigurationSettings(
       IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
@@ -149,7 +150,8 @@
   getRequirementMatchedAseConfigurationSettings(
       IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
       const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
-          requirement);
+          requirement,
+      bool isExact);
   bool isMatchedQosRequirement(LeAudioAseQosConfiguration setting_qos,
                                AseQosDirectionRequirement requirement_qos);
   std::optional<LeAudioBroadcastConfigurationSetting>
@@ -173,7 +175,7 @@
           matched_ase_configuration_settings,
       const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
           requirements,
-      bool isMatchContext);
+      bool isMatchContext, bool isExact);
 };
 
 class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index d931c4d..d4968a8 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -90,13 +90,15 @@
 
 cc_test {
     name: "BluetoothLeAudioCodecsProviderTest",
-    defaults: [
-        "latest_android_hardware_bluetooth_audio_ndk_shared",
-    ],
     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",
+    ],
     header_libs: [
         "libxsdc-utils",
     ],
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
index 8475d39..07e4997 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
@@ -95,7 +95,7 @@
 constexpr uint8_t kLeAudioCodecFrameDur20000us = 0x02;
 
 /* Audio Allocations */
-constexpr uint32_t kLeAudioLocationNotAllowed = 0x00000000;
+constexpr uint32_t kLeAudioLocationMonoAudio = 0x00000000;
 constexpr uint32_t kLeAudioLocationFrontLeft = 0x00000001;
 constexpr uint32_t kLeAudioLocationFrontRight = 0x00000002;
 constexpr uint32_t kLeAudioLocationFrontCenter = 0x00000004;
@@ -178,8 +178,8 @@
 
 /* Helper map for matching various audio channel allocation notations */
 std::map<uint32_t, uint32_t> audio_channel_allocation_map = {
-    {kLeAudioLocationNotAllowed,
-     CodecSpecificConfigurationLtv::AudioChannelAllocation::NOT_ALLOWED},
+    {kLeAudioLocationMonoAudio,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::MONO},
     {kLeAudioLocationFrontLeft,
      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT},
     {kLeAudioLocationFrontRight,
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
index 473777c..59c43a4 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
@@ -119,19 +119,36 @@
     // Mapping octetsPerCodecFrame to bitdepth for easier comparison.
     transport.bitdepth.push_back(codec_config.getOctetsPerCodecFrame());
     transport.frameDurationUs.push_back(codec_config.getFrameDurationUs());
-    switch (strategy_config.getAudioLocation()) {
-      case setting::AudioLocation::MONO:
+    if (strategy_config.hasAudioLocation()) {
+      switch (strategy_config.getAudioLocation()) {
+        case setting::AudioLocation::MONO:
+          if (strategy_config_channel_count == 1)
+            transport.channelMode.push_back(ChannelMode::MONO);
+          else
+            transport.channelMode.push_back(ChannelMode::DUALMONO);
+          break;
+        case setting::AudioLocation::STEREO:
+          transport.channelMode.push_back(ChannelMode::STEREO);
+          break;
+        default:
+          transport.channelMode.push_back(ChannelMode::UNKNOWN);
+          break;
+      }
+    } else if (strategy_config.hasAudioChannelAllocation()) {
+      auto count =
+          std::bitset<32>(strategy_config.getAudioChannelAllocation()).count();
+      if (count <= 1) {
         if (strategy_config_channel_count == 1)
           transport.channelMode.push_back(ChannelMode::MONO);
         else
           transport.channelMode.push_back(ChannelMode::DUALMONO);
-        break;
-      case setting::AudioLocation::STEREO:
+      } else if (count == 2) {
         transport.channelMode.push_back(ChannelMode::STEREO);
-        break;
-      default:
+      } else {
         transport.channelMode.push_back(ChannelMode::UNKNOWN);
-        break;
+      }
+    } else {
+      transport.channelMode.push_back(ChannelMode::UNKNOWN);
     }
   }
 
@@ -336,8 +353,12 @@
   for (const auto& scenario : supported_scenarios) {
     UnicastCapability unicast_encode_capability =
         GetUnicastCapability(scenario.getEncode());
+    LOG(INFO) << __func__ << ": Unicast capability encode = "
+              << unicast_encode_capability.toString();
     UnicastCapability unicast_decode_capability =
         GetUnicastCapability(scenario.getDecode());
+    LOG(INFO) << __func__ << ": Unicast capability decode = "
+              << unicast_decode_capability.toString();
     BroadcastCapability broadcast_capability = {.codecType =
                                                     CodecType::UNKNOWN};
 
@@ -384,22 +405,36 @@
     return {.codecType = CodecType::UNKNOWN};
   }
 
+  // Populate audio location
+  AudioLocation audio_location = AudioLocation::UNKNOWN;
+  if (strategy_configuration_iter->second.hasAudioLocation()) {
+    audio_location = GetAudioLocation(
+        strategy_configuration_iter->second.getAudioLocation());
+  }
+
+  // Populate audio channel allocation
+  std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>
+      audio_channel_allocation = std::nullopt;
+  if (strategy_configuration_iter->second.hasAudioChannelAllocation()) {
+    LOG(INFO) << __func__ << ": has allocation";
+    CodecSpecificConfigurationLtv::AudioChannelAllocation tmp;
+    tmp.bitmask =
+        strategy_configuration_iter->second.getAudioChannelAllocation();
+    audio_channel_allocation = tmp;
+  }
+
   CodecType codec_type =
       GetCodecType(codec_configuration_iter->second.getCodec());
   if (codec_type == CodecType::LC3) {
     return ComposeUnicastCapability(
-        codec_type,
-        GetAudioLocation(
-            strategy_configuration_iter->second.getAudioLocation()),
+        codec_type, audio_location, audio_channel_allocation,
         strategy_configuration_iter->second.getConnectedDevice(),
         strategy_configuration_iter->second.getChannelCount(),
         ComposeLc3Capability(codec_configuration_iter->second));
   } else if (codec_type == CodecType::APTX_ADAPTIVE_LE ||
              codec_type == CodecType::APTX_ADAPTIVE_LEX) {
     return ComposeUnicastCapability(
-        codec_type,
-        GetAudioLocation(
-            strategy_configuration_iter->second.getAudioLocation()),
+        codec_type, audio_location, audio_channel_allocation,
         strategy_configuration_iter->second.getConnectedDevice(),
         strategy_configuration_iter->second.getChannelCount(),
         ComposeAptxAdaptiveLeCapability(codec_configuration_iter->second));
@@ -435,11 +470,27 @@
   std::vector<std::optional<Lc3Capabilities>> bcastLc3Cap(
       1, std::optional(ComposeLc3Capability(codec_configuration_iter->second)));
 
+  // Populate audio location
+  AudioLocation audio_location = AudioLocation::UNKNOWN;
+  if (strategy_configuration_iter->second.hasAudioLocation()) {
+    audio_location = GetAudioLocation(
+        strategy_configuration_iter->second.getAudioLocation());
+  }
+
+  // Populate audio channel allocation
+  std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>
+      audio_channel_allocation = std::nullopt;
+  if (strategy_configuration_iter->second.hasAudioChannelAllocation()) {
+    LOG(INFO) << __func__ << ": has allocation";
+    CodecSpecificConfigurationLtv::AudioChannelAllocation tmp;
+    tmp.bitmask =
+        strategy_configuration_iter->second.getAudioChannelAllocation();
+    audio_channel_allocation = tmp;
+  }
+
   if (codec_type == CodecType::LC3) {
     return ComposeBroadcastCapability(
-        codec_type,
-        GetAudioLocation(
-            strategy_configuration_iter->second.getAudioLocation()),
+        codec_type, audio_location, audio_channel_allocation,
         strategy_configuration_iter->second.getChannelCount(), bcastLc3Cap);
   }
   return {.codecType = CodecType::UNKNOWN};
@@ -448,16 +499,21 @@
 template <class T>
 BroadcastCapability BluetoothLeAudioCodecsProvider::ComposeBroadcastCapability(
     const CodecType& codec_type, const AudioLocation& audio_location,
+    const std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>&
+        audio_channel_allocation,
     const uint8_t& channel_count, const std::vector<T>& capability) {
   return {.codecType = codec_type,
           .supportedChannel = audio_location,
           .channelCountPerStream = channel_count,
-          .leAudioCodecCapabilities = std::optional(capability)};
+          .leAudioCodecCapabilities = std::optional(capability),
+          .audioLocation = audio_channel_allocation};
 }
 
 template <class T>
 UnicastCapability BluetoothLeAudioCodecsProvider::ComposeUnicastCapability(
     const CodecType& codec_type, const AudioLocation& audio_location,
+    const std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>&
+        audio_channel_allocation,
     const uint8_t& device_cnt, const uint8_t& channel_count,
     const T& capability) {
   return {
@@ -467,6 +523,7 @@
       .channelCountPerDevice = channel_count,
       .leAudioCodecCapabilities =
           UnicastCapability::LeAudioCodecCapabilities(capability),
+      .audioLocation = audio_channel_allocation,
   };
 }
 
@@ -519,38 +576,87 @@
          codec_configuration.hasOctetsPerCodecFrame();
 }
 
+bool IsValidStereoAudioLocation(
+    const setting::StrategyConfiguration& strategy_configuration) {
+  if ((strategy_configuration.getConnectedDevice() == 2 &&
+       strategy_configuration.getChannelCount() == 1) ||
+      (strategy_configuration.getConnectedDevice() == 1 &&
+       strategy_configuration.getChannelCount() == 2)) {
+    // Stereo
+    // 1. two connected device, one for L one for R
+    // 2. one connected device for both L and R
+    return true;
+  } else if (strategy_configuration.getConnectedDevice() == 0 &&
+             strategy_configuration.getChannelCount() == 2) {
+    // Broadcast
+    return true;
+  }
+  return false;
+}
+
+bool IsValidMonoAudioLocation(
+    const setting::StrategyConfiguration& strategy_configuration) {
+  if (strategy_configuration.getConnectedDevice() == 1 &&
+      strategy_configuration.getChannelCount() == 1) {
+    return true;
+  }
+  return false;
+}
+
+bool IsValidAudioLocation(
+    const setting::StrategyConfiguration& strategy_configuration) {
+  if (strategy_configuration.getAudioLocation() ==
+      setting::AudioLocation::STEREO)
+    return IsValidStereoAudioLocation(strategy_configuration);
+  else if (strategy_configuration.getAudioLocation() ==
+           setting::AudioLocation::MONO)
+    return IsValidMonoAudioLocation(strategy_configuration);
+  return false;
+}
+
+bool IsValidAudioChannelAllocation(
+    const setting::StrategyConfiguration& strategy_configuration) {
+  // First, ensure that there's only 2 bitmask enabled
+  int audio_channel_allocation =
+      strategy_configuration.getAudioChannelAllocation();
+  int count = 0;
+  for (int bit = 0; bit < 32; ++bit)
+    if (audio_channel_allocation & (1 << bit)) ++count;
+  if (count > 2) {
+    LOG(WARNING) << "Cannot parse more than 2 audio location, input is "
+                 << audio_channel_allocation;
+    return false;
+  }
+
+  if (count == 2)
+    return IsValidStereoAudioLocation(strategy_configuration);
+  else
+    return IsValidMonoAudioLocation(strategy_configuration);
+}
+
 bool BluetoothLeAudioCodecsProvider::IsValidStrategyConfiguration(
     const setting::StrategyConfiguration& strategy_configuration) {
   if (!strategy_configuration.hasName() ||
-      !strategy_configuration.hasAudioLocation() ||
       !strategy_configuration.hasConnectedDevice() ||
       !strategy_configuration.hasChannelCount()) {
     return false;
   }
-  if (strategy_configuration.getAudioLocation() ==
-      setting::AudioLocation::STEREO) {
-    if ((strategy_configuration.getConnectedDevice() == 2 &&
-         strategy_configuration.getChannelCount() == 1) ||
-        (strategy_configuration.getConnectedDevice() == 1 &&
-         strategy_configuration.getChannelCount() == 2)) {
-      // Stereo
-      // 1. two connected device, one for L one for R
-      // 2. one connected device for both L and R
-      return true;
-    } else if (strategy_configuration.getConnectedDevice() == 0 &&
-               strategy_configuration.getChannelCount() == 2) {
-      // Broadcast
-      return true;
-    }
-  } else if (strategy_configuration.getAudioLocation() ==
-             setting::AudioLocation::MONO) {
-    if (strategy_configuration.getConnectedDevice() == 1 &&
-        strategy_configuration.getChannelCount() == 1) {
-      // Mono
-      return true;
-    }
-  }
-  return false;
+
+  // Both audio location field cannot be empty
+  if (!strategy_configuration.hasAudioLocation() &&
+      !strategy_configuration.hasAudioChannelAllocation())
+    return false;
+
+  // Any audio location field that presents must be valid
+  if (strategy_configuration.hasAudioLocation() &&
+      !IsValidAudioLocation(strategy_configuration))
+    return false;
+
+  if (strategy_configuration.hasAudioChannelAllocation() &&
+      !IsValidAudioChannelAllocation(strategy_configuration))
+    return false;
+
+  return true;
 }
 
 }  // namespace audio
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
index 5bf67e2..23b2bb6 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
@@ -23,6 +23,7 @@
 #include <vector>
 
 #include "aidl/android/hardware/bluetooth/audio/CodecInfo.h"
+#include "aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.h"
 #include "aidl/android/hardware/bluetooth/audio/SessionType.h"
 #include "aidl_android_hardware_bluetooth_audio_setting.h"
 
@@ -84,12 +85,18 @@
   template <class T>
   static inline UnicastCapability ComposeUnicastCapability(
       const CodecType& codec_type, const AudioLocation& audio_location,
+      const std::optional<
+          CodecSpecificConfigurationLtv::AudioChannelAllocation>&
+          audio_channel_allocation,
       const uint8_t& device_cnt, const uint8_t& channel_count,
       const T& capability);
 
   template <class T>
   static inline BroadcastCapability ComposeBroadcastCapability(
       const CodecType& codec_type, const AudioLocation& audio_location,
+      const std::optional<
+          CodecSpecificConfigurationLtv::AudioChannelAllocation>&
+          audio_channel_allocation,
       const uint8_t& channel_count, const std::vector<T>& capability);
 
   static inline Lc3Capabilities ComposeLc3Capability(
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
index dba2749..c47f7d5 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
@@ -64,19 +64,101 @@
 static const StrategyConfiguration kValidStrategyStereoOneCis(
     std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
     std::make_optional(AudioLocation::STEREO), std::make_optional(2),
-    std::make_optional(1));
+    std::make_optional(1), std::nullopt);
 static const StrategyConfiguration kValidStrategyStereoTwoCis(
     std::make_optional("STEREO_TWO_CISES_PER_DEVICE"),
     std::make_optional(AudioLocation::STEREO), std::make_optional(1),
-    std::make_optional(2));
+    std::make_optional(2), std::nullopt);
 static const StrategyConfiguration kValidStrategyMonoOneCis(
     std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
     std::make_optional(AudioLocation::MONO), std::make_optional(1),
-    std::make_optional(1));
+    std::make_optional(1), std::nullopt);
 static const StrategyConfiguration kValidStrategyBroadcastStereo(
     std::make_optional("BROADCAST_STEREO"),
     std::make_optional(AudioLocation::STEREO), std::make_optional(0),
-    std::make_optional(2));
+    std::make_optional(2), std::nullopt);
+
+static const StrategyConfiguration kValidStrategyStereoOneCisInt(
+    std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), std::nullopt,
+    std::make_optional(2), std::make_optional(1), std::make_optional(3));
+static const StrategyConfiguration kValidStrategyStereoTwoCisInt(
+    std::make_optional("STEREO_TWO_CISES_PER_DEVICE"), std::nullopt,
+    std::make_optional(1), std::make_optional(2), std::make_optional(3));
+static const StrategyConfiguration kValidStrategyMonoOneCisInt(
+    std::make_optional("MONO_ONE_CIS_PER_DEVICE"), std::nullopt,
+    std::make_optional(1), std::make_optional(1), std::make_optional(4));
+static const StrategyConfiguration kValidStrategyBroadcastStereoInt(
+    std::make_optional("BROADCAST_STEREO"), std::nullopt, std::make_optional(0),
+    std::make_optional(2), std::make_optional(3));
+
+static const StrategyConfiguration kValidStrategyStereoOneCisBoth(
+    std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+    std::make_optional(AudioLocation::STEREO), std::make_optional(2),
+    std::make_optional(1), std::make_optional(3));
+static const StrategyConfiguration kValidStrategyStereoTwoCisBoth(
+    std::make_optional("STEREO_TWO_CISES_PER_DEVICE"),
+    std::make_optional(AudioLocation::STEREO), std::make_optional(1),
+    std::make_optional(2), std::make_optional(3));
+static const StrategyConfiguration kValidStrategyMonoOneCisBoth(
+    std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
+    std::make_optional(AudioLocation::MONO), std::make_optional(1),
+    std::make_optional(1), std::make_optional(4));
+static const StrategyConfiguration kValidStrategyBroadcastStereoBoth(
+    std::make_optional("BROADCAST_STEREO"),
+    std::make_optional(AudioLocation::STEREO), std::make_optional(0),
+    std::make_optional(2), std::make_optional(3));
+
+// List of all invalid strategy configuration
+const auto kInvalidStrategyStereoTwoCisTwoDevice = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+        std::make_optional(AudioLocation::STEREO), std::make_optional(2),
+        std::make_optional(2), std::nullopt)});
+const auto kInvalidStrategyMonoTwoCisTwoDevice = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
+        std::make_optional(AudioLocation::STEREO), std::make_optional(2),
+        std::make_optional(2), std::nullopt)});
+const auto kInvalidStrategyNoName = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::nullopt, std::make_optional(AudioLocation::STEREO),
+        std::make_optional(2), std::make_optional(1), std::nullopt)});
+const auto kInvalidStrategyNoLocation = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), std::nullopt,
+        std::make_optional(2), std::make_optional(1), std::nullopt)});
+const auto kInvalidStrategyNoDevice = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+        std::make_optional(AudioLocation::STEREO), std::nullopt,
+        std::make_optional(1), std::nullopt)});
+const auto kInvalidStrategyNoChannel = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+        std::make_optional(AudioLocation::STEREO), std::make_optional(2),
+        std::nullopt, std::nullopt)});
+const auto kInvalidStrategyIntMoreBitmask = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+        std::make_optional(AudioLocation::STEREO), std::make_optional(2),
+        std::make_optional(1), std::make_optional(7))});
+const auto kInvalidStrategyIntStereoTwoCisTwoDevice = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), std::nullopt,
+        std::make_optional(2), std::make_optional(2), std::make_optional(3))});
+const auto kInvalidStrategyIntMonoTwoCisTwoDevice = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("MONO_ONE_CIS_PER_DEVICE"), std::nullopt,
+        std::make_optional(2), std::make_optional(2), std::make_optional(4))});
+const auto kInvalidStrategyIntBroadcast = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("MONO_ONE_CIS_PER_DEVICE"), std::nullopt,
+        std::make_optional(0), std::make_optional(1), std::make_optional(3))});
+const auto kInvalidStrategyBothStereoMonoInt = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+        std::make_optional(AudioLocation::STEREO), std::make_optional(2),
+        std::make_optional(1), std::make_optional(4))});
 
 // Define valid test list built from above valid components
 // Scenario, Configuration, CodecConfiguration, StrategyConfiguration
@@ -88,11 +170,16 @@
 static const std::vector<CodecConfigurationList> kValidCodecConfigurationList =
     {CodecConfigurationList(
         std::vector<CodecConfiguration>{kValidCodecLC3_16k_1})};
+
 static const std::vector<StrategyConfigurationList>
     kValidStrategyConfigurationList = {
         StrategyConfigurationList(std::vector<StrategyConfiguration>{
             kValidStrategyStereoOneCis, kValidStrategyStereoTwoCis,
-            kValidStrategyMonoOneCis, kValidStrategyBroadcastStereo})};
+            kValidStrategyMonoOneCis, kValidStrategyBroadcastStereo,
+            kValidStrategyStereoOneCisInt, kValidStrategyStereoTwoCisInt,
+            kValidStrategyMonoOneCisInt, kValidStrategyBroadcastStereoInt,
+            kValidStrategyStereoOneCisBoth, kValidStrategyStereoTwoCisBoth,
+            kValidStrategyMonoOneCisBoth, kValidStrategyBroadcastStereoBoth})};
 
 class BluetoothLeAudioCodecsProviderTest
     : public ::testing::TestWithParam<OffloadSetting> {
@@ -270,49 +357,19 @@
   static std::vector<StrategyConfigurationList>
   CreateInvalidStrategyConfigurations() {
     std::vector<StrategyConfigurationList>
-        invalid_strategy_configuration_test_cases;
-    invalid_strategy_configuration_test_cases.push_back(
-        StrategyConfigurationList(
-            std::vector<StrategyConfiguration>{StrategyConfiguration(
-                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
-                std::make_optional(AudioLocation::STEREO),
-                std::make_optional(2), std::make_optional(2))}));
-
-    invalid_strategy_configuration_test_cases.push_back(
-        StrategyConfigurationList(
-            std::vector<StrategyConfiguration>{StrategyConfiguration(
-                std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
-                std::make_optional(AudioLocation::STEREO),
-                std::make_optional(2), std::make_optional(2))}));
-
-    invalid_strategy_configuration_test_cases.push_back(
-        StrategyConfigurationList(
-            std::vector<StrategyConfiguration>{StrategyConfiguration(
-                std::nullopt, std::make_optional(AudioLocation::STEREO),
-                std::make_optional(2), std::make_optional(1))}));
-
-    invalid_strategy_configuration_test_cases.push_back(
-        StrategyConfigurationList(
-            std::vector<StrategyConfiguration>{StrategyConfiguration(
-                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), std::nullopt,
-                std::make_optional(2), std::make_optional(1))}));
-
-    invalid_strategy_configuration_test_cases.push_back(
-        StrategyConfigurationList(
-            std::vector<StrategyConfiguration>{StrategyConfiguration(
-                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
-                std::make_optional(AudioLocation::STEREO), std::nullopt,
-                std::make_optional(1))}));
-
-    invalid_strategy_configuration_test_cases.push_back(
-        StrategyConfigurationList(
-            std::vector<StrategyConfiguration>{StrategyConfiguration(
-                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
-                std::make_optional(AudioLocation::STEREO),
-                std::make_optional(2), std::nullopt)}));
-
-    invalid_strategy_configuration_test_cases.push_back(
-        StrategyConfigurationList(std::vector<StrategyConfiguration>{}));
+        invalid_strategy_configuration_test_cases = {
+            kInvalidStrategyStereoTwoCisTwoDevice,
+            kInvalidStrategyMonoTwoCisTwoDevice,
+            kInvalidStrategyNoName,
+            kInvalidStrategyNoLocation,
+            kInvalidStrategyNoDevice,
+            kInvalidStrategyNoChannel,
+            kInvalidStrategyIntMoreBitmask,
+            kInvalidStrategyIntStereoTwoCisTwoDevice,
+            kInvalidStrategyIntMonoTwoCisTwoDevice,
+            kInvalidStrategyIntBroadcast,
+            kInvalidStrategyBothStereoMonoInt,
+            StrategyConfigurationList(std::vector<StrategyConfiguration>{})};
 
     return invalid_strategy_configuration_test_cases;
   }
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
index eaace78..b6ebbd9 100644
--- a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
@@ -69,9 +69,9 @@
     <codecConfiguration name="APTX_ADAPTIVE_LEX_96k" codec="APTX_ADAPTIVE_LEX" samplingFrequency="96000" frameDurationUs="10000" octetsPerCodecFrame="816"/>
   </codecConfigurationList>
   <strategyConfigurationList>
-    <strategyConfiguration name="STEREO_ONE_CIS_PER_DEVICE" audioLocation="STEREO" connectedDevice="2" channelCount="1"/>
-    <strategyConfiguration name="STEREO_TWO_CISES_PER_DEVICE" audioLocation="STEREO" connectedDevice="1" channelCount="2"/>
-    <strategyConfiguration name="MONO_ONE_CIS_PER_DEVICE" audioLocation="MONO" connectedDevice="1" channelCount="1"/>
-    <strategyConfiguration name="BROADCAST_STEREO" audioLocation="STEREO" connectedDevice="0" channelCount="2"/>
+    <strategyConfiguration name="STEREO_ONE_CIS_PER_DEVICE" audioLocation="STEREO" connectedDevice="2" channelCount="1" audioChannelAllocation="3"/>
+    <strategyConfiguration name="STEREO_TWO_CISES_PER_DEVICE" audioLocation="STEREO" connectedDevice="1" channelCount="2" audioChannelAllocation="3"/>
+    <strategyConfiguration name="MONO_ONE_CIS_PER_DEVICE" audioLocation="MONO" connectedDevice="1" channelCount="1" audioChannelAllocation="4"/>
+    <strategyConfiguration name="BROADCAST_STEREO" audioLocation="STEREO" connectedDevice="0" channelCount="2" audioChannelAllocation="3"/>
   </strategyConfigurationList>
 </leAudioOffloadSetting>
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
index 03c8ade..d9ccab5 100644
--- a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
@@ -56,9 +56,12 @@
   <xs:element name="strategyConfiguration">
     <xs:complexType>
       <xs:attribute name="name" type="xs:string"/>
+      <!-- Deprecated definition of Audio Location, please use audioLocationInt -->
       <xs:attribute name="audioLocation" type="audioLocation"/>
       <xs:attribute name="connectedDevice" type="xs:unsignedByte"/>
       <xs:attribute name="channelCount" type="xs:unsignedByte"/>
+      <!-- Integer Audio Location to populate to audioLocation if present -->
+      <xs:attribute name="audioChannelAllocation" type="xs:int"/>
     </xs:complexType>
   </xs:element>
   <xs:simpleType name="audioLocation">
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
index a882174..b6c2f03 100644
--- a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
@@ -81,10 +81,12 @@
 
   public class StrategyConfiguration {
     ctor public StrategyConfiguration();
+    method public int getAudioChannelAllocation();
     method public aidl.android.hardware.bluetooth.audio.setting.AudioLocation getAudioLocation();
     method public short getChannelCount();
     method public short getConnectedDevice();
     method public String getName();
+    method public void setAudioChannelAllocation(int);
     method public void setAudioLocation(aidl.android.hardware.bluetooth.audio.setting.AudioLocation);
     method public void setChannelCount(short);
     method public void setConnectedDevice(short);
diff --git a/broadcastradio/aidl/default/fuzzer.cpp b/broadcastradio/aidl/default/fuzzer.cpp
index d535432..2492d47 100644
--- a/broadcastradio/aidl/default/fuzzer.cpp
+++ b/broadcastradio/aidl/default/fuzzer.cpp
@@ -24,6 +24,8 @@
 using ::android::fuzzService;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    // TODO(b/183141167): need to rewrite 'dump' to avoid SIGPIPE.
+    signal(SIGPIPE, SIG_IGN);
     const VirtualRadio& amFmRadioMock = VirtualRadio::getAmFmRadio();
     std::shared_ptr<BroadcastRadio> amFmRadio =
             ::ndk::SharedRefBase::make<BroadcastRadio>(amFmRadioMock);
diff --git a/compatibility_matrices/compatibility_matrix.202504.xml b/compatibility_matrices/compatibility_matrix.202504.xml
index 4b762ca..935382e 100644
--- a/compatibility_matrices/compatibility_matrix.202504.xml
+++ b/compatibility_matrices/compatibility_matrix.202504.xml
@@ -312,7 +312,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.security.secretkeeper</name>
-        <version>1</version>
+        <version>1-2</version>
         <interface>
             <name>ISecretkeeper</name>
             <instance>default</instance>
@@ -653,6 +653,15 @@
         </interface>
     </hal>
     <hal format="aidl">
+      <name>android.hardware.virtualization.capabilities</name>
+        <version>1</version>
+        <interface>
+            <name>IVmCapabilitiesService</name>
+            <instance>default</instance>
+            <instance>noop</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
         <name>android.hardware.weaver</name>
         <version>2</version>
         <interface>
diff --git a/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp b/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp
index 083a9aa..b41da3f 100644
--- a/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp
+++ b/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp
@@ -95,6 +95,18 @@
             << "Verified boot state must be \"UNVERIFIED\" aka \"orange\".";
 }
 
+// Check that the attested Verified Boot key is 32 bytes of zeroes since the bootloader is unlocked.
+TEST_P(BootloaderStateTest, VerifiedBootKeyAllZeroes) {
+    // Gate this test to avoid waiver issues.
+    if (get_vsr_api_level() <= __ANDROID_API_V__) {
+        return;
+    }
+
+    std::vector<uint8_t> expectedVbKey(32, 0);
+    ASSERT_EQ(attestedVbKey_, expectedVbKey) << "Verified Boot key digest must be 32 bytes of "
+                                                "zeroes since the bootloader is unlocked.";
+}
+
 // Following error codes from avb_slot_data() mean that slot data was loaded
 // (even if verification failed).
 static inline bool avb_slot_data_loaded(AvbSlotVerifyResult result) {
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 0ce6a15..09446ce 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -1908,16 +1908,29 @@
         }
     }
 
+    if (get_vsr_api_level() > __ANDROID_API_V__) {
+        // The Verified Boot key field should be exactly 32 bytes since it
+        // contains the SHA-256 hash of the key on locked devices or 32 bytes
+        // of zeroes on unlocked devices. This wasn't checked for earlier
+        // versions of the KeyMint HAL, so only only be strict for VSR-16+.
+        EXPECT_EQ(verified_boot_key.size(), 32);
+    } else if (get_vsr_api_level() == __ANDROID_API_V__) {
+        // The Verified Boot key field should be:
+        //   - Exactly 32 bytes on locked devices since it should contain
+        //     the SHA-256 hash of the key, or
+        //   - Up to 32 bytes of zeroes on unlocked devices (behaviour on
+        //     unlocked devices isn't specified in the HAL interface
+        //     specification).
+        // Thus, we can't check for strict equality in case unlocked devices
+        // report values with less than 32 bytes. This wasn't checked for
+        // earlier versions of the KeyMint HAL, so only check on VSR-15.
+        EXPECT_LE(verified_boot_key.size(), 32);
+    }
+
     // Verified Boot key should be all zeroes if the boot state is "orange".
     std::string empty_boot_key(32, '\0');
     std::string verified_boot_key_str((const char*)verified_boot_key.data(),
                                       verified_boot_key.size());
-    if (get_vsr_api_level() >= __ANDROID_API_V__) {
-        // The attestation should contain the SHA-256 hash of the verified boot
-        // key.  However, this was not checked for earlier versions of the KeyMint
-        // HAL so only be strict for VSR-V and above.
-        EXPECT_LE(verified_boot_key.size(), 32);
-    }
     EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
     if (!strcmp(property_value, "green")) {
         EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
diff --git a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
index 9f7322a..f7639bf 100644
--- a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
+++ b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
@@ -114,10 +114,22 @@
         const auto& vbKey = rot->asArray()->get(pos++);
         ASSERT_TRUE(vbKey);
         ASSERT_TRUE(vbKey->asBstr());
-        if (get_vsr_api_level() >= __ANDROID_API_V__) {
-            // The attestation should contain the SHA-256 hash of the verified boot
-            // key.  However, this not was checked for earlier versions of the KeyMint
-            // HAL so only be strict for VSR-V and above.
+        if (get_vsr_api_level() > __ANDROID_API_V__) {
+            // The Verified Boot key field should be exactly 32 bytes since it
+            // contains the SHA-256 hash of the key on locked devices or 32 bytes
+            // of zeroes on unlocked devices. This wasn't checked for earlier
+            // versions of the KeyMint HAL, so only only be strict for VSR-16+.
+            ASSERT_EQ(vbKey->asBstr()->value().size(), 32);
+        } else if (get_vsr_api_level() == __ANDROID_API_V__) {
+            // The Verified Boot key field should be:
+            //   - Exactly 32 bytes on locked devices since it should contain
+            //     the SHA-256 hash of the key, or
+            //   - Up to 32 bytes of zeroes on unlocked devices (behaviour on
+            //     unlocked devices isn't specified in the HAL interface
+            //     specification).
+            // Thus, we can't check for strict equality in case unlocked devices
+            // report values with less than 32 bytes. This wasn't checked for
+            // earlier versions of the KeyMint HAL, so only check on VSR-15.
             ASSERT_LE(vbKey->asBstr()->value().size(), 32);
         }
 
diff --git a/security/secretkeeper/aidl/Android.bp b/security/secretkeeper/aidl/Android.bp
index d282621..f0b7894 100644
--- a/security/secretkeeper/aidl/Android.bp
+++ b/security/secretkeeper/aidl/Android.bp
@@ -25,7 +25,7 @@
         "android.hardware.security.authgraph-V1",
     ],
     stability: "vintf",
-    frozen: true,
+    frozen: false,
     backend: {
         java: {
             enabled: true,
@@ -88,6 +88,6 @@
 rust_defaults {
     name: "secretkeeper_use_latest_hal_aidl_rust",
     rustlibs: [
-        "android.hardware.security.secretkeeper-V1-rust",
+        "android.hardware.security.secretkeeper-V2-rust",
     ],
 }
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
index 8ce37cd..ed48480 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
+++ b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -38,6 +38,7 @@
   byte[] processSecretManagementRequest(in byte[] request);
   void deleteIds(in android.hardware.security.secretkeeper.SecretId[] ids);
   void deleteAll();
+  android.hardware.security.secretkeeper.PublicKey getSecretkeeperIdentity();
   const int ERROR_UNKNOWN_KEY_ID = 1;
   const int ERROR_INTERNAL_ERROR = 2;
   const int ERROR_REQUEST_MALFORMED = 3;
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/PublicKey.aidl b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/PublicKey.aidl
new file mode 100644
index 0000000..f690abf
--- /dev/null
+++ b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/PublicKey.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.secretkeeper;
+/* @hide */
+@VintfStability
+parcelable PublicKey {
+  byte[] keyMaterial;
+}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
index b07dba8..91493a1 100644
--- a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -17,6 +17,7 @@
 package android.hardware.security.secretkeeper;
 
 import android.hardware.security.authgraph.IAuthGraphKeyExchange;
+import android.hardware.security.secretkeeper.PublicKey;
 import android.hardware.security.secretkeeper.SecretId;
 
 @VintfStability
@@ -101,4 +102,12 @@
      * Delete data of all clients.
      */
     void deleteAll();
+
+    /**
+     * Gets the public key of the secret keeper instance. This should be a CBOR-encoded
+     * COSE_Key, as a PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384, as defined in
+     * generateCertificateRequestV2.cddl. Clients must have a trusted way of ensuring
+     * this key is valid.
+     */
+    PublicKey getSecretkeeperIdentity();
 }
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/PublicKey.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/PublicKey.aidl
new file mode 100644
index 0000000..ccc89b3
--- /dev/null
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/PublicKey.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.secretkeeper;
+
+/**
+ * Contents of a pubkey.
+ * @hide
+ */
+@VintfStability
+parcelable PublicKey {
+    /**
+     * CBOR-encoded COSE_Key
+     */
+    byte[] keyMaterial;
+}
diff --git a/security/secretkeeper/aidl/vts/Android.bp b/security/secretkeeper/aidl/vts/Android.bp
index be07a7b..c84afae 100644
--- a/security/secretkeeper/aidl/vts/Android.bp
+++ b/security/secretkeeper/aidl/vts/Android.bp
@@ -38,6 +38,7 @@
     srcs: ["secretkeeper_test_client.rs"],
     defaults: [
         "rdroidtest.defaults",
+        "secretkeeper_use_latest_hal_aidl_rust",
     ],
     test_suites: [
         "general-tests",
@@ -45,7 +46,6 @@
     ],
     test_config: "AndroidTest.xml",
     rustlibs: [
-        "android.hardware.security.secretkeeper-V1-rust",
         "libauthgraph_boringssl",
         "libauthgraph_core",
         "libauthgraph_wire",
@@ -66,9 +66,10 @@
 rust_binary {
     name: "secretkeeper_cli",
     srcs: ["secretkeeper_cli.rs"],
+    defaults: ["secretkeeper_use_latest_hal_aidl_rust"],
     lints: "android",
-    rlibs: [
-        "android.hardware.security.secretkeeper-V1-rust",
+    prefer_rlib: true,
+    rustlibs: [
         "libanyhow",
         "libauthgraph_boringssl",
         "libauthgraph_core",
diff --git a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
index 449a99a..b944865 100644
--- a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
+++ b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
@@ -16,6 +16,7 @@
 
 use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
 use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::SecretId::SecretId;
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::PublicKey::PublicKey;
 use authgraph_vts_test as ag_vts;
 use authgraph_boringssl as boring;
 use authgraph_core::key;
@@ -70,20 +71,32 @@
     0x06, 0xAC, 0x36, 0x8B, 0x3C, 0x95, 0x50, 0x16, 0x67, 0x71, 0x65, 0x26, 0xEB, 0xD0, 0xC3, 0x98,
 ]);
 
-// Android expects the public key of Secretkeeper instance to be present in the Linux device tree.
+// Android expects the public key of Secretkeeper instance to be available either
+// a) by being present in the Linux device tree (prior to version 2 of the secretkeeper HAL), or
+// b) via the `getSecretKeeperIdentity` operation from v2 onwards.
 // This allows clients to (cryptographically) verify that they are indeed talking to the real
 // secretkeeper.
 // Note that this is the identity of the `default` instance (and not `nonsecure`)!
-fn get_secretkeeper_identity() -> Option<CoseKey> {
-    let path = Path::new(SECRETKEEPER_KEY_HOST_DT);
-    if path.exists() {
-        let key = fs::read(path).unwrap();
-        let mut key = CoseKey::from_slice(&key).unwrap();
-        key.canonicalize(CborOrdering::Lexicographic);
-        Some(key)
+fn get_secretkeeper_identity(instance: &str) -> Option<CoseKey> {
+    let sk = get_connection(instance);
+    let key_material = if sk.getInterfaceVersion().expect("Error getting sk interface version") >= 2 {
+        let PublicKey { keyMaterial } = sk.getSecretkeeperIdentity().expect("Error calling getSecretkeeperIdentity");
+        Some(keyMaterial)
     } else {
-        None
-    }
+        let path = Path::new(SECRETKEEPER_KEY_HOST_DT);
+        if path.exists() {
+            let key_material = fs::read(path).unwrap();
+            Some(key_material)
+        } else {
+            None
+        }
+    };
+
+    key_material.map(|km| {
+        let mut cose_key = CoseKey::from_slice(&km).expect("Error deserializing CoseKey from key material");
+        cose_key.canonicalize(CborOrdering::Lexicographic);
+        cose_key
+    })
 }
 
 fn get_instances() -> Vec<(String, String)> {
@@ -760,12 +773,12 @@
 }
 
 // This test checks that the identity of Secretkeeper (in context of AuthGraph key exchange) is
-// same as the one advertized in Linux device tree. This is only expected from `default` instance.
+// same as the one either a) advertized in Linux device tree or b) retrieved from SK itself
+// from (HAL v2 onwards). This is only expected from `default` instance.
 #[rdroidtest(get_instances())]
-#[ignore_if(|p| p != "default")]
 fn secretkeeper_check_identity(instance: String) {
-    let sk_key = get_secretkeeper_identity()
-        .expect("Failed to extract identity of default instance from device tree");
+    let sk_key = get_secretkeeper_identity(&instance)
+        .expect("Failed to extract identity of default instance");
     // Create a session with this expected identity. This succeeds only if the identity used by
     // Secretkeeper is sk_key.
     let _ = SkClient::with_expected_sk_identity(&instance, sk_key).unwrap();
diff --git a/security/secretkeeper/default/Android.bp b/security/secretkeeper/default/Android.bp
index 799188f..134afc9 100644
--- a/security/secretkeeper/default/Android.bp
+++ b/security/secretkeeper/default/Android.bp
@@ -28,9 +28,9 @@
     vendor_available: true,
     defaults: [
         "authgraph_use_latest_hal_aidl_rust",
+        "secretkeeper_use_latest_hal_aidl_rust",
     ],
     rustlibs: [
-        "android.hardware.security.secretkeeper-V1-rust",
         "libauthgraph_boringssl",
         "libauthgraph_core",
         "libauthgraph_hal",
@@ -50,9 +50,9 @@
     prefer_rlib: true,
     defaults: [
         "authgraph_use_latest_hal_aidl_rust",
+        "secretkeeper_use_latest_hal_aidl_rust",
     ],
     rustlibs: [
-        "android.hardware.security.secretkeeper-V1-rust",
         "libandroid_logger",
         "libbinder_rs",
         "liblog_rust",
diff --git a/security/secretkeeper/default/secretkeeper.xml b/security/secretkeeper/default/secretkeeper.xml
index 40aebe0..699fff0 100644
--- a/security/secretkeeper/default/secretkeeper.xml
+++ b/security/secretkeeper/default/secretkeeper.xml
@@ -19,7 +19,7 @@
 
     <hal format="aidl">
         <name>android.hardware.security.secretkeeper</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>ISecretkeeper</name>
             <instance>nonsecure</instance>
diff --git a/virtualization/capabilities_service/aidl/Android.bp b/virtualization/capabilities_service/aidl/Android.bp
new file mode 100644
index 0000000..b0bbbdd
--- /dev/null
+++ b/virtualization/capabilities_service/aidl/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_team: "trendy_team_virtualization",
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+    name: "android.hardware.virtualization.capabilities.capabilities_service",
+    vendor_available: true,
+    srcs: ["android/**/*.aidl"],
+    stability: "vintf",
+    backend: {
+        rust: {
+            enabled: true,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.virt",
+            ],
+        },
+    },
+    frozen: false,
+}
diff --git a/virtualization/capabilities_service/aidl/aidl_api/android.hardware.virtualization.capabilities.capabilities_service/current/android/hardware/virtualization/capabilities/IVmCapabilitiesService.aidl b/virtualization/capabilities_service/aidl/aidl_api/android.hardware.virtualization.capabilities.capabilities_service/current/android/hardware/virtualization/capabilities/IVmCapabilitiesService.aidl
new file mode 100644
index 0000000..68ff021
--- /dev/null
+++ b/virtualization/capabilities_service/aidl/aidl_api/android.hardware.virtualization.capabilities.capabilities_service/current/android/hardware/virtualization/capabilities/IVmCapabilitiesService.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.virtualization.capabilities;
+@VintfStability
+interface IVmCapabilitiesService {
+  void grantAccessToVendorTeeServices(in ParcelFileDescriptor vmFd, in String[] vendorTeeServices);
+}
diff --git a/virtualization/capabilities_service/aidl/android/hardware/virtualization/capabilities/IVmCapabilitiesService.aidl b/virtualization/capabilities_service/aidl/android/hardware/virtualization/capabilities/IVmCapabilitiesService.aidl
new file mode 100644
index 0000000..0d09ecb
--- /dev/null
+++ b/virtualization/capabilities_service/aidl/android/hardware/virtualization/capabilities/IVmCapabilitiesService.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.virtualization.capabilities;
+
+/**
+ * Encapsulates vendor-specific capabilities that can be granted to VMs.
+ */
+@VintfStability
+interface IVmCapabilitiesService {
+    /**
+     * Grant access for the VM represented by the given vm_fd to the given vendor-owned tee
+     * services. The names in |vendorTeeServices| must match the ones defined in the
+     * tee_service_contexts files.
+     * TODO(ioffe): link to the integration doc for custom smc filtering feature once
+     * it's ready.
+     */
+    void grantAccessToVendorTeeServices(
+            in ParcelFileDescriptor vmFd, in String[] vendorTeeServices);
+}