Merge "stagefright: distinguish HAL name from name in MediaCodecInfo" into main
diff --git a/media/aconfig/swcodec_flags.aconfig b/media/aconfig/swcodec_flags.aconfig
index 9dd1fdd..cb8a963 100644
--- a/media/aconfig/swcodec_flags.aconfig
+++ b/media/aconfig/swcodec_flags.aconfig
@@ -5,6 +5,16 @@
 container: "com.android.media.swcodec"
 
 flag {
+  name: "apexcodecs_base"
+  # ApexCodecs API is getting called early in the boot process, so we need to make
+  # sure that the flag value is stable from the early boot stage.
+  is_fixed_read_only: true
+  namespace: "codec_fwk"
+  description: "Feature flag for base implementation of apexcodecs"
+  bug: "401332082"
+}
+
+flag {
   name: "apv_software_codec"
   is_exported: true
   is_fixed_read_only: true
diff --git a/media/audio/aconfig/audio_framework.aconfig b/media/audio/aconfig/audio_framework.aconfig
index 3a1befa..a4956b8 100644
--- a/media/audio/aconfig/audio_framework.aconfig
+++ b/media/audio/aconfig/audio_framework.aconfig
@@ -289,3 +289,13 @@
     bug: "296232417"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "register_volume_callback_api_hardening"
+    namespace: "media_audio"
+    description:
+            "Add modify audio settings privilege permission to un/register volume group "
+            "callback APIs"
+    bug: "402502314"
+    is_fixed_read_only: true
+}
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/inputsurface/InputSurface.h b/media/codec2/hal/aidl/include/codec2/aidl/inputsurface/InputSurface.h
index 5c2cc2e..8e15778 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/inputsurface/InputSurface.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/inputsurface/InputSurface.h
@@ -17,15 +17,21 @@
 #pragma once
 
 #include <aidl/android/hardware/media/c2/BnInputSurface.h>
+#include <utils/RefBase.h>
 
+#include <C2.h>
+#include <C2Config.h>
 #include <codec2/aidl/Configurable.h>
 #include <util/C2InterfaceHelper.h>
 
-#include <C2.h>
-
 #include <memory>
 
+namespace aidl::android::hardware::media::c2::implementation {
+class InputSurfaceSource;
+}
+
 namespace aidl::android::hardware::media::c2::utils {
+struct InputSurfaceConnection;
 
 struct InputSurface : public BnInputSurface {
     InputSurface();
@@ -40,6 +46,61 @@
             const std::shared_ptr<IInputSink>& sink,
             std::shared_ptr<IInputSurfaceConnection>* connection) override;
 
+    // Constant definitions.
+    // Default image size for AImageReader
+    constexpr static uint32_t kDefaultImageWidth = 1280;
+    constexpr static uint32_t kDefaultImageHeight = 720;
+    // Default # of buffers for AImageReader
+    constexpr static uint32_t kDefaultImageBufferCount = 16;
+    constexpr static uint32_t kDefaultImageDataspace = HAL_DATASPACE_BT709;
+
+    // Configs
+    // Config for AImageReader creation
+    struct ImageConfig {
+        int32_t mWidth;         // image width
+        int32_t mHeight;        // image height
+        int32_t mFormat;        // image pixel format
+        int32_t mNumBuffers;    // number of max images for AImageReader(consumer)
+        uint64_t mUsage;        // image usage
+        uint32_t mDataspace;    // image dataspace
+    };
+
+    // Config for InputSurface active buffer stream control
+    struct StreamConfig {
+        // IN PARAMS
+        float mMinFps = 0.0;        // minimum fps (repeat frame to achieve this)
+        float mMaxFps = 0.0;        // max fps (via frame drop)
+        float mCaptureFps = 0.0;    // capture fps
+        float mCodedFps = 0.0;      // coded fps
+        bool mSuspended = false;    // suspended
+        int64_t mSuspendAtUs = 0;   // suspend time
+        int64_t mResumeAtUs = 0;   // resume time
+        bool mStopped = false;      // stopped
+        int64_t mStopAtUs = 0;      // stop time
+        int64_t mStartAtUs = 0;     // start time
+        int64_t mTimeOffsetUs = 0;  // time offset (input => codec)
+
+        // IN PARAMS (CODEC WRAPPER)
+        C2TimestampGapAdjustmentStruct::mode_t
+                mAdjustedFpsMode = C2TimestampGapAdjustmentStruct::NONE;
+        int64_t mAdjustedGapUs = 0;
+        int mPriority = INT_MAX;        // priority of queue thread (if any);
+                                        // INT_MAX for no-op
+    };
+
+    // TODO: optimize this
+    // The client requests the change of these configurations now.
+    // We can request the change of these configurations from HAL directly
+    // where onWorkDone() callback is called.
+    //
+    // Config for current work status w.r.t input buffers
+    struct WorkStatusConfig {
+        int32_t mLastDoneIndex = -1;      // Last work done input buffer index
+        uint32_t mLastDoneCount = 0;      // # of work done count
+        uint64_t mEmptyCount = 0;         // # of input buffers being emptied
+    };
+
+
 protected:
     class Interface;
     class ConfigurableIntf;
@@ -50,12 +111,29 @@
 
     virtual ~InputSurface() override;
 
+private:
+    ::android::sp<implementation::InputSurfaceSource> mSource;
+    std::shared_ptr<InputSurfaceConnection> mConnection;
 
-    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
-    static void OnBinderDied(void *cookie);
-    static void OnBinderUnlinked(void *cookie);
-    struct DeathContext;
-    DeathContext *mDeathContext;
+    ImageConfig mImageConfig;
+    StreamConfig mStreamConfig;
+    WorkStatusConfig mWorkStatusConfig;
+
+    std::mutex mLock;
+
+    friend class ConfigurableIntf;
+
+    bool updateConfig(
+            ImageConfig &imageConfig,
+            StreamConfig &streamConfig,
+            WorkStatusConfig &workStatusConfig,
+            int64_t *inputDelayUs);
+
+    void updateImageConfig(ImageConfig &config);
+    bool updateStreamConfig(StreamConfig &config, int64_t *inputDelayUs);
+    void updateWorkStatusConfig(WorkStatusConfig &config);
+
+    void release();
 };
 
 }  // namespace aidl::android::hardware::media::c2::utils
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/inputsurface/InputSurfaceConnection.h b/media/codec2/hal/aidl/include/codec2/aidl/inputsurface/InputSurfaceConnection.h
index 59361e1..7a57f18 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/inputsurface/InputSurfaceConnection.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/inputsurface/InputSurfaceConnection.h
@@ -16,17 +16,25 @@
 
 #pragma once
 
+#include <aidl/android/hardware/media/c2/BnInputSink.h>
 #include <aidl/android/hardware/media/c2/BnInputSurfaceConnection.h>
 #include <media/NdkImage.h>
+#include <utils/RefBase.h>
 
 #include <C2.h>
 
 #include <memory>
 
+namespace aidl::android::hardware::media::c2::implementation {
+class InputSurfaceSource;
+}
+
 namespace aidl::android::hardware::media::c2::utils {
 
 struct InputSurfaceConnection : public BnInputSurfaceConnection {
-    InputSurfaceConnection();
+    InputSurfaceConnection(
+            const std::shared_ptr<IInputSink>& sink,
+            ::android::sp<c2::implementation::InputSurfaceSource> const &source);
     c2_status_t status() const;
 
     // Methods from IInputSurfaceConnection follow.
@@ -51,6 +59,10 @@
 
 protected:
     virtual ~InputSurfaceConnection() override;
+
+private:
+    std::weak_ptr<IInputSink> mSink;
+    ::android::sp<c2::implementation::InputSurfaceSource> mSource;
 };
 
 }  // namespace aidl::android::hardware::media::c2::utils
diff --git a/media/codec2/hal/aidl/inputsurface/InputSurface.cpp b/media/codec2/hal/aidl/inputsurface/InputSurface.cpp
index 5f6d176..ce694ee 100644
--- a/media/codec2/hal/aidl/inputsurface/InputSurface.cpp
+++ b/media/codec2/hal/aidl/inputsurface/InputSurface.cpp
@@ -17,11 +17,29 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2-InputSurface"
 #include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_interface_utils.h>
+
+#include <mutex>
+
+#include <C2Config.h>
 
 #include <codec2/aidl/inputsurface/InputSurface.h>
+#include <codec2/aidl/inputsurface/InputSurfaceConnection.h>
+#include <codec2/aidl/inputsurface/InputSurfaceSource.h>
+
 
 namespace aidl::android::hardware::media::c2::utils {
 
+using ImageConfig = InputSurface::ImageConfig;
+using StreamConfig = InputSurface::StreamConfig;
+using WorkStatusConfig = InputSurface::WorkStatusConfig;
+
+template <typename T>
+static C2R BasicSetter(bool, C2InterfaceHelper::C2P<T> &) {
+    return C2R::Ok();
+}
+
 // Derived class of C2InterfaceHelper
 class InputSurface::Interface : public C2InterfaceHelper {
 public:
@@ -31,51 +49,524 @@
 
         setDerivedInstance(this);
 
+        addParameter(
+                DefineParam(mBlockSize, C2_PARAMKEY_BLOCK_SIZE)
+                .withDefault(new C2StreamBlockSizeInfo::output(
+                        0u, kDefaultImageWidth, kDefaultImageHeight))
+                .withFields({
+                        C2F(mBlockSize, width).inRange(2, 8192, 2),
+                        C2F(mBlockSize, height).inRange(2, 8192, 2),})
+                .withSetter(BlockSizeSetter)
+                .build());
+        addParameter(
+                DefineParam(mBlockCount, C2_PARAMKEY_BLOCK_COUNT)
+                .withDefault(new C2StreamBlockCountInfo::output(
+                    0u, kDefaultImageBufferCount))
+                .withFields({C2F(mBlockCount, value).any()})
+                .withSetter(BlockCountSetter)
+                .build());
+        addParameter(
+                DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
+                .withDefault(new C2StreamPixelFormatInfo::output(
+                        0u, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED))
+                .withFields({C2F(mPixelFormat, value).any()})
+                .withSetter(BasicSetter<decltype(mPixelFormat)::element_type>)
+                .build());
+        addParameter(
+                DefineParam(mUsage, C2_PARAMKEY_OUTPUT_STREAM_USAGE)
+                .withDefault(new C2StreamUsageTuning::output(0u, 0ULL))
+                .withFields({C2F(mUsage, value).any()})
+                .withSetter(BasicSetter<decltype(mUsage)::element_type>)
+                .build());
+        addParameter(
+                DefineParam(mDataspace, C2_PARAMKEY_DATA_SPACE)
+                .withDefault(new C2StreamDataSpaceInfo::output(
+                        0u, kDefaultImageDataspace))
+                .withFields({C2F(mDataspace, value).any()})
+                .withSetter(BasicSetter<decltype(mDataspace)::element_type>)
+                .build());
+
+        addParameter(
+                DefineParam(mMinFps, C2_PARAMKEY_INPUT_SURFACE_MIN_FRAME_RATE)
+                .withDefault(new C2PortMinFrameRateTuning::output(0.0))
+                .withFields({C2F(mMinFps, value).any()})
+                .withSetter(BasicSetter<decltype(mMinFps)::element_type>)
+                .build());
+        addParameter(
+                DefineParam(mMaxFps, C2_PARAMKEY_INPUT_SURFACE_MAX_FRAME_RATE)
+                .withDefault(new C2PortMaxFrameRateTuning::output(0.0))
+                .withFields({C2F(mMaxFps, value).any()})
+                .withSetter(BasicSetter<decltype(mMaxFps)::element_type>)
+                .build());
+        addParameter(
+                DefineParam(mCaptureFps, C2_PARAMKEY_INPUT_SURFACE_CAPTURE_FRAME_RATE)
+                .withDefault(new C2PortCaptureFrameRateTuning::output(0.0))
+                .withFields({C2F(mCaptureFps, value).any()})
+                .withSetter(BasicSetter<decltype(mCaptureFps)::element_type>)
+                .build());
+        addParameter(
+                DefineParam(mCodedFps, C2_PARAMKEY_FRAME_RATE)
+                .withDefault(new C2StreamFrameRateInfo::output(0u, 0.0))
+                .withFields({C2F(mCodedFps, value).any()})
+                .withSetter(BasicSetter<decltype(mCodedFps)::element_type>)
+                .build());
+        addParameter(
+                DefineParam(mTimeOffset, C2_PARAMKEY_FRAME_RATE)
+                .withDefault(new C2ComponentTimeOffsetTuning(0ULL))
+                .withFields({C2F(mTimeOffset, value).any()})
+                .withSetter(BasicSetter<decltype(mTimeOffset)::element_type>)
+                .build());
+        addParameter(
+                DefineParam(mStarted, C2_PARAMKEY_INPUT_SURFACE_START_AT)
+                .withDefault(new C2PortStartTimestampTuning::output(0ULL))
+                .withFields({
+                        C2F(mStarted, enabled).any(),
+                        C2F(mStarted, timestamp).any()})
+                .withSetter(BasicSetter<decltype(mStarted)::element_type>)
+                .build());
+        addParameter(
+                DefineParam(mStopped, C2_PARAMKEY_INPUT_SURFACE_STOP_AT)
+                .withDefault(new C2PortStopTimestampTuning::output())
+                .withFields({
+                        C2F(mStopped, enabled).any(),
+                        C2F(mStopped, timestamp).any()})
+                .withSetter(BasicSetter<decltype(mStopped)::element_type>)
+                .build());
+        addParameter(
+                DefineParam(mSuspended, C2_PARAMKEY_INPUT_SURFACE_SUSPEND_AT)
+                .withDefault(new C2PortSuspendTimestampTuning::output())
+                .withFields({
+                        C2F(mSuspended, enabled).any(),
+                        C2F(mSuspended, timestamp).any()})
+                .withSetter(BasicSetter<decltype(mSuspended)::element_type>)
+                .build());
+        addParameter(
+                DefineParam(mResumed, C2_PARAMKEY_INPUT_SURFACE_RESUME_AT)
+                .withDefault(new C2PortResumeTimestampTuning::output(0ULL))
+                .withFields({
+                        C2F(mResumed, enabled).any(),
+                        C2F(mResumed, timestamp).any()})
+                .withSetter(BasicSetter<decltype(mResumed)::element_type>)
+                .build());
+        addParameter(
+                DefineParam(mGap, C2_PARAMKEY_INPUT_SURFACE_TIMESTAMP_ADJUSTMENT)
+                .withDefault(new C2PortTimestampGapTuning::output(
+                        C2TimestampGapAdjustmentStruct::NONE, 0ULL))
+                .withFields({
+                        C2F(mGap, mode)
+                                .oneOf({
+                                        C2TimestampGapAdjustmentStruct::NONE,
+                                        C2TimestampGapAdjustmentStruct::MIN_GAP,
+                                        C2TimestampGapAdjustmentStruct::FIXED_GAP}),
+                        C2F(mGap, value).any()})
+                .withSetter(BasicSetter<decltype(mGap)::element_type>)
+                .build());
+        addParameter(
+                DefineParam(mStopTimeOffset, C2_PARAMKEY_INPUT_SURFACE_STOP_TIME_OFFSET)
+                .withDefault(new C2PortStopTimeOffset::output(0ULL))
+                .withFields({C2F(mStopTimeOffset, value).any()})
+                .withSetter(BasicSetter<decltype(mStopTimeOffset)::element_type>)
+                .build());
+
+        addParameter(
+                DefineParam(mInputDone, C2_PARAMKEY_LAYER_INDEX)
+                .withDefault(new C2StreamLayerIndexInfo::output(0u, UINT32_MAX))
+                .withFields({C2F(mInputDone, value).any()})
+                .withSetter(BasicSetter<decltype(mInputDone)::element_type>)
+                .build());
+        addParameter(
+                DefineParam(mInputDoneCount, C2_PARAMKEY_LAYER_INDEX)
+                .withDefault(new C2StreamLayerCountInfo::input(0u, 0))
+                .withFields({C2F(mInputDoneCount, value).any()})
+                .withSetter(InputDoneCountSetter)
+                .build());
+        addParameter(
+                DefineParam(mEmptyCount, C2_PARAMKEY_LAYER_COUNT)
+                .withDefault(new C2StreamLayerCountInfo::output(0u, 0))
+                .withFields({C2F(mEmptyCount, value).any()})
+                .withSetter(EmptyCountSetter)
+                .build());
+    }
+
+    void getImageConfig(ImageConfig* _Nonnull config) {
+        config->mWidth = mBlockSize->width;
+        config->mHeight = mBlockSize->height;
+        config->mFormat = mPixelFormat->value;
+        config->mNumBuffers = mBlockCount->value;
+        config->mUsage = mUsage->value;
+        config->mDataspace = mDataspace->value;
+    }
+
+    void getStreamConfig(StreamConfig* _Nonnull config) {
+        config->mMinFps = mMinFps->value;
+        config->mMaxFps = mMaxFps->value;
+        config->mCaptureFps = mCaptureFps->value;
+        config->mCodedFps = mCodedFps->value;
+        config->mTimeOffsetUs = mTimeOffset->value;
+
+        bool suspended = mSuspended->enabled;
+        bool resumed = mResumed->enabled;
+        CHECK(resumed != suspended);
+        config->mSuspended = suspended;
+        config->mSuspendAtUs = mSuspended->timestamp;
+        config->mResumeAtUs = mResumed->timestamp;
+        bool stopped = mStopped->enabled;
+        bool started = mStarted->enabled;
+        CHECK(stopped != started);
+        config->mStopped = stopped;
+        config->mStopAtUs = mStopped->timestamp;
+        config->mStartAtUs = mStarted->timestamp;
+
+        config->mAdjustedFpsMode = mGap->mode;
+        config->mAdjustedGapUs = mGap->value;
+    }
+
+    void getWorkStatusConfig(WorkStatusConfig* _Nonnull config) {
+        if (mInputDone->value == UINT32_MAX) {
+            config->mLastDoneIndex = -1;
+        } else {
+            config->mLastDoneIndex = mInputDone->value;
+        }
+        config->mLastDoneCount = mInputDoneCount->value;
+        config->mEmptyCount = mEmptyCount->value;
     }
 
 private:
+    // setters
+    static C2R BlockSizeSetter(bool mayBlock,
+            C2InterfaceHelper::C2P<C2StreamBlockSizeInfo::output> &me) {
+        (void)mayBlock;
+        uint32_t width_ = c2_min(me.v.width, 8192u);
+        uint32_t height_ = c2_min(me.v.height, 8192u);
+        if (width_ % 2 != 0) width_++;
+        if (height_ % 2 != 0) height_++;
+        me.set().width = width_;
+        me.set().height = height_;
+        return C2R::Ok();
+    }
+    static C2R BlockCountSetter(bool mayBlock,
+            C2InterfaceHelper::C2P<C2StreamBlockCountInfo::output> &me) {
+        (void)mayBlock;
+        me.set().value = c2_min(me.v.value, kDefaultImageBufferCount);
+        return C2R::Ok();
+    }
+
+    static C2R InputDoneCountSetter(bool mayBlock,
+            C2InterfaceHelper::C2P<C2StreamLayerCountInfo::input> &me) {
+        (void)mayBlock;
+        me.set().value = me.v.value + 1;
+        return C2R::Ok();
+    }
+
+    static C2R EmptyCountSetter(bool mayBlock,
+            C2InterfaceHelper::C2P<C2StreamLayerCountInfo::output> &me) {
+        (void)mayBlock;
+        me.set().value = me.v.value + 1;
+        return C2R::Ok();
+    }
+
+private:
+    // buffer configuraration
+    std::shared_ptr<C2StreamBlockSizeInfo::output> mBlockSize;
+    std::shared_ptr<C2StreamBlockCountInfo::output> mBlockCount;
+    std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
+    std::shared_ptr<C2StreamUsageTuning::output> mUsage;
+    std::shared_ptr<C2StreamDataSpaceInfo::output> mDataspace;
+
+    // input surface source configuration
+    std::shared_ptr<C2PortMinFrameRateTuning::output> mMinFps;
+    std::shared_ptr<C2PortMaxFrameRateTuning::output> mMaxFps;
+    std::shared_ptr<C2PortCaptureFrameRateTuning::output> mCaptureFps;
+    std::shared_ptr<C2StreamFrameRateInfo::output> mCodedFps;
+    std::shared_ptr<C2ComponentTimeOffsetTuning> mTimeOffset; // unsigned, but
+                                                              // signed
+    std::shared_ptr<C2PortSuspendTimestampTuning::output> mSuspended;
+    std::shared_ptr<C2PortResumeTimestampTuning::output> mResumed;
+    std::shared_ptr<C2PortStartTimestampTuning::output> mStarted;
+    std::shared_ptr<C2PortStopTimestampTuning::output> mStopped;
+    std::shared_ptr<C2PortTimestampGapTuning::output> mGap;
+    std::shared_ptr<C2PortStopTimeOffset::output> mStopTimeOffset; // query
+
+    // current work status configuration
+    // TODO: remove this and move this to onWorkDone()
+    std::shared_ptr<C2StreamLayerIndexInfo::output> mInputDone;
+    std::shared_ptr<C2StreamLayerCountInfo::input> mInputDoneCount;
+    std::shared_ptr<C2StreamLayerCountInfo::output> mEmptyCount;
 };
 
 class InputSurface::ConfigurableIntf : public ConfigurableC2Intf {
 public:
+    ConfigurableIntf(
+            const std::shared_ptr<InputSurface::Interface> &intf,
+            const std::shared_ptr<InputSurface> &surface)
+        : ConfigurableC2Intf("input-surface", 0),
+          mIntf(intf), mSurface(surface) {
+    }
+
+    virtual ~ConfigurableIntf() override = default;
+
+    virtual c2_status_t query(
+            const std::vector<C2Param::Index> &indices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>>* const params
+            ) const override {
+        // std::lock_guard<std::mutex> l(mConfigLock);
+        std::lock_guard<std::mutex> l(mConfigLock);
+        return mIntf->query({}, indices, mayBlock, params);
+    }
+
+    virtual c2_status_t config(
+            const std::vector<C2Param*> &params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures
+            ) override {
+        auto surface = mSurface.lock();
+        if (!surface) {
+            return C2_CORRUPTED;
+        }
+
+        c2_status_t err;
+        {
+            ImageConfig imageConfig;
+            StreamConfig streamConfig;
+            WorkStatusConfig workStatusConfig;
+            int64_t inputDelayUs = 0;
+
+            std::lock_guard<std::mutex> l(mConfigLock);
+            err = mIntf->config(params, mayBlock, failures);
+
+            mIntf->getImageConfig(&imageConfig);
+            mIntf->getStreamConfig(&streamConfig);
+            mIntf->getWorkStatusConfig(&workStatusConfig);
+            if (surface->updateConfig(
+                   imageConfig, streamConfig, workStatusConfig, &inputDelayUs)) {
+                C2PortStopTimeOffset::output offsetConfig(inputDelayUs);
+                std::vector<std::unique_ptr<C2SettingResult>> fail;
+                c2_status_t updateErr = mIntf->config({&offsetConfig}, mayBlock, &fail);
+            }
+        }
+        return err;
+    }
+
+    virtual c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+            ) const override {
+        std::lock_guard<std::mutex> l(mConfigLock);
+        return mIntf->querySupportedParams(params);
+    }
+
+    virtual c2_status_t querySupportedValues(
+            std::vector<C2FieldSupportedValuesQuery>& fields,
+            c2_blocking_t mayBlock) const override {
+        std::lock_guard<std::mutex> l(mConfigLock);
+        return mIntf->querySupportedValues(fields, mayBlock);
+    }
+
+private:
+    const std::shared_ptr<InputSurface::Interface> mIntf;
+    const std::weak_ptr<InputSurface> mSurface;
+
+    mutable std::mutex mConfigLock;
 };
 
-struct InputSurface::DeathContext {
-    // TODO;
-};
+InputSurface::InputSurface() {
+    mIntf = std::make_shared<Interface>(
+            std::make_shared<C2ReflectorHelper>());
 
-void InputSurface::OnBinderDied(void *cookie) {
-    (void) cookie;
-}
-
-void InputSurface::OnBinderUnlinked(void *cookie) {
-    (void) cookie;
-}
-
-InputSurface::InputSurface() : mDeathContext(nullptr) {
-    mInit = C2_OK;
+    // mConfigurable is initialized lazily.
+    // mInit indicates the initialization status of mConfigurable.
+    mInit = C2_NO_INIT;
 }
 
 InputSurface::~InputSurface() {
+    release();
 }
 
 ::ndk::ScopedAStatus InputSurface::getSurface(::aidl::android::view::Surface* surface) {
-    (void) surface;
-    return ::ndk::ScopedAStatus::ok();
+    std::lock_guard<std::mutex> l(mLock);
+    ANativeWindow *window = mSource->getNativeWindow();
+    if (window) {
+        surface->reset(window);
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(C2_CORRUPTED);
 }
 
 ::ndk::ScopedAStatus InputSurface::getConfigurable(
         std::shared_ptr<IConfigurable>* configurable) {
-    *configurable = mConfigurable;
-    return ::ndk::ScopedAStatus::ok();
+    if (mInit == C2_NO_INIT) {
+        mConfigurable = SharedRefBase::make<CachedConfigurable>(
+                std::make_unique<ConfigurableIntf>(mIntf, this->ref<InputSurface>()));
+        mInit = C2_OK;
+    }
+    if (mConfigurable) {
+        *configurable = mConfigurable;
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(C2_CORRUPTED);
 }
 
 ::ndk::ScopedAStatus InputSurface::connect(
         const std::shared_ptr<IInputSink>& sink,
         std::shared_ptr<IInputSurfaceConnection>* connection) {
-    (void) sink;
-    (void) connection;
+    mConnection = SharedRefBase::make<InputSurfaceConnection>(sink, mSource);
+    *connection = mConnection;
     return ::ndk::ScopedAStatus::ok();
 }
 
+void InputSurface::updateImageConfig(ImageConfig &config) {
+    std::unique_lock<std::mutex> l(mLock);
+    if (mImageConfig.mWidth != config.mWidth) {
+        mImageConfig.mWidth = config.mWidth;
+    }
+    if (mImageConfig.mHeight != config.mHeight) {
+        mImageConfig.mHeight = config.mHeight;
+    }
+    if (mImageConfig.mFormat != config.mFormat) {
+        mImageConfig.mFormat = config.mFormat;
+    }
+    if (mImageConfig.mNumBuffers != config.mNumBuffers) {
+        mImageConfig.mNumBuffers = config.mNumBuffers;
+    }
+    if (mImageConfig.mUsage != config.mUsage) {
+        mImageConfig.mUsage = config.mUsage;
+    }
+    if (mImageConfig.mDataspace != config.mDataspace) {
+        mImageConfig.mDataspace = config.mDataspace;
+    }
+}
+
+bool InputSurface::updateStreamConfig(
+        StreamConfig &config, int64_t *inputDelayUs) {
+    std::stringstream status;
+    c2_status_t err = C2_OK;
+    bool inputDelayUpdated = false;
+
+    std::unique_lock<std::mutex> l(mLock);
+    // handle StreamConfig changes.
+    // TRICKY: we do not unset frame delay repeating
+    if (config.mMinFps > 0 && config.mMinFps != mStreamConfig.mMinFps) {
+        int64_t us = 1e6 / config.mMinFps + 0.5;
+        c2_status_t res = mSource->setRepeatPreviousFrameDelayUs(us);
+        status << " minFps=" << config.mMinFps << " => repeatDelayUs=" << us;
+        if (res != C2_OK) {
+            status << " (=> " << asString(res) << ")";
+            err = res;
+        }
+        mStreamConfig.mMinFps = config.mMinFps;
+    }
+    bool fixedModeUpdate = false;
+    if (config.mAdjustedFpsMode != C2TimestampGapAdjustmentStruct::NONE && (
+            config.mAdjustedFpsMode != mStreamConfig.mAdjustedFpsMode ||
+            config.mAdjustedGapUs != mStreamConfig.mAdjustedGapUs)) {
+        // TODO: configure GapUs to connection
+        // The original codes do not update config, figure out why.
+        mStreamConfig.mAdjustedFpsMode = config.mAdjustedFpsMode;
+        mStreamConfig.mAdjustedGapUs = config.mAdjustedGapUs;
+        fixedModeUpdate = (config.mAdjustedFpsMode == C2TimestampGapAdjustmentStruct::FIXED_GAP);
+        // TODO: update Gap to Connection.
+    }
+    // TRICKY: we do not unset max fps to 0 unless using fixed fps
+    if ((config.mMaxFps > 0 || (fixedModeUpdate && config.mMaxFps == -1))
+            && config.mMaxFps != mStreamConfig.mMaxFps) {
+        c2_status_t res = mSource->setMaxFps(config.mMaxFps);
+        status << " maxFps=" << config.mMaxFps;
+        if (res != C2_OK) {
+            status << " (=> " << asString(res) << ")";
+            err = res;
+        }
+        mStreamConfig.mMaxFps = config.mMaxFps;
+    }
+    if (config.mTimeOffsetUs != mStreamConfig.mTimeOffsetUs) {
+        c2_status_t res = mSource->setTimeOffsetUs(config.mTimeOffsetUs);
+        status << " timeOffset " << config.mTimeOffsetUs << "us";
+        if (res != C2_OK) {
+            status << " (=> " << asString(res) << ")";
+            err = res;
+        }
+        mStreamConfig.mTimeOffsetUs = config.mTimeOffsetUs;
+    }
+    if (config.mCaptureFps != mStreamConfig.mCaptureFps ||
+            config.mCodedFps != mStreamConfig.mCodedFps) {
+        c2_status_t res = mSource->setTimeLapseConfig(
+                config.mCodedFps, config.mCaptureFps);
+        status << " timeLapse " << config.mCaptureFps << "fps as "
+               << config.mCodedFps << "fps";
+        if (res != C2_OK) {
+            status << " (=> " << asString(res) << ")";
+            err = res;
+        }
+        mStreamConfig.mCaptureFps = config.mCaptureFps;
+        mStreamConfig.mCodedFps = config.mCodedFps;
+    }
+    if (config.mStartAtUs != mStreamConfig.mStartAtUs ||
+            (config.mStopped != mStreamConfig.mStopped && !config.mStopped)) {
+        c2_status_t res = mSource->setStartTimeUs(config.mStartAtUs);
+        status << " start at " << config.mStartAtUs << "us";
+        if (res != C2_OK) {
+            status << " (=> " << asString(res) << ")";
+            err = res;
+        }
+        mStreamConfig.mStartAtUs = config.mStartAtUs;
+        mStreamConfig.mStopped = config.mStopped;
+    }
+    if (config.mSuspended != mStreamConfig.mSuspended) {
+        c2_status_t res = mSource->setSuspend(config.mSuspended, config.mSuspendAtUs);
+        status << " " << (config.mSuspended ? "suspend" : "resume")
+                << " at " << config.mSuspendAtUs << "us";
+        if (res != C2_OK) {
+            status << " (=> " << asString(res) << ")";
+            err = res;
+        }
+        mStreamConfig.mSuspended = config.mSuspended;
+        mStreamConfig.mSuspendAtUs = config.mSuspendAtUs;
+    }
+    if (config.mStopped != mStreamConfig.mStopped && config.mStopped) {
+        // start time has changed or started from stop.
+        c2_status_t res = mSource->setStopTimeUs(config.mStopAtUs);
+        status << " stop at " << config.mStopAtUs << "us";
+        if (res != C2_OK) {
+            status << " (=> " << asString(res) << ")";
+            err = res;
+        } else {
+            status << " delayUs";
+            res = mSource->getStopTimeOffsetUs(inputDelayUs);
+            if (res != C2_OK) {
+                status << " (=> " << asString(res) << ")";
+            } else {
+                status << "=" << *inputDelayUs << "us";
+                inputDelayUpdated = true;
+            }
+        }
+        mStreamConfig.mStopAtUs = config.mStopAtUs;
+        mStreamConfig.mStopped = config.mStopped;
+    }
+    if (status.str().empty()) {
+        ALOGD("StreamConfig not changed");
+    } else {
+        ALOGD("StreamConfig%s", status.str().c_str());
+    }
+    return inputDelayUpdated;
+}
+
+void InputSurface::updateWorkStatusConfig(WorkStatusConfig &config) {
+    (void)config;
+    // TODO
+}
+
+bool InputSurface::updateConfig(
+        ImageConfig &imageConfig, StreamConfig &streamConfig,
+        WorkStatusConfig &workStatusConfig, int64_t *inputDelayUs) {
+    updateImageConfig(imageConfig);
+    bool ret = updateStreamConfig(streamConfig, inputDelayUs);
+    updateWorkStatusConfig(workStatusConfig);
+
+    return ret;
+}
+
+void InputSurface::release() {
+    ALOGD("all refs are gone");
+    // TODO clean up
+}
+
 }  // namespace aidl::android::hardware::media::c2::utils
diff --git a/media/codec2/hal/aidl/inputsurface/InputSurfaceConnection.cpp b/media/codec2/hal/aidl/inputsurface/InputSurfaceConnection.cpp
index 44ca924..6a95472 100644
--- a/media/codec2/hal/aidl/inputsurface/InputSurfaceConnection.cpp
+++ b/media/codec2/hal/aidl/inputsurface/InputSurfaceConnection.cpp
@@ -19,15 +19,24 @@
 #include <android-base/logging.h>
 
 #include <codec2/aidl/inputsurface/InputSurfaceConnection.h>
+#include <codec2/aidl/inputsurface/InputSurfaceSource.h>
 
 namespace aidl::android::hardware::media::c2::utils {
 
-InputSurfaceConnection::InputSurfaceConnection() {
+InputSurfaceConnection::InputSurfaceConnection(
+        const std::shared_ptr<IInputSink>& sink,
+        ::android::sp<c2::implementation::InputSurfaceSource> const &source)
+        : mSink{sink}, mSource{source} {
 }
 
 InputSurfaceConnection::~InputSurfaceConnection() {
 }
 
+c2_status_t InputSurfaceConnection::status() const {
+    // TODO;
+    return C2_OK;
+}
+
 ::ndk::ScopedAStatus InputSurfaceConnection::disconnect() {
     return ::ndk::ScopedAStatus::ok();
 }
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 693ac4f..8b4e012 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -32,12 +32,14 @@
         "audiopolicy-aidl-cpp",
         "av-types-aidl-cpp",
         "spatializer-aidl-cpp",
+        "volumegroupcallback-aidl-cpp",
     ],
     export_static_lib_headers: [
         "audioflinger-aidl-cpp",
         "audiopolicy-aidl-cpp",
         "av-types-aidl-cpp",
         "spatializer-aidl-cpp",
+        "volumegroupcallback-aidl-cpp",
     ],
     target: {
         darwin: {
@@ -151,6 +153,7 @@
         "libutils",
         "packagemanager_aidl-cpp",
         "spatializer-aidl-cpp",
+        "volumegroupcallback-aidl-cpp",
     ],
     export_shared_lib_headers: [
         "audioflinger-aidl-cpp",
@@ -160,6 +163,7 @@
         "libmediametrics",
         "libmediautils",
         "spatializer-aidl-cpp",
+        "volumegroupcallback-aidl-cpp",
     ],
 
     include_dirs: [
@@ -472,6 +476,7 @@
         "capture_state_listener-aidl",
         "framework-permission-aidl",
         "spatializer-aidl",
+        "volumegroupcallback-aidl",
     ],
 
     double_loadable: true,
@@ -539,3 +544,30 @@
         },
     },
 }
+
+aidl_interface {
+    name: "volumegroupcallback-aidl",
+    unstable: true,
+    host_supported: true,
+    vendor_available: true,
+    local_include_dir: "aidl",
+    srcs: [
+        "aidl/android/media/INativeAudioVolumeGroupCallback.aidl",
+    ],
+    double_loadable: true,
+    defaults: [
+        "latest_android_media_audio_common_types_import_interface",
+    ],
+    backend: {
+        cpp: {
+            min_sdk_version: "29",
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.media",
+            ],
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+    },
+}
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 3dda043..3ef9225 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -40,6 +40,7 @@
 #include <system/audio.h>
 #include <android/media/GetInputForAttrResponse.h>
 #include <android/media/AudioMixerAttributesInternal.h>
+#include <android/media/audio/common/AudioVolumeGroupChangeEvent.h>
 
 #define VALUE_OR_RETURN_BINDER_STATUS(x) \
     ({ auto _tmp = (x); \
@@ -66,6 +67,7 @@
 using media::audio::common::AudioSource;
 using media::audio::common::AudioStreamType;
 using media::audio::common::AudioUsage;
+using media::audio::common::AudioVolumeGroupChangeEvent;
 using media::audio::common::Int;
 
 std::mutex AudioSystem::gMutex;
@@ -195,6 +197,7 @@
         }
         if (mValid) return mService;
         if (waitMs.count() < 0) waitMs = mWaitMs;
+        auto timepointLimit = std::chrono::steady_clock::now() + waitMs;
         ul.unlock();
 
         // mediautils::getService() installs a persistent new service notification.
@@ -205,6 +208,7 @@
         ul.lock();
         // return the IAudioFlinger interface which is adapted
         // from the media::IAudioFlingerService.
+        mCv.wait_until(ul, timepointLimit, isServiceValid_l);
         return mService;
     }
 
@@ -289,6 +293,7 @@
             mService = service;
             client = mClient;
             mValid = true;
+            mCv.notify_all();
         }
         // TODO(b/375280520) consider registerClient() within mMutex lock.
         const int64_t token = IPCThreadState::self()->clearCallingIdentity();
@@ -303,7 +308,12 @@
         return sp<AudioFlingerClientAdapter>::make(af);
     }
 
+    static bool isServiceValid_l() REQUIRES(mMutex) {
+        return mValid;
+    }
+
     static inline constinit std::mutex mMutex;
+    static inline constinit std::condition_variable mCv;
     static inline constinit sp<AudioSystem::AudioFlingerClient> mClient GUARDED_BY(mMutex);
     static inline constinit sp<IAudioFlinger> mService GUARDED_BY(mMutex);
     static inline constinit std::chrono::milliseconds mWaitMs
@@ -1022,6 +1032,7 @@
             client = mClient;
             mService = aps;
             mValid = true;
+            mCv.notify_all();
         }
         // TODO(b/375280520) consider registerClient() within mMutex lock.
         const int64_t token = IPCThreadState::self()->clearCallingIdentity();
@@ -1082,6 +1093,7 @@
         }
         if (mValid) return mService;
         if (waitMs.count() < 0) waitMs = mWaitMs;
+        auto timepointLimit = std::chrono::steady_clock::now() + waitMs;
         ul.unlock();
 
         auto service = mediautils::getService<
@@ -1092,6 +1104,7 @@
         // (whereupon mService contained the actual local service pointer to use).
         // we should always return mService.
         ul.lock();
+        mCv.wait_until(ul, timepointLimit, isServiceValid_l);
         return mService;
     }
 
@@ -1140,7 +1153,12 @@
     }
 private:
 
+    static bool isServiceValid_l() REQUIRES(mMutex) {
+        return mValid;
+    }
+
     static inline constinit std::mutex mMutex;
+    static inline constinit std::condition_variable mCv;
     static inline constinit sp<AudioSystem::AudioPolicyServiceClient> mClient GUARDED_BY(mMutex);
     static inline constinit sp<IAudioPolicyService> mService GUARDED_BY(mMutex);
     static inline constinit bool mValid GUARDED_BY(mMutex) = false;
@@ -1965,7 +1983,8 @@
     return (ret < 0) ? INVALID_OPERATION : NO_ERROR;
 }
 
-status_t AudioSystem::addAudioVolumeGroupCallback(const sp<AudioVolumeGroupCallback>& callback) {
+status_t AudioSystem::addAudioVolumeGroupCallback(
+        const sp<media::INativeAudioVolumeGroupCallback>& callback) {
     const sp<IAudioPolicyService> aps = get_audio_policy_service();
     if (aps == nullptr) return AudioPolicyServiceTraits::getError();
     const auto apc = AudioSystem::getAudioPolicyClient();
@@ -1979,7 +1998,8 @@
     return (ret < 0) ? INVALID_OPERATION : NO_ERROR;
 }
 
-status_t AudioSystem::removeAudioVolumeGroupCallback(const sp<AudioVolumeGroupCallback>& callback) {
+status_t AudioSystem::removeAudioVolumeGroupCallback(
+        const sp<media::INativeAudioVolumeGroupCallback>& callback) {
     const sp<IAudioPolicyService> aps = get_audio_policy_service();
     if (aps == nullptr) return AudioPolicyServiceTraits::getError();
     const auto apc = AudioSystem::getAudioPolicyClient();
@@ -2997,14 +3017,14 @@
 
 // ----------------------------------------------------------------------------
 int AudioSystem::AudioPolicyServiceClient::addAudioVolumeGroupCallback(
-        const sp<AudioVolumeGroupCallback>& callback) {
+        const sp<media::INativeAudioVolumeGroupCallback>& callback) {
     std::lock_guard _l(mMutex);
     return mAudioVolumeGroupCallbacks.insert(callback).second
             ? mAudioVolumeGroupCallbacks.size() : -1;
 }
 
 int AudioSystem::AudioPolicyServiceClient::removeAudioVolumeGroupCallback(
-        const sp<AudioVolumeGroupCallback>& callback) {
+        const sp<media::INativeAudioVolumeGroupCallback>& callback) {
     std::lock_guard _l(mMutex);
     return mAudioVolumeGroupCallbacks.erase(callback) > 0
             ? mAudioVolumeGroupCallbacks.size() : -1;
@@ -3012,13 +3032,12 @@
 
 Status AudioSystem::AudioPolicyServiceClient::onAudioVolumeGroupChanged(int32_t group,
                                                                         int32_t flags) {
-    volume_group_t groupLegacy = VALUE_OR_RETURN_BINDER_STATUS(
-            aidl2legacy_int32_t_volume_group_t(group));
-    int flagsLegacy = VALUE_OR_RETURN_BINDER_STATUS(convertReinterpret<int>(flags));
-
+    AudioVolumeGroupChangeEvent aidlEvent;
+    aidlEvent.groupId = group;
+    aidlEvent.flags = flags;
     std::lock_guard _l(mMutex);
     for (const auto& callback : mAudioVolumeGroupCallbacks) {
-        callback->onAudioVolumeGroupChanged(groupLegacy, flagsLegacy);
+        callback->onAudioVolumeGroupChanged(aidlEvent);
     }
     return Status::ok();
 }
@@ -3114,9 +3133,6 @@
     for (const auto& callback : mAudioPortCallbacks) {
         callback->onServiceDied();
     }
-    for (const auto& callback : mAudioVolumeGroupCallbacks) {
-        callback->onServiceDied();
-    }
 }
 
 ConversionResult<record_client_info_t>
diff --git a/media/libaudioclient/aidl/android/media/INativeAudioVolumeGroupCallback.aidl b/media/libaudioclient/aidl/android/media/INativeAudioVolumeGroupCallback.aidl
new file mode 100644
index 0000000..43c6a65
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/INativeAudioVolumeGroupCallback.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.audio.common.AudioVolumeGroupChangeEvent;
+
+/**
+ * The INativeAudioVolumeGroupCallback interface is a callback associated to the
+ * setVolumeGroupVolumeIndex API. The callback is used by the AudioPolicyManager
+ * implementation in native audio server to communicate volume changes.
+ * {@hide}
+ */
+oneway interface INativeAudioVolumeGroupCallback {
+    /**
+     * Called when the index applied by the AudioPolicyManager changes
+     */
+    void onAudioVolumeGroupChanged(in AudioVolumeGroupChangeEvent volumeChangeEvent);
+}
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index db010c8..16c3a7f 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -30,6 +30,7 @@
 #include <android/media/BnAudioFlingerClient.h>
 #include <android/media/BnAudioPolicyServiceClient.h>
 #include <android/media/EffectDescriptor.h>
+#include <android/media/INativeAudioVolumeGroupCallback.h>
 #include <android/media/INativeSpatializerCallback.h>
 #include <android/media/ISoundDose.h>
 #include <android/media/ISoundDoseCallback.h>
@@ -739,12 +740,12 @@
         virtual ~AudioVolumeGroupCallback() {}
 
         virtual void onAudioVolumeGroupChanged(volume_group_t group, int flags) = 0;
-        virtual void onServiceDied() = 0;
-
     };
 
-    static status_t addAudioVolumeGroupCallback(const sp<AudioVolumeGroupCallback>& callback);
-    static status_t removeAudioVolumeGroupCallback(const sp<AudioVolumeGroupCallback>& callback);
+    static status_t addAudioVolumeGroupCallback(
+            const sp<media::INativeAudioVolumeGroupCallback>& callback);
+    static status_t removeAudioVolumeGroupCallback(
+            const sp<media::INativeAudioVolumeGroupCallback>& callback);
 
     class AudioPortCallback : public virtual RefBase
     {
@@ -881,10 +882,10 @@
         }
 
         int addAudioVolumeGroupCallback(
-                const sp<AudioVolumeGroupCallback>& callback) EXCLUDES(mMutex);
+                const sp<media::INativeAudioVolumeGroupCallback>& callback) EXCLUDES(mMutex);
 
         int removeAudioVolumeGroupCallback(
-                const sp<AudioVolumeGroupCallback>& callback) EXCLUDES(mMutex);
+                const sp<media::INativeAudioVolumeGroupCallback>& callback) EXCLUDES(mMutex);
 
         bool isAudioVolumeGroupCbEnabled() const EXCLUDES(mMutex) {
             std::lock_guard _l(mMutex);
@@ -914,7 +915,8 @@
     private:
         mutable std::mutex mMutex;
         std::set<sp<AudioPortCallback>> mAudioPortCallbacks GUARDED_BY(mMutex);
-        std::set<sp<AudioVolumeGroupCallback>> mAudioVolumeGroupCallbacks GUARDED_BY(mMutex);
+        std::set<sp<media::INativeAudioVolumeGroupCallback>> mAudioVolumeGroupCallbacks
+                GUARDED_BY(mMutex);
     };
 
     private:
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index ca77a2f..2b37f19 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -48,7 +48,10 @@
 #include <binder/IMemory.h>
 #include <binder/IServiceManager.h>
 #include <binder/MemoryDealer.h>
+#include <com_android_graphics_libgui_flags.h>
 #include <cutils/properties.h>
+#include <gui/BufferItem.h>
+#include <gui/BufferItemConsumer.h>
 #include <gui/BufferQueue.h>
 #include <gui/Surface.h>
 #include <hidlmemory/FrameworkUtils.h>
@@ -770,6 +773,42 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
+class MediaCodec::ReleaseSurface {
+    public:
+        explicit ReleaseSurface(uint64_t usage) {
+            std::tie(mConsumer, mSurface) = BufferItemConsumer::create(usage);
+
+            struct FrameAvailableListener : public BufferItemConsumer::FrameAvailableListener {
+                FrameAvailableListener(const sp<BufferItemConsumer> &consumer) {
+                    mConsumer = consumer;
+                }
+                void onFrameAvailable(const BufferItem&) override {
+                    BufferItem buffer;
+                    // consume buffer
+                    sp<BufferItemConsumer> consumer = mConsumer.promote();
+                    if (consumer != nullptr && consumer->acquireBuffer(&buffer, 0) == NO_ERROR) {
+                        consumer->releaseBuffer(buffer.mGraphicBuffer, buffer.mFence);
+                    }
+                }
+
+                wp<BufferItemConsumer> mConsumer;
+            };
+            mFrameAvailableListener = sp<FrameAvailableListener>::make(mConsumer);
+            mConsumer->setFrameAvailableListener(mFrameAvailableListener);
+            mConsumer->setName(String8{"MediaCodec.release"});
+        }
+
+        const sp<Surface> &getSurface() {
+            return mSurface;
+        }
+
+    private:
+        sp<BufferItemConsumer> mConsumer;
+        sp<Surface> mSurface;
+        sp<BufferItemConsumer::FrameAvailableListener> mFrameAvailableListener;
+    };
+#else
 class MediaCodec::ReleaseSurface {
 public:
     explicit ReleaseSurface(uint64_t usage) {
@@ -807,6 +846,7 @@
     sp<IGraphicBufferConsumer> mConsumer;
     sp<Surface> mSurface;
 };
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
 
 ////////////////////////////////////////////////////////////////////////////////
 
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index 4bd0895..1891954 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -18,8 +18,15 @@
 #define LOG_TAG "MediaSync"
 #include <inttypes.h>
 
-#include <gui/BufferQueue.h>
+#include <com_android_graphics_libgui_flags.h>
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
+#include <gui/BufferItemConsumer.h>
+#include <gui/Surface.h>
+#else
 #include <gui/IGraphicBufferConsumer.h>
+#endif
+#include <gui/BufferQueue.h>
 #include <gui/IGraphicBufferProducer.h>
 
 #include <media/AudioTrack.h>
@@ -74,7 +81,11 @@
 
 MediaSync::~MediaSync() {
     if (mInput != NULL) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
+        mInput->abandon();
+#else
         mInput->consumerDisconnect();
+#endif
     }
     if (mOutput != NULL) {
         mOutput->disconnect(NATIVE_WINDOW_API_MEDIA);
@@ -204,6 +215,39 @@
         return INVALID_OPERATION;
     }
 
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
+    int usageFlags = 0;
+    mOutput->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usageFlags);
+
+    auto [newInput, surface] = BufferItemConsumer::create(usageFlags);
+
+    sp<InputListener> listener(new InputListener(this));
+    newInput->setFrameAvailableListener(listener);
+    newInput->setName(String8("MediaSync"));
+    // propagate usage bits from output surface
+    status_t status = newInput->setConsumerUsageBits(usageFlags);
+    if (status != OK) {
+        ALOGE("%s: Unable to set usage bits to %d", __FUNCTION__, usageFlags);
+        return status;
+    }
+
+    // set undequeued buffer count
+    int minUndequeuedBuffers;
+    mOutput->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers);
+    status = newInput->setMaxAcquiredBufferCount(minUndequeuedBuffers);
+    if (status != OK) {
+        ALOGE("%s: Unable to set setMaxAcquiredBufferCount to %d", __FUNCTION__,
+              minUndequeuedBuffers);
+        return status;
+    }
+
+    mMaxAcquiredBufferCount = minUndequeuedBuffers;
+    mUsageFlagsFromOutput = usageFlags;
+    mInput = newInput;
+    mListener = listener;
+    *outBufferProducer = surface->getIGraphicBufferProducer();
+    return OK;
+#else
     sp<IGraphicBufferProducer> bufferProducer;
     sp<IGraphicBufferConsumer> bufferConsumer;
     BufferQueue::createBufferQueue(&bufferProducer, &bufferConsumer);
@@ -227,6 +271,7 @@
         bufferConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBufferCount);
     }
     return status;
+#endif
 }
 
 void MediaSync::resync_l() {
@@ -339,7 +384,15 @@
 
 void MediaSync::setName(const AString &name) {
     Mutex::Autolock lock(mMutex);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
+    if (mInput) {
+        mInput->setName(String8(name.c_str()));
+    } else {
+        ALOGE("%s with name %s called without an mInput set", __FUNCTION__, name.c_str());
+    }
+#else
     mInput->setConsumerName(String8(name.c_str()));
+#endif
 }
 
 void MediaSync::flush() {
@@ -621,7 +674,11 @@
 
     ALOGV("acquired buffer %#llx from input", (long long)bufferItem.mGraphicBuffer->getId());
 
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
+    status = mInput->detachBuffer(bufferItem.mGraphicBuffer);
+#else
     status = mInput->detachBuffer(bufferItem.mSlot);
+#endif
     if (status != NO_ERROR) {
         ALOGE("detaching buffer from input failed (%d)", status);
         if (status == NO_INIT) {
@@ -634,7 +691,11 @@
     if (mBuffersFromInput.indexOfKey(bufferItem.mGraphicBuffer->getId()) >= 0) {
         // Something is wrong since this buffer should be at our hands, bail.
         ALOGE("received buffer multiple times from input");
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
+        mInput->abandon();
+#else
         mInput->consumerDisconnect();
+#endif
         onAbandoned_l(true /* isInput */);
         return;
     }
@@ -687,7 +748,11 @@
 
     if (mBuffersSentToOutput.indexOfKey(bufferItem.mGraphicBuffer->getId()) >= 0) {
         // Something is wrong since this buffer should be held by output now, bail.
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
+        mInput->abandon();
+#else
         mInput->consumerDisconnect();
+#endif
         onAbandoned_l(true /* isInput */);
         return;
     }
@@ -748,10 +813,18 @@
 
     // Attach and release the buffer back to the input.
     int consumerSlot;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
+    status_t status = mInput->attachBuffer(oldBuffer);
+#else
     status_t status = mInput->attachBuffer(&consumerSlot, oldBuffer);
+#endif
     ALOGE_IF(status != NO_ERROR, "attaching buffer to input failed (%d)", status);
     if (status == NO_ERROR) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
+        mInput->releaseBuffer(oldBuffer, fence);
+#else
         status = mInput->releaseBuffer(consumerSlot, 0 /* frameNumber */, fence);
+#endif
         ALOGE_IF(status != NO_ERROR, "releasing buffer to input failed (%d)", status);
     }
 
@@ -770,7 +843,11 @@
         if (isInput) {
             mOutput->disconnect(NATIVE_WINDOW_API_MEDIA);
         } else {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
+            mInput->abandon();
+#else
             mInput->consumerDisconnect();
+#endif
         }
         mIsAbandoned = true;
     }
@@ -815,6 +892,7 @@
     mSync->onFrameAvailableFromInput();
 }
 
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
 // We don't care about sideband streams, since we won't relay them.
 void MediaSync::InputListener::onSidebandStreamChanged() {
     ALOGE("onSidebandStreamChanged: got sideband stream unexpectedly.");
@@ -825,6 +903,7 @@
     Mutex::Autolock lock(mSync->mMutex);
     mSync->onAbandoned_l(true /* isInput */);
 }
+#endif
 
 MediaSync::OutputListener::OutputListener(const sp<MediaSync> &sync,
         const sp<IGraphicBufferProducer> &output)
diff --git a/media/libstagefright/include/media/stagefright/MediaSync.h b/media/libstagefright/include/media/stagefright/MediaSync.h
index f50fb8f..f6f36bb 100644
--- a/media/libstagefright/include/media/stagefright/MediaSync.h
+++ b/media/libstagefright/include/media/stagefright/MediaSync.h
@@ -17,7 +17,13 @@
 #ifndef MEDIA_SYNC_H
 #define MEDIA_SYNC_H
 
+#include <com_android_graphics_libgui_flags.h>
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
+#include <gui/BufferItemConsumer.h>
+#else
 #include <gui/IConsumerListener.h>
+#endif
 #include <gui/IProducerListener.h>
 
 #include <media/AudioResamplerPublic.h>
@@ -34,7 +40,9 @@
 class BufferItem;
 class Fence;
 class GraphicBuffer;
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
 class IGraphicBufferConsumer;
+#endif
 class IGraphicBufferProducer;
 struct MediaClock;
 struct VideoFrameScheduler;
@@ -140,13 +148,19 @@
 
     // This is a thin wrapper class that lets us listen to
     // IConsumerListener::onFrameAvailable from mInput.
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
+    class InputListener : public BufferItemConsumer::FrameAvailableListener {
+#else
     class InputListener : public IConsumerListener, public IBinder::DeathRecipient {
+#endif
       public:
         InputListener(const sp<MediaSync> &sync);
         virtual ~InputListener();
 
-        // From IConsumerListener
-        virtual void onFrameAvailable(const BufferItem &item);
+        // From FrameAvailableListener
+        virtual void onFrameAvailable(const BufferItem&) override;
+
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
 
         // From IConsumerListener
         // We don't care about released buffers because we detach each buffer as
@@ -160,8 +174,9 @@
 
         // From IBinder::DeathRecipient
         virtual void binderDied(const wp<IBinder> &who);
+#endif
 
-    private:
+      private:
         sp<MediaSync> mSync;
     };
 
@@ -192,7 +207,12 @@
     mutable Mutex mMutex;
     Condition mReleaseCondition;
     size_t mNumOutstandingBuffers;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION)
+    sp<BufferItemConsumer> mInput;
+    sp<InputListener> mListener;  // listener for mInput, so the reference isn't dropped.
+#else
     sp<IGraphicBufferConsumer> mInput;
+#endif
     sp<IGraphicBufferProducer> mOutput;
     int mUsageFlagsFromOutput;
     uint32_t mMaxAcquiredBufferCount; // max acquired buffer count
diff --git a/media/module/extractors/mp4/Android.bp b/media/module/extractors/mp4/Android.bp
index effd24a..f0aff32 100644
--- a/media/module/extractors/mp4/Android.bp
+++ b/media/module/extractors/mp4/Android.bp
@@ -52,6 +52,7 @@
 
     shared_libs: [
         "server_configurable_flags",
+        "libbase",
     ],
 
     host_supported: true,
diff --git a/media/module/extractors/mp4/MPEG4Extractor.cpp b/media/module/extractors/mp4/MPEG4Extractor.cpp
index 08345f0..0695ceb 100644
--- a/media/module/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/module/extractors/mp4/MPEG4Extractor.cpp
@@ -29,6 +29,10 @@
 
 #include <utils/Log.h>
 
+#include <android-base/properties.h>
+#ifdef __ANDROID__
+#include <android/api-level.h>
+#endif  //__ANDROID__
 #include "AC4Parser.h"
 #include "MPEG4Extractor.h"
 #include "SampleTable.h"
@@ -85,6 +89,22 @@
     kMaxAtomSize = 64 * 1024 * 1024,
 };
 
+static bool isAtLeastRelease([[maybe_unused]] int version,
+                             [[maybe_unused]] const std::string codeName) {
+#ifdef __ANDROID__
+    static std::once_flag sCheckOnce;
+    static std::string sDeviceCodeName;
+    static int sDeviceApiLevel = 0;
+    std::call_once(sCheckOnce, [&]() {
+        sDeviceCodeName = base::GetProperty("ro.build.version.codename", "");
+        sDeviceApiLevel = android_get_device_api_level();
+    });
+    return sDeviceApiLevel >= version || sDeviceCodeName == codeName;
+#else   //__ANDROID__
+    return true;
+#endif  //__ANDROID__
+}
+
 class MPEG4Source : public MediaTrackHelper {
 static const size_t  kMaxPcmFrameSize = 8192;
 public:
@@ -372,7 +392,9 @@
             return MEDIA_MIMETYPE_VIDEO_HEVC;
 
         case FOURCC("apv1"):
-            if (!com::android::media::extractor::flags::extractor_mp4_enable_apv()) {
+            // Enable APV codec support from Android Baklava
+            if (!(isAtLeastRelease(36, "Baklava") &&
+                  com::android::media::extractor::flags::extractor_mp4_enable_apv())) {
                 ALOGV("APV support not enabled");
                 return "application/octet-stream";
             }
@@ -2637,7 +2659,9 @@
         }
 
         case FOURCC("apvC"): {
-            if (!com::android::media::extractor::flags::extractor_mp4_enable_apv()) {
+            // Enable APV codec support from Android Baklava
+            if (!(isAtLeastRelease(36, "Baklava") &&
+                  com::android::media::extractor::flags::extractor_mp4_enable_apv())) {
                 ALOGV("APV support not enabled");
                 *offset += chunk_size;
                 break;
@@ -5239,8 +5263,12 @@
     mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
     mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
               !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
-    mIsAPV = com::android::media::extractor::flags::extractor_mp4_enable_apv() &&
-             !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_APV);
+    // Enable APV codec support from Android Baklava
+    mIsAPV = false;
+    if (isAtLeastRelease(36, "Baklava")) {
+        mIsAPV = com::android::media::extractor::flags::extractor_mp4_enable_apv() &&
+                 !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_APV);
+    }
     mIsAC4 = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC4);
     mIsDolbyVision = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION);
     mIsHeif = !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC) && mItemTable != NULL;
diff --git a/media/module/libapexcodecs/Android.bp b/media/module/libapexcodecs/Android.bp
index e49230a..27c1d22 100644
--- a/media/module/libapexcodecs/Android.bp
+++ b/media/module/libapexcodecs/Android.bp
@@ -20,6 +20,11 @@
 
 cc_defaults {
     name: "libcom.android.media.swcodec.apexcodecs-defaults",
+
+    defaults: [
+        "libcodec2-internal-defaults",
+    ],
+
     header_libs: [
         "libbase_headers",
     ],
@@ -31,8 +36,14 @@
         "libnativewindow",
     ],
 
+    static_libs: [
+        "android.media.swcodec.flags-aconfig-cc",
+    ],
+
     export_include_dirs: ["include"],
 
+    local_include_dirs: ["private"],
+
     export_shared_lib_headers: [
         "libbase",
         "libnativewindow",
@@ -53,6 +64,8 @@
     name: "libcom.android.media.swcodec.apexcodecs-testing",
     defaults: ["libcom.android.media.swcodec.apexcodecs-defaults"],
 
+    srcs: ["tests/ApexCodecsStoreTestImpl.cpp"],
+
     visibility: [
         ":__subpackages__",
     ],
@@ -67,6 +80,8 @@
         "//frameworks/av/media/codec2/hal/client",
     ],
 
+    srcs: ["ApexCodecsStoreImpl.cpp"],
+
     min_sdk_version: "apex_inherit",
     version_script: "libcom.android.media.swcodec.apexcodecs.map.txt",
     stubs: {
diff --git a/media/module/libapexcodecs/ApexCodecs.cpp b/media/module/libapexcodecs/ApexCodecs.cpp
index 6701e38..8dec439 100644
--- a/media/module/libapexcodecs/ApexCodecs.cpp
+++ b/media/module/libapexcodecs/ApexCodecs.cpp
@@ -14,18 +14,89 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "ApexCodecs"
+// #define LOG_NDEBUG 0
+#include <android-base/logging.h>
+
 #include <new>
+#include <map>
+#include <vector>
+
+#include <C2ParamInternal.h>
+#include <android_media_swcodec_flags.h>
 
 #include <android-base/no_destructor.h>
 #include <apex/ApexCodecs.h>
+#include <apex/ApexCodecsImpl.h>
 #include <apex/ApexCodecsParam.h>
 
 // TODO: remove when we have real implementations
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wunused-parameter"
 
+using ::android::apexcodecs::ApexComponentIntf;
+using ::android::apexcodecs::ApexComponentStoreIntf;
+using ::android::base::ERROR;
+
+struct ApexCodec_Component {
+    explicit ApexCodec_Component(std::unique_ptr<ApexComponentIntf> &&comp)
+        : mComponent(std::move(comp)) {
+    }
+
+    ApexCodec_Status start() {
+        return mComponent->start();
+    }
+
+    ApexCodec_Status flush() {
+        return mComponent->flush();
+    }
+
+    ApexCodec_Status reset() {
+        return mComponent->reset();
+    }
+
+private:
+    std::unique_ptr<ApexComponentIntf> mComponent;
+};
+
 struct ApexCodec_ComponentStore {
-    ApexCodec_ComponentStore() = default;
+    ApexCodec_ComponentStore() : mStore((ApexComponentStoreIntf *)GetApexComponentStore()) {
+        if (mStore == nullptr) {
+            return;
+        }
+        mC2Traits = mStore->listComponents();
+        mTraits.reserve(mC2Traits.size());
+        for (const std::shared_ptr<const C2Component::Traits> &trait : mC2Traits) {
+            mTraits.push_back(ApexCodec_ComponentTraits{
+                trait->name.c_str(),                // name
+                trait->mediaType.c_str(),           // mediaType
+                (ApexCodec_Kind)trait->kind,        // kind
+                (ApexCodec_Domain)trait->domain,    // domain
+            });
+        }
+    }
+
+    ApexCodec_ComponentTraits *getTraits(size_t index) {
+        if (mStore == nullptr) {
+            return nullptr;
+        }
+        if (index < mTraits.size()) {
+            return mTraits.data() + index;
+        } else {
+            return nullptr;
+        }
+    }
+
+    std::unique_ptr<ApexComponentIntf> createComponent(const char *name) {
+        if (mStore == nullptr) {
+            return nullptr;
+        }
+        return mStore->createComponent(name);
+    }
+private:
+    ApexComponentStoreIntf *mStore;
+    std::vector<std::shared_ptr<const C2Component::Traits>> mC2Traits;
+    std::vector<ApexCodec_ComponentTraits> mTraits;
 };
 
 ApexCodec_ComponentStore *ApexCodec_GetComponentStore() {
@@ -35,27 +106,61 @@
 
 ApexCodec_ComponentTraits *ApexCodec_Traits_get(
         ApexCodec_ComponentStore *store, size_t index) {
-    return nullptr;
+    if (!android::media::swcodec::flags::apexcodecs_base()) {
+        return nullptr;
+    }
+    return store->getTraits(index);
 }
 
 ApexCodec_Status ApexCodec_Component_create(
         ApexCodec_ComponentStore *store, const char *name, ApexCodec_Component **comp) {
+    if (!android::media::swcodec::flags::apexcodecs_base()) {
+        return APEXCODEC_STATUS_NOT_FOUND;
+    }
+    if (store == nullptr) {
+        LOG(ERROR) << "ApexCodec_Component_create: store is nullptr";
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    if (name == nullptr) {
+        LOG(ERROR) << "ApexCodec_Component_create: name is nullptr";
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    if (comp == nullptr) {
+        LOG(ERROR) << "ApexCodec_Component_create: comp is nullptr";
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
     *comp = nullptr;
-    return APEXCODEC_STATUS_NOT_FOUND;
+    std::unique_ptr<ApexComponentIntf> compIntf = store->createComponent(name);
+    if (compIntf == nullptr) {
+        return APEXCODEC_STATUS_NOT_FOUND;
+    }
+    *comp = new ApexCodec_Component(std::move(compIntf));
+    return APEXCODEC_STATUS_OK;
 }
 
-void ApexCodec_Component_destroy(ApexCodec_Component *comp) {}
+void ApexCodec_Component_destroy(ApexCodec_Component *comp) {
+    delete comp;
+}
 
 ApexCodec_Status ApexCodec_Component_start(ApexCodec_Component *comp) {
-    return APEXCODEC_STATUS_OMITTED;
+    if (comp == nullptr) {
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    return comp->start();
 }
 
 ApexCodec_Status ApexCodec_Component_flush(ApexCodec_Component *comp) {
-    return APEXCODEC_STATUS_OMITTED;
+    if (comp == nullptr) {
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    return comp->flush();
 }
 
 ApexCodec_Status ApexCodec_Component_reset(ApexCodec_Component *comp) {
-    return APEXCODEC_STATUS_OMITTED;
+    if (comp == nullptr) {
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    return comp->reset();
 }
 
 ApexCodec_Configurable *ApexCodec_Component_getConfigurable(
@@ -63,16 +168,148 @@
     return nullptr;
 }
 
+struct ApexCodec_Buffer {
+public:
+    ApexCodec_Buffer()
+          : mType(APEXCODEC_BUFFER_TYPE_EMPTY) {
+    }
+
+    ~ApexCodec_Buffer() {
+    }
+
+    void clear() {
+        mType = APEXCODEC_BUFFER_TYPE_EMPTY;
+        mBufferInfo.reset();
+        mLinearBuffer = {};
+        mGraphicBuffer = nullptr;
+        mConfigUpdates.reset();
+        mOwnedConfigUpdates.reset();
+    }
+
+    ApexCodec_BufferType getType() const {
+        return mType;
+    }
+
+    void setBufferInfo(ApexCodec_BufferFlags flags, uint64_t frameIndex, uint64_t timestampUs) {
+        mBufferInfo.emplace(BufferInfo{flags, frameIndex, timestampUs});
+    }
+
+    ApexCodec_Status setLinearBuffer(const ApexCodec_LinearBuffer *linearBuffer) {
+        if (mType != APEXCODEC_BUFFER_TYPE_EMPTY) {
+            return APEXCODEC_STATUS_BAD_STATE;
+        }
+        mType = APEXCODEC_BUFFER_TYPE_LINEAR;
+        if (linearBuffer == nullptr) {
+            mLinearBuffer.data = nullptr;
+            mLinearBuffer.size = 0;
+        } else {
+            mLinearBuffer = *linearBuffer;
+        }
+        return APEXCODEC_STATUS_OK;
+    }
+
+    ApexCodec_Status setGraphicBuffer(AHardwareBuffer *graphicBuffer) {
+        if (mType != APEXCODEC_BUFFER_TYPE_EMPTY) {
+            return APEXCODEC_STATUS_BAD_STATE;
+        }
+        mType = APEXCODEC_BUFFER_TYPE_GRAPHIC;
+        mGraphicBuffer = graphicBuffer;
+        return APEXCODEC_STATUS_OK;
+    }
+
+    ApexCodec_Status setConfigUpdates(const ApexCodec_LinearBuffer *configUpdates) {
+        if (configUpdates == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        if (mConfigUpdates.has_value()) {
+            return APEXCODEC_STATUS_BAD_STATE;
+        }
+        mOwnedConfigUpdates.reset();
+        mConfigUpdates.emplace(*configUpdates);
+        return APEXCODEC_STATUS_OK;
+    }
+
+    ApexCodec_Status getBufferInfo(
+            ApexCodec_BufferFlags *outFlags,
+            uint64_t *outFrameIndex,
+            uint64_t *outTimestampUs) const {
+        if (!mBufferInfo.has_value()) {
+            return APEXCODEC_STATUS_BAD_STATE;
+        }
+        *outFlags = mBufferInfo->flags;
+        *outFrameIndex = mBufferInfo->frameIndex;
+        *outTimestampUs = mBufferInfo->timestampUs;
+        return APEXCODEC_STATUS_OK;
+    }
+
+    ApexCodec_Status getLinearBuffer(ApexCodec_LinearBuffer *outLinearBuffer) const {
+        if (mType != APEXCODEC_BUFFER_TYPE_LINEAR) {
+            return APEXCODEC_STATUS_BAD_STATE;
+        }
+        *outLinearBuffer = mLinearBuffer;
+        return APEXCODEC_STATUS_OK;
+    }
+
+    ApexCodec_Status getGraphicBuffer(AHardwareBuffer **outGraphicBuffer) const {
+        if (mType != APEXCODEC_BUFFER_TYPE_GRAPHIC) {
+            return APEXCODEC_STATUS_BAD_STATE;
+        }
+        *outGraphicBuffer = mGraphicBuffer;
+        return APEXCODEC_STATUS_OK;
+    }
+
+    ApexCodec_Status getConfigUpdates(
+            ApexCodec_LinearBuffer *outConfigUpdates,
+            bool *outOwnedByClient) const {
+        if (!mConfigUpdates.has_value()) {
+            return APEXCODEC_STATUS_NOT_FOUND;
+        }
+        *outConfigUpdates = mConfigUpdates.value();
+        *outOwnedByClient = mOwnedConfigUpdates.has_value();
+        return APEXCODEC_STATUS_OK;
+    }
+
+    void setOwnedConfigUpdates(std::vector<uint8_t> &&configUpdates) {
+        mOwnedConfigUpdates = std::move(configUpdates);
+        mConfigUpdates.emplace(
+                ApexCodec_LinearBuffer{ configUpdates.data(), configUpdates.size() });
+    }
+
+private:
+    struct BufferInfo {
+        ApexCodec_BufferFlags flags;
+        uint64_t frameIndex;
+        uint64_t timestampUs;
+    };
+
+    ApexCodec_BufferType mType;
+    std::optional<BufferInfo> mBufferInfo;
+    ApexCodec_LinearBuffer mLinearBuffer;
+    AHardwareBuffer *mGraphicBuffer;
+    std::optional<ApexCodec_LinearBuffer> mConfigUpdates;
+    std::optional<std::vector<uint8_t>> mOwnedConfigUpdates;
+};
+
 ApexCodec_Buffer *ApexCodec_Buffer_create() {
-    return nullptr;
+    return new ApexCodec_Buffer;
 }
 
-void ApexCodec_Buffer_destroy(ApexCodec_Buffer *buffer) {}
+void ApexCodec_Buffer_destroy(ApexCodec_Buffer *buffer) {
+    delete buffer;
+}
 
-void ApexCodec_Buffer_clear(ApexCodec_Buffer *buffer) {}
+void ApexCodec_Buffer_clear(ApexCodec_Buffer *buffer) {
+    if (buffer == nullptr) {
+        return;
+    }
+    buffer->clear();
+}
 
 ApexCodec_BufferType ApexCodec_Buffer_getType(ApexCodec_Buffer *buffer) {
-    return APEXCODEC_BUFFER_TYPE_EMPTY;
+    if (buffer == nullptr) {
+        return APEXCODEC_BUFFER_TYPE_EMPTY;
+    }
+    return buffer->getType();
 }
 
 void ApexCodec_Buffer_setBufferInfo(
@@ -80,24 +317,37 @@
         ApexCodec_BufferFlags flags,
         uint64_t frameIndex,
         uint64_t timestampUs) {
+    if (buffer == nullptr) {
+        return;
+    }
+    buffer->setBufferInfo(flags, frameIndex, timestampUs);
 }
 
 ApexCodec_Status ApexCodec_Buffer_setLinearBuffer(
         ApexCodec_Buffer *buffer,
         const ApexCodec_LinearBuffer *linearBuffer) {
-    return APEXCODEC_STATUS_OMITTED;
+    if (buffer == nullptr) {
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    return buffer->setLinearBuffer(linearBuffer);
 }
 
 ApexCodec_Status ApexCodec_Buffer_setGraphicBuffer(
         ApexCodec_Buffer *buffer,
         AHardwareBuffer *graphicBuffer) {
-    return APEXCODEC_STATUS_OMITTED;
+    if (buffer == nullptr) {
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    return buffer->setGraphicBuffer(graphicBuffer);
 }
 
 ApexCodec_Status ApexCodec_Buffer_setConfigUpdates(
         ApexCodec_Buffer *buffer,
         const ApexCodec_LinearBuffer *configUpdates) {
-    return APEXCODEC_STATUS_OMITTED;
+    if (buffer == nullptr) {
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    return buffer->setConfigUpdates(configUpdates);
 }
 
 ApexCodec_Status ApexCodec_Buffer_getBufferInfo(
@@ -105,38 +355,274 @@
         ApexCodec_BufferFlags *outFlags,
         uint64_t *outFrameIndex,
         uint64_t *outTimestampUs) {
-    return APEXCODEC_STATUS_OMITTED;
+    if (buffer == nullptr) {
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    return buffer->getBufferInfo(outFlags, outFrameIndex, outTimestampUs);
 }
 
 ApexCodec_Status ApexCodec_Buffer_getLinearBuffer(
         ApexCodec_Buffer *buffer,
         ApexCodec_LinearBuffer *outLinearBuffer) {
-    return APEXCODEC_STATUS_OMITTED;
+    if (buffer == nullptr) {
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    return buffer->getLinearBuffer(outLinearBuffer);
 }
 
 ApexCodec_Status ApexCodec_Buffer_getGraphicBuffer(
         ApexCodec_Buffer *buffer,
         AHardwareBuffer **outGraphicBuffer) {
-    return APEXCODEC_STATUS_OMITTED;
+    if (buffer == nullptr) {
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    return buffer->getGraphicBuffer(outGraphicBuffer);
 }
 
 ApexCodec_Status ApexCodec_Buffer_getConfigUpdates(
         ApexCodec_Buffer *buffer,
         ApexCodec_LinearBuffer *outConfigUpdates,
         bool *outOwnedByClient) {
-    return APEXCODEC_STATUS_OMITTED;
+    if (buffer == nullptr) {
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    return buffer->getConfigUpdates(outConfigUpdates, outOwnedByClient);
 }
 
+struct ApexCodec_SupportedValues {
+public:
+    ApexCodec_SupportedValues(
+            const C2FieldSupportedValues &supportedValues,
+            const C2Value::type_t &numberType) {
+        mType = (ApexCodec_SupportedValuesType)supportedValues.type;
+        mNumberType = (ApexCodec_SupportedValuesNumberType)numberType;
+        switch (supportedValues.type) {
+            case C2FieldSupportedValues::RANGE: {
+                mValues.insert(mValues.end(), 5, ApexCodec_Value{});
+                ToApexCodecValue(supportedValues.range.min,   numberType, &mValues[0]);
+                ToApexCodecValue(supportedValues.range.max,   numberType, &mValues[1]);
+                ToApexCodecValue(supportedValues.range.step,  numberType, &mValues[2]);
+                ToApexCodecValue(supportedValues.range.num,   numberType, &mValues[3]);
+                ToApexCodecValue(supportedValues.range.denom, numberType, &mValues[4]);
+                break;
+            }
+            case C2FieldSupportedValues::VALUES:
+            case C2FieldSupportedValues::FLAGS: {
+                for (size_t i = 0; i < supportedValues.values.size(); ++i) {
+                    mValues.emplace_back();
+                    ToApexCodecValue(supportedValues.values[i], numberType, &mValues[i]);
+                }
+                break;
+            }
+            default:
+                // Unrecognized type; initialize as empty.
+                mType = APEXCODEC_SUPPORTED_VALUES_EMPTY;
+                break;
+        }
+    }
+
+    ~ApexCodec_SupportedValues() {
+    }
+
+    ApexCodec_Status getTypeAndValues(
+            ApexCodec_SupportedValuesType *type,
+            ApexCodec_SupportedValuesNumberType *numberType,
+            ApexCodec_Value **values,
+            uint32_t *numValues) {
+        if (type == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        if (numberType == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        if (values == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        if (numValues == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        *type = mType;
+        *numberType = mNumberType;
+        switch (mType) {
+            case APEXCODEC_SUPPORTED_VALUES_EMPTY: {
+                *values = nullptr;
+                *numValues = 0;
+                break;
+            }
+            case APEXCODEC_SUPPORTED_VALUES_RANGE:
+            case APEXCODEC_SUPPORTED_VALUES_VALUES:
+            case APEXCODEC_SUPPORTED_VALUES_FLAGS: {
+                if (mValues.empty()) {
+                    return APEXCODEC_STATUS_BAD_STATE;
+                }
+                *values = mValues.data();
+                *numValues = mValues.size();
+                break;
+            }
+            default:
+                return APEXCODEC_STATUS_BAD_STATE;
+        }
+        return APEXCODEC_STATUS_OK;
+    }
+
+    static bool ToApexCodecValue(
+            const C2Value::Primitive &value,
+            const C2Value::type_t &type,
+            ApexCodec_Value *outValue) {
+        switch (type) {
+            case C2Value::NO_INIT:
+                return false;
+            case C2Value::INT32:
+                outValue->i32 = value.i32;
+                return true;
+            case C2Value::UINT32:
+                outValue->u32 = value.u32;
+                return true;
+            case C2Value::INT64:
+                outValue->i64 = value.i64;
+                return true;
+            case C2Value::UINT64:
+                outValue->u64 = value.u64;
+                return true;
+            case C2Value::FLOAT:
+                outValue->f = value.fp;
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    static C2Value::type_t GetFieldType(
+            const std::shared_ptr<C2ParamReflector> &reflector,
+            const C2ParamField& field) {
+        std::unique_ptr<C2StructDescriptor> desc = reflector->describe(
+                _C2ParamInspector::GetIndex(field));
+
+        for (const C2FieldDescriptor &fieldDesc : *desc) {
+            if (_C2ParamInspector::GetOffset(fieldDesc) == _C2ParamInspector::GetOffset(field)) {
+                if (_C2ParamInspector::GetSize(fieldDesc) != _C2ParamInspector::GetSize(field)) {
+                    // Size doesn't match.
+                    return C2Value::NO_INIT;
+                }
+                switch (fieldDesc.type()) {
+                    case C2FieldDescriptor::INT32:
+                    case C2FieldDescriptor::UINT32:
+                    case C2FieldDescriptor::INT64:
+                    case C2FieldDescriptor::UINT64:
+                    case C2FieldDescriptor::FLOAT:
+                        return (C2Value::type_t)fieldDesc.type();
+                    default:
+                        // Unrecognized type.
+                        return C2Value::NO_INIT;
+                }
+            }
+        }
+        return C2Value::NO_INIT;
+    }
+
+private:
+    ApexCodec_SupportedValuesType mType;
+    ApexCodec_SupportedValuesNumberType mNumberType;
+    std::vector<ApexCodec_Value> mValues;
+};
+
 ApexCodec_Status ApexCodec_SupportedValues_getTypeAndValues(
         ApexCodec_SupportedValues *supportedValues,
         ApexCodec_SupportedValuesType *type,
         ApexCodec_SupportedValuesNumberType *numberType,
         ApexCodec_Value **values,
         uint32_t *numValues) {
-    return APEXCODEC_STATUS_OMITTED;
+    if (supportedValues == nullptr) {
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    return supportedValues->getTypeAndValues(type, numberType, values, numValues);
 }
 
-void ApexCodec_SupportedValues_destroy(ApexCodec_SupportedValues *values) {}
+void ApexCodec_SupportedValues_destroy(ApexCodec_SupportedValues *values) {
+    delete values;
+}
+
+struct ApexCodec_SettingResults {
+public:
+    explicit ApexCodec_SettingResults(
+            const std::shared_ptr<C2ParamReflector> &reflector,
+            const std::vector<C2SettingResult> &results) : mReflector(reflector) {
+        for (const C2SettingResult &c2Result : results) {
+            mResults.emplace_back();
+            Entry &entry = mResults.back();
+            entry.failure = (ApexCodec_SettingResultFailure)c2Result.failure;
+            entry.field.index = _C2ParamInspector::GetIndex(c2Result.field.paramOrField);
+            entry.field.offset = _C2ParamInspector::GetOffset(c2Result.field.paramOrField);
+            entry.field.size = _C2ParamInspector::GetSize(c2Result.field.paramOrField);
+            if (c2Result.field.values) {
+                entry.fieldValues = std::make_unique<ApexCodec_SupportedValues>(
+                        *c2Result.field.values,
+                        ApexCodec_SupportedValues::GetFieldType(mReflector,
+                                                                c2Result.field.paramOrField));
+                entry.field.values = entry.fieldValues.get();
+            } else {
+                entry.field.values = nullptr;
+            }
+            for (const C2ParamFieldValues &c2Conflict : c2Result.conflicts) {
+                entry.conflicts.emplace_back();
+                ApexCodec_ParamFieldValues &conflict = entry.conflicts.back();
+                conflict.index = _C2ParamInspector::GetIndex(c2Conflict.paramOrField);
+                conflict.offset = _C2ParamInspector::GetOffset(c2Conflict.paramOrField);
+                conflict.size = _C2ParamInspector::GetSize(c2Conflict.paramOrField);
+                if (c2Conflict.values) {
+                    entry.conflictValues.emplace_back(std::make_unique<ApexCodec_SupportedValues>(
+                            *c2Conflict.values,
+                            ApexCodec_SupportedValues::GetFieldType(mReflector,
+                                                                    c2Conflict.paramOrField)));
+                    conflict.values = entry.conflictValues.back().get();
+                } else {
+                    conflict.values = nullptr;
+                }
+            }
+        }
+    }
+
+    ~ApexCodec_SettingResults() {
+    }
+
+    ApexCodec_Status getResultAtIndex(
+            size_t index,
+            ApexCodec_SettingResultFailure *failure,
+            ApexCodec_ParamFieldValues *field,
+            ApexCodec_ParamFieldValues **conflicts,
+            size_t *numConflicts) {
+        if (failure == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        if (field == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        if (conflicts == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        if (numConflicts == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        if (index >= mResults.size()) {
+            return APEXCODEC_STATUS_NOT_FOUND;
+        }
+        *failure = mResults[index].failure;
+        *field = mResults[index].field;
+        *conflicts = mResults[index].conflicts.data();
+        *numConflicts = mResults[index].conflicts.size();
+        return APEXCODEC_STATUS_OK;
+    }
+private:
+    std::shared_ptr<C2ParamReflector> mReflector;
+    struct Entry {
+        ApexCodec_SettingResultFailure failure;
+        ApexCodec_ParamFieldValues field;
+        std::vector<ApexCodec_ParamFieldValues> conflicts;
+        std::unique_ptr<ApexCodec_SupportedValues> fieldValues;
+        std::vector<std::unique_ptr<ApexCodec_SupportedValues>> conflictValues;
+    };
+    std::vector<Entry> mResults;
+};
 
 ApexCodec_Status ApexCodec_SettingResults_getResultAtIndex(
         ApexCodec_SettingResults *results,
@@ -145,10 +631,15 @@
         ApexCodec_ParamFieldValues *field,
         ApexCodec_ParamFieldValues **conflicts,
         size_t *numConflicts) {
-    return APEXCODEC_STATUS_OMITTED;
+    if (results == nullptr) {
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    return results->getResultAtIndex(index, failure, field, conflicts, numConflicts);
 }
 
-void ApexCodec_SettingResults_destroy(ApexCodec_SettingResults *results) {}
+void ApexCodec_SettingResults_destroy(ApexCodec_SettingResults *results) {
+    delete results;
+}
 
 ApexCodec_Status ApexCodec_Component_process(
         ApexCodec_Component *comp,
@@ -175,11 +666,90 @@
     return APEXCODEC_STATUS_OMITTED;
 }
 
+struct ApexCodec_ParamDescriptors {
+public:
+    explicit ApexCodec_ParamDescriptors(
+            const std::vector<std::shared_ptr<C2ParamDescriptor>> &paramDescriptors) {
+        for (const std::shared_ptr<C2ParamDescriptor> &c2Descriptor : paramDescriptors) {
+            if (!c2Descriptor) {
+                continue;
+            }
+            uint32_t index = c2Descriptor->index();
+            Entry &entry = mDescriptors[index];
+            entry.index = index;
+            entry.attr = (ApexCodec_ParamAttribute)_C2ParamInspector::GetAttrib(*c2Descriptor);
+            entry.name = c2Descriptor->name();
+            for (const C2Param::Index &dependency : c2Descriptor->dependencies()) {
+                entry.dependencies.emplace_back((uint32_t)dependency);
+            }
+            mIndices.push_back(entry.index);
+        }
+    }
+
+    ~ApexCodec_ParamDescriptors() {
+    }
+
+    ApexCodec_Status getIndices(uint32_t **indices, size_t *numIndices) {
+        if (indices == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        if (numIndices == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        *indices = mIndices.data();
+        *numIndices = mIndices.size();
+        return APEXCODEC_STATUS_OK;
+    }
+
+    ApexCodec_Status getDescriptor(
+            uint32_t index,
+            ApexCodec_ParamAttribute *attr,
+            const char **name,
+            uint32_t **dependencies,
+            size_t *numDependencies) {
+        if (attr == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        if (name == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        if (dependencies == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        if (numDependencies == nullptr) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        auto it = mDescriptors.find(index);
+        if (it == mDescriptors.end()) {
+            return APEXCODEC_STATUS_BAD_VALUE;
+        }
+        const Entry &entry = it->second;
+        *attr = entry.attr;
+        *name = entry.name.c_str();
+        *dependencies = const_cast<uint32_t *>(entry.dependencies.data());
+        *numDependencies = entry.dependencies.size();
+        return APEXCODEC_STATUS_OK;
+    }
+
+private:
+    struct Entry {
+        uint32_t index;
+        ApexCodec_ParamAttribute attr;
+        C2String name;
+        std::vector<uint32_t> dependencies;
+    };
+    std::map<uint32_t, Entry> mDescriptors;
+    std::vector<uint32_t> mIndices;
+};
+
 ApexCodec_Status ApexCodec_ParamDescriptors_getIndices(
         ApexCodec_ParamDescriptors *descriptors,
         uint32_t **indices,
         size_t *numIndices) {
-    return APEXCODEC_STATUS_OMITTED;
+    if (descriptors == nullptr) {
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    return descriptors->getIndices(indices, numIndices);
 }
 
 ApexCodec_Status ApexCodec_ParamDescriptors_getDescriptor(
@@ -189,10 +759,14 @@
         const char **name,
         uint32_t **dependencies,
         size_t *numDependencies) {
-    return APEXCODEC_STATUS_OMITTED;
+    if (descriptors == nullptr) {
+        return APEXCODEC_STATUS_BAD_VALUE;
+    }
+    return descriptors->getDescriptor(index, attr, name, dependencies, numDependencies);
 }
 
 void ApexCodec_ParamDescriptors_destroy(ApexCodec_ParamDescriptors *descriptors) {
+    delete descriptors;
 }
 
 ApexCodec_Status ApexCodec_Configurable_querySupportedParams(
diff --git a/media/module/libapexcodecs/ApexCodecsImpl.cpp b/media/module/libapexcodecs/ApexCodecsImpl.cpp
new file mode 100644
index 0000000..a737c57
--- /dev/null
+++ b/media/module/libapexcodecs/ApexCodecsImpl.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/no_destructor.h>
+#include <apex/ApexCodecsImpl.h>
+
+namespace android::apexcodecs {
+
+class ApexComponentImpl : public ApexComponentIntf {
+public:
+    ApexComponentImpl(const std::shared_ptr<C2Component> &comp) : mComponent(comp) {}
+    virtual ApexCodec_Status start() = 0;
+    virtual ApexCodec_Status flush() = 0;
+    virtual ApexCodec_Status reset() = 0;
+    virtual ApexCodec_Configurable *getConfigurable() = 0;
+    virtual ApexCodec_Status process(
+            const ApexCodec_Buffer *input,
+            ApexCodec_Buffer *output,
+            size_t *consumed,
+            size_t *produced) = 0;
+private:
+    std::shared_ptr<C2Component> mComponent;
+};
+
+}  // namespace android::apexcodecs
\ No newline at end of file
diff --git a/media/module/libapexcodecs/ApexCodecsStoreImpl.cpp b/media/module/libapexcodecs/ApexCodecsStoreImpl.cpp
new file mode 100644
index 0000000..3beb510
--- /dev/null
+++ b/media/module/libapexcodecs/ApexCodecsStoreImpl.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/no_destructor.h>
+#include <apex/ApexCodecsImpl.h>
+
+namespace android::apexcodecs {
+
+class ApexComponentStoreImpl : public ApexComponentStoreIntf {
+public:
+    ApexComponentStoreImpl() = default;
+
+    std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() const override {
+        return {};
+    }
+    virtual std::unique_ptr<ApexComponentIntf> createComponent(const char *name [[maybe_unused]]) {
+        return nullptr;
+    }
+};
+
+}  // namespace android::apexcodecs
+
+extern "C" void *GetApexComponentStore() {
+    static ::android::base::NoDestructor<::android::apexcodecs::ApexComponentStoreImpl> sStore;
+    return sStore.get();
+}
\ No newline at end of file
diff --git a/media/module/libapexcodecs/TEST_MAPPING b/media/module/libapexcodecs/TEST_MAPPING
new file mode 100644
index 0000000..6ff6a24
--- /dev/null
+++ b/media/module/libapexcodecs/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "postsubmit": [
+    {
+      "name": "libcom.android.media.swcodec.apexcodecs-tests"
+    }
+  ]
+}
diff --git a/media/module/libapexcodecs/include/apex/ApexCodecs.h b/media/module/libapexcodecs/include/apex/ApexCodecs.h
index 96bd2da..8dfee97 100644
--- a/media/module/libapexcodecs/include/apex/ApexCodecs.h
+++ b/media/module/libapexcodecs/include/apex/ApexCodecs.h
@@ -455,7 +455,7 @@
  *                          input buffer's frame index.
  * \param outTimestampUs    the timestamp for the buffer in microseconds
  * \return  APEXCODEC_STATUS_OK         if successful
- * \return  APEXCODEC_STATUS_BAD_STATE  if |buffer| is empty
+ * \return  APEXCODEC_STATUS_BAD_STATE  if buffer info was never set
  */
 ApexCodec_Status ApexCodec_Buffer_getBufferInfo(
         ApexCodec_Buffer *_Nonnull buffer,
diff --git a/media/module/libapexcodecs/private/apex/ApexCodecsImpl.h b/media/module/libapexcodecs/private/apex/ApexCodecsImpl.h
new file mode 100644
index 0000000..f01af87
--- /dev/null
+++ b/media/module/libapexcodecs/private/apex/ApexCodecsImpl.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <C2Component.h>
+
+#include <apex/ApexCodecs.h>
+#include <apex/ApexCodecsParam.h>
+
+namespace android::apexcodecs {
+
+class ApexComponentIntf {
+public:
+    virtual ~ApexComponentIntf() = default;
+    virtual ApexCodec_Status start() = 0;
+    virtual ApexCodec_Status flush() = 0;
+    virtual ApexCodec_Status reset() = 0;
+    virtual ApexCodec_Configurable *getConfigurable() = 0;
+    virtual ApexCodec_Status process(
+            const ApexCodec_Buffer *input,
+            ApexCodec_Buffer *output,
+            size_t *consumed,
+            size_t *produced) = 0;
+};
+
+class ApexComponentStoreIntf {
+public:
+    virtual ~ApexComponentStoreIntf() = default;
+    virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() const = 0;
+    virtual std::unique_ptr<ApexComponentIntf> createComponent(const char *name) = 0;
+};
+
+}  // namespace android
+
+__BEGIN_DECLS
+
+void *GetApexComponentStore();
+
+__END_DECLS
\ No newline at end of file
diff --git a/media/module/libapexcodecs/tests/Android.bp b/media/module/libapexcodecs/tests/Android.bp
index d13a577..1d444ad 100644
--- a/media/module/libapexcodecs/tests/Android.bp
+++ b/media/module/libapexcodecs/tests/Android.bp
@@ -22,9 +22,16 @@
 cc_test {
     name: "libcom.android.media.swcodec.apexcodecs-tests",
     shared_libs: [
-        "libcom.android.media.swcodec.apexcodecs-testing",
+        "libbinder_ndk",
         "libcodec2",
+        "libnativewindow",
+    ],
+
+    static_libs: [
+        "libcom.android.media.swcodec.apexcodecs-testing",
     ],
 
     srcs: ["ApexCodecsTest.cpp"],
+
+    test_suites: ["general-tests"],
 }
diff --git a/media/module/libapexcodecs/tests/ApexCodecsStoreTestImpl.cpp b/media/module/libapexcodecs/tests/ApexCodecsStoreTestImpl.cpp
new file mode 100644
index 0000000..fb0e98e
--- /dev/null
+++ b/media/module/libapexcodecs/tests/ApexCodecsStoreTestImpl.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/no_destructor.h>
+#include <apex/ApexCodecsImpl.h>
+
+namespace android::apexcodecs::test {
+
+// This is a test implementation of ApexComponentStoreIntf.
+// It may contain different set of components than the APEX for testing purpose.
+class ApexComponentStoreImpl : public ApexComponentStoreIntf {
+public:
+    ApexComponentStoreImpl() = default;
+
+    std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() const override {
+        return {};
+    }
+    virtual std::unique_ptr<ApexComponentIntf> createComponent(const char *name [[maybe_unused]]) {
+        return nullptr;
+    }
+};
+
+}  // namespace android::apexcodecs::test
+
+extern "C" void *GetApexComponentStore() {
+    using ::android::apexcodecs::test::ApexComponentStoreImpl;
+    static ::android::base::NoDestructor<ApexComponentStoreImpl> sStore;
+    return sStore.get();
+}
\ No newline at end of file
diff --git a/media/module/libapexcodecs/tests/ApexCodecsTest.cpp b/media/module/libapexcodecs/tests/ApexCodecsTest.cpp
index f551ce7..3338aff 100644
--- a/media/module/libapexcodecs/tests/ApexCodecsTest.cpp
+++ b/media/module/libapexcodecs/tests/ApexCodecsTest.cpp
@@ -1,8 +1,10 @@
 #include <C2.h>
 #include <C2Component.h>
 
+#include <android/hardware_buffer_aidl.h>
 #include <apex/ApexCodecs.h>
 #include <apex/ApexCodecsParam.h>
+#include <gtest/gtest.h>
 
 // static_asserts for enum values match
 static_assert((uint32_t)APEXCODEC_STATUS_OK        == (uint32_t)C2_OK);
@@ -98,4 +100,169 @@
 static_assert((uint32_t)APEXCODEC_PARAM_IS_READ_ONLY  == (uint32_t)C2ParamDescriptor::IS_READ_ONLY);
 static_assert((uint32_t)APEXCODEC_PARAM_IS_HIDDEN     == (uint32_t)C2ParamDescriptor::IS_HIDDEN);
 static_assert((uint32_t)APEXCODEC_PARAM_IS_INTERNAL   == (uint32_t)C2ParamDescriptor::IS_INTERNAL);
-static_assert((uint32_t)APEXCODEC_PARAM_IS_CONSTANT   == (uint32_t)C2ParamDescriptor::IS_CONST);
\ No newline at end of file
+static_assert((uint32_t)APEXCODEC_PARAM_IS_CONSTANT   == (uint32_t)C2ParamDescriptor::IS_CONST);
+
+using ::aidl::android::hardware::HardwareBuffer;
+
+class SpApexCodecBuffer {
+public:
+    SpApexCodecBuffer() {
+        mBuffer = ApexCodec_Buffer_create();
+    }
+
+    ~SpApexCodecBuffer() {
+        ApexCodec_Buffer_destroy(mBuffer);
+    }
+
+    ApexCodec_Buffer* get() const {
+        return mBuffer;
+    }
+
+private:
+    ApexCodec_Buffer* mBuffer;
+};
+
+TEST(ApexCodecsTest, BufferCreateDestroyTest) {
+    SpApexCodecBuffer buffer;
+    ASSERT_NE(buffer.get(), nullptr);
+}
+
+TEST(ApexCodecsTest, BufferInitialStateTest) {
+    SpApexCodecBuffer buffer;
+    ASSERT_NE(buffer.get(), nullptr);
+    ASSERT_EQ(ApexCodec_Buffer_getType(buffer.get()), APEXCODEC_BUFFER_TYPE_EMPTY);
+
+    ApexCodec_BufferFlags flags;
+    uint64_t frameIndex;
+    uint64_t timestampUs;
+    ASSERT_EQ(ApexCodec_Buffer_getBufferInfo(buffer.get(), &flags, &frameIndex, &timestampUs),
+              APEXCODEC_STATUS_BAD_STATE);
+
+    ApexCodec_LinearBuffer linearBuffer;
+    ASSERT_EQ(ApexCodec_Buffer_getLinearBuffer(buffer.get(), &linearBuffer),
+              APEXCODEC_STATUS_BAD_STATE);
+
+    AHardwareBuffer* graphicBuffer;
+    ASSERT_EQ(ApexCodec_Buffer_getGraphicBuffer(buffer.get(), &graphicBuffer),
+              APEXCODEC_STATUS_BAD_STATE);
+
+    ApexCodec_LinearBuffer configUpdates;
+    bool ownedByClient;
+    ASSERT_EQ(ApexCodec_Buffer_getConfigUpdates(buffer.get(), &configUpdates, &ownedByClient),
+              APEXCODEC_STATUS_NOT_FOUND);
+}
+
+TEST(ApexCodecsTest, BufferSetGetInfoTest) {
+    SpApexCodecBuffer buffer;
+    ASSERT_NE(buffer.get(), nullptr);
+
+    ApexCodec_Buffer_setBufferInfo(buffer.get(), APEXCODEC_FLAG_END_OF_STREAM, 123, 456);
+
+    ApexCodec_BufferFlags flags;
+    uint64_t frameIndex;
+    uint64_t timestampUs;
+    ASSERT_EQ(ApexCodec_Buffer_getBufferInfo(buffer.get(), &flags, &frameIndex, &timestampUs),
+              APEXCODEC_STATUS_OK);
+    ASSERT_EQ(flags, APEXCODEC_FLAG_END_OF_STREAM);
+    ASSERT_EQ(frameIndex, 123);
+    ASSERT_EQ(timestampUs, 456);
+}
+
+TEST(ApexCodecsTest, BufferSetGetLinearBufferTest) {
+    SpApexCodecBuffer buffer;
+    ASSERT_NE(buffer.get(), nullptr);
+
+    uint8_t data[10];
+    ApexCodec_LinearBuffer linearBuffer;
+    linearBuffer.data = data;
+    linearBuffer.size = 10;
+    ASSERT_EQ(ApexCodec_Buffer_setLinearBuffer(buffer.get(), &linearBuffer), APEXCODEC_STATUS_OK);
+    ASSERT_EQ(ApexCodec_Buffer_getType(buffer.get()), APEXCODEC_BUFFER_TYPE_LINEAR);
+    // Clear the data to ensure that the buffer owns the data.
+    linearBuffer.data = nullptr;
+    linearBuffer.size = 0;
+    ASSERT_EQ(ApexCodec_Buffer_getLinearBuffer(buffer.get(), &linearBuffer), APEXCODEC_STATUS_OK);
+    ASSERT_EQ(linearBuffer.data, data);
+    ASSERT_EQ(linearBuffer.size, 10);
+
+    ASSERT_EQ(ApexCodec_Buffer_setLinearBuffer(buffer.get(), &linearBuffer),
+              APEXCODEC_STATUS_BAD_STATE);
+}
+
+TEST(ApexCodecsTest, BufferSetGetGraphicBufferTest) {
+    SpApexCodecBuffer buffer;
+    ASSERT_NE(buffer.get(), nullptr);
+
+    HardwareBuffer hardwareBuffer;
+    AHardwareBuffer_Desc desc;
+    desc.width = 100;
+    desc.height = 100;
+    desc.layers = 1;
+    desc.format = AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420;
+    desc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+    AHardwareBuffer* graphicBuffer = nullptr;
+    AHardwareBuffer_allocate(&desc, &graphicBuffer);
+    hardwareBuffer.reset(graphicBuffer);
+    ASSERT_NE(graphicBuffer, nullptr);
+    ASSERT_EQ(ApexCodec_Buffer_setGraphicBuffer(buffer.get(), graphicBuffer), APEXCODEC_STATUS_OK);
+    ASSERT_EQ(ApexCodec_Buffer_getType(buffer.get()), APEXCODEC_BUFFER_TYPE_GRAPHIC);
+    graphicBuffer = nullptr;
+    ASSERT_EQ(ApexCodec_Buffer_getGraphicBuffer(buffer.get(), &graphicBuffer), APEXCODEC_STATUS_OK);
+    ASSERT_NE(graphicBuffer, nullptr);
+
+    ASSERT_EQ(ApexCodec_Buffer_setGraphicBuffer(buffer.get(), graphicBuffer),
+              APEXCODEC_STATUS_BAD_STATE);
+}
+
+TEST(ApexCodecsTest, BufferSetGetConfigUpdatesTest) {
+    SpApexCodecBuffer buffer;
+    ASSERT_NE(buffer.get(), nullptr);
+
+    uint8_t configData[20];
+    ApexCodec_LinearBuffer configUpdates;
+    configUpdates.data = configData;
+    configUpdates.size = 20;
+    ASSERT_EQ(ApexCodec_Buffer_setConfigUpdates(buffer.get(), &configUpdates), APEXCODEC_STATUS_OK);
+
+    bool ownedByClient;
+    ASSERT_EQ(ApexCodec_Buffer_getConfigUpdates(buffer.get(), &configUpdates, &ownedByClient),
+              APEXCODEC_STATUS_OK);
+    ASSERT_EQ(configUpdates.data, configData);
+    ASSERT_EQ(configUpdates.size, 20);
+    ASSERT_EQ(ownedByClient, false);
+
+    ASSERT_EQ(ApexCodec_Buffer_setConfigUpdates(buffer.get(), &configUpdates),
+              APEXCODEC_STATUS_BAD_STATE);
+}
+
+TEST(ApexCodecsTest, BufferClearTest) {
+    SpApexCodecBuffer buffer;
+    ASSERT_NE(buffer.get(), nullptr);
+
+    uint8_t data[10];
+    ApexCodec_LinearBuffer linearBuffer;
+    linearBuffer.data = data;
+    linearBuffer.size = 10;
+    ASSERT_EQ(ApexCodec_Buffer_setLinearBuffer(buffer.get(), &linearBuffer), APEXCODEC_STATUS_OK);
+
+    uint8_t configData[20];
+    ApexCodec_LinearBuffer configUpdates;
+    configUpdates.data = configData;
+    configUpdates.size = 20;
+    ASSERT_EQ(ApexCodec_Buffer_setConfigUpdates(buffer.get(), &configUpdates), APEXCODEC_STATUS_OK);
+
+    ApexCodec_Buffer_clear(buffer.get());
+    ASSERT_EQ(ApexCodec_Buffer_getType(buffer.get()), APEXCODEC_BUFFER_TYPE_EMPTY);
+
+    ApexCodec_BufferFlags flags;
+    uint64_t frameIndex;
+    uint64_t timestampUs;
+    ASSERT_EQ(ApexCodec_Buffer_getBufferInfo(buffer.get(), &flags, &frameIndex, &timestampUs),
+              APEXCODEC_STATUS_BAD_STATE);
+    ASSERT_EQ(ApexCodec_Buffer_getLinearBuffer(buffer.get(), &linearBuffer),
+              APEXCODEC_STATUS_BAD_STATE);
+    bool ownedByClient;
+
+    ASSERT_EQ(ApexCodec_Buffer_getConfigUpdates(buffer.get(), &configUpdates, &ownedByClient),
+              APEXCODEC_STATUS_NOT_FOUND);
+}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 49e1422c..1ce9b8e 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1147,7 +1147,9 @@
                                         audio_channel_mask_t channelMask,
                                         audio_output_flags_t flags,
                                         bool directOnly) {
-    sp<IOProfile> profile;
+    sp<IOProfile> directOnlyProfile = nullptr;
+    sp<IOProfile> compressOffloadProfile = nullptr;
+    sp<IOProfile> profile = nullptr;
     for (const auto& hwModule : hwModules) {
         for (const auto& curProfile : hwModule->getOutputProfiles()) {
              if (curProfile->getCompatibilityScore(devices,
@@ -1169,19 +1171,21 @@
                 return curProfile;
              }
 
-             // when searching for direct outputs, if several profiles are compatible, give priority
-             // to one with offload capability
-             if (profile != 0 &&
-                 ((curProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0)) {
-                continue;
-             }
              profile = curProfile;
-             if ((profile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
-                 break;
+             if ((flags == AUDIO_OUTPUT_FLAG_DIRECT) &&
+                 curProfile->getFlags() == AUDIO_OUTPUT_FLAG_DIRECT) {
+                 directOnlyProfile = curProfile;
+             }
+
+             if ((curProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+                 compressOffloadProfile = curProfile;
              }
         }
     }
-    return profile;
+
+    return directOnlyProfile ? directOnlyProfile
+                            : (compressOffloadProfile ? compressOffloadProfile : profile);
+
 }
 
 sp<IOProfile> AudioPolicyManager::getSpatializerOutputProfile(
diff --git a/services/audiopolicy/tests/resources/test_phone_apm_configuration.xml b/services/audiopolicy/tests/resources/test_phone_apm_configuration.xml
index efe1400..98299e6 100644
--- a/services/audiopolicy/tests/resources/test_phone_apm_configuration.xml
+++ b/services/audiopolicy/tests/resources/test_phone_apm_configuration.xml
@@ -43,6 +43,8 @@
                 </mixPort>
                 <mixPort name="compressed_offload" role="source"
                          flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD AUDIO_OUTPUT_FLAG_NON_BLOCKING AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD">
+                    <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
+                             samplingRates="48000 96000 384000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                     <profile name="" format="AUDIO_FORMAT_MP3"
                              samplingRates="8000 16000 24000 32000 44100 48000 96000"
                              channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/>
diff --git a/services/camera/virtualcamera/Android.bp b/services/camera/virtualcamera/Android.bp
index a39229a..c76bb1b 100644
--- a/services/camera/virtualcamera/Android.bp
+++ b/services/camera/virtualcamera/Android.bp
@@ -1,5 +1,5 @@
 package {
-    default_team: "trendy_team_xr_framework",
+    default_team: "trendy_team_virtual_device_framework",
     // See: http://go/android-license-faq
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
diff --git a/services/camera/virtualcamera/aidl/Android.bp b/services/camera/virtualcamera/aidl/Android.bp
index b3fe3ad..b3c0bce 100644
--- a/services/camera/virtualcamera/aidl/Android.bp
+++ b/services/camera/virtualcamera/aidl/Android.bp
@@ -1,5 +1,5 @@
 package {
-    default_team: "trendy_team_xr_framework",
+    default_team: "trendy_team_virtual_device_framework",
     // See: http://go/android-license-faq
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
diff --git a/services/camera/virtualcamera/flags/Android.bp b/services/camera/virtualcamera/flags/Android.bp
index 5fa8852..fc72e22 100644
--- a/services/camera/virtualcamera/flags/Android.bp
+++ b/services/camera/virtualcamera/flags/Android.bp
@@ -1,5 +1,5 @@
 package {
-    default_team: "trendy_team_xr_framework",
+    default_team: "trendy_team_virtual_device_framework",
 }
 
 soong_config_module_type {
diff --git a/services/camera/virtualcamera/fuzzer/Android.bp b/services/camera/virtualcamera/fuzzer/Android.bp
index 6a72167..6b8d9cb 100644
--- a/services/camera/virtualcamera/fuzzer/Android.bp
+++ b/services/camera/virtualcamera/fuzzer/Android.bp
@@ -16,7 +16,7 @@
  *
  *****************************************************************************/
 package {
-    default_team: "trendy_team_xr_framework",
+    default_team: "trendy_team_virtual_device_framework",
     // See: http://go/android-license-faq
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
diff --git a/services/camera/virtualcamera/tests/Android.bp b/services/camera/virtualcamera/tests/Android.bp
index 543cc10..f67f2b3 100644
--- a/services/camera/virtualcamera/tests/Android.bp
+++ b/services/camera/virtualcamera/tests/Android.bp
@@ -1,5 +1,5 @@
 package {
-    default_team: "trendy_team_xr_framework",
+    default_team: "trendy_team_virtual_device_framework",
     // See: http://go/android-license-faq
     default_applicable_licenses: ["Android-Apache-2.0"],
 }