Merge "Migrate from android::String isEmpty to empty" into main
diff --git a/camera/include/camera/StringUtils.h b/camera/include/camera/StringUtils.h
index 547750f..80c419f 100644
--- a/camera/include/camera/StringUtils.h
+++ b/camera/include/camera/StringUtils.h
@@ -17,8 +17,6 @@
 #ifndef ANDROID_SERVERS_CAMERA_STRINGUTILS_H
 #define ANDROID_SERVERS_CAMERA_STRINGUTILS_H
 
-#include <codecvt>
-#include <locale>
 #include <memory>
 #include <optional>
 #include <string>
@@ -65,8 +63,8 @@
     }
 
     inline std::string toStdString(const String16 &str) {
-        std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
-        return convert.to_bytes(str.c_str());
+        String8 str8(str);
+        return std::string(str8.c_str());
     }
 
     /**
@@ -74,8 +72,9 @@
      * len is the number of characters.
      */
     inline std::string toStdString(const char16_t *str, size_t len) {
-        std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
-        return convert.to_bytes(str, str + len);
+        String16 str16(str, len);
+        String8 str8(str16);
+        return std::string(str8.c_str());
     }
 } // namespace android
 
diff --git a/media/codec2/hal/aidl/Android.bp b/media/codec2/hal/aidl/Android.bp
index 3bc7548..b19f78c 100644
--- a/media/codec2/hal/aidl/Android.bp
+++ b/media/codec2/hal/aidl/Android.bp
@@ -8,6 +8,7 @@
     name: "libcodec2_aidl_client",
 
     srcs: [
+        "BufferTypes.cpp",
         "ParamTypes.cpp",
     ],
 
@@ -17,7 +18,9 @@
     ],
 
     shared_libs: [
+        "android.hardware.common-V2-ndk",
         "android.hardware.media.bufferpool@2.0",
+        "android.hardware.media.bufferpool2-V1-ndk",
         "android.hardware.media.c2-V1-ndk",
         "libbinder_ndk",
         "libbase",
@@ -27,9 +30,14 @@
         "libcutils",
         "liblog",
         "libnativewindow",
+        "libstagefright_aidl_bufferpool2",
         "libutils",
     ],
 
+    static_libs: [
+        "libaidlcommonsupport",
+    ],
+
     export_include_dirs: [
         "include",
     ],
diff --git a/media/codec2/hal/aidl/BufferTypes.cpp b/media/codec2/hal/aidl/BufferTypes.cpp
index 319ba62..1cd3555 100644
--- a/media/codec2/hal/aidl/BufferTypes.cpp
+++ b/media/codec2/hal/aidl/BufferTypes.cpp
@@ -15,10 +15,15 @@
  */
 
 //#define LOG_NDEBUG 0
-#define LOG_TAG "Codec2-types"
+#define LOG_TAG "Codec2-AIDL-BufferTypes"
 #include <android-base/logging.h>
 
-#include <codec2/hidl/1.0/types.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <aidl/android/hardware/media/bufferpool2/BufferStatusMessage.h>
+#include <bufferpool2/BufferPoolTypes.h>
+#include <codec2/aidl/BufferTypes.h>
+#include <codec2/common/BufferTypes.h>
+#include <cutils/native_handle.h>
 #include <media/stagefright/foundation/AUtils.h>
 
 #include <C2AllocatorIon.h>
@@ -28,1431 +33,42 @@
 #include <C2Component.h>
 #include <C2FenceFactory.h>
 #include <C2Param.h>
-#include <C2ParamInternal.h>
 #include <C2PlatformSupport.h>
 #include <C2Work.h>
-#include <util/C2ParamUtils.h>
 
 #include <algorithm>
 #include <functional>
 #include <iomanip>
 #include <unordered_map>
 
+#include "ParamTypes-specialization.h"
+
 namespace android {
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace utils {
 
-using ::android::hardware::Return;
-using ::android::hardware::media::bufferpool::BufferPoolData;
-using ::android::hardware::media::bufferpool::V2_0::BufferStatusMessage;
-using ::android::hardware::media::bufferpool::V2_0::ResultStatus;
-using ::android::hardware::media::bufferpool::V2_0::implementation::
-        ClientManager;
-using ::android::hardware::media::bufferpool::V2_0::implementation::
-        TransactionId;
+using ::aidl::android::hardware::media::bufferpool2::BufferPoolData;
+using ::aidl::android::hardware::media::bufferpool2::BufferStatusMessage;
+using ::aidl::android::hardware::media::bufferpool2::ResultStatus;
+using ::aidl::android::hardware::media::bufferpool2::implementation::BufferPoolStatus;
+using ::aidl::android::hardware::media::bufferpool2::implementation::ClientManager;
+using ::aidl::android::hardware::media::c2::BaseBlock;
+using ::aidl::android::hardware::media::c2::utils::BufferPoolTypes;
 
-const char* asString(Status status, const char* def) {
-    return asString(static_cast<c2_status_t>(status), def);
-}
+using AidlNativeHandle = ::aidl::android::hardware::common::NativeHandle;
 
-namespace /* unnamed */ {
-
-template <typename EnumClass>
-typename std::underlying_type<EnumClass>::type underlying_value(
-        EnumClass x) {
-    return static_cast<typename std::underlying_type<EnumClass>::type>(x);
-}
-
-template <typename Common, typename DstVector, typename SrcVector>
-void copyVector(DstVector* d, const SrcVector& s) {
-    static_assert(sizeof(Common) == sizeof(decltype((*d)[0])),
-            "DstVector's component size does not match Common");
-    static_assert(sizeof(Common) == sizeof(decltype(s[0])),
-            "SrcVector's component size does not match Common");
-    d->resize(s.size());
-    std::copy(
-            reinterpret_cast<const Common*>(&s[0]),
-            reinterpret_cast<const Common*>(&s[0] + s.size()),
-            reinterpret_cast<Common*>(&(*d)[0]));
-}
-
-// C2ParamField -> ParamField
-bool objcpy(ParamField *d, const C2ParamField &s) {
-    d->index = static_cast<ParamIndex>(_C2ParamInspector::GetIndex(s));
-    d->fieldId.offset = static_cast<uint32_t>(_C2ParamInspector::GetOffset(s));
-    d->fieldId.size = static_cast<uint32_t>(_C2ParamInspector::GetSize(s));
-    return true;
-}
-
-struct C2ParamFieldBuilder : public C2ParamField {
-    C2ParamFieldBuilder() : C2ParamField(
-            static_cast<C2Param::Index>(static_cast<uint32_t>(0)), 0, 0) {
-    }
-    // ParamField -> C2ParamField
-    C2ParamFieldBuilder(const ParamField& s) : C2ParamField(
-            static_cast<C2Param::Index>(static_cast<uint32_t>(s.index)),
-            static_cast<uint32_t>(s.fieldId.offset),
-            static_cast<uint32_t>(s.fieldId.size)) {
-    }
-};
-
-// C2WorkOrdinalStruct -> WorkOrdinal
-bool objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
-    d->frameIndex = static_cast<uint64_t>(s.frameIndex.peeku());
-    d->timestampUs = static_cast<uint64_t>(s.timestamp.peeku());
-    d->customOrdinal = static_cast<uint64_t>(s.customOrdinal.peeku());
-    return true;
-}
-
-// WorkOrdinal -> C2WorkOrdinalStruct
-bool objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
-    d->frameIndex = c2_cntr64_t(s.frameIndex);
-    d->timestamp = c2_cntr64_t(s.timestampUs);
-    d->customOrdinal = c2_cntr64_t(s.customOrdinal);
-    return true;
-}
-
-// C2FieldSupportedValues::range's type -> ValueRange
-bool objcpy(
-        ValueRange* d,
-        const decltype(C2FieldSupportedValues::range)& s) {
-    d->min = static_cast<PrimitiveValue>(s.min.u64);
-    d->max = static_cast<PrimitiveValue>(s.max.u64);
-    d->step = static_cast<PrimitiveValue>(s.step.u64);
-    d->num = static_cast<PrimitiveValue>(s.num.u64);
-    d->denom = static_cast<PrimitiveValue>(s.denom.u64);
-    return true;
-}
-
-// C2FieldSupportedValues -> FieldSupportedValues
-bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
-    switch (s.type) {
-    case C2FieldSupportedValues::EMPTY: {
-            d->empty(::android::hidl::safe_union::V1_0::Monostate{});
-            break;
-        }
-    case C2FieldSupportedValues::RANGE: {
-            ValueRange range{};
-            if (!objcpy(&range, s.range)) {
-                LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
-                d->range(range);
-                return false;
-            }
-            d->range(range);
-            break;
-        }
-    case C2FieldSupportedValues::VALUES: {
-            hidl_vec<PrimitiveValue> values;
-            copyVector<uint64_t>(&values, s.values);
-            d->values(values);
-            break;
-        }
-    case C2FieldSupportedValues::FLAGS: {
-            hidl_vec<PrimitiveValue> flags;
-            copyVector<uint64_t>(&flags, s.values);
-            d->flags(flags);
-            break;
-        }
-    default:
-        LOG(DEBUG) << "Unrecognized C2FieldSupportedValues::type_t "
-                   << "with underlying value " << underlying_value(s.type)
-                   << ".";
-        return false;
-    }
-    return true;
-}
-
-// ValueRange -> C2FieldSupportedValues::range's type
-bool objcpy(
-        decltype(C2FieldSupportedValues::range)* d,
-        const ValueRange& s) {
-    d->min.u64 = static_cast<uint64_t>(s.min);
-    d->max.u64 = static_cast<uint64_t>(s.max);
-    d->step.u64 = static_cast<uint64_t>(s.step);
-    d->num.u64 = static_cast<uint64_t>(s.num);
-    d->denom.u64 = static_cast<uint64_t>(s.denom);
-    return true;
-}
-
-// FieldSupportedValues -> C2FieldSupportedValues
-bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
-    switch (s.getDiscriminator()) {
-    case FieldSupportedValues::hidl_discriminator::empty: {
-            d->type = C2FieldSupportedValues::EMPTY;
-            break;
-        }
-    case FieldSupportedValues::hidl_discriminator::range: {
-            d->type = C2FieldSupportedValues::RANGE;
-            if (!objcpy(&d->range, s.range())) {
-                LOG(ERROR) << "Invalid FieldSupportedValues::range.";
-                return false;
-            }
-            d->values.resize(0);
-            break;
-        }
-    case FieldSupportedValues::hidl_discriminator::values: {
-            d->type = C2FieldSupportedValues::VALUES;
-            copyVector<uint64_t>(&d->values, s.values());
-            break;
-        }
-    case FieldSupportedValues::hidl_discriminator::flags: {
-            d->type = C2FieldSupportedValues::FLAGS;
-            copyVector<uint64_t>(&d->values, s.flags());
-            break;
-        }
-    default:
-        LOG(WARNING) << "Unrecognized FieldSupportedValues::getDiscriminator()";
-        return false;
-    }
-    return true;
-}
-
-} // unnamed namespace
-
-// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
-bool objcpy(
-        FieldSupportedValuesQuery* d,
-        const C2FieldSupportedValuesQuery& s) {
-    if (!objcpy(&d->field, s.field())) {
-        LOG(ERROR) << "Invalid C2FieldSupportedValuesQuery::field.";
-        return false;
-    }
-    switch (s.type()) {
-    case C2FieldSupportedValuesQuery::POSSIBLE:
-        d->type = FieldSupportedValuesQuery::Type::POSSIBLE;
-        break;
-    case C2FieldSupportedValuesQuery::CURRENT:
-        d->type = FieldSupportedValuesQuery::Type::CURRENT;
-        break;
-    default:
-        LOG(DEBUG) << "Unrecognized C2FieldSupportedValuesQuery::type_t "
-                   << "with underlying value " << underlying_value(s.type())
-                   << ".";
-        d->type = static_cast<FieldSupportedValuesQuery::Type>(s.type());
-    }
-    return true;
-}
-
-// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
-bool objcpy(
-        C2FieldSupportedValuesQuery* d,
-        const FieldSupportedValuesQuery& s) {
-    C2FieldSupportedValuesQuery::type_t dType;
-    switch (s.type) {
-    case FieldSupportedValuesQuery::Type::POSSIBLE:
-        dType = C2FieldSupportedValuesQuery::POSSIBLE;
-        break;
-    case FieldSupportedValuesQuery::Type::CURRENT:
-        dType = C2FieldSupportedValuesQuery::CURRENT;
-        break;
-    default:
-        LOG(DEBUG) << "Unrecognized FieldSupportedValuesQuery::Type "
-                   << "with underlying value " << underlying_value(s.type)
-                   << ".";
-        dType = static_cast<C2FieldSupportedValuesQuery::type_t>(s.type);
-    }
-    *d = C2FieldSupportedValuesQuery(C2ParamFieldBuilder(s.field), dType);
-    return true;
-}
-
-// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
-bool objcpy(
-        FieldSupportedValuesQueryResult* d,
-        const C2FieldSupportedValuesQuery& s) {
-    d->status = static_cast<Status>(s.status);
-    return objcpy(&d->values, s.values);
-}
-
-// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
-// C2FieldSupportedValuesQuery
-bool objcpy(
-        C2FieldSupportedValuesQuery* d,
-        const FieldSupportedValuesQuery& sq,
-        const FieldSupportedValuesQueryResult& sr) {
-    if (!objcpy(d, sq)) {
-        LOG(ERROR) << "Invalid FieldSupportedValuesQuery.";
-        return false;
-    }
-    d->status = static_cast<c2_status_t>(sr.status);
-    if (!objcpy(&d->values, sr.values)) {
-        LOG(ERROR) << "Invalid FieldSupportedValuesQueryResult::values.";
-        return false;
-    }
-    return true;
-}
-
-// C2Component::Traits -> IComponentStore::ComponentTraits
-bool objcpy(
-        IComponentStore::ComponentTraits *d,
-        const C2Component::Traits &s) {
-    d->name = s.name;
-
-    switch (s.domain) {
-    case C2Component::DOMAIN_VIDEO:
-        d->domain = IComponentStore::ComponentTraits::Domain::VIDEO;
-        break;
-    case C2Component::DOMAIN_AUDIO:
-        d->domain = IComponentStore::ComponentTraits::Domain::AUDIO;
-        break;
-    case C2Component::DOMAIN_IMAGE:
-        d->domain = IComponentStore::ComponentTraits::Domain::IMAGE;
-        break;
-    case C2Component::DOMAIN_OTHER:
-        d->domain = IComponentStore::ComponentTraits::Domain::OTHER;
-        break;
-    default:
-        LOG(DEBUG) << "Unrecognized C2Component::domain_t "
-                   << "with underlying value " << underlying_value(s.domain)
-                   << ".";
-        d->domain = static_cast<IComponentStore::ComponentTraits::Domain>(
-                s.domain);
-    }
-
-    switch (s.kind) {
-    case C2Component::KIND_DECODER:
-        d->kind = IComponentStore::ComponentTraits::Kind::DECODER;
-        break;
-    case C2Component::KIND_ENCODER:
-        d->kind = IComponentStore::ComponentTraits::Kind::ENCODER;
-        break;
-    case C2Component::KIND_OTHER:
-        d->kind = IComponentStore::ComponentTraits::Kind::OTHER;
-        break;
-    default:
-        LOG(DEBUG) << "Unrecognized C2Component::kind_t "
-                   << "with underlying value " << underlying_value(s.kind)
-                   << ".";
-        d->kind = static_cast<IComponentStore::ComponentTraits::Kind>(
-                s.kind);
-    }
-
-    d->rank = static_cast<uint32_t>(s.rank);
-
-    d->mediaType = s.mediaType;
-
-    d->aliases.resize(s.aliases.size());
-    for (size_t ix = s.aliases.size(); ix > 0; ) {
-        --ix;
-        d->aliases[ix] = s.aliases[ix];
-    }
-    return true;
-}
-
-// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
-bool objcpy(
-        C2Component::Traits* d,
-        const IComponentStore::ComponentTraits& s) {
-    d->name = s.name.c_str();
-
-    switch (s.domain) {
-    case IComponentStore::ComponentTraits::Domain::VIDEO:
-        d->domain = C2Component::DOMAIN_VIDEO;
-        break;
-    case IComponentStore::ComponentTraits::Domain::AUDIO:
-        d->domain = C2Component::DOMAIN_AUDIO;
-        break;
-    case IComponentStore::ComponentTraits::Domain::IMAGE:
-        d->domain = C2Component::DOMAIN_IMAGE;
-        break;
-    case IComponentStore::ComponentTraits::Domain::OTHER:
-        d->domain = C2Component::DOMAIN_OTHER;
-        break;
-    default:
-        LOG(DEBUG) << "Unrecognized ComponentTraits::Domain "
-                   << "with underlying value " << underlying_value(s.domain)
-                   << ".";
-        d->domain = static_cast<C2Component::domain_t>(s.domain);
-    }
-
-    switch (s.kind) {
-    case IComponentStore::ComponentTraits::Kind::DECODER:
-        d->kind = C2Component::KIND_DECODER;
-        break;
-    case IComponentStore::ComponentTraits::Kind::ENCODER:
-        d->kind = C2Component::KIND_ENCODER;
-        break;
-    case IComponentStore::ComponentTraits::Kind::OTHER:
-        d->kind = C2Component::KIND_OTHER;
-        break;
-    default:
-        LOG(DEBUG) << "Unrecognized ComponentTraits::Kind "
-                   << "with underlying value " << underlying_value(s.kind)
-                   << ".";
-        d->kind = static_cast<C2Component::kind_t>(s.kind);
-    }
-
-    d->rank = static_cast<C2Component::rank_t>(s.rank);
-    d->mediaType = s.mediaType.c_str();
-    d->aliases.resize(s.aliases.size());
-    for (size_t i = 0; i < s.aliases.size(); ++i) {
-        d->aliases[i] = s.aliases[i];
-    }
-    return true;
-}
-
-namespace /* unnamed */ {
-
-// C2ParamFieldValues -> ParamFieldValues
-bool objcpy(ParamFieldValues *d, const C2ParamFieldValues &s) {
-    if (!objcpy(&d->paramOrField, s.paramOrField)) {
-        LOG(ERROR) << "Invalid C2ParamFieldValues::paramOrField.";
-        return false;
-    }
-    if (s.values) {
-        d->values.resize(1);
-        if (!objcpy(&d->values[0], *s.values)) {
-            LOG(ERROR) << "Invalid C2ParamFieldValues::values.";
-            return false;
-        }
-        return true;
-    }
-    d->values.resize(0);
-    return true;
-}
-
-// ParamFieldValues -> C2ParamFieldValues
-bool objcpy(C2ParamFieldValues *d, const ParamFieldValues &s) {
-    d->paramOrField = C2ParamFieldBuilder(s.paramOrField);
-    if (s.values.size() == 1) {
-        d->values = std::make_unique<C2FieldSupportedValues>();
-        if (!objcpy(d->values.get(), s.values[0])) {
-            LOG(ERROR) << "Invalid ParamFieldValues::values.";
-            return false;
-        }
-        return true;
-    } else if (s.values.size() == 0) {
-        d->values.reset();
-        return true;
-    }
-    LOG(ERROR) << "Invalid ParamFieldValues: "
-                  "Two or more FieldSupportedValues objects exist in "
-                  "ParamFieldValues. "
-                  "Only zero or one is allowed.";
-    return false;
-}
-
-} // unnamed namespace
-
-// C2SettingResult -> SettingResult
-bool objcpy(SettingResult *d, const C2SettingResult &s) {
-    switch (s.failure) {
-    case C2SettingResult::BAD_TYPE:
-        d->failure = SettingResult::Failure::BAD_TYPE;
-        break;
-    case C2SettingResult::BAD_PORT:
-        d->failure = SettingResult::Failure::BAD_PORT;
-        break;
-    case C2SettingResult::BAD_INDEX:
-        d->failure = SettingResult::Failure::BAD_INDEX;
-        break;
-    case C2SettingResult::READ_ONLY:
-        d->failure = SettingResult::Failure::READ_ONLY;
-        break;
-    case C2SettingResult::MISMATCH:
-        d->failure = SettingResult::Failure::MISMATCH;
-        break;
-    case C2SettingResult::BAD_VALUE:
-        d->failure = SettingResult::Failure::BAD_VALUE;
-        break;
-    case C2SettingResult::CONFLICT:
-        d->failure = SettingResult::Failure::CONFLICT;
-        break;
-    case C2SettingResult::UNSUPPORTED:
-        d->failure = SettingResult::Failure::UNSUPPORTED;
-        break;
-    case C2SettingResult::INFO_BAD_VALUE:
-        d->failure = SettingResult::Failure::INFO_BAD_VALUE;
-        break;
-    case C2SettingResult::INFO_CONFLICT:
-        d->failure = SettingResult::Failure::INFO_CONFLICT;
-        break;
-    default:
-        LOG(DEBUG) << "Unrecognized C2SettingResult::Failure "
-                   << "with underlying value " << underlying_value(s.failure)
-                   << ".";
-        d->failure = static_cast<SettingResult::Failure>(s.failure);
-    }
-    if (!objcpy(&d->field, s.field)) {
-        LOG(ERROR) << "Invalid C2SettingResult::field.";
-        return false;
-    }
-    d->conflicts.resize(s.conflicts.size());
-    size_t i = 0;
-    for (const C2ParamFieldValues& sConflict : s.conflicts) {
-        ParamFieldValues &dConflict = d->conflicts[i++];
-        if (!objcpy(&dConflict, sConflict)) {
-            LOG(ERROR) << "Invalid C2SettingResult::conflicts["
-                       << i - 1 << "].";
-            return false;
-        }
-    }
-    return true;
-}
-
-// SettingResult -> std::unique_ptr<C2SettingResult>
-bool objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
-    *d = std::unique_ptr<C2SettingResult>(new C2SettingResult {
-            .field = C2ParamFieldValues(C2ParamFieldBuilder()) });
-    if (!*d) {
-        LOG(ERROR) << "No memory for C2SettingResult.";
-        return false;
-    }
-
-    // failure
-    switch (s.failure) {
-    case SettingResult::Failure::BAD_TYPE:
-        (*d)->failure = C2SettingResult::BAD_TYPE;
-        break;
-    case SettingResult::Failure::BAD_PORT:
-        (*d)->failure = C2SettingResult::BAD_PORT;
-        break;
-    case SettingResult::Failure::BAD_INDEX:
-        (*d)->failure = C2SettingResult::BAD_INDEX;
-        break;
-    case SettingResult::Failure::READ_ONLY:
-        (*d)->failure = C2SettingResult::READ_ONLY;
-        break;
-    case SettingResult::Failure::MISMATCH:
-        (*d)->failure = C2SettingResult::MISMATCH;
-        break;
-    case SettingResult::Failure::BAD_VALUE:
-        (*d)->failure = C2SettingResult::BAD_VALUE;
-        break;
-    case SettingResult::Failure::CONFLICT:
-        (*d)->failure = C2SettingResult::CONFLICT;
-        break;
-    case SettingResult::Failure::UNSUPPORTED:
-        (*d)->failure = C2SettingResult::UNSUPPORTED;
-        break;
-    case SettingResult::Failure::INFO_BAD_VALUE:
-        (*d)->failure = C2SettingResult::INFO_BAD_VALUE;
-        break;
-    case SettingResult::Failure::INFO_CONFLICT:
-        (*d)->failure = C2SettingResult::INFO_CONFLICT;
-        break;
-    default:
-        LOG(DEBUG) << "Unrecognized SettingResult::Failure "
-                   << "with underlying value " << underlying_value(s.failure)
-                   << ".";
-        (*d)->failure = static_cast<C2SettingResult::Failure>(s.failure);
-    }
-
-    // field
-    if (!objcpy(&(*d)->field, s.field)) {
-        LOG(ERROR) << "Invalid SettingResult::field.";
-        return false;
-    }
-
-    // conflicts
-    (*d)->conflicts.clear();
-    (*d)->conflicts.reserve(s.conflicts.size());
-    for (const ParamFieldValues& sConflict : s.conflicts) {
-        (*d)->conflicts.emplace_back(
-                C2ParamFieldValues{ C2ParamFieldBuilder(), nullptr });
-        if (!objcpy(&(*d)->conflicts.back(), sConflict)) {
-            LOG(ERROR) << "Invalid SettingResult::conflicts.";
-            return false;
-        }
-    }
-    return true;
-}
-
-// C2ParamDescriptor -> ParamDescriptor
-bool objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
-    d->index = static_cast<ParamIndex>(s.index());
-    d->attrib = static_cast<hidl_bitfield<ParamDescriptor::Attrib>>(
-            _C2ParamInspector::GetAttrib(s));
-    d->name = s.name();
-    copyVector<uint32_t>(&d->dependencies, s.dependencies());
-    return true;
-}
-
-// ParamDescriptor -> C2ParamDescriptor
-bool objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
-    std::vector<C2Param::Index> dDependencies;
-    dDependencies.reserve(s.dependencies.size());
-    for (const ParamIndex& sDependency : s.dependencies) {
-        dDependencies.emplace_back(static_cast<uint32_t>(sDependency));
-    }
-    *d = std::make_shared<C2ParamDescriptor>(
-            C2Param::Index(static_cast<uint32_t>(s.index)),
-            static_cast<C2ParamDescriptor::attrib_t>(s.attrib),
-            C2String(s.name.c_str()),
-            std::move(dDependencies));
-    return true;
-}
-
-// C2StructDescriptor -> StructDescriptor
-bool objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
-    d->type = static_cast<ParamIndex>(s.coreIndex().coreIndex());
-    d->fields.resize(s.numFields());
-    size_t i = 0;
-    for (const auto& sField : s) {
-        FieldDescriptor& dField = d->fields[i++];
-        dField.fieldId.offset = static_cast<uint32_t>(
-                _C2ParamInspector::GetOffset(sField));
-        dField.fieldId.size = static_cast<uint32_t>(
-                _C2ParamInspector::GetSize(sField));
-        dField.type = static_cast<hidl_bitfield<FieldDescriptor::Type>>(
-                sField.type());
-        dField.extent = static_cast<uint32_t>(sField.extent());
-        dField.name = static_cast<hidl_string>(sField.name());
-        const auto& sNamedValues = sField.namedValues();
-        dField.namedValues.resize(sNamedValues.size());
-        size_t j = 0;
-        for (const auto& sNamedValue : sNamedValues) {
-            FieldDescriptor::NamedValue& dNamedValue = dField.namedValues[j++];
-            dNamedValue.name = static_cast<hidl_string>(sNamedValue.first);
-            dNamedValue.value = static_cast<PrimitiveValue>(
-                    sNamedValue.second.u64);
-        }
-    }
-    return true;
-}
-
-// StructDescriptor -> C2StructDescriptor
-bool objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
-    C2Param::CoreIndex dIndex = C2Param::CoreIndex(static_cast<uint32_t>(s.type));
-    std::vector<C2FieldDescriptor> dFields;
-    dFields.reserve(s.fields.size());
-    for (const auto &sField : s.fields) {
-        C2FieldDescriptor dField = {
-            static_cast<uint32_t>(sField.type),
-            sField.extent,
-            sField.name,
-            sField.fieldId.offset,
-            sField.fieldId.size };
-        C2FieldDescriptor::NamedValuesType namedValues;
-        namedValues.reserve(sField.namedValues.size());
-        for (const auto& sNamedValue : sField.namedValues) {
-            namedValues.emplace_back(
-                sNamedValue.name,
-                C2Value::Primitive(static_cast<uint64_t>(sNamedValue.value)));
-        }
-        _C2ParamInspector::AddNamedValues(dField, std::move(namedValues));
-        dFields.emplace_back(dField);
-    }
-    *d = std::make_unique<C2StructDescriptor>(
-            _C2ParamInspector::CreateStructDescriptor(dIndex, std::move(dFields)));
-    return true;
-}
-
-namespace /* unnamed */ {
-
-// Find or add a hidl BaseBlock object from a given C2Handle* to a list and an
-// associated map.
-// Note: The handle is not cloned.
-bool _addBaseBlock(
-        uint32_t* index,
-        const C2Handle* handle,
-        std::list<BaseBlock>* baseBlocks,
-        std::map<const void*, uint32_t>* baseBlockIndices) {
-    if (!handle) {
-        LOG(ERROR) << "addBaseBlock called on a null C2Handle.";
-        return false;
-    }
-    auto it = baseBlockIndices->find(handle);
-    if (it != baseBlockIndices->end()) {
-        *index = it->second;
-    } else {
-        *index = baseBlocks->size();
-        baseBlockIndices->emplace(handle, *index);
-        baseBlocks->emplace_back();
-
-        BaseBlock &dBaseBlock = baseBlocks->back();
-        // This does not clone the handle.
-        dBaseBlock.nativeBlock(
-                reinterpret_cast<const native_handle_t*>(handle));
-
-    }
-    return true;
-}
-
-// Find or add a hidl BaseBlock object from a given BufferPoolData to a list and
-// an associated map.
-bool _addBaseBlock(
-        uint32_t* index,
-        const std::shared_ptr<BufferPoolData> bpData,
-        BufferPoolSender* bufferPoolSender,
-        std::list<BaseBlock>* baseBlocks,
-        std::map<const void*, uint32_t>* baseBlockIndices) {
-    if (!bpData) {
-        LOG(ERROR) << "addBaseBlock called on a null BufferPoolData.";
-        return false;
-    }
-    auto it = baseBlockIndices->find(bpData.get());
-    if (it != baseBlockIndices->end()) {
-        *index = it->second;
-    } else {
-        *index = baseBlocks->size();
-        baseBlockIndices->emplace(bpData.get(), *index);
-        baseBlocks->emplace_back();
-
-        BaseBlock &dBaseBlock = baseBlocks->back();
-
-        if (bufferPoolSender) {
-            BufferStatusMessage pooledBlock;
-            ResultStatus bpStatus = bufferPoolSender->send(
-                    bpData,
-                    &pooledBlock);
-
-            if (bpStatus != ResultStatus::OK) {
-                LOG(ERROR) << "Failed to send buffer with BufferPool. Error: "
-                           << static_cast<int32_t>(bpStatus)
-                           << ".";
-                return false;
-            }
-            dBaseBlock.pooledBlock(pooledBlock);
-        }
-    }
-    return true;
-}
-
-bool addBaseBlock(
-        uint32_t* index,
-        const C2Handle* handle,
-        const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
-        BufferPoolSender* bufferPoolSender,
-        std::list<BaseBlock>* baseBlocks,
-        std::map<const void*, uint32_t>* baseBlockIndices) {
-    if (!blockPoolData) {
-        // No BufferPoolData ==> NATIVE block.
-        return _addBaseBlock(
-                index, handle,
-                baseBlocks, baseBlockIndices);
-    }
-    switch (blockPoolData->getType()) {
-    case _C2BlockPoolData::TYPE_BUFFERPOOL: {
-            // BufferPoolData
-            std::shared_ptr<BufferPoolData> bpData;
-            if (!_C2BlockFactory::GetBufferPoolData(blockPoolData, &bpData)
-                    || !bpData) {
-                LOG(ERROR) << "BufferPoolData unavailable in a block.";
-                return false;
-            }
-            return _addBaseBlock(
-                    index, bpData,
-                    bufferPoolSender, baseBlocks, baseBlockIndices);
-        }
-    case _C2BlockPoolData::TYPE_BUFFERQUEUE:
-        uint32_t gen;
-        uint64_t bqId;
-        int32_t bqSlot;
-        // Update handle if migration happened.
-        if (_C2BlockFactory::GetBufferQueueData(
-                blockPoolData, &gen, &bqId, &bqSlot)) {
-            android::MigrateNativeCodec2GrallocHandle(
-                    const_cast<native_handle_t*>(handle), gen, bqId, bqSlot);
-        }
-        return _addBaseBlock(
-                index, handle,
-                baseBlocks, baseBlockIndices);
-    default:
-        LOG(ERROR) << "Unknown C2BlockPoolData type.";
-        return false;
-    }
-}
-
-// C2Fence -> hidl_handle
-// Note: File descriptors are not duplicated. The original file descriptor must
-// not be closed before the transaction is complete.
-bool objcpy(hidl_handle* d, const C2Fence& s) {
-    d->setTo(nullptr);
-    native_handle_t* handle = _C2FenceFactory::CreateNativeHandle(s);
-    if (handle) {
-        d->setTo(handle, true /* owns */);
-//  } else if (!s.ready()) {
-//      // TODO: we should wait for unmarshallable fences but this may not be
-//      // the best place for it. We can safely ignore here as at this time
-//      // all fences used here are marshallable.
-    }
-    return true;
-}
-
-// C2ConstLinearBlock -> Block
-// Note: Native handles are not duplicated. The original handles must not be
-// closed before the transaction is complete.
-bool objcpy(Block* d, const C2ConstLinearBlock& s,
-        BufferPoolSender* bufferPoolSender,
-        std::list<BaseBlock>* baseBlocks,
-        std::map<const void*, uint32_t>* baseBlockIndices) {
-    std::shared_ptr<const _C2BlockPoolData> bpData =
-            _C2BlockFactory::GetLinearBlockPoolData(s);
-    if (!addBaseBlock(&d->index, s.handle(), bpData,
-            bufferPoolSender, baseBlocks, baseBlockIndices)) {
-        LOG(ERROR) << "Invalid block data in C2ConstLinearBlock.";
-        return false;
-    }
-
-    // Create the metadata.
-    C2Hidl_RangeInfo dRangeInfo;
-    dRangeInfo.offset = static_cast<uint32_t>(s.offset());
-    dRangeInfo.length = static_cast<uint32_t>(s.size());
-    if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRangeInfo })) {
-        LOG(ERROR) << "Invalid range info in C2ConstLinearBlock.";
-        return false;
-    }
-
-    // Copy the fence
-    if (!objcpy(&d->fence, s.fence())) {
-        LOG(ERROR) << "Invalid C2ConstLinearBlock::fence.";
-        return false;
-    }
-    return true;
-}
-
-// C2ConstGraphicBlock -> Block
-// Note: Native handles are not duplicated. The original handles must not be
-// closed before the transaction is complete.
-bool objcpy(Block* d, const C2ConstGraphicBlock& s,
-        BufferPoolSender* bufferPoolSender,
-        std::list<BaseBlock>* baseBlocks,
-        std::map<const void*, uint32_t>* baseBlockIndices) {
-    std::shared_ptr<const _C2BlockPoolData> bpData =
-            _C2BlockFactory::GetGraphicBlockPoolData(s);
-    if (!addBaseBlock(&d->index, s.handle(), bpData,
-            bufferPoolSender, baseBlocks, baseBlockIndices)) {
-        LOG(ERROR) << "Invalid block data in C2ConstGraphicBlock.";
-        return false;
-    }
-
-    // Create the metadata.
-    C2Hidl_RectInfo dRectInfo;
-    C2Rect sRect = s.crop();
-    dRectInfo.left = static_cast<uint32_t>(sRect.left);
-    dRectInfo.top = static_cast<uint32_t>(sRect.top);
-    dRectInfo.width = static_cast<uint32_t>(sRect.width);
-    dRectInfo.height = static_cast<uint32_t>(sRect.height);
-    if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRectInfo })) {
-        LOG(ERROR) << "Invalid rect info in C2ConstGraphicBlock.";
-        return false;
-    }
-
-    // Copy the fence
-    if (!objcpy(&d->fence, s.fence())) {
-        LOG(ERROR) << "Invalid C2ConstGraphicBlock::fence.";
-        return false;
-    }
-    return true;
-}
-
-// C2BufferData -> Buffer
-// This function only fills in d->blocks.
-bool objcpy(Buffer* d, const C2BufferData& s,
-        BufferPoolSender* bufferPoolSender,
-        std::list<BaseBlock>* baseBlocks,
-        std::map<const void*, uint32_t>* baseBlockIndices) {
-    d->blocks.resize(
-            s.linearBlocks().size() +
-            s.graphicBlocks().size());
-    size_t i = 0;
-    for (const C2ConstLinearBlock& linearBlock : s.linearBlocks()) {
-        Block& dBlock = d->blocks[i++];
-        if (!objcpy(
-                &dBlock, linearBlock,
-                bufferPoolSender, baseBlocks, baseBlockIndices)) {
-            LOG(ERROR) << "Invalid C2BufferData::linearBlocks. "
-                       << "(Destination index = " << i - 1 << ".)";
-            return false;
-        }
-    }
-    for (const C2ConstGraphicBlock& graphicBlock : s.graphicBlocks()) {
-        Block& dBlock = d->blocks[i++];
-        if (!objcpy(
-                &dBlock, graphicBlock,
-                bufferPoolSender, baseBlocks, baseBlockIndices)) {
-            LOG(ERROR) << "Invalid C2BufferData::graphicBlocks. "
-                       << "(Destination index = " << i - 1 << ".)";
-            return false;
-        }
-    }
-    return true;
-}
-
-// C2Buffer -> Buffer
-bool objcpy(Buffer* d, const C2Buffer& s,
-        BufferPoolSender* bufferPoolSender,
-        std::list<BaseBlock>* baseBlocks,
-        std::map<const void*, uint32_t>* baseBlockIndices) {
-    if (!createParamsBlob(&d->info, s.info())) {
-        LOG(ERROR) << "Invalid C2Buffer::info.";
-        return false;
-    }
-    if (!objcpy(d, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
-        LOG(ERROR) << "Invalid C2Buffer::data.";
-        return false;
-    }
-    return true;
-}
-
-// C2InfoBuffer -> InfoBuffer
-bool objcpy(InfoBuffer* d, const C2InfoBuffer& s,
-        BufferPoolSender* bufferPoolSender,
-        std::list<BaseBlock>* baseBlocks,
-        std::map<const void*, uint32_t>* baseBlockIndices) {
-    d->index = static_cast<ParamIndex>(s.index());
-    Buffer& dBuffer = d->buffer;
-    if (!objcpy(&dBuffer, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
-        LOG(ERROR) << "Invalid C2InfoBuffer::data";
-        return false;
-    }
-    return true;
-}
-
-// C2FrameData -> FrameData
-bool objcpy(FrameData* d, const C2FrameData& s,
-        BufferPoolSender* bufferPoolSender,
-        std::list<BaseBlock>* baseBlocks,
-        std::map<const void*, uint32_t>* baseBlockIndices) {
-    d->flags = static_cast<hidl_bitfield<FrameData::Flags>>(s.flags);
-    if (!objcpy(&d->ordinal, s.ordinal)) {
-        LOG(ERROR) << "Invalid C2FrameData::ordinal.";
-        return false;
-    }
-
-    d->buffers.resize(s.buffers.size());
-    size_t i = 0;
-    for (const std::shared_ptr<C2Buffer>& sBuffer : s.buffers) {
-        Buffer& dBuffer = d->buffers[i++];
-        if (!sBuffer) {
-            // A null (pointer to) C2Buffer corresponds to a Buffer with empty
-            // info and blocks.
-            dBuffer.info.resize(0);
-            dBuffer.blocks.resize(0);
-            continue;
-        }
-        if (!objcpy(
-                &dBuffer, *sBuffer,
-                bufferPoolSender, baseBlocks, baseBlockIndices)) {
-            LOG(ERROR) << "Invalid C2FrameData::buffers["
-                       << i - 1 << "].";
-            return false;
-        }
-    }
-
-    if (!createParamsBlob(&d->configUpdate, s.configUpdate)) {
-        LOG(ERROR) << "Invalid C2FrameData::configUpdate.";
-        return false;
-    }
-
-    d->infoBuffers.resize(s.infoBuffers.size());
-    i = 0;
-    for (const C2InfoBuffer& sInfoBuffer : s.infoBuffers) {
-        InfoBuffer& dInfoBuffer = d->infoBuffers[i++];
-        if (!objcpy(&dInfoBuffer, sInfoBuffer,
-                bufferPoolSender, baseBlocks, baseBlockIndices)) {
-            LOG(ERROR) << "Invalid C2FrameData::infoBuffers["
-                       << i - 1 << "].";
-            return false;
-        }
-    }
-
-    return true;
-}
-
-} // unnamed namespace
-
-// DefaultBufferPoolSender's implementation
-
-DefaultBufferPoolSender::DefaultBufferPoolSender(
-        const sp<IClientManager>& receiverManager,
-        std::chrono::steady_clock::duration refreshInterval)
-    : mReceiverManager(receiverManager),
-      mRefreshInterval(refreshInterval) {
-}
-
-void DefaultBufferPoolSender::setReceiver(
-        const sp<IClientManager>& receiverManager,
-        std::chrono::steady_clock::duration refreshInterval) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    if (mReceiverManager != receiverManager) {
-        mReceiverManager = receiverManager;
-        mConnections.clear();
-    }
-    mRefreshInterval = refreshInterval;
-}
-
-ResultStatus DefaultBufferPoolSender::send(
-        const std::shared_ptr<BufferPoolData>& bpData,
-        BufferStatusMessage* bpMessage) {
-    int64_t connectionId = bpData->mConnectionId;
-    if (connectionId == 0) {
-        LOG(WARNING) << "registerSender -- invalid sender connection id (0).";
-        return ResultStatus::CRITICAL_ERROR;
-    }
-    std::lock_guard<std::mutex> lock(mMutex);
-    if (!mReceiverManager) {
-        LOG(ERROR) << "No access to receiver's BufferPool.";
-        return ResultStatus::NOT_FOUND;
-    }
-    if (!mSenderManager) {
-        mSenderManager = ClientManager::getInstance();
-        if (!mSenderManager) {
-            LOG(ERROR) << "Failed to retrieve local BufferPool ClientManager.";
-            return ResultStatus::CRITICAL_ERROR;
-        }
-    }
-
-    int64_t receiverConnectionId{0};
-    auto foundConnection = mConnections.find(connectionId);
-    bool isNewConnection = foundConnection == mConnections.end();
-    std::chrono::steady_clock::time_point now =
-            std::chrono::steady_clock::now();
-    if (isNewConnection ||
-            (now - foundConnection->second.lastSent > mRefreshInterval)) {
-        // Initialize the bufferpool connection.
-        ResultStatus rs =
-                mSenderManager->registerSender(mReceiverManager,
-                                               connectionId,
-                                               &receiverConnectionId);
-        if ((rs != ResultStatus::OK) && (rs != ResultStatus::ALREADY_EXISTS)) {
-            LOG(WARNING) << "registerSender -- returned error: "
-                         << static_cast<int32_t>(rs)
-                         << ".";
-            return rs;
-        } else if (receiverConnectionId == 0) {
-            LOG(WARNING) << "registerSender -- "
-                            "invalid receiver connection id (0).";
-            return ResultStatus::CRITICAL_ERROR;
-        } else {
-            if (isNewConnection) {
-                foundConnection = mConnections.try_emplace(
-                        connectionId, receiverConnectionId, now).first;
-            } else {
-                foundConnection->second.receiverConnectionId = receiverConnectionId;
-            }
-        }
-    } else {
-        receiverConnectionId = foundConnection->second.receiverConnectionId;
-    }
-
-    uint64_t transactionId;
-    int64_t timestampUs;
-    ResultStatus rs = mSenderManager->postSend(
-            receiverConnectionId, bpData, &transactionId, &timestampUs);
-    if (rs != ResultStatus::OK) {
-        LOG(ERROR) << "ClientManager::postSend -- returned error: "
-                   << static_cast<int32_t>(rs)
-                   << ".";
-        mConnections.erase(foundConnection);
-        return rs;
-    }
-    if (!bpMessage) {
-        LOG(ERROR) << "Null output parameter for BufferStatusMessage.";
-        mConnections.erase(foundConnection);
-        return ResultStatus::CRITICAL_ERROR;
-    }
-    bpMessage->connectionId = receiverConnectionId;
-    bpMessage->bufferId = bpData->mId;
-    bpMessage->transactionId = transactionId;
-    bpMessage->timestampUs = timestampUs;
-    foundConnection->second.lastSent = now;
-    return rs;
-}
-
-// std::list<std::unique_ptr<C2Work>> -> WorkBundle
-bool objcpy(
-        WorkBundle* d,
-        const std::list<std::unique_ptr<C2Work>>& s,
-        BufferPoolSender* bufferPoolSender) {
-    // baseBlocks holds a list of BaseBlock objects that Blocks can refer to.
-    std::list<BaseBlock> baseBlocks;
-
-    // baseBlockIndices maps a raw pointer to native_handle_t or BufferPoolData
-    // inside baseBlocks to the corresponding index into baseBlocks. The keys
-    // (pointers) are used to identify blocks that have the same "base block" in
-    // s, a list of C2Work objects. Because baseBlocks will be copied into a
-    // hidl_vec eventually, the values of baseBlockIndices are zero-based
-    // integer indices instead of list iterators.
-    //
-    // Note that the pointers can be raw because baseBlockIndices has a shorter
-    // lifespan than all of base blocks.
-    std::map<const void*, uint32_t> baseBlockIndices;
-
-    d->works.resize(s.size());
-    size_t i = 0;
-    for (const std::unique_ptr<C2Work>& sWork : s) {
-        Work &dWork = d->works[i++];
-        if (!sWork) {
-            LOG(WARNING) << "Null C2Work encountered.";
-            continue;
-        }
-
-        // chain info is not in use currently.
-
-        // input
-        if (!objcpy(&dWork.input, sWork->input,
-                bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
-            LOG(ERROR) << "Invalid C2Work::input.";
-            return false;
-        }
-
-        // worklets
-        if (sWork->worklets.size() == 0) {
-            LOG(DEBUG) << "Work with no worklets.";
-        } else {
-            // Parcel the worklets.
-            hidl_vec<Worklet> &dWorklets = dWork.worklets;
-            dWorklets.resize(sWork->worklets.size());
-            size_t j = 0;
-            for (const std::unique_ptr<C2Worklet>& sWorklet : sWork->worklets)
-            {
-                if (!sWorklet) {
-                    LOG(WARNING) << "Null C2Work::worklets["
-                                 << j << "].";
-                    continue;
-                }
-                Worklet &dWorklet = dWorklets[j++];
-
-                // component id
-                dWorklet.componentId = static_cast<uint32_t>(
-                        sWorklet->component);
-
-                // tunings
-                if (!createParamsBlob(&dWorklet.tunings, sWorklet->tunings)) {
-                    LOG(ERROR) << "Invalid C2Work::worklets["
-                               << j - 1 << "]->tunings.";
-                    return false;
-                }
-
-                // failures
-                dWorklet.failures.resize(sWorklet->failures.size());
-                size_t k = 0;
-                for (const std::unique_ptr<C2SettingResult>& sFailure :
-                        sWorklet->failures) {
-                    if (!sFailure) {
-                        LOG(WARNING) << "Null C2Work::worklets["
-                                     << j - 1 << "]->failures["
-                                     << k << "].";
-                        continue;
-                    }
-                    if (!objcpy(&dWorklet.failures[k++], *sFailure)) {
-                        LOG(ERROR) << "Invalid C2Work::worklets["
-                                   << j - 1 << "]->failures["
-                                   << k - 1 << "].";
-                        return false;
-                    }
-                }
-
-                // output
-                if (!objcpy(&dWorklet.output, sWorklet->output,
-                        bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
-                    LOG(ERROR) << "Invalid C2Work::worklets["
-                               << j - 1 << "]->output.";
-                    return false;
-                }
-            }
-        }
-
-        // worklets processed
-        dWork.workletsProcessed = sWork->workletsProcessed;
-
-        // result
-        dWork.result = static_cast<Status>(sWork->result);
-    }
-
-    // Copy std::list<BaseBlock> to hidl_vec<BaseBlock>.
-    {
-        d->baseBlocks.resize(baseBlocks.size());
-        size_t i = 0;
-        for (const BaseBlock& baseBlock : baseBlocks) {
-            d->baseBlocks[i++] = baseBlock;
-        }
-    }
-
-    return true;
-}
-
-namespace /* unnamed */ {
-
-struct C2BaseBlock {
-    enum type_t {
-        LINEAR,
-        GRAPHIC,
-    };
-    type_t type;
-    std::shared_ptr<C2LinearBlock> linear;
-    std::shared_ptr<C2GraphicBlock> graphic;
-};
-
-// hidl_handle -> C2Fence
-// Note: File descriptors are not duplicated. The original file descriptor must
-// not be closed before the transaction is complete.
-bool objcpy(C2Fence* d, const hidl_handle& s) {
-    const native_handle_t* handle = s.getNativeHandle();
-    *d = _C2FenceFactory::CreateFromNativeHandle(handle);
-    return true;
-}
-
-// C2LinearBlock, vector<C2Param*>, C2Fence -> C2Buffer
-bool createLinearBuffer(
-        std::shared_ptr<C2Buffer>* buffer,
-        const std::shared_ptr<C2LinearBlock>& block,
-        const std::vector<C2Param*>& meta,
-        const C2Fence& fence) {
-    // Check the block meta. It should have exactly 1 C2Info:
-    // C2Hidl_RangeInfo.
-    if ((meta.size() != 1) || !meta[0]) {
-        LOG(ERROR) << "Invalid C2LinearBlock::meta.";
-        return false;
-    }
-    if (meta[0]->size() != sizeof(C2Hidl_RangeInfo)) {
-        LOG(ERROR) << "Invalid range info in C2LinearBlock.";
-        return false;
-    }
-    C2Hidl_RangeInfo *rangeInfo =
-            reinterpret_cast<C2Hidl_RangeInfo*>(meta[0]);
-
-    // Create C2Buffer from C2LinearBlock.
-    *buffer = C2Buffer::CreateLinearBuffer(block->share(
-            rangeInfo->offset, rangeInfo->length,
-            fence));
-    if (!(*buffer)) {
-        LOG(ERROR) << "CreateLinearBuffer failed.";
-        return false;
-    }
-    return true;
-}
-
-// C2GraphicBlock, vector<C2Param*>, C2Fence -> C2Buffer
-bool createGraphicBuffer(
-        std::shared_ptr<C2Buffer>* buffer,
-        const std::shared_ptr<C2GraphicBlock>& block,
-        const std::vector<C2Param*>& meta,
-        const C2Fence& fence) {
-    // Check the block meta. It should have exactly 1 C2Info:
-    // C2Hidl_RectInfo.
-    if ((meta.size() != 1) || !meta[0]) {
-        LOG(ERROR) << "Invalid C2GraphicBlock::meta.";
-        return false;
-    }
-    if (meta[0]->size() != sizeof(C2Hidl_RectInfo)) {
-        LOG(ERROR) << "Invalid rect info in C2GraphicBlock.";
-        return false;
-    }
-    C2Hidl_RectInfo *rectInfo =
-            reinterpret_cast<C2Hidl_RectInfo*>(meta[0]);
-
-    // Create C2Buffer from C2GraphicBlock.
-    *buffer = C2Buffer::CreateGraphicBuffer(block->share(
-            C2Rect(rectInfo->width, rectInfo->height).
-            at(rectInfo->left, rectInfo->top),
-            fence));
-    if (!(*buffer)) {
-        LOG(ERROR) << "CreateGraphicBuffer failed.";
-        return false;
-    }
-    return true;
-}
-
-// Buffer -> C2Buffer
-// Note: The native handles will be cloned.
-bool objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
-        const std::vector<C2BaseBlock>& baseBlocks) {
-    *d = nullptr;
-
-    // Currently, a non-null C2Buffer must contain exactly 1 block.
-    if (s.blocks.size() == 0) {
-        return true;
-    } else if (s.blocks.size() != 1) {
-        LOG(ERROR) << "Invalid Buffer: "
-                      "Currently, a C2Buffer must contain exactly 1 block.";
-        return false;
-    }
-
-    const Block &sBlock = s.blocks[0];
-    if (sBlock.index >= baseBlocks.size()) {
-        LOG(ERROR) << "Invalid Buffer::blocks[0].index: "
-                      "Array index out of range.";
-        return false;
-    }
-    const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
-
-    // Parse meta.
-    std::vector<C2Param*> sBlockMeta;
-    if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
-        LOG(ERROR) << "Invalid Buffer::blocks[0].meta.";
-        return false;
-    }
-
-    // Copy fence.
-    C2Fence dFence;
-    if (!objcpy(&dFence, sBlock.fence)) {
-        LOG(ERROR) << "Invalid Buffer::blocks[0].fence.";
-        return false;
-    }
-
-    // Construct a block.
-    switch (baseBlock.type) {
-    case C2BaseBlock::LINEAR:
-        if (!createLinearBuffer(d, baseBlock.linear, sBlockMeta, dFence)) {
-            LOG(ERROR) << "Invalid C2BaseBlock::linear.";
-            return false;
-        }
-        break;
-    case C2BaseBlock::GRAPHIC:
-        if (!createGraphicBuffer(d, baseBlock.graphic, sBlockMeta, dFence)) {
-            LOG(ERROR) << "Invalid C2BaseBlock::graphic.";
-            return false;
-        }
-        break;
-    default:
-        LOG(ERROR) << "Invalid C2BaseBlock::type.";
-        return false;
-    }
-
-    // Parse info
-    std::vector<C2Param*> params;
-    if (!parseParamsBlob(&params, s.info)) {
-        LOG(ERROR) << "Invalid Buffer::info.";
-        return false;
-    }
-    for (C2Param* param : params) {
-        if (param == nullptr) {
-            LOG(ERROR) << "Null param in Buffer::info.";
-            return false;
-        }
-        std::shared_ptr<C2Param> c2param{
-                C2Param::Copy(*param).release()};
-        if (!c2param) {
-            LOG(ERROR) << "Invalid param in Buffer::info.";
-            return false;
-        }
-        c2_status_t status =
-                (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
-        if (status != C2_OK) {
-            LOG(ERROR) << "C2Buffer::setInfo failed.";
-            return false;
-        }
-    }
-
-    return true;
-}
-
-// InfoBuffer -> C2InfoBuffer
-bool objcpy(std::vector<C2InfoBuffer> *d, const InfoBuffer& s,
-        const std::vector<C2BaseBlock>& baseBlocks) {
-
-    // Currently, a non-null C2InfoBufer must contain exactly 1 block.
-    if (s.buffer.blocks.size() == 0) {
-        return true;
-    } else if (s.buffer.blocks.size() != 1) {
-        LOG(ERROR) << "Invalid InfoBuffer::Buffer "
-                      "Currently, a C2InfoBuffer must contain exactly 1 block.";
-        return false;
-    }
-
-    const Block &sBlock = s.buffer.blocks[0];
-    if (sBlock.index >= baseBlocks.size()) {
-        LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].index: "
-                      "Array index out of range.";
-        return false;
-    }
-    const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
-
-    // Parse meta.
-    std::vector<C2Param*> sBlockMeta;
-    if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
-        LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].meta.";
-        return false;
-    }
-
-    // Copy fence.
-    C2Fence dFence;
-    if (!objcpy(&dFence, sBlock.fence)) {
-        LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].fence.";
-        return false;
-    }
-
-    // Construct a block.
-    switch (baseBlock.type) {
-    case C2BaseBlock::LINEAR:
-        if (sBlockMeta.size() == 1 && sBlockMeta[0] != nullptr &&
-            sBlockMeta[0]->size() == sizeof(C2Hidl_RangeInfo)) {
-            C2Hidl_RangeInfo *rangeInfo =
-                    reinterpret_cast<C2Hidl_RangeInfo*>(sBlockMeta[0]);
-            d->emplace_back(C2InfoBuffer::CreateLinearBuffer(
-                    s.index,
-                    baseBlock.linear->share(
-                            rangeInfo->offset, rangeInfo->length, dFence)));
-            return true;
-        }
-        LOG(ERROR) << "Invalid Meta for C2BaseBlock::Linear InfoBuffer.";
-        break;
-    case C2BaseBlock::GRAPHIC:
-        // It's not used now
-        LOG(ERROR) << "Non-Used C2BaseBlock::type for InfoBuffer.";
-        break;
-    default:
-        LOG(ERROR) << "Invalid C2BaseBlock::type for InfoBuffer.";
-        break;
-    }
-
-    return false;
-}
-
-// FrameData -> C2FrameData
-bool objcpy(C2FrameData* d, const FrameData& s,
-        const std::vector<C2BaseBlock>& baseBlocks) {
-    d->flags = static_cast<C2FrameData::flags_t>(s.flags);
-    if (!objcpy(&d->ordinal, s.ordinal)) {
-        LOG(ERROR) << "Invalid FrameData::ordinal.";
-        return false;
-    }
-    d->buffers.clear();
-    d->buffers.reserve(s.buffers.size());
-    for (const Buffer& sBuffer : s.buffers) {
-        std::shared_ptr<C2Buffer> dBuffer;
-        if (!objcpy(&dBuffer, sBuffer, baseBlocks)) {
-            LOG(ERROR) << "Invalid FrameData::buffers.";
-            return false;
-        }
-        d->buffers.emplace_back(dBuffer);
-    }
-
-    std::vector<C2Param*> params;
-    if (!parseParamsBlob(&params, s.configUpdate)) {
-        LOG(ERROR) << "Invalid FrameData::configUpdate.";
-        return false;
-    }
-    d->configUpdate.clear();
-    for (C2Param* param : params) {
-        d->configUpdate.emplace_back(C2Param::Copy(*param));
-        if (!d->configUpdate.back()) {
-            LOG(ERROR) << "Unexpected error while parsing "
-                          "FrameData::configUpdate.";
-            return false;
-        }
-    }
-
-    d->infoBuffers.clear();
-    if (s.infoBuffers.size() == 0) {
-        // InfoBuffer is optional
-        return true;
-    }
-    d->infoBuffers.reserve(s.infoBuffers.size());
-    for (const InfoBuffer &sInfoBuffer: s.infoBuffers) {
-        if (!objcpy(&(d->infoBuffers), sInfoBuffer, baseBlocks)) {
-            LOG(ERROR) << "Invalid Framedata::infoBuffers.";
-            return false;
-        }
-    }
-    return true;
-}
+constexpr BaseBlock::Tag NATIVE_BLOCK = BaseBlock::nativeBlock;
+constexpr BaseBlock::Tag POOLED_BLOCK = BaseBlock::pooledBlock;
 
 // BaseBlock -> C2BaseBlock
+template<>
 bool objcpy(C2BaseBlock* d, const BaseBlock& s) {
-    switch (s.getDiscriminator()) {
-    case BaseBlock::hidl_discriminator::nativeBlock: {
-            if (s.nativeBlock() == nullptr) {
+    switch (s.getTag()) {
+    case NATIVE_BLOCK: {
+            if (isAidlNativeHandleEmpty(s.get<NATIVE_BLOCK>())) {
                 LOG(ERROR) << "Null BaseBlock::nativeBlock handle";
                 return false;
             }
             native_handle_t* sHandle =
-                    native_handle_clone(s.nativeBlock());
+                    ::android::dupFromAidl(s.get<NATIVE_BLOCK>());
             if (sHandle == nullptr) {
                 LOG(ERROR) << "Null BaseBlock::nativeBlock.";
                 return false;
@@ -1460,15 +76,17 @@
             const C2Handle *sC2Handle =
                     reinterpret_cast<const C2Handle*>(sHandle);
 
+            // If successful, the handle is deleted(!) and fds are owned by the block.
             d->linear = _C2BlockFactory::CreateLinearBlock(sC2Handle);
             if (d->linear) {
-                d->type = C2BaseBlock::LINEAR;
+                d->type = ::android::C2BaseBlock::LINEAR;
                 return true;
             }
 
+            // If successful, the handle is deleted(!) and fds are owned by the block.
             d->graphic = _C2BlockFactory::CreateGraphicBlock(sC2Handle);
             if (d->graphic) {
-                d->type = C2BaseBlock::GRAPHIC;
+                d->type = ::android::C2BaseBlock::GRAPHIC;
                 return true;
             }
 
@@ -1479,13 +97,12 @@
             }
             return false;
         }
-    case BaseBlock::hidl_discriminator::pooledBlock: {
-            const BufferStatusMessage &bpMessage =
-                    s.pooledBlock();
-            sp<ClientManager> bp = ClientManager::getInstance();
+    case POOLED_BLOCK: {
+            const BufferStatusMessage &bpMessage = s.get<POOLED_BLOCK>();
+            std::shared_ptr<ClientManager> bp = ClientManager::getInstance();
             std::shared_ptr<BufferPoolData> bpData;
             native_handle_t *cHandle;
-            ResultStatus bpStatus = bp->receive(
+            BufferPoolStatus bpStatus = bp->receive(
                     bpMessage.connectionId,
                     bpMessage.transactionId,
                     bpMessage.bufferId,
@@ -1494,23 +111,24 @@
                     &bpData);
             if (bpStatus != ResultStatus::OK) {
                 LOG(ERROR) << "Failed to receive buffer from bufferpool -- "
-                           << "resultStatus = " << underlying_value(bpStatus)
-                           << ".";
+                           << "resultStatus = " << bpStatus << ".";
                 return false;
             } else if (!bpData) {
                 LOG(ERROR) << "No data in bufferpool transaction.";
                 return false;
             }
 
+            // If successful, the handle is deleted(!) and fds are owned by the block.
             d->linear = _C2BlockFactory::CreateLinearBlock(cHandle, bpData);
             if (d->linear) {
-                d->type = C2BaseBlock::LINEAR;
+                d->type = ::android::C2BaseBlock::LINEAR;
                 return true;
             }
 
+            // If successful, the handle is deleted(!) and fds are owned by the block.
             d->graphic = _C2BlockFactory::CreateGraphicBlock(cHandle, bpData);
             if (d->graphic) {
-                d->type = C2BaseBlock::GRAPHIC;
+                d->type = ::android::C2BaseBlock::GRAPHIC;
                 return true;
             }
             if (cHandle) {
@@ -1525,404 +143,193 @@
     default:
         LOG(ERROR) << "Unrecognized BaseBlock's discriminator with "
                    << "underlying value "
-                   << underlying_value(s.getDiscriminator()) << ".";
+                   << ::android::underlying_value(s.getTag()) << ".";
         return false;
     }
 }
 
-} // unnamed namespace
+// C2Fence -> AidlNativeHandle
+template<>
+bool objcpy(AidlNativeHandle* d, const C2Fence& s) {
+    // fds are not duplicated here
+    native_handle_t* handle = _C2FenceFactory::CreateNativeHandle(s);
+    if (handle) {
+        // |d| copies the fds without duplicating
+        *d = makeToAidl(handle);
+        // no fds are duplicated, just delete the handle
+        // Note: C2Fence still owns the fds and should not be cleared
+        // before the transaction is complete.
+        native_handle_delete(handle);
+//  } else if (!s.ready()) {
+//      // TODO: we should wait for unmarshallable fences but this may not be
+//      // the best place for it. We can safely ignore here as at this time
+//      // all fences used here are marshallable.
+    }
+    return true;
+}
+
+// AidlNativeHandle -> C2Fence
+template<>
+bool objcpy(C2Fence* d, const AidlNativeHandle& s) {
+    // makeFromAidl does not duplicate the fds.
+    native_handle_t* handle = makeFromAidl(s);
+    // C2Fence duplicates and owns the fds
+    *d = _C2FenceFactory::CreateFromNativeHandle(handle);
+    if (handle) {
+        // |handle| should not be closed here, as the fds are owned by |s|
+        native_handle_delete(handle);
+    }
+    return true;
+}
+
+template<>
+void SetHandle(BaseBlock *block, const C2Handle *handle) {
+    block->set<BaseBlock::nativeBlock>(makeToAidl(handle));
+}
+
+template<>
+void SetPooledBlock<BufferPoolTypes>(
+        BaseBlock *baseBlock,
+        const typename BufferPoolTypes::BufferStatusMessage &pooledBlock) {
+    baseBlock->set<POOLED_BLOCK>(pooledBlock);
+}
+
+template<>
+bool GetBufferPoolData<BufferPoolTypes>(
+        const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
+        std::shared_ptr<typename BufferPoolTypes::BufferPoolData> *bpData) {
+    return _C2BlockFactory::GetBufferPoolData(blockPoolData, bpData);
+}
+
+}  // namespace android
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace utils {
+
+namespace bufferpool2 = ::aidl::android::hardware::media::bufferpool2;
+namespace bufferpool2_impl = ::aidl::android::hardware::media::bufferpool2::implementation;
+
+// DefaultBufferPoolSender's implementation
+
+DefaultBufferPoolSender::DefaultBufferPoolSender(
+        const std::shared_ptr<IClientManager>& receiverManager,
+        std::chrono::steady_clock::duration refreshInterval)
+    : mReceiverManager(receiverManager),
+      mRefreshInterval(refreshInterval) {
+}
+
+void DefaultBufferPoolSender::setReceiver(
+        const std::shared_ptr<IClientManager>& receiverManager,
+        std::chrono::steady_clock::duration refreshInterval) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mReceiverManager != receiverManager) {
+        mReceiverManager = receiverManager;
+        mConnections.clear();
+    }
+    mRefreshInterval = refreshInterval;
+}
+
+BufferPoolTypes::BufferPoolStatus DefaultBufferPoolSender::send(
+        const std::shared_ptr<bufferpool2::BufferPoolData>& bpData,
+        bufferpool2::BufferStatusMessage* bpMessage) {
+    int64_t connectionId = bpData->mConnectionId;
+    if (connectionId == 0) {
+        LOG(WARNING) << "registerSender -- invalid sender connection id (0).";
+        return bufferpool2::ResultStatus::CRITICAL_ERROR;
+    }
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!mReceiverManager) {
+        LOG(ERROR) << "No access to receiver's BufferPool.";
+        return bufferpool2::ResultStatus::NOT_FOUND;
+    }
+    if (!mSenderManager) {
+        mSenderManager = ClientManager::getInstance();
+        if (!mSenderManager) {
+            LOG(ERROR) << "Failed to retrieve local BufferPool ClientManager.";
+            return bufferpool2::ResultStatus::CRITICAL_ERROR;
+        }
+    }
+
+    int64_t receiverConnectionId{0};
+    auto foundConnection = mConnections.find(connectionId);
+    bool isNewConnection = foundConnection == mConnections.end();
+    std::chrono::steady_clock::time_point now =
+            std::chrono::steady_clock::now();
+    if (isNewConnection ||
+            (now - foundConnection->second.lastSent > mRefreshInterval)) {
+        // Initialize the bufferpool connection.
+        bufferpool2_impl::BufferPoolStatus rs =
+                mSenderManager->registerSender(mReceiverManager,
+                                               connectionId,
+                                               &receiverConnectionId,
+                                               &isNewConnection);
+        if ((rs != bufferpool2::ResultStatus::OK)
+                && (rs != bufferpool2::ResultStatus::ALREADY_EXISTS)) {
+            LOG(WARNING) << "registerSender -- returned error: "
+                         << static_cast<int32_t>(rs)
+                         << ".";
+            return rs;
+        } else if (receiverConnectionId == 0) {
+            LOG(WARNING) << "registerSender -- "
+                            "invalid receiver connection id (0).";
+            return bufferpool2::ResultStatus::CRITICAL_ERROR;
+        } else {
+            if (isNewConnection) {
+                foundConnection = mConnections.try_emplace(
+                        connectionId, receiverConnectionId, now).first;
+            } else {
+                foundConnection->second.receiverConnectionId = receiverConnectionId;
+            }
+        }
+    } else {
+        receiverConnectionId = foundConnection->second.receiverConnectionId;
+    }
+
+    uint64_t transactionId;
+    int64_t timestampUs;
+    bufferpool2_impl::BufferPoolStatus rs = mSenderManager->postSend(
+            receiverConnectionId, bpData, &transactionId, &timestampUs);
+    if (rs != bufferpool2::ResultStatus::OK) {
+        LOG(ERROR) << "ClientManager::postSend -- returned error: "
+                   << static_cast<int32_t>(rs)
+                   << ".";
+        mConnections.erase(foundConnection);
+        return rs;
+    }
+    if (!bpMessage) {
+        LOG(ERROR) << "Null output parameter for BufferStatusMessage.";
+        mConnections.erase(foundConnection);
+        return bufferpool2::ResultStatus::CRITICAL_ERROR;
+    }
+    bpMessage->connectionId = receiverConnectionId;
+    bpMessage->bufferId = bpData->mId;
+    bpMessage->transactionId = transactionId;
+    bpMessage->timestampUs = timestampUs;
+    foundConnection->second.lastSent = now;
+    return rs;
+}
+
+// std::list<std::unique_ptr<C2Work>> -> WorkBundle
+bool ToAidl(
+        WorkBundle* d,
+        const std::list<std::unique_ptr<C2Work>>& s,
+        ::android::BufferPoolSender<BufferPoolTypes>* bufferPoolSender) {
+    return ::android::objcpy(d, s, bufferPoolSender);
+}
 
 // WorkBundle -> std::list<std::unique_ptr<C2Work>>
-bool objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
-    // Convert BaseBlocks to C2BaseBlocks.
-    std::vector<C2BaseBlock> dBaseBlocks(s.baseBlocks.size());
-    for (size_t i = 0; i < s.baseBlocks.size(); ++i) {
-        if (!objcpy(&dBaseBlocks[i], s.baseBlocks[i])) {
-            LOG(ERROR) << "Invalid WorkBundle::baseBlocks["
-                       << i << "].";
-            return false;
-        }
-    }
-
-    d->clear();
-    for (const Work& sWork : s.works) {
-        d->emplace_back(std::make_unique<C2Work>());
-        C2Work& dWork = *d->back();
-
-        // chain info is not in use currently.
-
-        // input
-        if (!objcpy(&dWork.input, sWork.input, dBaseBlocks)) {
-            LOG(ERROR) << "Invalid Work::input.";
-            return false;
-        }
-
-        // worklet(s)
-        dWork.worklets.clear();
-        for (const Worklet& sWorklet : sWork.worklets) {
-            std::unique_ptr<C2Worklet> dWorklet = std::make_unique<C2Worklet>();
-
-            // component id
-            dWorklet->component = static_cast<c2_node_id_t>(
-                    sWorklet.componentId);
-
-            // tunings
-            if (!copyParamsFromBlob(&dWorklet->tunings, sWorklet.tunings)) {
-                LOG(ERROR) << "Invalid Worklet::tunings";
-                return false;
-            }
-
-            // failures
-            dWorklet->failures.clear();
-            dWorklet->failures.reserve(sWorklet.failures.size());
-            for (const SettingResult& sFailure : sWorklet.failures) {
-                std::unique_ptr<C2SettingResult> dFailure;
-                if (!objcpy(&dFailure, sFailure)) {
-                    LOG(ERROR) << "Invalid Worklet::failures.";
-                    return false;
-                }
-                dWorklet->failures.emplace_back(std::move(dFailure));
-            }
-
-            // output
-            if (!objcpy(&dWorklet->output, sWorklet.output, dBaseBlocks)) {
-                LOG(ERROR) << "Invalid Worklet::output.";
-                return false;
-            }
-
-            dWork.worklets.emplace_back(std::move(dWorklet));
-        }
-
-        // workletsProcessed
-        dWork.workletsProcessed = sWork.workletsProcessed;
-
-        // result
-        dWork.result = static_cast<c2_status_t>(sWork.result);
-    }
-
-    return true;
-}
-
-constexpr size_t PARAMS_ALIGNMENT = 8;  // 64-bit alignment
-static_assert(PARAMS_ALIGNMENT % alignof(C2Param) == 0, "C2Param alignment mismatch");
-static_assert(PARAMS_ALIGNMENT % alignof(C2Info) == 0, "C2Param alignment mismatch");
-static_assert(PARAMS_ALIGNMENT % alignof(C2Tuning) == 0, "C2Param alignment mismatch");
-
-// Params -> std::vector<C2Param*>
-bool parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
-    // assuming blob is const here
-    size_t size = blob.size();
-    size_t ix = 0;
-    size_t old_ix = 0;
-    const uint8_t *data = blob.data();
-    C2Param *p = nullptr;
-
-    do {
-        p = C2ParamUtils::ParseFirst(data + ix, size - ix);
-        if (p) {
-            params->emplace_back(p);
-            old_ix = ix;
-            ix += p->size();
-            ix = align(ix, PARAMS_ALIGNMENT);
-            if (ix <= old_ix || ix > size) {
-                android_errorWriteLog(0x534e4554, "238083570");
-                break;
-            }
-        }
-    } while (p);
-
-    if (ix != size) {
-        LOG(ERROR) << "parseParamsBlob -- inconsistent sizes.";
-        return false;
-    }
-    return true;
-}
-
-namespace /* unnamed */ {
-
-/**
- * Concatenates a list of C2Params into a params blob. T is a container type
- * whose member type is compatible with C2Param*.
- *
- * \param[out] blob target blob
- * \param[in] params parameters to concatenate
- * \retval C2_OK if the blob was successfully created
- * \retval C2_BAD_VALUE if the blob was not successful created (this only
- *         happens if the parameters were not const)
- */
-template <typename T>
-bool _createParamsBlob(hidl_vec<uint8_t> *blob, const T &params) {
-    // assuming the parameter values are const
-    size_t size = 0;
-    for (const auto &p : params) {
-        if (!p) {
-            continue;
-        }
-        size += p->size();
-        size = align(size, PARAMS_ALIGNMENT);
-    }
-    blob->resize(size);
-    size_t ix = 0;
-    for (const auto &p : params) {
-        if (!p) {
-            continue;
-        }
-        // NEVER overwrite even if param values (e.g. size) changed
-        size_t paramSize = std::min(p->size(), size - ix);
-        std::copy(
-                reinterpret_cast<const uint8_t*>(&*p),
-                reinterpret_cast<const uint8_t*>(&*p) + paramSize,
-                &(*blob)[ix]);
-        ix += paramSize;
-        ix = align(ix, PARAMS_ALIGNMENT);
-    }
-    blob->resize(ix);
-    if (ix != size) {
-        LOG(ERROR) << "createParamsBlob -- inconsistent sizes.";
-        return false;
-    }
-    return true;
-}
-
-/**
- * Parses a params blob and create a vector of new T objects that contain copies
- * of the params in the blob. T is C2Param or its compatible derived class.
- *
- * \param[out] params the resulting vector
- * \param[in] blob parameter blob to parse
- * \retval C2_OK if the full blob was parsed and params was constructed
- * \retval C2_BAD_VALUE otherwise
- */
-template <typename T>
-bool _copyParamsFromBlob(
-        std::vector<std::unique_ptr<T>>* params,
-        Params blob) {
-
-    std::vector<C2Param*> paramPointers;
-    if (!parseParamsBlob(&paramPointers, blob)) {
-        LOG(ERROR) << "copyParamsFromBlob -- failed to parse.";
-        return false;
-    }
-
-    params->resize(paramPointers.size());
-    size_t i = 0;
-    for (C2Param* const& paramPointer : paramPointers) {
-        if (!paramPointer) {
-            LOG(ERROR) << "copyParamsFromBlob -- null paramPointer.";
-            return false;
-        }
-        (*params)[i++].reset(reinterpret_cast<T*>(
-                C2Param::Copy(*paramPointer).release()));
-    }
-    return true;
-}
-
-} // unnamed namespace
-
-// std::vector<const C2Param*> -> Params
-bool createParamsBlob(
-        hidl_vec<uint8_t> *blob,
-        const std::vector<const C2Param*> &params) {
-    return _createParamsBlob(blob, params);
-}
-
-// std::vector<C2Param*> -> Params
-bool createParamsBlob(
-        hidl_vec<uint8_t> *blob,
-        const std::vector<C2Param*> &params) {
-    return _createParamsBlob(blob, params);
-}
-
-// std::vector<std::unique_ptr<C2Param>> -> Params
-bool createParamsBlob(
-        hidl_vec<uint8_t> *blob,
-        const std::vector<std::unique_ptr<C2Param>> &params) {
-    return _createParamsBlob(blob, params);
-}
-
-// std::vector<std::unique_ptr<C2Tuning>> -> Params
-bool createParamsBlob(
-        hidl_vec<uint8_t> *blob,
-        const std::vector<std::unique_ptr<C2Tuning>> &params) {
-    return _createParamsBlob(blob, params);
-}
-
-// std::vector<std::shared_ptr<const C2Info>> -> Params
-bool createParamsBlob(
-        hidl_vec<uint8_t> *blob,
-        const std::vector<std::shared_ptr<const C2Info>> &params) {
-    return _createParamsBlob(blob, params);
-}
-
-// Params -> std::vector<std::unique_ptr<C2Param>>
-bool copyParamsFromBlob(
-        std::vector<std::unique_ptr<C2Param>>* params,
-        Params blob) {
-    return _copyParamsFromBlob(params, blob);
-}
-
-// Params -> std::vector<std::unique_ptr<C2Tuning>>
-bool copyParamsFromBlob(
-        std::vector<std::unique_ptr<C2Tuning>>* params,
-        Params blob) {
-    return _copyParamsFromBlob(params, blob);
-}
-
-// Params -> update std::vector<std::unique_ptr<C2Param>>
-bool updateParamsFromBlob(
-        const std::vector<C2Param*>& params,
-        const Params& blob) {
-    std::unordered_map<uint32_t, C2Param*> index2param;
-    for (C2Param* const& param : params) {
-        if (!param) {
-            LOG(ERROR) << "updateParamsFromBlob -- null output param.";
-            return false;
-        }
-        if (index2param.find(param->index()) == index2param.end()) {
-            index2param.emplace(param->index(), param);
-        }
-    }
-
-    std::vector<C2Param*> paramPointers;
-    if (!parseParamsBlob(&paramPointers, blob)) {
-        LOG(ERROR) << "updateParamsFromBlob -- failed to parse.";
-        return false;
-    }
-
-    for (C2Param* const& paramPointer : paramPointers) {
-        if (!paramPointer) {
-            LOG(ERROR) << "updateParamsFromBlob -- null input param.";
-            return false;
-        }
-        decltype(index2param)::iterator i = index2param.find(
-                paramPointer->index());
-        if (i == index2param.end()) {
-            LOG(DEBUG) << "updateParamsFromBlob -- index "
-                       << paramPointer->index() << " not found. Skipping...";
-            continue;
-        }
-        if (!i->second->updateFrom(*paramPointer)) {
-            LOG(ERROR) << "updateParamsFromBlob -- size mismatch: "
-                       << params.size() << " vs " << paramPointer->size()
-                       << " (index = " << i->first << ").";
-            return false;
-        }
-    }
-    return true;
-}
-
-// Convert BufferPool ResultStatus to c2_status_t.
-c2_status_t toC2Status(ResultStatus rs) {
-    switch (rs) {
-    case ResultStatus::OK:
-        return C2_OK;
-    case ResultStatus::NO_MEMORY:
-        return C2_NO_MEMORY;
-    case ResultStatus::ALREADY_EXISTS:
-        return C2_DUPLICATE;
-    case ResultStatus::NOT_FOUND:
-        return C2_NOT_FOUND;
-    case ResultStatus::CRITICAL_ERROR:
-        return C2_CORRUPTED;
-    default:
-        LOG(WARNING) << "Unrecognized BufferPool ResultStatus: "
-                     << static_cast<int32_t>(rs) << ".";
-        return C2_CORRUPTED;
-    }
-}
-
-namespace /* unnamed */ {
-
-template <typename BlockProcessor>
-void forEachBlock(C2FrameData& frameData,
-                  BlockProcessor process) {
-    for (const std::shared_ptr<C2Buffer>& buffer : frameData.buffers) {
-        if (buffer) {
-            for (const C2ConstGraphicBlock& block :
-                    buffer->data().graphicBlocks()) {
-                process(block);
-            }
-        }
-    }
-}
-
-template <typename BlockProcessor>
-void forEachBlock(const std::list<std::unique_ptr<C2Work>>& workList,
-                  BlockProcessor process,
-                  bool processInput, bool processOutput) {
-    for (const std::unique_ptr<C2Work>& work : workList) {
-        if (!work) {
-            continue;
-        }
-        if (processInput) {
-            forEachBlock(work->input, process);
-        }
-        if (processOutput) {
-            for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
-                if (worklet) {
-                    forEachBlock(worklet->output,
-                                 process);
-                }
-            }
-        }
-    }
-}
-
-} // unnamed namespace
-
-bool beginTransferBufferQueueBlock(const C2ConstGraphicBlock& block) {
-    std::shared_ptr<_C2BlockPoolData> data =
-            _C2BlockFactory::GetGraphicBlockPoolData(block);
-    if (data && _C2BlockFactory::GetBufferQueueData(data)) {
-        _C2BlockFactory::BeginTransferBlockToClient(data);
-        return true;
-    }
-    return false;
-}
-
-void beginTransferBufferQueueBlocks(
-        const std::list<std::unique_ptr<C2Work>>& workList,
-        bool processInput, bool processOutput) {
-    forEachBlock(workList, beginTransferBufferQueueBlock,
-                 processInput, processOutput);
-}
-
-bool endTransferBufferQueueBlock(
-        const C2ConstGraphicBlock& block,
-        bool transfer) {
-    std::shared_ptr<_C2BlockPoolData> data =
-            _C2BlockFactory::GetGraphicBlockPoolData(block);
-    if (data && _C2BlockFactory::GetBufferQueueData(data)) {
-        _C2BlockFactory::EndTransferBlockToClient(data, transfer);
-        return true;
-    }
-    return false;
-}
-
-void endTransferBufferQueueBlocks(
-        const std::list<std::unique_ptr<C2Work>>& workList,
-        bool transfer,
-        bool processInput, bool processOutput) {
-    forEachBlock(workList,
-                 std::bind(endTransferBufferQueueBlock,
-                           std::placeholders::_1, transfer),
-                 processInput, processOutput);
-}
-
-bool displayBufferQueueBlock(const C2ConstGraphicBlock& block) {
-    std::shared_ptr<_C2BlockPoolData> data =
-            _C2BlockFactory::GetGraphicBlockPoolData(block);
-    if (data && _C2BlockFactory::GetBufferQueueData(data)) {
-        _C2BlockFactory::DisplayBlockToBufferQueue(data);
-        return true;
-    }
-    return false;
+bool FromAidl(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
+    return ::android::objcpy(d, s);
 }
 
 }  // namespace utils
-}  // namespace V1_0
 }  // namespace c2
 }  // namespace media
 }  // namespace hardware
 }  // namespace android
+}  // namespace aidl
 
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/BufferTypes.h b/media/codec2/hal/aidl/include/codec2/aidl/BufferTypes.h
index f111f81..470863c 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/BufferTypes.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/BufferTypes.h
@@ -14,156 +14,36 @@
  * limitations under the License.
  */
 
-#ifndef CODEC2_HIDL_V1_0_UTILS_TYPES_H
-#define CODEC2_HIDL_V1_0_UTILS_TYPES_H
+#ifndef CODEC2_AIDL_BUFFER_TYPES_H
+#define CODEC2_AIDL_BUFFER_TYPES_H
 
-#include <bufferpool/ClientManager.h>
-#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
-#include <android/hardware/media/bufferpool/2.0/types.h>
-#include <android/hardware/media/c2/1.0/IComponentStore.h>
-#include <android/hardware/media/c2/1.0/types.h>
-#include <android/hidl/safe_union/1.0/types.h>
+#include <codec2/common/BufferTypes.h>
 
-#include <C2Component.h>
-#include <C2Param.h>
-#include <C2ParamDef.h>
-#include <C2Work.h>
-#include <util/C2Debug-base.h>
+#include <aidl/android/hardware/media/bufferpool2/BufferStatusMessage.h>
+#include <aidl/android/hardware/media/bufferpool2/IClientManager.h>
+#include <aidl/android/hardware/media/bufferpool2/ResultStatus.h>
+#include <aidl/android/hardware/media/c2/WorkBundle.h>
 
-#include <chrono>
+#include <bufferpool2/BufferPoolTypes.h>
+#include <bufferpool2/ClientManager.h>
 
-using namespace std::chrono_literals;
 
+namespace aidl {
 namespace android {
 namespace hardware {
 namespace media {
 namespace c2 {
-namespace V1_0 {
 namespace utils {
 
-using ::android::hardware::hidl_bitfield;
-using ::android::hardware::hidl_handle;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::status_t;
-using ::android::sp;
-using ::android::hardware::media::bufferpool::V2_0::implementation::
-        ConnectionId;
+namespace bufferpool2 = ::aidl::android::hardware::media::bufferpool2;
 
-// Types of metadata for Blocks.
-struct C2Hidl_Range {
-    uint32_t offset;
-    uint32_t length; // Do not use "size" because the name collides with C2Info::size().
-};
-typedef C2GlobalParam<C2Info, C2Hidl_Range, 0> C2Hidl_RangeInfo;
+using namespace std::chrono_literals;
 
-struct C2Hidl_Rect {
-    uint32_t left;
-    uint32_t top;
-    uint32_t width;
-    uint32_t height;
-};
-typedef C2GlobalParam<C2Info, C2Hidl_Rect, 1> C2Hidl_RectInfo;
-
-// Make asString() and operator<< work with Status as well as c2_status_t.
-C2_DECLARE_AS_STRING_AND_DEFINE_STREAM_OUT(Status);
-
-/**
- * All objcpy() functions will return a boolean value indicating whether the
- * conversion succeeds or not.
- */
-
-// C2SettingResult -> SettingResult
-bool objcpy(
-        SettingResult* d,
-        const C2SettingResult& s);
-
-// SettingResult -> std::unique_ptr<C2SettingResult>
-bool objcpy(
-        std::unique_ptr<C2SettingResult>* d,
-        const SettingResult& s);
-
-// C2ParamDescriptor -> ParamDescriptor
-bool objcpy(
-        ParamDescriptor* d,
-        const C2ParamDescriptor& s);
-
-// ParamDescriptor -> std::shared_ptr<C2ParamDescriptor>
-bool objcpy(
-        std::shared_ptr<C2ParamDescriptor>* d,
-        const ParamDescriptor& s);
-
-// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
-bool objcpy(
-        FieldSupportedValuesQuery* d,
-        const C2FieldSupportedValuesQuery& s);
-
-// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
-bool objcpy(
-        C2FieldSupportedValuesQuery* d,
-        const FieldSupportedValuesQuery& s);
-
-// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
-bool objcpy(
-        FieldSupportedValuesQueryResult* d,
-        const C2FieldSupportedValuesQuery& s);
-
-// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult -> C2FieldSupportedValuesQuery
-bool objcpy(
-        C2FieldSupportedValuesQuery* d,
-        const FieldSupportedValuesQuery& sq,
-        const FieldSupportedValuesQueryResult& sr);
-
-// C2Component::Traits -> ComponentTraits
-bool objcpy(
-        IComponentStore::ComponentTraits* d,
-        const C2Component::Traits& s);
-
-// ComponentTraits -> C2Component::Traits
-bool objcpy(
-        C2Component::Traits* d,
-        const IComponentStore::ComponentTraits& s);
-
-// C2StructDescriptor -> StructDescriptor
-bool objcpy(
-        StructDescriptor* d,
-        const C2StructDescriptor& s);
-
-// StructDescriptor -> C2StructDescriptor
-bool objcpy(
-        std::unique_ptr<C2StructDescriptor>* d,
-        const StructDescriptor& s);
-
-// Abstract class to be used in
-// objcpy(std::list<std::unique_ptr<C2Work>> -> WorkBundle).
-struct BufferPoolSender {
-    typedef ::android::hardware::media::bufferpool::V2_0::
-            ResultStatus ResultStatus;
-    typedef ::android::hardware::media::bufferpool::V2_0::
-            BufferStatusMessage BufferStatusMessage;
-    typedef ::android::hardware::media::bufferpool::
-            BufferPoolData BufferPoolData;
-
-    /**
-     * Send bpData and return BufferStatusMessage that can be supplied to
-     * IClientManager::receive() in the receiving process.
-     *
-     * This function will be called from within the function
-     * objcpy(std::list<std::unique_ptr<C2Work>> -> WorkBundle).
-     *
-     * \param[in] bpData BufferPoolData identifying the buffer to send.
-     * \param[out] bpMessage BufferStatusMessage of the transaction. Information
-     *    inside \p bpMessage should be passed to the receiving process by some
-     *    other means so it can call receive() properly.
-     * \return ResultStatus value that determines the success of the operation.
-     *    (See the possible values of ResultStatus in
-     *    hardware/interfaces/media/bufferpool/2.0/types.hal.)
-     */
-    virtual ResultStatus send(
-            const std::shared_ptr<BufferPoolData>& bpData,
-            BufferStatusMessage* bpMessage) = 0;
-
-    virtual ~BufferPoolSender() = default;
+struct BufferPoolTypes {
+    typedef bufferpool2::BufferPoolData BufferPoolData;
+    typedef bufferpool2::ResultStatus ResultStatus;
+    typedef bufferpool2::implementation::BufferPoolStatus BufferPoolStatus;
+    typedef bufferpool2::BufferStatusMessage BufferStatusMessage;
 };
 
 // Default implementation of BufferPoolSender.
@@ -173,18 +53,16 @@
 // hold a strong reference to the IClientManager instance and use it to call
 // IClientManager::registerSender() to establish the bufferpool connection when
 // send() is called.
-struct DefaultBufferPoolSender : BufferPoolSender {
-    typedef ::android::hardware::media::bufferpool::V2_0::implementation::
-            ClientManager ClientManager;
-    typedef ::android::hardware::media::bufferpool::V2_0::
-            IClientManager IClientManager;
+struct DefaultBufferPoolSender : ::android::BufferPoolSender<BufferPoolTypes> {
+    typedef bufferpool2::implementation::ClientManager ClientManager;
+    typedef bufferpool2::IClientManager IClientManager;
 
     // Set the IClientManager instance of the receiving process and the refresh
     // interval for the connection. The default interval is 4.5 seconds, which
     // is slightly shorter than the amount of time the bufferpool will keep an
     // inactive connection for.
     DefaultBufferPoolSender(
-            const sp<IClientManager>& receiverManager = nullptr,
+            const std::shared_ptr<IClientManager>& receiverManager = nullptr,
             std::chrono::steady_clock::duration refreshInterval = 4500ms);
 
     // Set the IClientManager instance of the receiving process and the refresh
@@ -192,20 +70,20 @@
     // is slightly shorter than the amount of time the bufferpool will keep an
     // inactive connection for.
     void setReceiver(
-            const sp<IClientManager>& receiverManager,
+            const std::shared_ptr<IClientManager>& receiverManager,
             std::chrono::steady_clock::duration refreshInterval = 4500ms);
 
     // Implementation of BufferPoolSender::send(). send() will establish a
     // bufferpool connection if needed, then send the bufferpool data over to
     // the receiving process.
-    virtual ResultStatus send(
+    BufferPoolStatus send(
             const std::shared_ptr<BufferPoolData>& bpData,
             BufferStatusMessage* bpMessage) override;
 
 private:
     std::mutex mMutex;
-    sp<ClientManager> mSenderManager;
-    sp<IClientManager> mReceiverManager;
+    std::shared_ptr<ClientManager> mSenderManager;
+    std::shared_ptr<IClientManager> mReceiverManager;
     std::chrono::steady_clock::duration mRefreshInterval;
 
     struct Connection {
@@ -227,137 +105,28 @@
 
 // std::list<std::unique_ptr<C2Work>> -> WorkBundle
 // Note: If bufferpool will be used, bpSender must not be null.
-bool objcpy(
+bool ToAidl(
         WorkBundle* d,
         const std::list<std::unique_ptr<C2Work>>& s,
-        BufferPoolSender* bpSender = nullptr);
+        ::android::BufferPoolSender<BufferPoolTypes>* bpSender = nullptr);
 
 // WorkBundle -> std::list<std::unique_ptr<C2Work>>
-bool objcpy(
+bool FromAidl(
         std::list<std::unique_ptr<C2Work>>* d,
         const WorkBundle& s);
 
 /**
- * Parses a params blob and returns C2Param pointers to its params. The pointers
- * point to locations inside the underlying buffer of \p blob. If \p blob is
- * destroyed, the pointers become invalid.
- *
- * \param[out] params target vector of C2Param pointers
- * \param[in] blob parameter blob to parse
- * \retval true if the full blob was parsed
- * \retval false otherwise
- */
-bool parseParamsBlob(
-        std::vector<C2Param*> *params,
-        const hidl_vec<uint8_t> &blob);
-
-/**
- * Concatenates a list of C2Params into a params blob.
- *
- * \param[out] blob target blob
- * \param[in] params parameters to concatenate
- * \retval true if the blob was successfully created
- * \retval false if the blob was not successful (this only happens if the
- *         parameters were not const)
- */
-bool createParamsBlob(
-        hidl_vec<uint8_t> *blob,
-        const std::vector<C2Param*> &params);
-bool createParamsBlob(
-        hidl_vec<uint8_t> *blob,
-        const std::vector<std::unique_ptr<C2Param>> &params);
-bool createParamsBlob(
-        hidl_vec<uint8_t> *blob,
-        const std::vector<std::shared_ptr<const C2Info>> &params);
-bool createParamsBlob(
-        hidl_vec<uint8_t> *blob,
-        const std::vector<std::unique_ptr<C2Tuning>> &params);
-
-/**
- * Parses a params blob and create a vector of C2Params whose members are copies
- * of the params in the blob.
- *
- * \param[out] params the resulting vector
- * \param[in] blob parameter blob to parse
- * \retval true if the full blob was parsed and params was constructed
- * \retval false otherwise
- */
-bool copyParamsFromBlob(
-        std::vector<std::unique_ptr<C2Param>>* params,
-        Params blob);
-bool copyParamsFromBlob(
-        std::vector<std::unique_ptr<C2Tuning>>* params,
-        Params blob);
-
-/**
- * Parses a params blob and applies updates to params.
- *
- * \param[in,out] params params to be updated
- * \param[in] blob parameter blob containing updates
- * \retval true if the full blob was parsed and params was updated
- * \retval false otherwise
- */
-bool updateParamsFromBlob(
-        const std::vector<C2Param*>& params,
-        const Params& blob);
-
-/**
  * Converts a BufferPool status value to c2_status_t.
  * \param BufferPool status
  * \return Corresponding c2_status_t
  */
-c2_status_t toC2Status(::android::hardware::media::bufferpool::V2_0::
-        ResultStatus rs);
-
-// BufferQueue-Based Block Operations
-// ==================================
-
-// Call before transferring block to other processes.
-//
-// The given block is ready to transfer to other processes. This will guarantee
-// the given block data is not mutated by bufferqueue migration.
-bool beginTransferBufferQueueBlock(const C2ConstGraphicBlock& block);
-
-// Call beginTransferBufferQueueBlock() on blocks in the given workList.
-// processInput determines whether input blocks are yielded. processOutput
-// works similarly on output blocks. (The default value of processInput is
-// false while the default value of processOutput is true. This implies that in
-// most cases, only output buffers contain bufferqueue-based blocks.)
-void beginTransferBufferQueueBlocks(
-        const std::list<std::unique_ptr<C2Work>>& workList,
-        bool processInput = false,
-        bool processOutput = true);
-
-// Call after transferring block is finished and make sure that
-// beginTransferBufferQueueBlock() is called before.
-//
-// The transfer of given block is finished. If transfer is successful the given
-// block is not owned by process anymore. Since transfer is finished the given
-// block data is OK to mutate by bufferqueue migration after this call.
-bool endTransferBufferQueueBlock(const C2ConstGraphicBlock& block,
-                                 bool transfer);
-
-// Call endTransferBufferQueueBlock() on blocks in the given workList.
-// processInput determines whether input blocks are yielded. processOutput
-// works similarly on output blocks. (The default value of processInput is
-// false while the default value of processOutput is true. This implies that in
-// most cases, only output buffers contain bufferqueue-based blocks.)
-void endTransferBufferQueueBlocks(
-        const std::list<std::unique_ptr<C2Work>>& workList,
-        bool transfer,
-        bool processInput = false,
-        bool processOutput = true);
-
-// The given block is ready to be rendered. the given block is not owned by
-// process anymore. If migration is in progress, this returns false in order
-// not to render.
-bool displayBufferQueueBlock(const C2ConstGraphicBlock& block);
+c2_status_t toC2Status(BufferPoolTypes::BufferPoolStatus rs);
 
 }  // namespace utils
-}  // namespace V1_0
 }  // namespace c2
 }  // namespace media
 }  // namespace hardware
 }  // namespace android
+}  // namespace aidl
 
-#endif  // CODEC2_HIDL_V1_0_UTILS_TYPES_H
+#endif  // CODEC2_AIDL_BUFFER_TYPES_H
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index ecd5463..638e72c 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -52,7 +52,6 @@
         "android.hardware.drm@1.0",
         "android.hardware.media.c2@1.0",
         "android.hardware.media.omx@1.0",
-        "android.hardware.graphics.mapper@4.0",
         "libbase",
         "libbinder",
         "libcodec2",
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 228ad7e..3bb6593 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -26,9 +26,6 @@
 #include <android-base/properties.h>
 #include <android/hardware/cas/native/1.0/types.h>
 #include <android/hardware/drm/1.0/types.h>
-#include <android/hardware/graphics/common/1.2/types.h>
-#include <android/hardware/graphics/mapper/4.0/IMapper.h>
-#include <gralloctypes/Gralloc4.h>
 #include <hidlmemory/FrameworkUtils.h>
 #include <media/hardware/HardwareAPI.h>
 #include <media/stagefright/CodecBase.h>
@@ -38,6 +35,7 @@
 #include <media/stagefright/foundation/AUtils.h>
 #include <mediadrm/ICrypto.h>
 #include <nativebase/nativebase.h>
+#include <ui/GraphicBufferMapper.h>
 #include <ui/Fence.h>
 
 #include <C2AllocatorGralloc.h>
@@ -1039,34 +1037,15 @@
 }
 
 using ::aidl::android::hardware::graphics::common::Cta861_3;
-using ::aidl::android::hardware::graphics::common::Dataspace;
 using ::aidl::android::hardware::graphics::common::Smpte2086;
 
-using ::android::gralloc4::MetadataType_Cta861_3;
-using ::android::gralloc4::MetadataType_Dataspace;
-using ::android::gralloc4::MetadataType_Smpte2086;
-using ::android::gralloc4::MetadataType_Smpte2094_40;
-
-using ::android::hardware::Return;
-using ::android::hardware::hidl_vec;
-
-using Error4 = ::android::hardware::graphics::mapper::V4_0::Error;
-using IMapper4 = ::android::hardware::graphics::mapper::V4_0::IMapper;
-
 namespace {
 
-sp<IMapper4> GetMapper4() {
-    static ::android::base::NoDestructor<sp<IMapper4>> sMapper(IMapper4::getService());
-    return *sMapper;
-}
-
-class Gralloc4Buffer {
+class GrallocBuffer {
 public:
-    Gralloc4Buffer(const C2Handle *const handle) : mBuffer(nullptr) {
-        sp<IMapper4> mapper = GetMapper4();
-        if (!mapper) {
-            return;
-        }
+    GrallocBuffer(const C2Handle *const handle) : mBuffer(nullptr) {
+        GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+
         // Unwrap raw buffer handle from the C2Handle
         native_handle_t *nh = UnwrapNativeCodec2GrallocHandle(handle);
         if (!nh) {
@@ -1074,13 +1053,14 @@
         }
         // Import the raw handle so IMapper can use the buffer. The imported
         // handle must be freed when the client is done with the buffer.
-        mapper->importBuffer(
-                hardware::hidl_handle(nh),
-                [&](const Error4 &error, void *buffer) {
-                    if (error == Error4::NONE) {
-                        mBuffer = buffer;
-                    }
-                });
+        status_t status = mapper.importBufferNoValidate(
+                nh,
+                &mBuffer);
+
+        if (status != OK) {
+            ALOGE("Failed to import buffer. Status: %d.", status);
+            return;
+        }
 
         // TRICKY: UnwrapNativeCodec2GrallocHandle creates a new handle but
         //         does not clone the fds. Thus we need to delete the handle
@@ -1088,19 +1068,19 @@
         native_handle_delete(nh);
     }
 
-    ~Gralloc4Buffer() {
-        sp<IMapper4> mapper = GetMapper4();
-        if (mapper && mBuffer) {
+    ~GrallocBuffer() {
+        GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+        if (mBuffer) {
             // Free the imported buffer handle. This does not release the
             // underlying buffer itself.
-            mapper->freeBuffer(mBuffer);
+            mapper.freeBuffer(mBuffer);
         }
     }
 
-    void *get() const { return mBuffer; }
+    buffer_handle_t get() const { return mBuffer; }
     operator bool() const { return (mBuffer != nullptr); }
 private:
-    void *mBuffer;
+    buffer_handle_t mBuffer;
 };
 
 }  // namspace
@@ -1110,69 +1090,48 @@
         std::shared_ptr<C2StreamHdrStaticMetadataInfo::input> *staticInfo,
         std::shared_ptr<C2StreamHdrDynamicMetadataInfo::input> *dynamicInfo) {
     c2_status_t err = C2_OK;
-    sp<IMapper4> mapper = GetMapper4();
-    Gralloc4Buffer buffer(handle);
-    if (!mapper || !buffer) {
+    GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+    GrallocBuffer buffer(handle);
+    if (!buffer) {
         // Gralloc4 not supported; nothing to do
         return err;
     }
-    Error4 mapperErr = Error4::NONE;
     if (staticInfo) {
-        ALOGV("Grabbing static HDR info from gralloc4 metadata");
+        ALOGV("Grabbing static HDR info from gralloc metadata");
         staticInfo->reset(new C2StreamHdrStaticMetadataInfo::input(0u));
         memset(&(*staticInfo)->mastering, 0, sizeof((*staticInfo)->mastering));
         (*staticInfo)->maxCll = 0;
         (*staticInfo)->maxFall = 0;
-        IMapper4::get_cb cb = [&mapperErr, staticInfo](Error4 err, const hidl_vec<uint8_t> &vec) {
-            mapperErr = err;
-            if (err != Error4::NONE) {
-                return;
-            }
 
-            std::optional<Smpte2086> smpte2086;
-            gralloc4::decodeSmpte2086(vec, &smpte2086);
+        std::optional<Smpte2086> smpte2086;
+        status_t status = mapper.getSmpte2086(buffer.get(), &smpte2086);
+        if (status != OK) {
+            err = C2_CORRUPTED;
+        } else {
             if (smpte2086) {
-                (*staticInfo)->mastering.red.x    = smpte2086->primaryRed.x;
-                (*staticInfo)->mastering.red.y    = smpte2086->primaryRed.y;
-                (*staticInfo)->mastering.green.x  = smpte2086->primaryGreen.x;
-                (*staticInfo)->mastering.green.y  = smpte2086->primaryGreen.y;
-                (*staticInfo)->mastering.blue.x   = smpte2086->primaryBlue.x;
-                (*staticInfo)->mastering.blue.y   = smpte2086->primaryBlue.y;
-                (*staticInfo)->mastering.white.x  = smpte2086->whitePoint.x;
-                (*staticInfo)->mastering.white.y  = smpte2086->whitePoint.y;
+                  (*staticInfo)->mastering.red.x    = smpte2086->primaryRed.x;
+                  (*staticInfo)->mastering.red.y    = smpte2086->primaryRed.y;
+                  (*staticInfo)->mastering.green.x  = smpte2086->primaryGreen.x;
+                  (*staticInfo)->mastering.green.y  = smpte2086->primaryGreen.y;
+                  (*staticInfo)->mastering.blue.x   = smpte2086->primaryBlue.x;
+                  (*staticInfo)->mastering.blue.y   = smpte2086->primaryBlue.y;
+                  (*staticInfo)->mastering.white.x  = smpte2086->whitePoint.x;
+                  (*staticInfo)->mastering.white.y  = smpte2086->whitePoint.y;
 
-                (*staticInfo)->mastering.maxLuminance = smpte2086->maxLuminance;
-                (*staticInfo)->mastering.minLuminance = smpte2086->minLuminance;
-            } else {
-                mapperErr = Error4::BAD_VALUE;
+                  (*staticInfo)->mastering.maxLuminance = smpte2086->maxLuminance;
+                  (*staticInfo)->mastering.minLuminance = smpte2086->minLuminance;
             }
-        };
-        Return<void> ret = mapper->get(buffer.get(), MetadataType_Smpte2086, cb);
-        if (!ret.isOk()) {
-            err = C2_REFUSED;
-        } else if (mapperErr != Error4::NONE) {
-            err = C2_CORRUPTED;
         }
-        cb = [&mapperErr, staticInfo](Error4 err, const hidl_vec<uint8_t> &vec) {
-            mapperErr = err;
-            if (err != Error4::NONE) {
-                return;
-            }
 
-            std::optional<Cta861_3> cta861_3;
-            gralloc4::decodeCta861_3(vec, &cta861_3);
-            if (cta861_3) {
-                (*staticInfo)->maxCll   = cta861_3->maxContentLightLevel;
-                (*staticInfo)->maxFall  = cta861_3->maxFrameAverageLightLevel;
-            } else {
-                mapperErr = Error4::BAD_VALUE;
-            }
-        };
-        ret = mapper->get(buffer.get(), MetadataType_Cta861_3, cb);
-        if (!ret.isOk()) {
-            err = C2_REFUSED;
-        } else if (mapperErr != Error4::NONE) {
+        std::optional<Cta861_3> cta861_3;
+        status = mapper.getCta861_3(buffer.get(), &cta861_3);
+        if (status != OK) {
             err = C2_CORRUPTED;
+        } else {
+            if (cta861_3) {
+                  (*staticInfo)->maxCll   = cta861_3->maxContentLightLevel;
+                  (*staticInfo)->maxFall  = cta861_3->maxFrameAverageLightLevel;
+            }
         }
     }
 
@@ -1181,23 +1140,19 @@
     }
 
     if (dynamicInfo) {
-        ALOGV("Grabbing dynamic HDR info from gralloc4 metadata");
+        ALOGV("Grabbing dynamic HDR info from gralloc metadata");
         dynamicInfo->reset();
-        IMapper4::get_cb cb = [&mapperErr, dynamicInfo](Error4 err, const hidl_vec<uint8_t> &vec) {
-            mapperErr = err;
-            if (err != Error4::NONE) {
-                return;
-            }
-            if (!dynamicInfo) {
-                return;
-            }
-            *dynamicInfo = C2StreamHdrDynamicMetadataInfo::input::AllocShared(
-                    vec.size(), 0u, C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40);
-            memcpy((*dynamicInfo)->m.data, vec.data(), vec.size());
-        };
-        Return<void> ret = mapper->get(buffer.get(), MetadataType_Smpte2094_40, cb);
-        if (!ret.isOk() || mapperErr != Error4::NONE) {
+        std::optional<std::vector<uint8_t>> vec;
+        status_t status = mapper.getSmpte2094_40(buffer.get(), &vec);
+        if (status != OK) {
             dynamicInfo->reset();
+            err = C2_CORRUPTED;
+        } else {
+            if (vec) {
+                *dynamicInfo = C2StreamHdrDynamicMetadataInfo::input::AllocShared(
+                      vec->size(), 0u, C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40);
+                memcpy((*dynamicInfo)->m.data, vec->data(), vec->size());
+            }
         }
     }
 
@@ -1210,25 +1165,18 @@
         const std::shared_ptr<const C2StreamHdrDynamicMetadataInfo::output> &dynamicInfo,
         const C2Handle *const handle) {
     c2_status_t err = C2_OK;
-    sp<IMapper4> mapper = GetMapper4();
-    Gralloc4Buffer buffer(handle);
-    if (!mapper || !buffer) {
+    GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+    GrallocBuffer buffer(handle);
+    if (!buffer) {
         // Gralloc4 not supported; nothing to do
         return err;
     }
-    {
-        hidl_vec<uint8_t> metadata;
-        if (gralloc4::encodeDataspace(static_cast<Dataspace>(dataSpace), &metadata) == OK) {
-            Return<Error4> ret = mapper->set(buffer.get(), MetadataType_Dataspace, metadata);
-            if (!ret.isOk()) {
-                err = C2_REFUSED;
-            } else if (ret != Error4::NONE) {
-                err = C2_CORRUPTED;
-            }
-        }
+    status_t status = mapper.setDataspace(buffer.get(), static_cast<ui::Dataspace>(dataSpace));
+    if (status != OK) {
+       err = C2_CORRUPTED;
     }
     if (staticInfo && *staticInfo) {
-        ALOGV("Setting static HDR info as gralloc4 metadata");
+        ALOGV("Setting static HDR info as gralloc metadata");
         std::optional<Smpte2086> smpte2086 = Smpte2086{
             {staticInfo->mastering.red.x, staticInfo->mastering.red.y},
             {staticInfo->mastering.green.x, staticInfo->mastering.green.y},
@@ -1237,7 +1185,6 @@
             staticInfo->mastering.maxLuminance,
             staticInfo->mastering.minLuminance,
         };
-        hidl_vec<uint8_t> vec;
         if (0.0 <= smpte2086->primaryRed.x && smpte2086->primaryRed.x <= 1.0
                 && 0.0 <= smpte2086->primaryRed.y && smpte2086->primaryRed.y <= 1.0
                 && 0.0 <= smpte2086->primaryGreen.x && smpte2086->primaryGreen.x <= 1.0
@@ -1246,12 +1193,9 @@
                 && 0.0 <= smpte2086->primaryBlue.y && smpte2086->primaryBlue.y <= 1.0
                 && 0.0 <= smpte2086->whitePoint.x && smpte2086->whitePoint.x <= 1.0
                 && 0.0 <= smpte2086->whitePoint.y && smpte2086->whitePoint.y <= 1.0
-                && 0.0 <= smpte2086->maxLuminance && 0.0 <= smpte2086->minLuminance
-                && gralloc4::encodeSmpte2086(smpte2086, &vec) == OK) {
-            Return<Error4> ret = mapper->set(buffer.get(), MetadataType_Smpte2086, vec);
-            if (!ret.isOk()) {
-                err = C2_REFUSED;
-            } else if (ret != Error4::NONE) {
+                && 0.0 <= smpte2086->maxLuminance && 0.0 <= smpte2086->minLuminance) {
+            status = mapper.setSmpte2086(buffer.get(), smpte2086);
+            if (status != OK) {
                 err = C2_CORRUPTED;
             }
         }
@@ -1259,41 +1203,23 @@
             staticInfo->maxCll,
             staticInfo->maxFall,
         };
-        if (0.0 <= cta861_3->maxContentLightLevel && 0.0 <= cta861_3->maxFrameAverageLightLevel
-                && gralloc4::encodeCta861_3(cta861_3, &vec) == OK) {
-            Return<Error4> ret = mapper->set(buffer.get(), MetadataType_Cta861_3, vec);
-            if (!ret.isOk()) {
-                err = C2_REFUSED;
-            } else if (ret != Error4::NONE) {
+        if (0.0 <= cta861_3->maxContentLightLevel && 0.0 <= cta861_3->maxFrameAverageLightLevel) {
+            status = mapper.setCta861_3(buffer.get(), cta861_3);
+            if (status != OK) {
                 err = C2_CORRUPTED;
             }
         }
     }
     if (dynamicInfo && *dynamicInfo && dynamicInfo->flexCount() > 0) {
-        ALOGV("Setting dynamic HDR info as gralloc4 metadata");
-        std::optional<IMapper4::MetadataType> metadataType;
-        switch (dynamicInfo->m.type_) {
-        case C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_10:
-            // TODO
-            break;
-        case C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40:
-            metadataType = MetadataType_Smpte2094_40;
-            break;
-        }
+        ALOGV("Setting dynamic HDR info as gralloc metadata");
+        if (dynamicInfo->m.type_ == C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40) {
+            std::optional<std::vector<uint8_t>> smpte2094_40 = std::vector<uint8_t>();
+            smpte2094_40->resize(dynamicInfo->flexCount());
+            memcpy(smpte2094_40->data(), dynamicInfo->m.data, dynamicInfo->flexCount());
 
-        if (metadataType) {
-            std::vector<uint8_t> smpte2094_40;
-            smpte2094_40.resize(dynamicInfo->flexCount());
-            memcpy(smpte2094_40.data(), dynamicInfo->m.data, dynamicInfo->flexCount());
-
-            hidl_vec<uint8_t> vec;
-            if (gralloc4::encodeSmpte2094_40({ smpte2094_40 }, &vec) == OK) {
-                Return<Error4> ret = mapper->set(buffer.get(), *metadataType, vec);
-                if (!ret.isOk()) {
-                    err = C2_REFUSED;
-                } else if (ret != Error4::NONE) {
-                    err = C2_CORRUPTED;
-                }
+            status = mapper.setSmpte2094_40(buffer.get(), smpte2094_40);
+            if (status != OK) {
+                err = C2_CORRUPTED;
             }
         } else {
             err = C2_BAD_VALUE;
diff --git a/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp b/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp
index b97f347..2016b2a 100644
--- a/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp
+++ b/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp
@@ -192,7 +192,9 @@
     sp<MetaData> trackMeta = new MetaData;
     convertMessageToMetaData(format, trackMeta);
     mCurrentTrack[trackIndex] = new MediaAdapter(trackMeta);
-    mWriter->addSource(mCurrentTrack[trackIndex]);
+    if (mWriter->addSource(mCurrentTrack[trackIndex]) != OK) {
+        mCurrentTrack[trackIndex] = nullptr;
+    }
 }
 
 void WriterFuzzerBase::start() {
@@ -202,13 +204,14 @@
 
 void WriterFuzzerBase::sendBuffersToWriter(sp<MediaAdapter> &currentTrack, int32_t trackIndex,
                                            int32_t startFrameIndex, int32_t endFrameIndex) {
+    if (!mCurrentTrack[trackIndex]) {
+        return;
+    }
     vector<FrameData> bufferInfo = mBufferSource->getFrameList(trackIndex);
     for (int idx = startFrameIndex; idx < endFrameIndex; ++idx) {
         sp<ABuffer> buffer = new ABuffer((void *)bufferInfo[idx].buf, bufferInfo[idx].size);
         MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
 
-        // Released in MediaAdapter::signalBufferReturned().
-        mediaBuffer->add_ref();
         mediaBuffer->set_range(buffer->offset(), buffer->size());
         MetaDataBase &sampleMetaData = mediaBuffer->meta_data();
         sampleMetaData.setInt64(kKeyTime, bufferInfo[idx].timeUs);
@@ -219,8 +222,13 @@
             sampleMetaData.setInt32(kKeyIsSyncFrame, true);
         }
 
+        // Released in MediaAdapter::signalBufferReturned().
+        mediaBuffer->add_ref();
+
         // This pushBuffer will wait until the mediaBuffer is consumed.
-        currentTrack->pushBuffer(mediaBuffer);
+        if (currentTrack->pushBuffer(mediaBuffer) != OK) {
+            mediaBuffer->release();
+        }
     }
 }
 
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 42c4986..bbfe763 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -990,13 +990,6 @@
                     &size,
                     &cmdStatus);
         }
-
-        if (isVolumeControl()) {
-            // Force initializing the volume as 0 for volume control effect for safer ramping
-            uint32_t left = 0;
-            uint32_t right = 0;
-            setVolumeInternal(&left, &right, true /*controller*/);
-        }
     }
 
     // mConfig.outputCfg.buffer.frameCount cannot be zero.
@@ -2096,7 +2089,7 @@
 AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& thread,
                                        audio_session_t sessionId)
     : mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
-      mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
+      mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
       mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX),
       mEffectCallback(new EffectCallback(wp<EffectChain>(this), thread))
 {
@@ -2342,6 +2335,15 @@
     return NO_ERROR;
 }
 
+std::optional<size_t> AudioFlinger::EffectChain::findVolumeControl_l(size_t from, size_t to) const {
+    for (size_t i = std::min(to, mEffects.size()); i > from; i--) {
+        if (mEffects[i - 1]->isVolumeControlEnabled()) {
+            return i - 1;
+        }
+    }
+    return std::nullopt;
+}
+
 ssize_t AudioFlinger::EffectChain::getInsertIndex(const effect_descriptor_t& desc) {
     // Insert effects are inserted at the end of mEffects vector as they are processed
     //  after track and auxiliary effects.
@@ -2511,29 +2513,38 @@
 {
     uint32_t newLeft = *left;
     uint32_t newRight = *right;
-    bool hasControl = false;
-    int ctrlIdx = -1;
-    size_t size = mEffects.size();
+    const size_t size = mEffects.size();
 
     // first update volume controller
-    for (size_t i = size; i > 0; i--) {
-        if (mEffects[i - 1]->isVolumeControlEnabled()) {
-            ctrlIdx = i - 1;
-            hasControl = true;
-            break;
-        }
-    }
+    const auto volumeControlIndex = findVolumeControl_l(0, size);
+    const int ctrlIdx = volumeControlIndex.value_or(-1);
+    const sp<EffectModule> volumeControlEffect =
+            volumeControlIndex.has_value() ? mEffects[ctrlIdx] : nullptr;
+    const sp<EffectModule> cachedVolumeControlEffect = mVolumeControlEffect.promote();
 
-    if (!force && ctrlIdx == mVolumeCtrlIdx &&
+    if (!force && volumeControlEffect == cachedVolumeControlEffect &&
             *left == mLeftVolume && *right == mRightVolume) {
-        if (hasControl) {
+        if (volumeControlIndex.has_value()) {
             *left = mNewLeftVolume;
             *right = mNewRightVolume;
         }
-        return hasControl;
+        return volumeControlIndex.has_value();
     }
 
-    mVolumeCtrlIdx = ctrlIdx;
+    if (volumeControlEffect != cachedVolumeControlEffect) {
+        // The volume control effect is a new one. Set the old one as full volume. Set the new onw
+        // as zero for safe ramping.
+        if (cachedVolumeControlEffect != nullptr) {
+            uint32_t leftMax = 1 << 24;
+            uint32_t rightMax = 1 << 24;
+            cachedVolumeControlEffect->setVolume(&leftMax, &rightMax, true /*controller*/);
+        }
+        if (volumeControlEffect != nullptr) {
+            uint32_t leftZero = 0;
+            uint32_t rightZero = 0;
+            volumeControlEffect->setVolume(&leftZero, &rightZero, true /*controller*/);
+        }
+    }
     mLeftVolume = newLeft;
     mRightVolume = newRight;
 
@@ -2570,7 +2581,7 @@
 
     setVolumeForOutput_l(*left, *right);
 
-    return hasControl;
+    return volumeControlIndex.has_value();
 }
 
 // resetVolume_l() must be called with ThreadBase::mLock or EffectChain::mLock held
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index e1a76fc..24e20f3 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -673,6 +673,8 @@
 
     ssize_t getInsertIndex(const effect_descriptor_t& desc);
 
+    std::optional<size_t> findVolumeControl_l(size_t from, size_t to) const;
+
     mutable  Mutex mLock;        // mutex protecting effect list
              Vector< sp<EffectModule> > mEffects; // list of effect modules
              audio_session_t mSessionId; // audio session ID
@@ -685,7 +687,6 @@
 
              int32_t mTailBufferCount;   // current effect tail buffer count
              int32_t mMaxTailBuffers;    // maximum effect tail buffers
-             int mVolumeCtrlIdx;         // index of insert effect having control over volume
              uint32_t mLeftVolume;       // previous volume on left channel
              uint32_t mRightVolume;      // previous volume on right channel
              uint32_t mNewLeftVolume;       // new volume on left channel
@@ -698,6 +699,8 @@
              KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
 
              const sp<EffectCallback> mEffectCallback;
+
+             wp<EffectModule> mVolumeControlEffect;
 };
 
 class DeviceEffectProxy : public EffectBase {
diff --git a/services/camera/libcameraservice/device3/StatusTracker.cpp b/services/camera/libcameraservice/device3/StatusTracker.cpp
index ea1f2c1..bd78e0a 100644
--- a/services/camera/libcameraservice/device3/StatusTracker.cpp
+++ b/services/camera/libcameraservice/device3/StatusTracker.cpp
@@ -172,6 +172,7 @@
         }
     }
 
+    bool waitForIdleFence = false;
     // After new pending states appear, or timeout, check if we're idle.  Even
     // with timeout, need to check to account for fences that may still be
     // clearing out
@@ -196,6 +197,7 @@
             ssize_t idx = mStates.indexOfKey(newState.id);
             // Ignore notices for unknown components
             if (idx >= 0) {
+                bool validFence = newState.fence != Fence::NO_FENCE;
                 // Update single component state
                 mStates.replaceValueAt(idx, newState.state);
                 mIdleFence = Fence::merge(String8("idleFence"),
@@ -204,6 +206,8 @@
                 ComponentState newState = getDeviceStateLocked();
                 if (newState != prevState) {
                     mStateTransitions.add(newState);
+                } else if (validFence && !waitForIdleFence) {
+                    waitForIdleFence = true;
                 }
                 prevState = newState;
             }
@@ -227,6 +231,13 @@
     }
     mStateTransitions.clear();
 
+    if (waitForIdleFence) {
+        auto ret = mIdleFence->wait(kWaitDuration);
+        if (ret == NO_ERROR) {
+            mComponentsChanged = true;
+        }
+    }
+
     return true;
 }