Merge "CSD: Add csd start/stop of BT categorized devices" into main
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 866dc72..921aab2 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -165,11 +165,6 @@
     include_dirs: [
         "system/media/private/camera/include",
     ],
-    product_variables: {
-        pdk: {
-            enabled: false,
-        },
-    },
 }
 
 cc_test {
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index bd679e5..af00e55 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -5384,7 +5384,7 @@
      * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_DEFAULT">CameraMetadata#SENSOR_PIXEL_MODE_DEFAULT</a> mode.
      * They can be queried through
      * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#get">CameraCharacteristics#get</a> with
-     * <a href="https://developer.android.com/reference/CameraCharacteristics.html#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION)">CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION)</a>.
+     * <a href="https://developer.android.com/reference/CameraCharacteristics.html#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION">CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION</a>.
      * Unless reported by both
      * <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html">StreamConfigurationMap</a>s, the outputs from
      * <code>android.scaler.streamConfigurationMapMaximumResolution</code> and
@@ -5399,13 +5399,12 @@
      * <ul>
      * <li>
      * <p>The mandatory stream combinations listed in
-     *   <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics/mandatoryMaximumResolutionStreamCombinations.html">mandatoryMaximumResolutionStreamCombinations</a>
-     *   would not apply.</p>
+     *   android.scaler.mandatoryMaximumResolutionStreamCombinations  would not apply.</p>
      * </li>
      * <li>
      * <p>The bayer pattern of {@code RAW} streams when
      *   <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>
-     *   is selected will be the one listed in <a href="https://developer.android.com/reference/android/sensor/info/binningFactor.html">binningFactor</a>.</p>
+     *   is selected will be the one listed in ACAMERA_SENSOR_INFO_BINNING_FACTOR.</p>
      * </li>
      * <li>
      * <p>The following keys will always be present:</p>
@@ -5419,6 +5418,7 @@
      * </ul>
      *
      * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
+     * @see ACAMERA_SENSOR_INFO_BINNING_FACTOR
      * @see ACAMERA_SENSOR_INFO_PIXEL_ARRAY_SIZE_MAXIMUM_RESOLUTION
      * @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
      */
diff --git a/cmds/screenrecord/Overlay.cpp b/cmds/screenrecord/Overlay.cpp
index 17d7046..a19ef8e 100644
--- a/cmds/screenrecord/Overlay.cpp
+++ b/cmds/screenrecord/Overlay.cpp
@@ -90,9 +90,12 @@
 
 status_t Overlay::stop() {
     ALOGV("Overlay::stop");
-    Mutex::Autolock _l(mMutex);
-    mState = STOPPING;
-    mEventCond.signal();
+    {
+        Mutex::Autolock _l(mMutex);
+        mState = STOPPING;
+        mEventCond.signal();
+    }
+    join();
     return NO_ERROR;
 }
 
diff --git a/media/codec2/hal/aidl/Android.bp b/media/codec2/hal/aidl/Android.bp
new file mode 100644
index 0000000..01cd354
--- /dev/null
+++ b/media/codec2/hal/aidl/Android.bp
@@ -0,0 +1,149 @@
+package {
+    default_applicable_licenses: ["frameworks_av_license"],
+}
+
+// DO NOT DEPEND ON THIS DIRECTLY
+// use libcodec2-aidl-client-defaults instead
+cc_library {
+    name: "libcodec2_aidl_client",
+
+    srcs: [
+        "ParamTypes.cpp",
+    ],
+
+    header_libs: [
+        "libcodec2_hal_common",
+        "libcodec2_internal", // private
+        "libgui_headers",
+    ],
+
+    shared_libs: [
+        "android.hardware.media.bufferpool@2.0",
+        "android.hardware.media.c2-V1-ndk",
+        "libbinder_ndk",
+        "libbase",
+        "libcodec2",
+        "libcodec2_vndk",
+        "libcutils",
+        "liblog",
+        "libnativewindow",
+        "libutils",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    export_shared_lib_headers: [
+        "android.hardware.media.c2-V1-ndk",
+        "libcodec2",
+    ],
+}
+
+// DO NOT DEPEND ON THIS DIRECTLY
+// use libcodec2-hidl-defaults instead
+//cc_library {
+//    name: "libcodec2_hidl@1.0",
+//    vendor_available: true,
+//    min_sdk_version: "29",
+//    apex_available: [
+//        "//apex_available:platform",
+//        "com.android.media.swcodec",
+//    ],
+//
+//    defaults: ["hidl_defaults"],
+//
+//    srcs: [
+//        "Component.cpp",
+//        "ComponentInterface.cpp",
+//        "ComponentStore.cpp",
+//        "Configurable.cpp",
+//        "InputBufferManager.cpp",
+//        "InputSurface.cpp",
+//        "InputSurfaceConnection.cpp",
+//        "types.cpp",
+//    ],
+//
+//    header_libs: [
+//        "libbinder_headers",
+//        "libcodec2_hal_common",
+//        "libcodec2_internal", // private
+//        "libsystem_headers",
+//    ],
+//
+//    shared_libs: [
+//        "android.hardware.graphics.bufferqueue@1.0",
+//        "android.hardware.graphics.bufferqueue@2.0",
+//        "android.hardware.graphics.common@1.0",
+//        "android.hardware.media@1.0",
+//        "android.hardware.media.bufferpool@2.0",
+//        "android.hardware.media.c2@1.0",
+//        "android.hardware.media.omx@1.0",
+//        "libbase",
+//        "libcodec2",
+//        "libcodec2_vndk",
+//        "libcodec2_hidl_plugin_stub",
+//        "libcutils",
+//        "libhidlbase",
+//        "liblog",
+//        "libstagefright_bufferpool@2.0.1",
+//        "libstagefright_bufferqueue_helper_novndk",
+//        "libui",
+//        "libutils",
+//    ],
+//
+//    target: {
+//        vendor: {
+//            exclude_shared_libs: [
+//                "libstagefright_bufferqueue_helper_novndk",
+//                "libcodec2_hidl_plugin_stub",
+//            ],
+//            shared_libs: [
+//                "libstagefright_bufferqueue_helper",
+//                "libcodec2_hidl_plugin",
+//            ],
+//        },
+//        apex: {
+//            exclude_shared_libs: [
+//                "libcodec2_hidl_plugin",
+//                "libcodec2_hidl_plugin_stub",
+//            ],
+//        },
+//    },
+//
+//    export_include_dirs: [
+//        "include",
+//    ],
+//
+//    export_shared_lib_headers: [
+//        "android.hardware.media.c2@1.0",
+//        "libcodec2",
+//        "libcodec2_vndk",
+//        "libhidlbase",
+//        "libstagefright_bufferpool@2.0.1",
+//        "libui",
+//    ],
+//}
+//
+//// public dependency for Codec 2.0 HAL service implementations
+//cc_defaults {
+//    name: "libcodec2-hidl-defaults@1.0",
+//    defaults: ["libcodec2-impl-defaults"],
+//
+//    shared_libs: [
+//        "android.hardware.media.c2@1.0",
+//        "libcodec2_hidl@1.0",
+//    ],
+//}
+
+// public dependency for Codec 2.0 HAL client
+cc_defaults {
+    name: "libcodec2-aidl-client-defaults",
+    min_sdk_version: "34",
+    defaults: ["libcodec2-impl-defaults"],
+
+    shared_libs: [
+        "android.hardware.media.c2-V1-ndk",
+        "libcodec2_aidl_client",
+    ],
+}
diff --git a/media/codec2/hal/aidl/BufferTypes.cpp b/media/codec2/hal/aidl/BufferTypes.cpp
new file mode 100644
index 0000000..319ba62
--- /dev/null
+++ b/media/codec2/hal/aidl/BufferTypes.cpp
@@ -0,0 +1,1928 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-types"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/types.h>
+#include <media/stagefright/foundation/AUtils.h>
+
+#include <C2AllocatorIon.h>
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2Buffer.h>
+#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>
+
+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;
+
+const char* asString(Status status, const char* def) {
+    return asString(static_cast<c2_status_t>(status), def);
+}
+
+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;
+}
+
+// BaseBlock -> C2BaseBlock
+bool objcpy(C2BaseBlock* d, const BaseBlock& s) {
+    switch (s.getDiscriminator()) {
+    case BaseBlock::hidl_discriminator::nativeBlock: {
+            if (s.nativeBlock() == nullptr) {
+                LOG(ERROR) << "Null BaseBlock::nativeBlock handle";
+                return false;
+            }
+            native_handle_t* sHandle =
+                    native_handle_clone(s.nativeBlock());
+            if (sHandle == nullptr) {
+                LOG(ERROR) << "Null BaseBlock::nativeBlock.";
+                return false;
+            }
+            const C2Handle *sC2Handle =
+                    reinterpret_cast<const C2Handle*>(sHandle);
+
+            d->linear = _C2BlockFactory::CreateLinearBlock(sC2Handle);
+            if (d->linear) {
+                d->type = C2BaseBlock::LINEAR;
+                return true;
+            }
+
+            d->graphic = _C2BlockFactory::CreateGraphicBlock(sC2Handle);
+            if (d->graphic) {
+                d->type = C2BaseBlock::GRAPHIC;
+                return true;
+            }
+
+            LOG(ERROR) << "Unknown handle type in BaseBlock::nativeBlock.";
+            if (sHandle) {
+                native_handle_close(sHandle);
+                native_handle_delete(sHandle);
+            }
+            return false;
+        }
+    case BaseBlock::hidl_discriminator::pooledBlock: {
+            const BufferStatusMessage &bpMessage =
+                    s.pooledBlock();
+            sp<ClientManager> bp = ClientManager::getInstance();
+            std::shared_ptr<BufferPoolData> bpData;
+            native_handle_t *cHandle;
+            ResultStatus bpStatus = bp->receive(
+                    bpMessage.connectionId,
+                    bpMessage.transactionId,
+                    bpMessage.bufferId,
+                    bpMessage.timestampUs,
+                    &cHandle,
+                    &bpData);
+            if (bpStatus != ResultStatus::OK) {
+                LOG(ERROR) << "Failed to receive buffer from bufferpool -- "
+                           << "resultStatus = " << underlying_value(bpStatus)
+                           << ".";
+                return false;
+            } else if (!bpData) {
+                LOG(ERROR) << "No data in bufferpool transaction.";
+                return false;
+            }
+
+            d->linear = _C2BlockFactory::CreateLinearBlock(cHandle, bpData);
+            if (d->linear) {
+                d->type = C2BaseBlock::LINEAR;
+                return true;
+            }
+
+            d->graphic = _C2BlockFactory::CreateGraphicBlock(cHandle, bpData);
+            if (d->graphic) {
+                d->type = C2BaseBlock::GRAPHIC;
+                return true;
+            }
+            if (cHandle) {
+                // Though we got cloned handle, creating block failed.
+                native_handle_close(cHandle);
+                native_handle_delete(cHandle);
+            }
+
+            LOG(ERROR) << "Unknown handle type in BaseBlock::pooledBlock.";
+            return false;
+        }
+    default:
+        LOG(ERROR) << "Unrecognized BaseBlock's discriminator with "
+                   << "underlying value "
+                   << underlying_value(s.getDiscriminator()) << ".";
+        return false;
+    }
+}
+
+} // unnamed namespace
+
+// 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;
+}
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
diff --git a/media/codec2/hal/aidl/ParamTypes-specialization.h b/media/codec2/hal/aidl/ParamTypes-specialization.h
new file mode 100644
index 0000000..e409b34
--- /dev/null
+++ b/media/codec2/hal/aidl/ParamTypes-specialization.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_AIDL_UTILS_PARAM_TYPES_SPECIALIZATIONS_H
+#define CODEC2_AIDL_UTILS_PARAM_TYPES_SPECIALIZATIONS_H
+
+#include <aidl/android/hardware/media/c2/FieldId.h>
+#include <aidl/android/hardware/media/c2/FieldSupportedValues.h>
+#include <aidl/android/hardware/media/c2/Params.h>
+#include <aidl/android/hardware/media/c2/Status.h>
+#include <codec2/common/ParamTypes.h>
+
+namespace android {
+
+using ::aidl::android::hardware::media::c2::FieldId;
+using ::aidl::android::hardware::media::c2::FieldSupportedValues;
+using ::aidl::android::hardware::media::c2::Params;
+using ::aidl::android::hardware::media::c2::Status;
+
+// {offset, size} -> FieldId
+template<>
+void SetFieldId(FieldId *d, uint32_t offset, uint32_t size);
+
+// FieldId -> offset
+template<>
+uint32_t GetOffsetFromFieldId(const FieldId &s);
+
+// FieldId -> size
+template<>
+uint32_t GetSizeFromFieldId(const FieldId &s);
+
+template<>
+void SetStatus(Status *dst, c2_status_t src);
+
+template<>
+c2_status_t GetStatus(const Status &status);
+
+// C2FieldSupportedValues -> FieldSupportedValues
+template<>
+bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s);
+
+// FieldSupportedValues -> C2FieldSupportedValues
+template<>
+bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s);
+
+template<>
+struct _ParamsBlobHelper<Params> { typedef std::vector<uint8_t> BlobType; };
+
+template<>
+const std::vector<uint8_t> &GetBlob<Params>(const Params &params);
+
+template<>
+std::vector<uint8_t> *GetBlob<Params>(Params *params);
+
+} // namespace android
+
+
+
+#endif  // CODEC2_AIDL_UTILS_PARAM_TYPES_SPECIALIZATIONS_H
diff --git a/media/codec2/hal/aidl/ParamTypes.cpp b/media/codec2/hal/aidl/ParamTypes.cpp
new file mode 100644
index 0000000..0a430f9
--- /dev/null
+++ b/media/codec2/hal/aidl/ParamTypes.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-AIDL-ParamTypes"
+#include <android-base/logging.h>
+
+#include <codec2/aidl/ParamTypes.h>
+#include <codec2/common/ParamTypes.h>
+
+#include "ParamTypes-specialization.h"
+
+namespace android {
+
+using ::aidl::android::hardware::media::c2::FieldId;
+using ::aidl::android::hardware::media::c2::FieldSupportedValues;
+using ::aidl::android::hardware::media::c2::Params;
+using ::aidl::android::hardware::media::c2::Status;
+using ::aidl::android::hardware::media::c2::ValueRange;
+
+// {offset, size} -> FieldId
+template<>
+void SetFieldId(FieldId *d, uint32_t offset, uint32_t size) {
+    d->offset = offset;
+    d->sizeBytes = size;
+}
+
+// FieldId -> offset
+template<>
+uint32_t GetOffsetFromFieldId(const FieldId &s) {
+    return s.offset;
+}
+
+// FieldId -> size
+template<>
+uint32_t GetSizeFromFieldId(const FieldId &s) {
+    return s.sizeBytes;
+}
+
+template<>
+void SetStatus(Status *dst, c2_status_t src) {
+    dst->status = src;
+}
+
+template<>
+c2_status_t GetStatus(const Status &status) {
+    return static_cast<c2_status_t>(status.status);
+}
+
+static constexpr FieldSupportedValues::Tag EMPTY = FieldSupportedValues::empty;
+static constexpr FieldSupportedValues::Tag RANGE = FieldSupportedValues::range;
+static constexpr FieldSupportedValues::Tag VALUES = FieldSupportedValues::values;
+static constexpr FieldSupportedValues::Tag FLAGS = FieldSupportedValues::flags;
+
+// C2FieldSupportedValues -> FieldSupportedValues
+template<>
+bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
+    switch (s.type) {
+    case C2FieldSupportedValues::EMPTY: {
+            d->set<EMPTY>(true);
+            break;
+        }
+    case C2FieldSupportedValues::RANGE: {
+            ValueRange range{};
+            if (!objcpy(&range, s.range)) {
+                LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
+                d->set<RANGE>(range);
+                return false;
+            }
+            d->set<RANGE>(range);
+            break;
+        }
+    case C2FieldSupportedValues::VALUES: {
+            std::vector<int64_t> values;
+            copyVector<int64_t>(&values, s.values);
+            d->set<VALUES>(values);
+            break;
+        }
+    case C2FieldSupportedValues::FLAGS: {
+            std::vector<int64_t> flags;
+            copyVector<int64_t>(&flags, s.values);
+            d->set<FLAGS>(flags);
+            break;
+        }
+    default:
+        LOG(DEBUG) << "Unrecognized C2FieldSupportedValues::type_t "
+                   << "with underlying value " << underlying_value(s.type)
+                   << ".";
+        return false;
+    }
+    return true;
+}
+
+// FieldSupportedValues -> C2FieldSupportedValues
+template<>
+bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
+    switch (s.getTag()) {
+    case FieldSupportedValues::empty: {
+            d->type = C2FieldSupportedValues::EMPTY;
+            break;
+        }
+    case FieldSupportedValues::range: {
+            d->type = C2FieldSupportedValues::RANGE;
+            if (!objcpy(&d->range, s.get<RANGE>())) {
+                LOG(ERROR) << "Invalid FieldSupportedValues::range.";
+                return false;
+            }
+            d->values.resize(0);
+            break;
+        }
+    case FieldSupportedValues::values: {
+            d->type = C2FieldSupportedValues::VALUES;
+            copyVector<uint64_t>(&d->values, s.get<VALUES>());
+            break;
+        }
+    case FieldSupportedValues::flags: {
+            d->type = C2FieldSupportedValues::FLAGS;
+            copyVector<uint64_t>(&d->values, s.get<FLAGS>());
+            break;
+        }
+    default:
+        LOG(WARNING) << "Unrecognized FieldSupportedValues::getDiscriminator()";
+        return false;
+    }
+    return true;
+}
+
+template<>
+const std::vector<uint8_t> &GetBlob<Params>(const Params &params) {
+    return params.params;
+}
+
+template<>
+std::vector<uint8_t> *GetBlob<Params>(Params *params) {
+    return &params->params;
+}
+
+} // namespace android
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace utils {
+
+const char* asString(Status status, const char* def) {
+    return asString(static_cast<c2_status_t>(status.status), def);
+}
+
+namespace /* unnamed */ {
+
+} // unnamed namespace
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
+bool ToAidl(
+        FieldSupportedValuesQuery* d,
+        const C2FieldSupportedValuesQuery& s) {
+    return ::android::objcpy(d, nullptr, s);
+}
+
+// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
+bool FromAidl(
+        C2FieldSupportedValuesQuery* d,
+        const FieldSupportedValuesQuery& s) {
+    return ::android::objcpy(d, s);
+}
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
+bool ToAidl(
+        FieldSupportedValuesQueryResult* d,
+        const C2FieldSupportedValuesQuery& s) {
+    return ::android::objcpy(nullptr, d, s);
+}
+
+// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
+// C2FieldSupportedValuesQuery
+bool FromAidl(
+        C2FieldSupportedValuesQuery* d,
+        const FieldSupportedValuesQuery& sq,
+        const FieldSupportedValuesQueryResult& sr) {
+    return ::android::objcpy(d, sq, sr);
+}
+
+// C2Component::Traits -> IComponentStore::ComponentTraits
+bool ToAidl(
+        IComponentStore::ComponentTraits *d,
+        const C2Component::Traits &s) {
+    return ::android::objcpy(d, s);
+}
+
+// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
+bool FromAidl(
+        C2Component::Traits* d,
+        const IComponentStore::ComponentTraits& s) {
+    return ::android::objcpy(d, s);
+}
+
+// C2SettingResult -> SettingResult
+bool ToAidl(SettingResult *d, const C2SettingResult &s) {
+    return ::android::objcpy(d, s);
+}
+
+// SettingResult -> std::unique_ptr<C2SettingResult>
+bool FromAidl(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
+    return ::android::objcpy(d, s);
+}
+
+// C2ParamDescriptor -> ParamDescriptor
+bool ToAidl(ParamDescriptor *d, const C2ParamDescriptor &s) {
+    return ::android::objcpy(d, s);
+}
+
+// ParamDescriptor -> C2ParamDescriptor
+bool FromAidl(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
+    return ::android::objcpy(d, s);
+}
+
+// C2StructDescriptor -> StructDescriptor
+bool ToAidl(StructDescriptor *d, const C2StructDescriptor &s) {
+    return ::android::objcpy(d, s);
+}
+
+// StructDescriptor -> C2StructDescriptor
+bool FromAidl(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
+    return ::android::objcpy(d, s);
+}
+
+// Params -> std::vector<C2Param*>
+bool ParseParamsBlob(std::vector<C2Param*> *params, const Params &blob) {
+    return ::android::parseParamsBlob(params, blob);
+}
+
+// std::vector<const C2Param*> -> Params
+bool CreateParamsBlob(
+        Params *blob,
+        const std::vector<const C2Param*> &params) {
+    return ::android::_createParamsBlob(blob, params);
+}
+
+// std::vector<C2Param*> -> Params
+bool CreateParamsBlob(
+        Params *blob,
+        const std::vector<C2Param*> &params) {
+    return ::android::_createParamsBlob(blob, params);
+}
+
+// std::vector<std::unique_ptr<C2Param>> -> Params
+bool CreateParamsBlob(
+        Params *blob,
+        const std::vector<std::unique_ptr<C2Param>> &params) {
+    return ::android::_createParamsBlob(blob, params);
+}
+
+// std::vector<std::unique_ptr<C2Tuning>> -> Params
+bool CreateParamsBlob(
+        Params *blob,
+        const std::vector<std::unique_ptr<C2Tuning>> &params) {
+    return ::android::_createParamsBlob(blob, params);
+}
+
+// std::vector<std::shared_ptr<const C2Info>> -> Params
+bool CreateParamsBlob(
+        Params *blob,
+        const std::vector<std::shared_ptr<const C2Info>> &params) {
+    return ::android::_createParamsBlob(blob, params);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Param>>
+bool CopyParamsFromBlob(
+        std::vector<std::unique_ptr<C2Param>>* params,
+        Params blob) {
+    return ::android::_copyParamsFromBlob(params, blob);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Tuning>>
+bool CopyParamsFromBlob(
+        std::vector<std::unique_ptr<C2Tuning>>* params,
+        Params blob) {
+    return ::android::_copyParamsFromBlob(params, blob);
+}
+
+// Params -> update std::vector<std::unique_ptr<C2Param>>
+bool UpdateParamsFromBlob(
+        const std::vector<C2Param*>& params,
+        const Params& blob) {
+    return ::android::updateParamsFromBlob(params, blob);
+}
+
+}  // namespace utils
+}  // 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
new file mode 100644
index 0000000..f111f81
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/BufferTypes.h
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_TYPES_H
+#define CODEC2_HIDL_V1_0_UTILS_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 <C2Component.h>
+#include <C2Param.h>
+#include <C2ParamDef.h>
+#include <C2Work.h>
+#include <util/C2Debug-base.h>
+
+#include <chrono>
+
+using namespace std::chrono_literals;
+
+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;
+
+// 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;
+
+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;
+};
+
+// Default implementation of BufferPoolSender.
+//
+// To use DefaultBufferPoolSender, the IClientManager instance of the receiving
+// process must be set before send() can operate. DefaultBufferPoolSender will
+// 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;
+
+    // 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,
+            std::chrono::steady_clock::duration refreshInterval = 4500ms);
+
+    // 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.
+    void setReceiver(
+            const sp<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(
+            const std::shared_ptr<BufferPoolData>& bpData,
+            BufferStatusMessage* bpMessage) override;
+
+private:
+    std::mutex mMutex;
+    sp<ClientManager> mSenderManager;
+    sp<IClientManager> mReceiverManager;
+    std::chrono::steady_clock::duration mRefreshInterval;
+
+    struct Connection {
+        int64_t receiverConnectionId;
+        std::chrono::steady_clock::time_point lastSent;
+        Connection(int64_t receiverConnectionId,
+                   std::chrono::steady_clock::time_point lastSent)
+              : receiverConnectionId(receiverConnectionId),
+                lastSent(lastSent) {
+        }
+    };
+
+    // Map of connections.
+    //
+    // The key is the connection id. One sender-receiver pair may have multiple
+    // connections.
+    std::map<int64_t, Connection> mConnections;
+};
+
+// std::list<std::unique_ptr<C2Work>> -> WorkBundle
+// Note: If bufferpool will be used, bpSender must not be null.
+bool objcpy(
+        WorkBundle* d,
+        const std::list<std::unique_ptr<C2Work>>& s,
+        BufferPoolSender* bpSender = nullptr);
+
+// WorkBundle -> std::list<std::unique_ptr<C2Work>>
+bool objcpy(
+        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);
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CODEC2_HIDL_V1_0_UTILS_TYPES_H
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ParamTypes.h b/media/codec2/hal/aidl/include/codec2/aidl/ParamTypes.h
new file mode 100644
index 0000000..ff69039
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ParamTypes.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_AIDL_UTILS_PARAM_TYPES_H
+#define CODEC2_AIDL_UTILS_PARAM_TYPES_H
+
+#include <aidl/android/hardware/media/c2/FieldSupportedValuesQuery.h>
+#include <aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.h>
+#include <aidl/android/hardware/media/c2/IComponentStore.h>
+#include <aidl/android/hardware/media/c2/ParamDescriptor.h>
+#include <aidl/android/hardware/media/c2/SettingResult.h>
+#include <aidl/android/hardware/media/c2/Status.h>
+#include <aidl/android/hardware/media/c2/StructDescriptor.h>
+
+#include <C2Component.h>
+#include <C2Param.h>
+#include <C2ParamDef.h>
+#include <util/C2Debug-base.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace utils {
+
+// 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 ToAidl(
+        SettingResult* d,
+        const C2SettingResult& s);
+
+// SettingResult -> std::unique_ptr<C2SettingResult>
+bool FromAidl(
+        std::unique_ptr<C2SettingResult>* d,
+        const SettingResult& s);
+
+// C2ParamDescriptor -> ParamDescriptor
+bool ToAidl(
+        ParamDescriptor* d,
+        const C2ParamDescriptor& s);
+
+// ParamDescriptor -> std::shared_ptr<C2ParamDescriptor>
+bool FromAidl(
+        std::shared_ptr<C2ParamDescriptor>* d,
+        const ParamDescriptor& s);
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
+bool ToAidl(
+        FieldSupportedValuesQuery* d,
+        const C2FieldSupportedValuesQuery& s);
+
+// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
+bool FromAidl(
+        C2FieldSupportedValuesQuery* d,
+        const FieldSupportedValuesQuery& s);
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
+bool ToAidl(
+        FieldSupportedValuesQueryResult* d,
+        const C2FieldSupportedValuesQuery& s);
+
+// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult -> C2FieldSupportedValuesQuery
+bool FromAidl(
+        C2FieldSupportedValuesQuery* d,
+        const FieldSupportedValuesQuery& sq,
+        const FieldSupportedValuesQueryResult& sr);
+
+// C2Component::Traits -> ComponentTraits
+bool ToAidl(
+        IComponentStore::ComponentTraits* d,
+        const C2Component::Traits& s);
+
+// ComponentTraits -> C2Component::Traits
+bool FromAidl(
+        C2Component::Traits* d,
+        const IComponentStore::ComponentTraits& s);
+
+// C2StructDescriptor -> StructDescriptor
+bool ToAidl(
+        StructDescriptor* d,
+        const C2StructDescriptor& s);
+
+// StructDescriptor -> C2StructDescriptor
+bool FromAidl(
+        std::unique_ptr<C2StructDescriptor>* d,
+        const StructDescriptor& 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 Params &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(
+        Params *blob,
+        const std::vector<C2Param*> &params);
+bool CreateParamsBlob(
+        Params *blob,
+        const std::vector<std::unique_ptr<C2Param>> &params);
+bool CreateParamsBlob(
+        Params *blob,
+        const std::vector<std::shared_ptr<const C2Info>> &params);
+bool CreateParamsBlob(
+        Params *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,
+        const Params &blob);
+bool CopyParamsFromBlob(
+        std::vector<std::unique_ptr<C2Tuning>>* params,
+        const 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);
+
+}  // namespace utils
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // CODEC2_AIDL_UTILS_PARAM_TYPES_H
diff --git a/media/codec2/hal/client/Android.bp b/media/codec2/hal/client/Android.bp
index 31244fe..43dae1d 100644
--- a/media/codec2/hal/client/Android.bp
+++ b/media/codec2/hal/client/Android.bp
@@ -10,12 +10,6 @@
 cc_library_headers {
     name: "libcodec2_client_headers",
     export_include_dirs: ["include"],
-    vendor_available: true,
-    apex_available: [
-        "//apex_available:platform",
-        "com.android.media",
-        "com.android.media.swcodec",
-    ],
     min_sdk_version: "29",
     host_supported: true,
     target: {
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index 97c0806..62e7b34 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -16,8 +16,9 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2Client"
+#define ATRACE_TAG  ATRACE_TAG_VIDEO
 #include <android-base/logging.h>
-
+#include <utils/Trace.h>
 #include <codec2/hidl/client.h>
 #include <C2Debug.h>
 #include <C2BufferPriv.h>
@@ -1577,6 +1578,7 @@
         const C2ConstGraphicBlock& block,
         const QueueBufferInput& input,
         QueueBufferOutput* output) {
+    ScopedTrace trace(ATRACE_TAG,"Codec2Client::Component::queueToOutputSurface");
     return mOutputBufferQueue->outputBuffer(block, input, output);
 }
 
diff --git a/media/codec2/hal/client/output.cpp b/media/codec2/hal/client/output.cpp
index 4eebd1c..2f9773e 100644
--- a/media/codec2/hal/client/output.cpp
+++ b/media/codec2/hal/client/output.cpp
@@ -16,7 +16,9 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2-OutputBufferQueue"
+#define ATRACE_TAG  ATRACE_TAG_VIDEO
 #include <android-base/logging.h>
+#include <utils/Trace.h>
 
 #include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
 #include <codec2/hidl/output.h>
@@ -388,6 +390,7 @@
     uint32_t generation;
     uint64_t bqId;
     int32_t bqSlot;
+    ScopedTrace trace(ATRACE_TAG,"Codec2-OutputBufferQueue::outputBuffer");
     bool display = V1_0::utils::displayBufferQueueBlock(block);
     if (!getBufferQueueAssignment(block, &generation, &bqId, &bqSlot) ||
         bqId == 0) {
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 86fd8ab..a75ce70 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -46,6 +46,7 @@
 #include <media/stagefright/BufferProducerWrapper.h>
 #include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/PersistentSurface.h>
+#include <media/stagefright/RenderedFrameInfo.h>
 #include <utils/NativeHandle.h>
 
 #include "C2OMXNode.h"
@@ -672,8 +673,7 @@
     }
 
     void onOutputFramesRendered(int64_t mediaTimeUs, nsecs_t renderTimeNs) override {
-        mCodec->mCallback->onOutputFramesRendered(
-                {RenderedFrameInfo(mediaTimeUs, renderTimeNs)});
+        mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs, renderTimeNs)});
     }
 
     void onOutputBuffersChanged() override {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 51082d1..14160f7 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -592,6 +592,8 @@
     size_t bufferSize = 0;
     c2_status_t blockRes = C2_OK;
     bool copied = false;
+    ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
+            "CCodecBufferChannel::decrypt(%s)", mName).c_str());
     if (mSendEncryptedInfoBuffer) {
         static const C2MemoryUsage kDefaultReadWriteUsage{
             C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
diff --git a/media/codec2/vndk/C2Buffer.cpp b/media/codec2/vndk/C2Buffer.cpp
index 018e269..a56a216 100644
--- a/media/codec2/vndk/C2Buffer.cpp
+++ b/media/codec2/vndk/C2Buffer.cpp
@@ -16,7 +16,9 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "C2Buffer"
+#define ATRACE_TAG  ATRACE_TAG_VIDEO
 #include <utils/Log.h>
+#include <utils/Trace.h>
 
 #include <list>
 #include <map>
@@ -33,6 +35,7 @@
 
 namespace {
 
+using android::ScopedTrace;
 using android::C2AllocatorBlob;
 using android::C2AllocatorGralloc;
 using android::C2AllocatorIon;
@@ -1159,6 +1162,7 @@
         uint32_t capacity,
         C2MemoryUsage usage,
         std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+    ScopedTrace trace(ATRACE_TAG,"C2PooledBlockPool::fetchLinearBlock");
     if (mBufferPoolVer == VER_HIDL && mImpl) {
         return mImpl->fetchLinearBlock(capacity, usage, block);
     }
@@ -1174,6 +1178,7 @@
         uint32_t format,
         C2MemoryUsage usage,
         std::shared_ptr<C2GraphicBlock> *block) {
+    ScopedTrace trace(ATRACE_TAG,"C2PooledBlockPool::fetchGraphicBlock");
     if (mBufferPoolVer == VER_HIDL && mImpl) {
         return mImpl->fetchGraphicBlock(width, height, format, usage, block);
     }
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index f2cd585..b1838a3 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -16,8 +16,10 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "C2BqBuffer"
+#define ATRACE_TAG  ATRACE_TAG_VIDEO
 #include <android/hardware_buffer.h>
 #include <utils/Log.h>
+#include <utils/Trace.h>
 
 #include <ui/BufferQueueDefs.h>
 #include <ui/GraphicBuffer.h>
@@ -37,6 +39,7 @@
 #include <map>
 #include <mutex>
 
+using ::android::ScopedTrace;
 using ::android::BufferQueueDefs::NUM_BUFFER_SLOTS;
 using ::android::C2AllocatorGralloc;
 using ::android::C2AndroidMemoryUsage;
@@ -1054,6 +1057,7 @@
         uint32_t format,
         C2MemoryUsage usage,
         std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+    ScopedTrace trace(ATRACE_TAG,"C2BufferQueueBlockPool::fetchGraphicBlock");
     if (mImpl) {
         return mImpl->fetchGraphicBlock(width, height, format, usage, block, nullptr);
     }
diff --git a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
index d55a3d8..d8c2292 100644
--- a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
+++ b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
@@ -114,8 +114,8 @@
 }
 
 namespace {
-    constexpr int kSpinNumForLock = 100;
-    constexpr int kSpinNumForUnlock = 200;
+    constexpr int kSpinNumForLock = 0;
+    constexpr int kSpinNumForUnlock = 0;
 
     enum : uint32_t {
         FUTEX_UNLOCKED = 0,
@@ -125,32 +125,65 @@
 }
 
 int C2SyncVariables::lock() {
-    uint32_t old;
+    uint32_t old = FUTEX_UNLOCKED;
+
+    // see if we can lock uncontended immediately (if previously unlocked)
+    if (mLock.compare_exchange_strong(old, FUTEX_LOCKED_UNCONTENDED)) {
+        return 0;
+    }
+
+    // spin to see if we can get it with a short wait without involving kernel
     for (int i = 0; i < kSpinNumForLock; i++) {
-        old = 0;
+        sched_yield();
+
+        old = FUTEX_UNLOCKED;
         if (mLock.compare_exchange_strong(old, FUTEX_LOCKED_UNCONTENDED)) {
             return 0;
         }
-        sched_yield();
     }
 
-    if (old == FUTEX_LOCKED_UNCONTENDED)
+    // still locked, if other side thinks it was uncontended, now it is contended, so let them
+    // know that they need to wake us up.
+    if (old == FUTEX_LOCKED_UNCONTENDED) {
         old = mLock.exchange(FUTEX_LOCKED_CONTENDED);
+        // It is possible that the other holder released the lock at this very moment (and old
+        // becomes UNLOCKED), If so, we will not involve the kernel to wait for the lock to be
+        // released, but are still marking our lock contended (even though we are the only
+        // holders.)
+    }
 
-    while (old) {
-        (void) syscall(__NR_futex, &mLock, FUTEX_WAIT, FUTEX_LOCKED_CONTENDED, NULL, NULL, 0);
+    // while the futex is still locked by someone else
+    while (old != FUTEX_UNLOCKED) {
+        // wait until other side releases the lock (and still contented)
+        (void)syscall(__NR_futex, &mLock, FUTEX_WAIT, FUTEX_LOCKED_CONTENDED, NULL, NULL, 0);
+        // try to relock
         old = mLock.exchange(FUTEX_LOCKED_CONTENDED);
     }
     return 0;
 }
 
 int C2SyncVariables::unlock() {
-    if (mLock.exchange(FUTEX_UNLOCKED) == FUTEX_LOCKED_UNCONTENDED) return 0;
+    // TRICKY: here we assume that we are holding this lock
 
+    // unlock the lock immediately (since we were holding it)
+    // If it is (still) locked uncontested, we are done (no need to involve the kernel)
+    if (mLock.exchange(FUTEX_UNLOCKED) == FUTEX_LOCKED_UNCONTENDED) {
+        return 0;
+    }
+
+    // We don't need to spin for unlock as here we know already we have a waiter who we need to
+    // wake up. This code was here in case someone just happened to lock this lock (uncontested)
+    // before we would wake up other waiters to avoid a syscall. It is unsure if this ever gets
+    // exercised or if this is the behavior we want. (Note that if this code is removed, the same
+    // situation is still handled in lock() by the woken up waiter that realizes that the lock is
+    // now taken.)
     for (int i = 0; i < kSpinNumForUnlock; i++) {
-        if (mLock.load()) {
+        // here we seem to check if someone relocked this lock, and if they relocked uncontested,
+        // we up it to contested (since there are other waiters.)
+        if (mLock.load() != FUTEX_UNLOCKED) {
             uint32_t old = FUTEX_LOCKED_UNCONTENDED;
             mLock.compare_exchange_strong(old, FUTEX_LOCKED_CONTENDED);
+            // this is always true here so we return immediately
             if (old) {
                 return 0;
             }
@@ -158,7 +191,8 @@
         sched_yield();
     }
 
-    (void) syscall(__NR_futex, &mLock, FUTEX_WAKE, 1, NULL, NULL, 0);
+    // wake up one waiter
+    (void)syscall(__NR_futex, &mLock, FUTEX_WAKE, 1, NULL, NULL, 0);
     return 0;
 }
 
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 7648c76..74f7e6b 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -623,6 +623,11 @@
  * (e.g. a USB audio interface, a DAC connected to headphones) to
  * specify allowable configurations of a particular device.
  *
+ * Channel masks are for input only, output only, or both input and output.
+ * These channel masks are different than those defined in AudioFormat.java.
+ * If an app gets a channel mask from Java API and wants to use it in AAudio,
+ * conversion should be done by the app.
+ *
  * Added in API level 32.
  */
 enum {
@@ -630,10 +635,6 @@
      * Invalid channel mask
      */
     AAUDIO_CHANNEL_INVALID = -1,
-
-    /**
-     * Output audio channel mask
-     */
     AAUDIO_CHANNEL_FRONT_LEFT = 1 << 0,
     AAUDIO_CHANNEL_FRONT_RIGHT = 1 << 1,
     AAUDIO_CHANNEL_FRONT_CENTER = 1 << 2,
@@ -661,62 +662,112 @@
     AAUDIO_CHANNEL_FRONT_WIDE_LEFT = 1 << 24,
     AAUDIO_CHANNEL_FRONT_WIDE_RIGHT = 1 << 25,
 
+    /**
+     * Supported for Input and Output
+     */
     AAUDIO_CHANNEL_MONO = AAUDIO_CHANNEL_FRONT_LEFT,
+    /**
+     * Supported for Input and Output
+     */
     AAUDIO_CHANNEL_STEREO = AAUDIO_CHANNEL_FRONT_LEFT |
                             AAUDIO_CHANNEL_FRONT_RIGHT,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_2POINT1 = AAUDIO_CHANNEL_FRONT_LEFT |
                              AAUDIO_CHANNEL_FRONT_RIGHT |
                              AAUDIO_CHANNEL_LOW_FREQUENCY,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_TRI = AAUDIO_CHANNEL_FRONT_LEFT |
                          AAUDIO_CHANNEL_FRONT_RIGHT |
                          AAUDIO_CHANNEL_FRONT_CENTER,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_TRI_BACK = AAUDIO_CHANNEL_FRONT_LEFT |
                               AAUDIO_CHANNEL_FRONT_RIGHT |
                               AAUDIO_CHANNEL_BACK_CENTER,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_3POINT1 = AAUDIO_CHANNEL_FRONT_LEFT |
                              AAUDIO_CHANNEL_FRONT_RIGHT |
                              AAUDIO_CHANNEL_FRONT_CENTER |
                              AAUDIO_CHANNEL_LOW_FREQUENCY,
+    /**
+     * Supported for Input and Output
+     */
     AAUDIO_CHANNEL_2POINT0POINT2 = AAUDIO_CHANNEL_FRONT_LEFT |
                                    AAUDIO_CHANNEL_FRONT_RIGHT |
                                    AAUDIO_CHANNEL_TOP_SIDE_LEFT |
                                    AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
+    /**
+     * Supported for Input and Output
+     */
     AAUDIO_CHANNEL_2POINT1POINT2 = AAUDIO_CHANNEL_2POINT0POINT2 |
                                    AAUDIO_CHANNEL_LOW_FREQUENCY,
+    /**
+     * Supported for Input and Output
+     */
     AAUDIO_CHANNEL_3POINT0POINT2 = AAUDIO_CHANNEL_FRONT_LEFT |
                                    AAUDIO_CHANNEL_FRONT_RIGHT |
                                    AAUDIO_CHANNEL_FRONT_CENTER |
                                    AAUDIO_CHANNEL_TOP_SIDE_LEFT |
                                    AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
+    /**
+     * Supported for Input and Output
+     */
     AAUDIO_CHANNEL_3POINT1POINT2 = AAUDIO_CHANNEL_3POINT0POINT2 |
                                    AAUDIO_CHANNEL_LOW_FREQUENCY,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_QUAD = AAUDIO_CHANNEL_FRONT_LEFT |
                           AAUDIO_CHANNEL_FRONT_RIGHT |
                           AAUDIO_CHANNEL_BACK_LEFT |
                           AAUDIO_CHANNEL_BACK_RIGHT,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_QUAD_SIDE = AAUDIO_CHANNEL_FRONT_LEFT |
                                AAUDIO_CHANNEL_FRONT_RIGHT |
                                AAUDIO_CHANNEL_SIDE_LEFT |
                                AAUDIO_CHANNEL_SIDE_RIGHT,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_SURROUND = AAUDIO_CHANNEL_FRONT_LEFT |
                               AAUDIO_CHANNEL_FRONT_RIGHT |
                               AAUDIO_CHANNEL_FRONT_CENTER |
                               AAUDIO_CHANNEL_BACK_CENTER,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_PENTA = AAUDIO_CHANNEL_QUAD |
                            AAUDIO_CHANNEL_FRONT_CENTER,
-    // aka 5POINT1_BACK
+    /**
+     * Supported for Input and Output. aka 5POINT1_BACK
+     */
     AAUDIO_CHANNEL_5POINT1 = AAUDIO_CHANNEL_FRONT_LEFT |
                              AAUDIO_CHANNEL_FRONT_RIGHT |
                              AAUDIO_CHANNEL_FRONT_CENTER |
                              AAUDIO_CHANNEL_LOW_FREQUENCY |
                              AAUDIO_CHANNEL_BACK_LEFT |
                              AAUDIO_CHANNEL_BACK_RIGHT,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_5POINT1_SIDE = AAUDIO_CHANNEL_FRONT_LEFT |
                                   AAUDIO_CHANNEL_FRONT_RIGHT |
                                   AAUDIO_CHANNEL_FRONT_CENTER |
                                   AAUDIO_CHANNEL_LOW_FREQUENCY |
                                   AAUDIO_CHANNEL_SIDE_LEFT |
                                   AAUDIO_CHANNEL_SIDE_RIGHT,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_6POINT1 = AAUDIO_CHANNEL_FRONT_LEFT |
                              AAUDIO_CHANNEL_FRONT_RIGHT |
                              AAUDIO_CHANNEL_FRONT_CENTER |
@@ -724,32 +775,55 @@
                              AAUDIO_CHANNEL_BACK_LEFT |
                              AAUDIO_CHANNEL_BACK_RIGHT |
                              AAUDIO_CHANNEL_BACK_CENTER,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_7POINT1 = AAUDIO_CHANNEL_5POINT1 |
                              AAUDIO_CHANNEL_SIDE_LEFT |
                              AAUDIO_CHANNEL_SIDE_RIGHT,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_5POINT1POINT2 = AAUDIO_CHANNEL_5POINT1 |
                                    AAUDIO_CHANNEL_TOP_SIDE_LEFT |
                                    AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_5POINT1POINT4 = AAUDIO_CHANNEL_5POINT1 |
                                    AAUDIO_CHANNEL_TOP_FRONT_LEFT |
                                    AAUDIO_CHANNEL_TOP_FRONT_RIGHT |
                                    AAUDIO_CHANNEL_TOP_BACK_LEFT |
                                    AAUDIO_CHANNEL_TOP_BACK_RIGHT,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_7POINT1POINT2 = AAUDIO_CHANNEL_7POINT1 |
                                    AAUDIO_CHANNEL_TOP_SIDE_LEFT |
                                    AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_7POINT1POINT4 = AAUDIO_CHANNEL_7POINT1 |
                                    AAUDIO_CHANNEL_TOP_FRONT_LEFT |
                                    AAUDIO_CHANNEL_TOP_FRONT_RIGHT |
                                    AAUDIO_CHANNEL_TOP_BACK_LEFT |
                                    AAUDIO_CHANNEL_TOP_BACK_RIGHT,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_9POINT1POINT4 = AAUDIO_CHANNEL_7POINT1POINT4 |
                                    AAUDIO_CHANNEL_FRONT_WIDE_LEFT |
                                    AAUDIO_CHANNEL_FRONT_WIDE_RIGHT,
+    /**
+     * Supported for only Output
+     */
     AAUDIO_CHANNEL_9POINT1POINT6 = AAUDIO_CHANNEL_9POINT1POINT4 |
                                    AAUDIO_CHANNEL_TOP_SIDE_LEFT |
                                    AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
-
+    /**
+     * Supported for only Input
+     */
     AAUDIO_CHANNEL_FRONT_BACK = AAUDIO_CHANNEL_FRONT_CENTER |
                                 AAUDIO_CHANNEL_BACK_CENTER,
 };
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 359c140..4269aa2 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -817,7 +817,7 @@
     (void) updateAndGetPosition_l();
 
     // save start timestamp
-    if (isOffloadedOrDirect_l()) {
+    if (isAfTrackOffloadedOrDirect_l()) {
         if (getTimestamp_l(mStartTs) != OK) {
             mStartTs.mPosition = 0;
         }
@@ -838,7 +838,7 @@
         mTimestampStaleTimeReported = false;
         mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID;
 
-        if (!isOffloadedOrDirect_l()
+        if (!isAfTrackOffloadedOrDirect_l()
                 && mStartEts.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] > 0) {
             // Server side has consumed something, but is it finished consuming?
             // It is possible since flush and stop are asynchronous that the server
@@ -1917,6 +1917,7 @@
     mAfChannelCount = audio_channel_count_from_out_mask(output.afChannelMask);
     mAfFormat = output.afFormat;
     mAfLatency = output.afLatencyMs;
+    mAfTrackFlags = output.afTrackFlags;
 
     mLatency = mAfLatency + (1000LL * mFrameCount) / mSampleRate;
 
@@ -3182,7 +3183,7 @@
     // To avoid a race, read the presented frames first.  This ensures that presented <= consumed.
 
     status_t status;
-    if (isOffloadedOrDirect_l()) {
+    if (isAfTrackOffloadedOrDirect_l()) {
         // use Binder to get timestamp
         media::AudioTimestampInternal ts;
         mAudioTrack->getTimestamp(&ts, &status);
@@ -3294,7 +3295,7 @@
         ALOGV_IF(status != WOULD_BLOCK, "%s(%d): getTimestamp error:%#x", __func__, mPortId, status);
         return status;
     }
-    if (isOffloadedOrDirect_l()) {
+    if (isAfTrackOffloadedOrDirect_l()) {
         if (isOffloaded_l() && (mState == STATE_PAUSED || mState == STATE_PAUSED_STOPPING)) {
             // use cached paused position in case another offloaded track is running.
             timestamp.mPosition = mPausedPosition;
@@ -3740,7 +3741,7 @@
     // This is conservatively figured - if we encounter an unexpected error
     // then we will not wait.
     bool wait = false;
-    if (isOffloadedOrDirect_l()) {
+    if (isAfTrackOffloadedOrDirect_l()) {
         AudioTimestamp ts;
         status_t status = getTimestamp_l(ts);
         if (status == WOULD_BLOCK) {
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 4bd12b8..515e708 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -116,6 +116,8 @@
             legacy2aidl_audio_channel_mask_t_AudioChannelLayout(afChannelMask, false /*isInput*/));
     aidl.afFormat = VALUE_OR_RETURN(
             legacy2aidl_audio_format_t_AudioFormatDescription(afFormat));
+    aidl.afTrackFlags = VALUE_OR_RETURN(
+            legacy2aidl_audio_output_flags_t_int32_t_mask(afTrackFlags));
     aidl.outputId = VALUE_OR_RETURN(legacy2aidl_audio_io_handle_t_int32_t(outputId));
     aidl.portId = VALUE_OR_RETURN(legacy2aidl_audio_port_handle_t_int32_t(portId));
     aidl.audioTrack = audioTrack;
@@ -144,6 +146,8 @@
                                                                 false /*isInput*/));
     legacy.afFormat = VALUE_OR_RETURN(
             aidl2legacy_AudioFormatDescription_audio_format_t(aidl.afFormat));
+    legacy.afTrackFlags = VALUE_OR_RETURN(
+            aidl2legacy_int32_t_audio_output_flags_t_mask(aidl.afTrackFlags));
     legacy.outputId = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_io_handle_t(aidl.outputId));
     legacy.portId = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_port_handle_t(aidl.portId));
     legacy.audioTrack = aidl.audioTrack;
diff --git a/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl b/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl
index 42e0bb4..ab60461 100644
--- a/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl
+++ b/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl
@@ -43,6 +43,7 @@
     AudioChannelLayout afChannelMask;
     AudioFormatDescription afFormat;
     int afLatencyMs;
+    int afTrackFlags;
     /** Interpreted as audio_io_handle_t. */
     int outputId;
     /** Interpreted as audio_port_handle_t. */
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 8f712db..523383f 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1238,6 +1238,11 @@
             bool     isDirect_l() const
                 { return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; }
 
+            bool     isAfTrackOffloadedOrDirect_l() const
+                { return isOffloadedOrDirect_l() ||
+                        (mAfTrackFlags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|
+                                AUDIO_OUTPUT_FLAG_DIRECT)) != 0; }
+
             // pure pcm data is mixable (which excludes HW_AV_SYNC, with embedded timing)
             bool     isPurePcmData_l() const
                 { return audio_is_linear_pcm(mFormat)
@@ -1295,6 +1300,7 @@
     uint32_t                mAfSampleRate;          // AudioFlinger sample rate
     uint32_t                mAfChannelCount;        // AudioFlinger channel count
     audio_format_t          mAfFormat;              // AudioFlinger format
+    audio_output_flags_t    mAfTrackFlags;          // AudioFlinger track flags
 
     // constant after constructor or set()
     audio_format_t          mFormat;                // as requested by client, not forced to 16-bit
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 3c96862..35a3208 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -119,6 +119,7 @@
         uint32_t afLatencyMs;
         audio_channel_mask_t afChannelMask;
         audio_format_t afFormat;
+        audio_output_flags_t afTrackFlags;
         audio_io_handle_t outputId;
         audio_port_handle_t portId;
         sp<media::IAudioTrack> audioTrack;
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
index ae4a530..b8e62ae 100644
--- a/media/libaudiohal/impl/EffectHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -56,6 +56,7 @@
 using ::aidl::android::hardware::audio::effect::Descriptor;
 using ::aidl::android::hardware::audio::effect::IEffect;
 using ::aidl::android::hardware::audio::effect::IFactory;
+using ::aidl::android::hardware::audio::effect::State;
 
 namespace android {
 namespace effect {
@@ -165,13 +166,20 @@
 
 // write to input FMQ here, wait for statusMQ STATUS_OK, and read from output FMQ
 status_t EffectHalAidl::process() {
+    State state = State::INIT;
+    if (mConversion->isBypassing() || !mEffect->getState(&state).isOk() ||
+        state != State::PROCESSING) {
+        ALOGI("%s skipping %s process because it's %s", __func__, mDesc.common.name.c_str(),
+              mConversion->isBypassing()
+                      ? "bypassing"
+                      : aidl::android::hardware::audio::effect::toString(state).c_str());
+        return OK;
+    }
+
     auto statusQ = mConversion->getStatusMQ();
     auto inputQ = mConversion->getInputMQ();
     auto outputQ = mConversion->getOutputMQ();
     auto efGroup = mConversion->getEventFlagGroup();
-    if (mConversion->isBypassing()) {
-        return OK;
-    }
     if (!statusQ || !statusQ->isValid() || !inputQ || !inputQ->isValid() || !outputQ ||
         !outputQ->isValid() || !efGroup) {
         ALOGE("%s invalid FMQ [Status %d I %d O %d] efGroup %p", __func__,
diff --git a/media/libaudiohal/impl/EffectProxy.cpp b/media/libaudiohal/impl/EffectProxy.cpp
index fc2da6b..5e465d9 100644
--- a/media/libaudiohal/impl/EffectProxy.cpp
+++ b/media/libaudiohal/impl/EffectProxy.cpp
@@ -92,9 +92,7 @@
                                                                 "noActiveEffctFound");
     }
 
-    const size_t newIndex = std::distance(mSubEffects.begin(), itor);
-    mActiveSubIdx = newIndex;
-
+    mActiveSubIdx = std::distance(mSubEffects.begin(), itor);
     ALOGI("%s: active %soffload sub-effect %zu descriptor: %s", __func__,
           offload->isOffload ? "" : "non-", mActiveSubIdx,
           ::android::audio::utils::toString(mSubEffects[mActiveSubIdx].descriptor.common.id.uuid)
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 1551e33..8d408dd 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -165,6 +165,7 @@
             pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
     if (pConfig->inputCfg.format != kProcessFormat) return -EINVAL;
 
+    pContext->mChannelCount = channelCount;
     pContext->mConfig = *pConfig;
 
     Visualizer_reset(pContext);
@@ -229,8 +230,6 @@
     pContext->mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED;
 
     // measurement initialization
-    pContext->mChannelCount =
-            audio_channel_count_from_out_mask(pContext->mConfig.inputCfg.channels);
     pContext->mMeasurementMode = MEASUREMENT_MODE_NONE;
     pContext->mMeasurementWindowSizeInBuffers = MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS;
     pContext->mMeasurementBufferIdx = 0;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index a91b24a..1a32e61 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -43,6 +43,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/OMXClient.h>
 #include <media/stagefright/PersistentSurface.h>
+#include <media/stagefright/RenderedFrameInfo.h>
 #include <media/stagefright/SurfaceUtils.h>
 #include <media/hardware/HardwareAPI.h>
 #include <media/MediaBufferHolder.h>
@@ -634,7 +635,8 @@
     if (!mBufferChannel) {
         mBufferChannel = std::make_shared<ACodecBufferChannel>(
                 new AMessage(kWhatInputBufferFilled, this),
-                new AMessage(kWhatOutputBufferDrained, this));
+                new AMessage(kWhatOutputBufferDrained, this),
+                new AMessage(kWhatPollForRenderedBuffers, this));
     }
     return mBufferChannel;
 }
@@ -744,6 +746,7 @@
     // if we have not yet started the codec, we can simply set the native window
     if (mBuffers[kPortIndexInput].size() == 0) {
         mNativeWindow = surface;
+        initializeFrameTracking();
         return OK;
     }
 
@@ -852,6 +855,7 @@
 
     mNativeWindow = nativeWindow;
     mNativeWindowUsageBits = usageBits;
+    initializeFrameTracking();
     return OK;
 }
 
@@ -962,7 +966,6 @@
                 BufferInfo info;
                 info.mStatus = BufferInfo::OWNED_BY_US;
                 info.mFenceFd = -1;
-                info.mRenderInfo = NULL;
                 info.mGraphicBuffer = NULL;
                 info.mNewGraphicBuffer = false;
 
@@ -1230,6 +1233,7 @@
 
     *bufferCount = def.nBufferCountActual;
     *bufferSize =  def.nBufferSize;
+    initializeFrameTracking();
     return err;
 }
 
@@ -1268,7 +1272,6 @@
         info.mStatus = BufferInfo::OWNED_BY_US;
         info.mFenceFd = fenceFd;
         info.mIsReadFence = false;
-        info.mRenderInfo = NULL;
         info.mGraphicBuffer = graphicBuffer;
         info.mNewGraphicBuffer = false;
         info.mDequeuedAt = mDequeueCounter;
@@ -1345,7 +1348,6 @@
         BufferInfo info;
         info.mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
         info.mFenceFd = -1;
-        info.mRenderInfo = NULL;
         info.mGraphicBuffer = NULL;
         info.mNewGraphicBuffer = false;
         info.mDequeuedAt = mDequeueCounter;
@@ -1441,42 +1443,6 @@
     return err;
 }
 
-void ACodec::updateRenderInfoForDequeuedBuffer(
-        ANativeWindowBuffer *buf, int fenceFd, BufferInfo *info) {
-
-    info->mRenderInfo =
-        mRenderTracker.updateInfoForDequeuedBuffer(
-                buf, fenceFd, info - &mBuffers[kPortIndexOutput][0]);
-
-    // check for any fences already signaled
-    notifyOfRenderedFrames(false /* dropIncomplete */, info->mRenderInfo);
-}
-
-void ACodec::onFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) {
-    if (mRenderTracker.onFrameRendered(mediaTimeUs, systemNano) != OK) {
-        mRenderTracker.dumpRenderQueue();
-    }
-}
-
-void ACodec::notifyOfRenderedFrames(bool dropIncomplete, FrameRenderTracker::Info *until) {
-    std::list<FrameRenderTracker::Info> done =
-        mRenderTracker.checkFencesAndGetRenderedFrames(until, dropIncomplete);
-
-    // unlink untracked frames
-    for (std::list<FrameRenderTracker::Info>::const_iterator it = done.cbegin();
-            it != done.cend(); ++it) {
-        ssize_t index = it->getIndex();
-        if (index >= 0 && (size_t)index < mBuffers[kPortIndexOutput].size()) {
-            mBuffers[kPortIndexOutput][index].mRenderInfo = NULL;
-        } else if (index >= 0) {
-            // THIS SHOULD NEVER HAPPEN
-            ALOGE("invalid index %zd in %zu", index, mBuffers[kPortIndexOutput].size());
-        }
-    }
-
-    mCallback->onOutputFramesRendered(done);
-}
-
 void ACodec::onFirstTunnelFrameReady() {
     mCallback->onFirstTunnelFrameReady();
 }
@@ -1531,7 +1497,6 @@
 
                 info->mStatus = BufferInfo::OWNED_BY_US;
                 info->setWriteFence(fenceFd, "dequeueBufferFromNativeWindow");
-                updateRenderInfoForDequeuedBuffer(buf, fenceFd, info);
                 return info;
             }
         }
@@ -1576,18 +1541,96 @@
     oldest->mNewGraphicBuffer = true;
     oldest->mStatus = BufferInfo::OWNED_BY_US;
     oldest->setWriteFence(fenceFd, "dequeueBufferFromNativeWindow for oldest");
-    mRenderTracker.untrackFrame(oldest->mRenderInfo);
-    oldest->mRenderInfo = NULL;
 
     ALOGV("replaced oldest buffer #%u with age %u, graphicBuffer %p",
             (unsigned)(oldest - &mBuffers[kPortIndexOutput][0]),
             mDequeueCounter - oldest->mDequeuedAt,
             oldest->mGraphicBuffer->handle);
-
-    updateRenderInfoForDequeuedBuffer(buf, fenceFd, oldest);
     return oldest;
 }
 
+void ACodec::initializeFrameTracking() {
+    mTrackedFrames.clear();
+
+    int isWindowToDisplay = 0;
+    mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+            &isWindowToDisplay);
+    mIsWindowToDisplay = isWindowToDisplay == 1;
+    // No frame tracking is needed if we're not sending frames to the display
+    if (!mIsWindowToDisplay) {
+        // Return early so we don't call into SurfaceFlinger (requiring permissions)
+        return;
+    }
+
+    int hasPresentFenceTimes = 0;
+    mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT,
+            &hasPresentFenceTimes);
+    mHasPresentFenceTimes = hasPresentFenceTimes == 1;
+    if (!mHasPresentFenceTimes) {
+        ALOGI("Using latch times for frame rendered signals - present fences not supported");
+    }
+
+    status_t err = native_window_enable_frame_timestamps(mNativeWindow.get(), true);
+    if (err) {
+        ALOGE("Failed to enable frame timestamps (%d)", err);
+    }
+}
+
+void ACodec::trackReleasedFrame(int64_t frameId, int64_t mediaTimeUs, int64_t desiredRenderTimeNs) {
+    // If the render time is earlier than now, then we're suggesting it should be rendered ASAP,
+    // so track the frame as if the desired render time is now.
+    int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
+    if (desiredRenderTimeNs < nowNs) {
+        desiredRenderTimeNs = nowNs;
+    }
+    // We've just queued a frame to the surface, so keep track of it and later check to see if it is
+    // actually rendered.
+    TrackedFrame frame;
+    frame.id = frameId;
+    frame.mediaTimeUs = mediaTimeUs;
+    frame.desiredRenderTimeNs = desiredRenderTimeNs;
+    mTrackedFrames.push_back(frame);
+}
+
+void ACodec::pollForRenderedFrames() {
+    std::list<RenderedFrameInfo> renderedFrameInfos;
+    // Scan all frames and check to see if the frames that SHOULD have been rendered by now, have,
+    // in fact, been rendered.
+    int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
+    while (!mTrackedFrames.empty()) {
+        TrackedFrame & frame = mTrackedFrames.front();
+        // Frames that should have been rendered at least 100ms in the past are checked
+        if (frame.desiredRenderTimeNs > nowNs - 100*1000*1000LL) {
+            break;
+        }
+
+        status_t err;
+        nsecs_t latchOrPresentTimeNs = NATIVE_WINDOW_TIMESTAMP_INVALID;
+        err = native_window_get_frame_timestamps(mNativeWindow.get(), frame.id,
+                /* outRequestedPresentTime */ nullptr, /* outAcquireTime */ nullptr,
+                mHasPresentFenceTimes ? nullptr : &latchOrPresentTimeNs, // latch time
+                /* outFirstRefreshStartTime */ nullptr, /* outLastRefreshStartTime */ nullptr,
+                /* outGpuCompositionDoneTime */ nullptr,
+                mHasPresentFenceTimes ? &latchOrPresentTimeNs : nullptr, // display present time,
+                /* outDequeueReadyTime */ nullptr, /* outReleaseTime */ nullptr);
+        if (err) {
+            ALOGE("Failed to get frame timestamps for %lld: %d", (long long) frame.id, err);
+        }
+        // If we don't have a render time by now, then consider the frame as dropped
+        if (latchOrPresentTimeNs != NATIVE_WINDOW_TIMESTAMP_PENDING &&
+            latchOrPresentTimeNs != NATIVE_WINDOW_TIMESTAMP_INVALID) {
+            renderedFrameInfos.push_back(RenderedFrameInfo(frame.mediaTimeUs,
+                                                           latchOrPresentTimeNs));
+        }
+
+        mTrackedFrames.pop_front();
+    }
+
+    if (!renderedFrameInfos.empty()) {
+        mCallback->onOutputFramesRendered(renderedFrameInfos);
+    }
+}
+
 status_t ACodec::freeBuffersOnPort(OMX_U32 portIndex) {
     if (portIndex == kPortIndexInput) {
         mBufferChannel->setInputBufferArray({});
@@ -1663,11 +1706,6 @@
         ::close(info->mFenceFd);
     }
 
-    if (portIndex == kPortIndexOutput) {
-        mRenderTracker.untrackFrame(info->mRenderInfo, i);
-        info->mRenderInfo = NULL;
-    }
-
     // remove buffer even if mOMXNode->freeBuffer fails
     mBuffers[portIndex].erase(mBuffers[portIndex].begin() + i);
     return err;
@@ -6032,22 +6070,10 @@
     sp<RefBase> obj;
     CHECK(msg->findObject("messages", &obj));
     sp<MessageList> msgList = static_cast<MessageList *>(obj.get());
-
-    bool receivedRenderedEvents = false;
     for (std::list<sp<AMessage>>::const_iterator it = msgList->getList().cbegin();
           it != msgList->getList().cend(); ++it) {
         (*it)->setWhat(ACodec::kWhatOMXMessageItem);
         mCodec->handleMessage(*it);
-        int32_t type;
-        CHECK((*it)->findInt32("type", &type));
-        if (type == omx_message::FRAME_RENDERED) {
-            receivedRenderedEvents = true;
-        }
-    }
-
-    if (receivedRenderedEvents) {
-        // NOTE: all buffers are rendered in this case
-        mCodec->notifyOfRenderedFrames();
     }
     return true;
 }
@@ -6609,15 +6635,6 @@
     info->mDequeuedAt = ++mCodec->mDequeueCounter;
     info->mStatus = BufferInfo::OWNED_BY_US;
 
-    if (info->mRenderInfo != NULL) {
-        // The fence for an emptied buffer must have signaled, but there still could be queued
-        // or out-of-order dequeued buffers in the render queue prior to this buffer. Drop these,
-        // as we will soon requeue this buffer to the surface. While in theory we could still keep
-        // track of buffers that are requeued to the surface, it is better to add support to the
-        // buffer-queue to notify us of released buffers and their fences (in the future).
-        mCodec->notifyOfRenderedFrames(true /* dropIncomplete */);
-    }
-
     // byte buffers cannot take fences, so wait for any fence now
     if (mCodec->mNativeWindow == NULL) {
         (void)mCodec->waitForFence(fenceFd, "onOMXFillBufferDone");
@@ -6824,14 +6841,6 @@
             mCodec->mLastHdr10PlusBuffer = hdr10PlusInfo;
         }
 
-        // save buffers sent to the surface so we can get render time when they return
-        int64_t mediaTimeUs = -1;
-        buffer->meta()->findInt64("timeUs", &mediaTimeUs);
-        if (mediaTimeUs >= 0) {
-            mCodec->mRenderTracker.onFrameQueued(
-                    mediaTimeUs, info->mGraphicBuffer, new Fence(::dup(info->mFenceFd)));
-        }
-
         int64_t timestampNs = 0;
         if (!msg->findInt64("timestampNs", &timestampNs)) {
             // use media timestamp if client did not request a specific render timestamp
@@ -6845,11 +6854,25 @@
         err = native_window_set_buffers_timestamp(mCodec->mNativeWindow.get(), timestampNs);
         ALOGW_IF(err != NO_ERROR, "failed to set buffer timestamp: %d", err);
 
+        uint64_t frameId;
+        err = native_window_get_next_frame_id(mCodec->mNativeWindow.get(), &frameId);
+
         info->checkReadFence("onOutputBufferDrained before queueBuffer");
         err = mCodec->mNativeWindow->queueBuffer(
                     mCodec->mNativeWindow.get(), info->mGraphicBuffer.get(), info->mFenceFd);
-        // TODO(b/266211548): Poll the native window for rendered buffers, since when queueing
-        // buffers, the frame event history delta is retrieved.
+
+        int64_t mediaTimeUs = -1;
+        buffer->meta()->findInt64("timeUs", &mediaTimeUs);
+        if (mCodec->mIsWindowToDisplay) {
+            mCodec->trackReleasedFrame(frameId, mediaTimeUs, timestampNs);
+            mCodec->pollForRenderedFrames();
+        } else {
+            // When the surface is an intermediate surface, onFrameRendered is triggered immediately
+            // when the frame is queued to the non-display surface
+            mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs,
+                                                                         timestampNs)});
+        }
+
         info->mFenceFd = -1;
         if (err == OK) {
             info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
@@ -7076,7 +7099,6 @@
     ++mCodec->mNodeGeneration;
 
     mCodec->mComponentName = componentName;
-    mCodec->mRenderTracker.setComponentName(componentName);
     mCodec->mFlags = 0;
 
     if (componentName.endsWith(".secure")) {
@@ -7713,7 +7735,6 @@
 
 void ACodec::ExecutingState::stateEntered() {
     ALOGV("[%s] Now Executing", mCodec->mComponentName.c_str());
-    mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC));
     mCodec->processDeferredMessages();
 }
 
@@ -7824,7 +7845,15 @@
                     mCodec->signalSubmitOutputMetadataBufferIfEOS_workaround();
                 }
             }
-            return true;
+            handled = true;
+            break;
+        }
+
+        case kWhatPollForRenderedBuffers:
+        {
+            mCodec->pollForRenderedFrames();
+            handled = true;
+            break;
         }
 
         default:
@@ -8520,7 +8549,7 @@
 }
 
 bool ACodec::ExecutingState::onOMXFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) {
-    mCodec->onFrameRendered(mediaTimeUs, systemNano);
+    mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs, systemNano)});
     return true;
 }
 
@@ -8694,7 +8723,7 @@
 
 bool ACodec::OutputPortSettingsChangedState::onOMXFrameRendered(
         int64_t mediaTimeUs, nsecs_t systemNano) {
-    mCodec->onFrameRendered(mediaTimeUs, systemNano);
+    mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs, systemNano)});
     return true;
 }
 
@@ -8725,10 +8754,6 @@
                             OMX_CommandPortEnable, kPortIndexOutput);
                 }
 
-                // Clear the RenderQueue in which queued GraphicBuffers hold the
-                // actual buffer references in order to free them early.
-                mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC));
-
                 if (err == OK) {
                     err = mCodec->allocateBuffersOnPort(kPortIndexOutput);
                     ALOGE_IF(err != OK, "Failed to allocate output port buffers after port "
@@ -9112,8 +9137,6 @@
         // the native window for rendering. Let's get those back as well.
         mCodec->waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs();
 
-        mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC));
-
         mCodec->mCallback->onFlushCompleted();
 
         mCodec->mPortEOS[kPortIndexInput] =
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 8f2bed2..ad42813 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -32,6 +32,7 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/ACodec.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/MediaCodecBuffer.h>
 #include <system/window.h>
@@ -87,9 +88,11 @@
 }
 
 ACodecBufferChannel::ACodecBufferChannel(
-        const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained)
+        const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained,
+        const sp<AMessage> &pollForRenderedBuffers)
     : mInputBufferFilled(inputBufferFilled),
       mOutputBufferDrained(outputBufferDrained),
+      mPollForRenderedBuffers(pollForRenderedBuffers),
       mHeapSeqNum(-1) {
 }
 
@@ -488,7 +491,7 @@
 }
 
 void ACodecBufferChannel::pollForRenderedBuffers() {
-    // TODO(b/266211548): Poll the native window for rendered buffers.
+    mPollForRenderedBuffers->post();
 }
 
 status_t ACodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index b5bd975..57937f9 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -16,7 +16,7 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "FrameDecoder"
-
+#define ATRACE_TAG  ATRACE_TAG_VIDEO
 #include "include/FrameDecoder.h"
 #include "include/FrameCaptureLayer.h"
 #include "include/HevcUtils.h"
@@ -41,6 +41,7 @@
 #include <media/stagefright/Utils.h>
 #include <private/media/VideoFrame.h>
 #include <utils/Log.h>
+#include <utils/Trace.h>
 
 namespace android {
 
@@ -340,6 +341,7 @@
 }
 
 sp<IMemory> FrameDecoder::extractFrame(FrameRect *rect) {
+    ScopedTrace trace(ATRACE_TAG, "FrameDecoder::ExtractFrame");
     status_t err = onExtractRect(rect);
     if (err == OK) {
         err = extractInternal();
@@ -713,6 +715,7 @@
     }
     converter.setSrcColorSpace(standard, range, transfer);
     if (converter.isValid()) {
+        ScopedTrace trace(ATRACE_TAG, "FrameDecoder::ColorConverter");
         converter.convert(
                 (const uint8_t *)videoFrameBuffer->data(),
                 width, height, stride,
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index a0d56f8..c5475cf 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -77,6 +77,7 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/OMXClient.h>
 #include <media/stagefright/PersistentSurface.h>
+#include <media/stagefright/RenderedFrameInfo.h>
 #include <media/stagefright/SurfaceUtils.h>
 #include <nativeloader/dlext_namespaces.h>
 #include <private/android_filesystem_config.h>
@@ -408,7 +409,7 @@
         std::scoped_lock lock{mLock};
         // Unregistering from DeathRecipient notification.
         if (mService != nullptr) {
-            AIBinder_unlinkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
+            AIBinder_unlinkToDeath(mService->asBinder().get(), mDeathRecipient.get(), mCookie);
             mService = nullptr;
         }
     }
@@ -448,13 +449,15 @@
     std::shared_ptr<IResourceManagerClient> mClient;
     ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
     std::shared_ptr<IResourceManagerService> mService;
+    BinderDiedContext* mCookie;
 };
 
 MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy(
         pid_t pid, uid_t uid, const std::shared_ptr<IResourceManagerClient> &client) :
     mPid(pid), mUid(uid), mClient(client),
     mDeathRecipient(::ndk::ScopedAIBinder_DeathRecipient(
-            AIBinder_DeathRecipient_new(BinderDiedCallback))) {
+            AIBinder_DeathRecipient_new(BinderDiedCallback))),
+    mCookie(nullptr) {
     if (mUid == MediaCodec::kNoUid) {
         mUid = AIBinder_getCallingUid();
     }
@@ -512,9 +515,9 @@
 
     // Create the context that is passed as cookie to the binder death notification.
     // The context gets deleted at BinderUnlinkedCallback.
-    BinderDiedContext* context = new BinderDiedContext{.mRMServiceProxy = weak_from_this()};
+    mCookie = new BinderDiedContext{.mRMServiceProxy = weak_from_this()};
     // Register for the callbacks by linking to death notification.
-    AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), context);
+    AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), mCookie);
 
     // If the RM was restarted, re-register all the resources.
     if (mBinderDied) {
@@ -869,7 +872,7 @@
             const sp<AMessage> &outputFormat) override;
     virtual void onInputSurfaceDeclined(status_t err) override;
     virtual void onSignaledInputEOS(status_t err) override;
-    virtual void onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) override;
+    virtual void onOutputFramesRendered(const std::list<RenderedFrameInfo> &done) override;
     virtual void onOutputBuffersChanged() override;
     virtual void onFirstTunnelFrameReady() override;
 private:
@@ -978,7 +981,7 @@
     notify->post();
 }
 
-void CodecCallback::onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) {
+void CodecCallback::onOutputFramesRendered(const std::list<RenderedFrameInfo> &done) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatOutputFramesRendered);
     if (MediaCodec::CreateFramesRenderedMessage(done, notify)) {
@@ -6076,12 +6079,10 @@
     return onQueueInputBuffer(msg);
 }
 
-//static
-size_t MediaCodec::CreateFramesRenderedMessage(
-        const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg) {
+template<typename T>
+static size_t CreateFramesRenderedMessageInternal(const std::list<T> &done, sp<AMessage> &msg) {
     size_t index = 0;
-    for (std::list<FrameRenderTracker::Info>::const_iterator it = done.cbegin();
-            it != done.cend(); ++it) {
+    for (typename std::list<T>::const_iterator it = done.cbegin(); it != done.cend(); ++it) {
         if (it->getRenderTimeNs() < 0) {
             continue; // dropped frame from tracking
         }
@@ -6092,6 +6093,18 @@
     return index;
 }
 
+//static
+size_t MediaCodec::CreateFramesRenderedMessage(
+        const std::list<RenderedFrameInfo> &done, sp<AMessage> &msg) {
+    return CreateFramesRenderedMessageInternal(done, msg);
+}
+
+//static
+size_t MediaCodec::CreateFramesRenderedMessage(
+        const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg) {
+    return CreateFramesRenderedMessageInternal(done, msg);
+}
+
 status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) {
     size_t index;
     CHECK(msg->findSize("index", &index));
diff --git a/media/libstagefright/http/Android.bp b/media/libstagefright/http/Android.bp
index f25318d..4383d6f 100644
--- a/media/libstagefright/http/Android.bp
+++ b/media/libstagefright/http/Android.bp
@@ -37,10 +37,4 @@
         ],
         cfi: true,
     },
-
-    product_variables: {
-        pdk: {
-            enabled: false,
-        },
-    },
 }
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index 903280f..a464504 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -29,6 +29,7 @@
 #include <media/IOMX.h>
 
 namespace android {
+ struct ACodec;
 namespace hardware {
 class HidlMemory;
 };
@@ -63,7 +64,8 @@
     };
 
     ACodecBufferChannel(
-            const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained);
+            const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained,
+            const sp<AMessage> &pollForRenderedBuffers);
     virtual ~ACodecBufferChannel();
 
     // BufferChannelBase interface
@@ -138,6 +140,7 @@
 
     const sp<AMessage> mInputBufferFilled;
     const sp<AMessage> mOutputBufferDrained;
+    const sp<AMessage> mPollForRenderedBuffers;
 
     sp<MemoryDealer> mDealer;
     sp<IMemory> mDecryptDestination;
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index e535d5d..ec4a04c 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -19,7 +19,7 @@
 
 #include <set>
 #include <stdint.h>
-#include <list>
+#include <deque>
 #include <vector>
 #include <android/native_window.h>
 #include <media/hardware/MetadataBufferType.h>
@@ -27,9 +27,9 @@
 #include <media/IOMX.h>
 #include <media/stagefright/AHierarchicalStateMachine.h>
 #include <media/stagefright/CodecBase.h>
-#include <media/stagefright/FrameRenderTracker.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/SkipCutBuffer.h>
+#include <ui/GraphicBuffer.h>
 #include <utils/NativeHandle.h>
 #include <OMX_Audio.h>
 #include <hardware/gralloc.h>
@@ -156,6 +156,7 @@
         kWhatForceStateTransition    = 'fstt',
         kWhatCheckIfStuck            = 'Cstk',
         kWhatSubmitExtraOutputMetadataBuffer = 'sbxo',
+        kWhatPollForRenderedBuffers  = 'pfrb',
     };
 
     enum {
@@ -177,6 +178,13 @@
                             | static_cast<uint64_t>(BufferUsage::VIDEO_DECODER),
     };
 
+    struct TrackedFrame {
+        int64_t id;
+        int64_t mediaTimeUs;
+        int64_t desiredRenderTimeNs;
+        nsecs_t renderTimeNs;
+    };
+
     struct BufferInfo {
         enum Status {
             OWNED_BY_US,
@@ -204,7 +212,6 @@
         sp<GraphicBuffer> mGraphicBuffer;
         bool mNewGraphicBuffer;
         int mFenceFd;
-        FrameRenderTracker::Info *mRenderInfo;
 
         // The following field and 4 methods are used for debugging only
         bool mIsReadFence;
@@ -253,6 +260,8 @@
 
     bool mUsingNativeWindow;
     sp<ANativeWindow> mNativeWindow;
+    bool mIsWindowToDisplay;
+    bool mHasPresentFenceTimes;
     int mNativeWindowUsageBits;
     android_native_rect_t mLastNativeWindowCrop;
     int32_t mLastNativeWindowDataSpace;
@@ -267,7 +276,7 @@
     // format updates. This will equal to mOutputFormat until the first actual frame is received.
     sp<AMessage> mBaseOutputFormat;
 
-    FrameRenderTracker mRenderTracker; // render information for buffers rendered by ACodec
+    std::deque<TrackedFrame> mTrackedFrames; // render information for buffers sent to a window
     std::vector<BufferInfo> mBuffers[2];
     bool mPortEOS[2];
     status_t mInputEOSResult;
@@ -349,6 +358,10 @@
     status_t freeOutputBuffersNotOwnedByComponent();
     BufferInfo *dequeueBufferFromNativeWindow();
 
+    void initializeFrameTracking();
+    void trackReleasedFrame(int64_t frameId, int64_t mediaTimeUs, int64_t desiredRenderTimeNs);
+    void pollForRenderedFrames();
+
     inline bool storingMetadataInDecodedBuffers() {
         return (mPortMode[kPortIndexOutput] == IOMX::kPortModeDynamicANWBuffer) && !mIsEncoder;
     }
@@ -571,21 +584,6 @@
     void processDeferredMessages();
 
     void onFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano);
-    // called when we have dequeued a buffer |buf| from the native window to track render info.
-    // |fenceFd| is the dequeue fence, and |info| points to the buffer info where this buffer is
-    // stored.
-    void updateRenderInfoForDequeuedBuffer(
-            ANativeWindowBuffer *buf, int fenceFd, BufferInfo *info);
-
-    // Checks to see if any frames have rendered up until |until|, and to notify client
-    // (MediaCodec) of rendered frames up-until the frame pointed to by |until| or the first
-    // unrendered frame. These frames are removed from the render queue.
-    // If |dropIncomplete| is true, unrendered frames up-until |until| will be dropped from the
-    // queue, allowing all rendered framed up till then to be notified of.
-    // (This will effectively clear the render queue up-until (and including) |until|.)
-    // If |until| is NULL, or is not in the rendered queue, this method will check all frames.
-    void notifyOfRenderedFrames(
-            bool dropIncomplete = false, FrameRenderTracker::Info *until = NULL);
 
     void onFirstTunnelFrameReady();
 
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index 916d41e..90347f9 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -41,7 +41,7 @@
 struct BufferProducerWrapper;
 class MediaCodecBuffer;
 struct PersistentSurface;
-struct RenderedFrameInfo;
+class RenderedFrameInfo;
 class Surface;
 struct ICrypto;
 class IMemory;
diff --git a/media/libstagefright/include/media/stagefright/FrameRenderTracker.h b/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
index c14755a..cab7ecc 100644
--- a/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
+++ b/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
@@ -32,61 +32,59 @@
 
 namespace android {
 
-// Tracks the render information about a frame. Frames go through several states while
-// the render information is tracked:
-//
-// 1. queued frame: mMediaTime and mGraphicBuffer are set for the frame. mFence is the
-// queue fence (read fence). mIndex is negative, and mRenderTimeNs is invalid.
-// Key characteristics: mFence is not NULL and mIndex is negative.
-//
-// 2. dequeued frame: mFence is updated with the dequeue fence (write fence). mIndex is set.
-// Key characteristics: mFence is not NULL and mIndex is non-negative. mRenderTime is still
-// invalid.
-//
-// 3. rendered frame or frame: mFence is cleared, mRenderTimeNs is set.
-// Key characteristics: mFence is NULL.
-//
-struct RenderedFrameInfo {
-    // set by client during onFrameQueued or onFrameRendered
-    int64_t getMediaTimeUs() const  { return mMediaTimeUs; }
-
-    // -1 if frame is not yet rendered
-    nsecs_t getRenderTimeNs() const { return mRenderTimeNs; }
-
-    // set by client during updateRenderInfoForDequeuedBuffer; -1 otherwise
-    ssize_t getIndex() const        { return mIndex; }
-
-    // creates information for a queued frame
-    RenderedFrameInfo(int64_t mediaTimeUs, const sp<GraphicBuffer> &graphicBuffer,
-            const sp<Fence> &fence)
-        : mMediaTimeUs(mediaTimeUs),
-          mRenderTimeNs(-1),
-          mIndex(-1),
-          mGraphicBuffer(graphicBuffer),
-          mFence(fence) {
-    }
-
-    // creates information for a frame rendered on a tunneled surface
-    RenderedFrameInfo(int64_t mediaTimeUs, nsecs_t renderTimeNs)
-        : mMediaTimeUs(mediaTimeUs),
-          mRenderTimeNs(renderTimeNs),
-          mIndex(-1),
-          mGraphicBuffer(NULL),
-          mFence(NULL) {
-    }
-
-private:
-    int64_t mMediaTimeUs;
-    nsecs_t mRenderTimeNs;
-    ssize_t mIndex;         // to be used by client
-    sp<GraphicBuffer> mGraphicBuffer;
-    sp<Fence> mFence;
-
-    friend struct FrameRenderTracker;
-};
-
 struct FrameRenderTracker {
-    typedef RenderedFrameInfo Info;
+    // Tracks the render information about a frame. Frames go through several states while
+    // the render information is tracked:
+    //
+    // 1. queued frame: mMediaTime and mGraphicBuffer are set for the frame. mFence is the
+    // queue fence (read fence). mIndex is negative, and mRenderTimeNs is invalid.
+    // Key characteristics: mFence is not NULL and mIndex is negative.
+    //
+    // 2. dequeued frame: mFence is updated with the dequeue fence (write fence). mIndex is set.
+    // Key characteristics: mFence is not NULL and mIndex is non-negative. mRenderTime is still
+    // invalid.
+    //
+    // 3. rendered frame or frame: mFence is cleared, mRenderTimeNs is set.
+    // Key characteristics: mFence is NULL.
+    //
+    struct Info {
+        // set by client during onFrameQueued or onFrameRendered
+        int64_t getMediaTimeUs() const  { return mMediaTimeUs; }
+
+        // -1 if frame is not yet rendered
+        nsecs_t getRenderTimeNs() const { return mRenderTimeNs; }
+
+        // set by client during updateRenderInfoForDequeuedBuffer; -1 otherwise
+        ssize_t getIndex() const        { return mIndex; }
+
+        // creates information for a queued frame
+        Info(int64_t mediaTimeUs, const sp<GraphicBuffer> &graphicBuffer,
+                const sp<Fence> &fence)
+          : mMediaTimeUs(mediaTimeUs),
+            mRenderTimeNs(-1),
+            mIndex(-1),
+            mGraphicBuffer(graphicBuffer),
+            mFence(fence) {
+        }
+
+        // creates information for a frame rendered on a tunneled surface
+        Info(int64_t mediaTimeUs, nsecs_t renderTimeNs)
+            : mMediaTimeUs(mediaTimeUs),
+            mRenderTimeNs(renderTimeNs),
+            mIndex(-1),
+            mGraphicBuffer(NULL),
+            mFence(NULL) {
+        }
+
+    private:
+        int64_t mMediaTimeUs;
+        nsecs_t mRenderTimeNs;
+        ssize_t mIndex;         // to be used by client
+        sp<GraphicBuffer> mGraphicBuffer;
+        sp<Fence> mFence;
+
+        friend struct FrameRenderTracker;
+    };
 
     FrameRenderTracker();
 
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 05bc9cc..da15ed4 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -64,6 +64,7 @@
 class MediaCodecBuffer;
 class IMemory;
 struct PersistentSurface;
+class RenderedFrameInfo;
 class SoftwareRenderer;
 class Surface;
 namespace hardware {
@@ -281,6 +282,8 @@
     // by adding rendered frame information to a base notification message. Returns the number
     // of frames that were rendered.
     static size_t CreateFramesRenderedMessage(
+            const std::list<RenderedFrameInfo> &done, sp<AMessage> &msg);
+    static size_t CreateFramesRenderedMessage(
             const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg);
 
     static status_t CanFetchLinearBlock(
diff --git a/media/libstagefright/include/media/stagefright/RenderedFrameInfo.h b/media/libstagefright/include/media/stagefright/RenderedFrameInfo.h
new file mode 100644
index 0000000..4b8a58d
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/RenderedFrameInfo.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RENDERED_FRAME_INFO_H
+#define RENDERED_FRAME_INFO_H
+
+namespace android {
+
+class RenderedFrameInfo {
+public:
+    RenderedFrameInfo(int64_t mediaTimeUs, int64_t renderTimeNs)
+        : mMediaTimeUs(mediaTimeUs), mRenderTimeNs(renderTimeNs) {}
+
+    int64_t getMediaTimeUs() const  { return mMediaTimeUs; }
+    nsecs_t getRenderTimeNs() const { return mRenderTimeNs;}
+
+private:
+    int64_t mMediaTimeUs;
+    nsecs_t mRenderTimeNs;
+};
+
+} // android
+
+#endif // RENDERED_FRAME_INFO_H
\ No newline at end of file
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 5dbcd08..6068d68 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -73,14 +73,14 @@
 }
 
 bool MtpDataPacket::getUInt8(uint8_t& value) {
-    if (mPacketSize - mOffset < sizeof(value))
+    if ((mPacketSize - mOffset < sizeof(value)) || (mOffset >= mBufferSize))
         return false;
     value = mBuffer[mOffset++];
     return true;
 }
 
 bool MtpDataPacket::getUInt16(uint16_t& value) {
-    if (mPacketSize - mOffset < sizeof(value))
+    if ((mPacketSize - mOffset < sizeof(value)) || ((mOffset+1) >= mBufferSize))
         return false;
     int offset = mOffset;
     value = (uint16_t)mBuffer[offset] | ((uint16_t)mBuffer[offset + 1] << 8);
@@ -89,7 +89,7 @@
 }
 
 bool MtpDataPacket::getUInt32(uint32_t& value) {
-    if (mPacketSize - mOffset < sizeof(value))
+    if ((mPacketSize - mOffset < sizeof(value)) || ((mOffset+3) >= mBufferSize))
         return false;
     int offset = mOffset;
     value = (uint32_t)mBuffer[offset] | ((uint32_t)mBuffer[offset + 1] << 8) |
@@ -99,7 +99,7 @@
 }
 
 bool MtpDataPacket::getUInt64(uint64_t& value) {
-    if (mPacketSize - mOffset < sizeof(value))
+    if ((mPacketSize - mOffset < sizeof(value)) || ((mOffset+7) >= mBufferSize))
         return false;
     int offset = mOffset;
     value = (uint64_t)mBuffer[offset] | ((uint64_t)mBuffer[offset + 1] << 8) |
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index fded4f5..8b9dde3 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -161,11 +161,6 @@
         "libgui",
     ],
 
-    product_variables: {
-        pdk: {
-            enabled: false,
-        },
-    },
     version_script: "libmediandk.map.txt",
     stubs: {
         symbol_file: "libmediandk.map.txt",
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
index 9e0d5e4..be8b2b4 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
@@ -322,7 +322,7 @@
             ByteBuffer inputCodecBuffer = mediaCodec.getInputBuffer(inputBufferId);
             BufferInfo bufInfo;
             if (mNumInFramesProvided >= mNumInFramesRequired) {
-                Log.i(TAG, "Input frame limit reached");
+                Log.i(TAG, "Input frame limit reached provided: " + mNumInFramesProvided);
                 mIndex = mInputBufferInfo.size() - 1;
                 bufInfo = mInputBufferInfo.get(mIndex);
                 if ((bufInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) == 0) {
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java
index 84554d3..306aeee 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java
@@ -21,6 +21,7 @@
 import androidx.annotation.NonNull;
 import java.nio.ByteBuffer;
 import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 public class FrameReleaseQueue {
     private static final String TAG = "FrameReleaseQueue";
@@ -28,7 +29,7 @@
     private MediaCodec mCodec;
     private LinkedBlockingQueue<FrameInfo> mFrameInfoQueue;
     private ReleaseThread mReleaseThread;
-    private boolean doFrameRelease = false;
+    private AtomicBoolean doFrameRelease = new AtomicBoolean(false);
     private boolean mRender = false;
     private int mWaitTime = 40; // milliseconds per frame
     private int mWaitTimeCorrection = 0;
@@ -49,19 +50,19 @@
 
     private class ReleaseThread extends Thread {
         public void run() {
-            int nextReleaseTime = 0;
+            long nextReleaseTime = 0;
             int loopCount = 0;
-            while (doFrameRelease || mFrameInfoQueue.size() > 0) {
+            while (doFrameRelease.get() || mFrameInfoQueue.size() > 0) {
                 FrameInfo curFrameInfo = mFrameInfoQueue.peek();
                 if (curFrameInfo == null) {
                     nextReleaseTime += mWaitTime;
                 } else {
-                    if (curFrameInfo.displayTime == 0) {
+                    if (firstReleaseTime == -1 || curFrameInfo.displayTime <= 0) {
                         // first frame of loop
                         firstReleaseTime = getCurSysTime();
                         nextReleaseTime = firstReleaseTime + mWaitTime;
                         popAndRelease(curFrameInfo, true);
-                    } else if (!doFrameRelease && mFrameInfoQueue.size() == 1) {
+                    } else if (!doFrameRelease.get() && mFrameInfoQueue.size() == 1) {
                         // EOS
                         Log.i(TAG, "EOS");
                         popAndRelease(curFrameInfo, false);
@@ -83,12 +84,13 @@
                         }
                         if (curFrameInfo != null && curFrameInfo.displayTime > curMediaTime) {
                             if ((curFrameInfo.displayTime - curMediaTime) < THRESHOLD_TIME) {
+                                // release the frame now as we are already there
                                 popAndRelease(curFrameInfo, true);
                             }
                         }
                     }
                 }
-                int sleepTime = nextReleaseTime - getCurSysTime();
+                long sleepTime = nextReleaseTime - getCurSysTime();
                 if (sleepTime > 0) {
                     try {
                         mReleaseThread.sleep(sleepTime);
@@ -109,7 +111,7 @@
     public FrameReleaseQueue(boolean render, int frameRate) {
         this.mFrameInfoQueue = new LinkedBlockingQueue();
         this.mReleaseThread = new ReleaseThread();
-        this.doFrameRelease = true;
+        this.doFrameRelease.set(true);
         this.mRender = render;
         this.mWaitTime = 1000 / frameRate; // wait time in milliseconds per frame
         int waitTimeRemainder = 1000 % frameRate;
@@ -163,7 +165,7 @@
     }
 
     public void stopFrameRelease() {
-        doFrameRelease = false;
+        doFrameRelease.set(false);
         try {
             mReleaseThread.join();
             Log.i(TAG, "Joined frame release thread");
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 1e59bf8..761270b 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1096,7 +1096,7 @@
                                       input.sharedBuffer, sessionId, &output.flags,
                                       callingPid, adjAttributionSource, input.clientInfo.clientTid,
                                       &lStatus, portId, input.audioTrackCallback, isSpatialized,
-                                      isBitPerfect);
+                                      isBitPerfect, &output.afTrackFlags);
         LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (track == 0));
         // we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless
 
@@ -4314,7 +4314,7 @@
 
     response->id = idOut;
     response->enabled = enabledOut != 0;
-    response->effect = handle->asIEffect();
+    response->effect = handle.get() ? handle->asIEffect() : nullptr;
     response->desc = VALUE_OR_RETURN_STATUS(
             legacy2aidl_effect_descriptor_t_EffectDescriptor(descOut));
 
diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h
index be51d51..6ee1ec9 100644
--- a/services/audioflinger/IAfThread.h
+++ b/services/audioflinger/IAfThread.h
@@ -398,7 +398,8 @@
             audio_port_handle_t portId,
             const sp<media::IAudioTrackCallback>& callback,
             bool isSpatialized,
-            bool isBitPerfect) = 0;
+            bool isBitPerfect,
+            audio_output_flags_t* afTrackFlags) = 0;
 
     virtual status_t addTrack_l(const sp<IAfTrack>& track) = 0;
     virtual bool destroyTrack_l(const sp<IAfTrack>& track) = 0;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 978c4aa..5f54e11 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -58,7 +58,7 @@
 
     sp<PlayAudioOpCallback> mOpCallback;
     // called by PlayAudioOpCallback when OP_PLAY_AUDIO is updated in AppOp callback
-    void checkPlayAudioForUsage();
+    void checkPlayAudioForUsage(bool doBroadcast);
 
     wp<IAfThreadBase> mThread;
     std::atomic_bool mHasOpPlayAudio;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 575bcf9..a36494c 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2378,7 +2378,8 @@
         audio_port_handle_t portId,
         const sp<media::IAudioTrackCallback>& callback,
         bool isSpatialized,
-        bool isBitPerfect)
+        bool isBitPerfect,
+        audio_output_flags_t *afTrackFlags)
 {
     size_t frameCount = *pFrameCount;
     size_t notificationFrameCount = *pNotificationFrameCount;
@@ -2696,6 +2697,7 @@
         if (mType == DIRECT) {
             trackFlags = static_cast<audio_output_flags_t>(trackFlags | AUDIO_OUTPUT_FLAG_DIRECT);
         }
+        *afTrackFlags = trackFlags;
 
         track = IAfTrack::create(this, client, streamType, attr, sampleRate, format,
                           channelMask, frameCount,
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 474da8e..79f75ca 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -935,7 +935,8 @@
                                 audio_port_handle_t portId,
                                 const sp<media::IAudioTrackCallback>& callback,
                                 bool isSpatialized,
-                                bool isBitPerfect) final;
+                                bool isBitPerfect,
+                                audio_output_flags_t* afTrackFlags) final;
 
     bool isTrackActive(const sp<IAfTrack>& track) const final {
         return mActiveTracks.indexOf(track) >= 0;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 1a00681..ecea9eb 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -611,7 +611,9 @@
 
 void OpPlayAudioMonitor::onFirstRef()
 {
-    checkPlayAudioForUsage();
+    // make sure not to broadcast the initial state since it is not needed and could
+    // cause a deadlock since this method can be called with the mThread->mLock held
+    checkPlayAudioForUsage(/*doBroadcast=*/false);
     if (mAttributionSource.packageName.has_value()) {
         mOpCallback = new PlayAudioOpCallback(this);
         mAppOpsManager.startWatchingMode(AppOpsManager::OP_PLAY_AUDIO,
@@ -626,7 +628,7 @@
 // Note this method is never called (and never to be) for audio server / patch record track
 // - not called from constructor due to check on UID,
 // - not called from PlayAudioOpCallback because the callback is not installed in this case
-void OpPlayAudioMonitor::checkPlayAudioForUsage()
+void OpPlayAudioMonitor::checkPlayAudioForUsage(bool doBroadcast)
 {
     const bool hasAppOps = mAttributionSource.packageName.has_value()
         && mAppOpsManager.checkAudioOpNoThrow(
@@ -636,11 +638,13 @@
     bool shouldChange = !hasAppOps;  // check if we need to update.
     if (mHasOpPlayAudio.compare_exchange_strong(shouldChange, hasAppOps)) {
         ALOGD("OpPlayAudio: track:%d usage:%d %smuted", mId, mUsage, hasAppOps ? "not " : "");
-        auto thread = mThread.promote();
-        if (thread != nullptr && thread->type() == IAfThreadBase::OFFLOAD) {
-            // Wake up Thread if offloaded, otherwise it may be several seconds for update.
-            Mutex::Autolock _l(thread->mutex());
-            thread->broadcast_l();
+        if (doBroadcast) {
+            auto thread = mThread.promote();
+            if (thread != nullptr && thread->type() == IAfThreadBase::OFFLOAD) {
+                // Wake up Thread if offloaded, otherwise it may be several seconds for update.
+                Mutex::Autolock _l(thread->mutex());
+                thread->broadcast_l();
+            }
         }
     }
 }
@@ -658,7 +662,7 @@
     }
     sp<OpPlayAudioMonitor> monitor = mMonitor.promote();
     if (monitor != NULL) {
-        monitor->checkPlayAudioForUsage();
+        monitor->checkPlayAudioForUsage(/*doBroadcast=*/true);
     }
 }
 
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 6d3c7a5..cbab6fa 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -5892,6 +5892,8 @@
         "  clear-stream-use-case-override clear the stream use case override\n"
         "  set-zoom-override <-1/0/1> enable or disable zoom override\n"
         "      Valid values -1: do not override, 0: override to OFF, 1: override to ZOOM\n"
+        "  set-watchdog <VALUE> enables or disables the camera service watchdog\n"
+        "      Valid values 0=disable, 1=enable\n"
         "  watch <start|stop|dump|print|clear> manages tag monitoring in connected clients\n"
         "  help print this message\n");
 }
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 8144792..68e9ad4 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -452,15 +452,27 @@
         newFormat->setString(KEY_MIME, mimeHeic);
         newFormat->setInt32(KEY_WIDTH, mOutputWidth);
         newFormat->setInt32(KEY_HEIGHT, mOutputHeight);
-        if (mUseGrid) {
+    }
+
+    if (mUseGrid || mUseHeic) {
+        int32_t gridRows, gridCols, tileWidth, tileHeight;
+        if (newFormat->findInt32(KEY_GRID_ROWS, &gridRows) &&
+                newFormat->findInt32(KEY_GRID_COLUMNS, &gridCols) &&
+                newFormat->findInt32(KEY_TILE_WIDTH, &tileWidth) &&
+                newFormat->findInt32(KEY_TILE_HEIGHT, &tileHeight)) {
+            mGridWidth = tileWidth;
+            mGridHeight = tileHeight;
+            mGridRows = gridRows;
+            mGridCols = gridCols;
+        } else {
             newFormat->setInt32(KEY_TILE_WIDTH, mGridWidth);
             newFormat->setInt32(KEY_TILE_HEIGHT, mGridHeight);
             newFormat->setInt32(KEY_GRID_ROWS, mGridRows);
             newFormat->setInt32(KEY_GRID_COLUMNS, mGridCols);
-            int32_t left, top, right, bottom;
-            if (newFormat->findRect("crop", &left, &top, &right, &bottom)) {
-                newFormat->setRect("crop", 0, 0, mOutputWidth - 1, mOutputHeight - 1);
-            }
+        }
+        int32_t left, top, right, bottom;
+        if (newFormat->findRect("crop", &left, &top, &right, &bottom)) {
+            newFormat->setRect("crop", 0, 0, mOutputWidth - 1, mOutputHeight - 1);
         }
     }
     newFormat->setInt32(KEY_IS_DEFAULT, 1 /*isPrimary*/);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 52ba782..a275cfb 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -4014,8 +4014,11 @@
                 sp<Camera3Device> parent = mParent.promote();
                 if (parent != nullptr) {
                     const std::string& streamCameraId = outputStream->getPhysicalCameraId();
+                    // Consider the case where clients are sending a single logical camera request
+                    // to physical output/outputs
+                    bool singleRequest = captureRequest->mSettingsList.size() == 1;
                     for (const auto& settings : captureRequest->mSettingsList) {
-                        if ((streamCameraId.empty() &&
+                        if (((streamCameraId.empty() || singleRequest) &&
                                 parent->getId() == settings.cameraId) ||
                                 streamCameraId == settings.cameraId) {
                             outputStream->fireBufferRequestForFrameNumber(
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.cpp b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
index f8cdb80..e26fd28 100644
--- a/services/mediaresourcemanager/ResourceManagerMetrics.cpp
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
@@ -434,7 +434,7 @@
 
 void ResourceManagerMetrics::pushReclaimAtom(const ClientInfoParcel& clientInfo,
                         const std::vector<int>& priorities,
-                        const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
+                        const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
                         const PidUidVector& idList, bool reclaimed) {
     // Construct the metrics for codec reclaim as a pushed atom.
     // 1. Information about the requester.
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.h b/services/mediaresourcemanager/ResourceManagerMetrics.h
index 3124aa2..d99c5b1 100644
--- a/services/mediaresourcemanager/ResourceManagerMetrics.h
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.h
@@ -135,7 +135,7 @@
     // To be called when after a reclaim event.
     void pushReclaimAtom(const ClientInfoParcel& clientInfo,
                          const std::vector<int>& priorities,
-                         const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
+                         const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
                          const PidUidVector& idList, bool reclaimed);
 
     // Add this pid/uid set to monitor for the process termination state.
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 23b23cc..dbde27c 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -44,47 +44,82 @@
 
 namespace android {
 
-//static
-std::mutex ResourceManagerService::sCookieLock;
-//static
-uintptr_t ResourceManagerService::sCookieCounter = 0;
-//static
-std::map<uintptr_t, sp<DeathNotifier> > ResourceManagerService::sCookieToDeathNotifierMap;
+class DeathNotifier : public std::enable_shared_from_this<DeathNotifier> {
 
-class DeathNotifier : public RefBase {
+    // BinderDiedContext defines the cookie that is passed as DeathRecipient.
+    // Since this can maintain more context than a raw pointer, we can
+    // validate the scope of DeathNotifier, before deferencing it upon the binder death.
+    struct BinderDiedContext {
+        std::weak_ptr<DeathNotifier> mDeathNotifier;
+    };
 public:
-    DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
-                  const ClientInfoParcel& clientInfo);
+    DeathNotifier(const std::shared_ptr<IResourceManagerClient>& client,
+                  const std::shared_ptr<ResourceManagerService>& service,
+                  const ClientInfoParcel& clientInfo,
+                  AIBinder_DeathRecipient* recipient);
 
-    virtual ~DeathNotifier() {}
+    virtual ~DeathNotifier() {
+        unlink();
+    }
+
+    void unlink() {
+        if (mClient != nullptr) {
+            // Register for the callbacks by linking to death notification.
+            AIBinder_unlinkToDeath(mClient->asBinder().get(), mRecipient, mCookie);
+            mClient = nullptr;
+        }
+    }
 
     // Implement death recipient
     static void BinderDiedCallback(void* cookie);
+    static void BinderUnlinkedCallback(void* cookie);
     virtual void binderDied();
 
+private:
+    void link() {
+        // Create the context that is passed as cookie to the binder death notification.
+        // The context gets deleted at BinderUnlinkedCallback.
+        mCookie = new BinderDiedContext{.mDeathNotifier = weak_from_this()};
+        // Register for the callbacks by linking to death notification.
+        AIBinder_linkToDeath(mClient->asBinder().get(), mRecipient, mCookie);
+    }
+
 protected:
+    std::shared_ptr<IResourceManagerClient> mClient;
     std::weak_ptr<ResourceManagerService> mService;
     const ClientInfoParcel mClientInfo;
+    AIBinder_DeathRecipient* mRecipient;
+    BinderDiedContext* mCookie;
 };
 
-DeathNotifier::DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
-                             const ClientInfoParcel& clientInfo)
-    : mService(service), mClientInfo(clientInfo) {}
+DeathNotifier::DeathNotifier(const std::shared_ptr<IResourceManagerClient>& client,
+                             const std::shared_ptr<ResourceManagerService>& service,
+                             const ClientInfoParcel& clientInfo,
+                             AIBinder_DeathRecipient* recipient)
+    : mClient(client), mService(service), mClientInfo(clientInfo),
+      mRecipient(recipient), mCookie(nullptr) {
+    link();
+}
+
+//static
+void DeathNotifier::BinderUnlinkedCallback(void* cookie) {
+    BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
+    // Since we don't need the context anymore, we are deleting it now.
+    delete context;
+}
 
 //static
 void DeathNotifier::BinderDiedCallback(void* cookie) {
-    sp<DeathNotifier> notifier;
-    {
-        std::scoped_lock lock{ResourceManagerService::sCookieLock};
-        auto it = ResourceManagerService::sCookieToDeathNotifierMap.find(
-                reinterpret_cast<uintptr_t>(cookie));
-        if (it == ResourceManagerService::sCookieToDeathNotifierMap.end()) {
-            return;
+    BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
+
+    // Validate the context and check if the DeathNotifier object is still in scope.
+    if (context != nullptr) {
+        std::shared_ptr<DeathNotifier> thiz = context->mDeathNotifier.lock();
+        if (thiz != nullptr) {
+            thiz->binderDied();
+        } else {
+            ALOGI("DeathNotifier is out of scope already");
         }
-        notifier = it->second;
-    }
-    if (notifier.get() != nullptr) {
-        notifier->binderDied();
     }
 }
 
@@ -103,9 +138,11 @@
 
 class OverrideProcessInfoDeathNotifier : public DeathNotifier {
 public:
-    OverrideProcessInfoDeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
-                                     const ClientInfoParcel& clientInfo)
-            : DeathNotifier(service, clientInfo) {}
+    OverrideProcessInfoDeathNotifier(const std::shared_ptr<IResourceManagerClient>& client,
+                                     const std::shared_ptr<ResourceManagerService>& service,
+                                     const ClientInfoParcel& clientInfo,
+                                     AIBinder_DeathRecipient* recipient)
+            : DeathNotifier(client, service, clientInfo, recipient) {}
 
     virtual ~OverrideProcessInfoDeathNotifier() {}
 
@@ -124,7 +161,7 @@
 }
 
 template <typename T>
-static String8 getString(const std::vector<T> &items) {
+static String8 getString(const std::vector<T>& items) {
     String8 itemsStr;
     for (size_t i = 0; i < items.size(); ++i) {
         itemsStr.appendFormat("%s ", toString(items[i]).string());
@@ -165,8 +202,8 @@
 
 static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
         const ResourceInfos& infos) {
-    for (size_t i = 0; i < infos.size(); ++i) {
-        if (hasResourceType(type, subType, infos[i].resources)) {
+    for (const auto& [id, info] : infos) {
+        if (hasResourceType(type, subType, info.resources)) {
             return true;
         }
     }
@@ -174,41 +211,37 @@
 }
 
 static ResourceInfos& getResourceInfosForEdit(int pid, PidResourceInfosMap& map) {
-    ssize_t index = map.indexOfKey(pid);
-    if (index < 0) {
+    PidResourceInfosMap::iterator found = map.find(pid);
+    if (found == map.end()) {
         // new pid
         ResourceInfos infosForPid;
-        map.add(pid, infosForPid);
+        auto [it, inserted] = map.emplace(pid, infosForPid);
+        found = it;
     }
 
-    return map.editValueFor(pid);
+    return found->second;
 }
 
 static ResourceInfo& getResourceInfoForEdit(uid_t uid, int64_t clientId,
                                             const std::string& name,
         const std::shared_ptr<IResourceManagerClient>& client, ResourceInfos& infos) {
-    ssize_t index = infos.indexOfKey(clientId);
+    ResourceInfos::iterator found = infos.find(clientId);
 
-    if (index < 0) {
-        ResourceInfo info;
-        info.uid = uid;
-        info.clientId = clientId;
-        if (name.empty()) {
-            info.name = "<unknown client>";
-        } else {
-            info.name = name;
-        }
-        info.client = client;
-        info.cookie = 0;
-        info.pendingRemoval = false;
-
-        index = infos.add(clientId, info);
+    if (found == infos.end()) {
+        ResourceInfo info{.uid = uid,
+                          .clientId = clientId,
+                          .name = name.empty()? "<unknown client>" : name,
+                          .client = client,
+                          .deathNotifier = nullptr,
+                          .pendingRemoval = false};
+        auto [it, inserted] = infos.emplace(clientId, info);
+        found = it;
     }
 
-    return infos.editValueAt(index);
+    return found->second;
 }
 
-static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel> &resources) {
+static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel>& resources) {
     static const char* const kServiceName = "media_resource_monitor";
     sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName));
     if (binder != NULL) {
@@ -249,7 +282,7 @@
     std::map<int, int> overridePidMapCopy;
     String8 serviceLog;
     {
-        Mutex::Autolock lock(mLock);
+        std::scoped_lock lock{mLock};
         mapCopy = mMap;  // Shadow copy, real copy will happen on write.
         supportsMultipleSecureCodecs = mSupportsMultipleSecureCodecs;
         supportsSecureWithNonSecureCodec = mSupportsSecureWithNonSecureCodec;
@@ -269,8 +302,7 @@
     result.append(buffer);
 
     result.append("  Processes:\n");
-    for (size_t i = 0; i < mapCopy.size(); ++i) {
-        int pid = mapCopy.keyAt(i);
+    for (const auto& [pid, infos] : mapCopy) {
         snprintf(buffer, SIZE, "    Pid: %d\n", pid);
         result.append(buffer);
         int priority = 0;
@@ -281,17 +313,16 @@
         }
         result.append(buffer);
 
-        const ResourceInfos &infos = mapCopy.valueAt(i);
-        for (size_t j = 0; j < infos.size(); ++j) {
+        for (const auto& [infoKey, info] : infos) {
             result.append("      Client:\n");
-            snprintf(buffer, SIZE, "        Id: %lld\n", (long long)infos[j].clientId);
+            snprintf(buffer, SIZE, "        Id: %lld\n", (long long)info.clientId);
             result.append(buffer);
 
-            std::string clientName = infos[j].name;
+            std::string clientName = info.name;
             snprintf(buffer, SIZE, "        Name: %s\n", clientName.c_str());
             result.append(buffer);
 
-            const ResourceList &resources = infos[j].resources;
+            const ResourceList& resources = info.resources;
             result.append("        Resources:\n");
             for (auto it = resources.begin(); it != resources.end(); it++) {
                 snprintf(buffer, SIZE, "          %s\n", toString(it->second).string());
@@ -347,7 +378,8 @@
       mSupportsMultipleSecureCodecs(true),
       mSupportsSecureWithNonSecureCodec(true),
       mCpuBoostCount(0),
-      mDeathRecipient(AIBinder_DeathRecipient_new(DeathNotifier::BinderDiedCallback)) {
+      mDeathRecipient(::ndk::ScopedAIBinder_DeathRecipient(
+                      AIBinder_DeathRecipient_new(DeathNotifier::BinderDiedCallback))) {
     mSystemCB->noteResetVideo();
     // Create ResourceManagerMetrics that handles all the metrics.
     mResourceManagerMetrics = std::make_unique<ResourceManagerMetrics>(mProcessInfo);
@@ -388,7 +420,7 @@
     String8 log = String8::format("config(%s)", getString(policies).string());
     mServiceLog->add(log);
 
-    Mutex::Autolock lock(mLock);
+    std::scoped_lock lock{mLock};
     for (size_t i = 0; i < policies.size(); ++i) {
         const std::string &type = policies[i].type;
         const std::string &value = policies[i].value;
@@ -461,7 +493,7 @@
             pid, uid, (long long) clientId, getString(resources).string());
     mServiceLog->add(log);
 
-    Mutex::Autolock lock(mLock);
+    std::scoped_lock lock{mLock};
     if (!mProcessInfo->isPidUidTrusted(pid, uid)) {
         pid_t callingPid = IPCThreadState::self()->getCallingPid();
         uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -502,9 +534,9 @@
             mergeResources(it->second, res);
         }
     }
-    if (info.cookie == 0 && client != nullptr) {
-        info.cookie = addCookieAndLink_l(client,
-                new DeathNotifier(ref<ResourceManagerService>(), clientInfo));
+    if (info.deathNotifier == nullptr && client != nullptr) {
+        info.deathNotifier = std::make_shared<DeathNotifier>(
+            client, ref<ResourceManagerService>(), clientInfo, mDeathRecipient.get());
     }
     if (mObserverService != nullptr && !resourceAdded.empty()) {
         mObserverService->onResourceAdded(uid, pid, resourceAdded);
@@ -523,27 +555,27 @@
             pid, uid, (long long) clientId, getString(resources).string());
     mServiceLog->add(log);
 
-    Mutex::Autolock lock(mLock);
+    std::scoped_lock lock{mLock};
     if (!mProcessInfo->isPidTrusted(pid)) {
         pid_t callingPid = IPCThreadState::self()->getCallingPid();
         ALOGW("%s called with untrusted pid %d, using calling pid %d", __FUNCTION__,
                 pid, callingPid);
         pid = callingPid;
     }
-    ssize_t index = mMap.indexOfKey(pid);
-    if (index < 0) {
+    PidResourceInfosMap::iterator found = mMap.find(pid);
+    if (found == mMap.end()) {
         ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
         return Status::ok();
     }
-    ResourceInfos &infos = mMap.editValueAt(index);
+    ResourceInfos& infos = found->second;
 
-    index = infos.indexOfKey(clientId);
-    if (index < 0) {
+    ResourceInfos::iterator foundClient = infos.find(clientId);
+    if (foundClient == infos.end()) {
         ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
         return Status::ok();
     }
 
-    ResourceInfo &info = infos.editValueAt(index);
+    ResourceInfo& info = foundClient->second;
     ResourceList resourceRemoved;
     for (size_t i = 0; i < resources.size(); ++i) {
         const auto &res = resources[i];
@@ -593,27 +625,27 @@
             pid, uid, (long long) clientId);
     mServiceLog->add(log);
 
-    Mutex::Autolock lock(mLock);
+    std::scoped_lock lock{mLock};
     if (checkValid && !mProcessInfo->isPidTrusted(pid)) {
         pid_t callingPid = IPCThreadState::self()->getCallingPid();
         ALOGW("%s called with untrusted pid %d, using calling pid %d", __FUNCTION__,
                 pid, callingPid);
         pid = callingPid;
     }
-    ssize_t index = mMap.indexOfKey(pid);
-    if (index < 0) {
+    PidResourceInfosMap::iterator found = mMap.find(pid);
+    if (found == mMap.end()) {
         ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
         return Status::ok();
     }
-    ResourceInfos &infos = mMap.editValueAt(index);
+    ResourceInfos& infos = found->second;
 
-    index = infos.indexOfKey(clientId);
-    if (index < 0) {
+    ResourceInfos::iterator foundClient = infos.find(clientId);
+    if (foundClient == infos.end()) {
         ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
         return Status::ok();
     }
 
-    const ResourceInfo &info = infos[index];
+    const ResourceInfo& info = foundClient->second;
     for (auto it = info.resources.begin(); it != info.resources.end(); it++) {
         onLastRemoved(it->second, info);
     }
@@ -621,20 +653,18 @@
     // Since this client has been removed, update the metrics collector.
     mResourceManagerMetrics->notifyClientReleased(clientInfo);
 
-    removeCookieAndUnlink_l(info.client, info.cookie);
-
     if (mObserverService != nullptr && !info.resources.empty()) {
         mObserverService->onResourceRemoved(info.uid, pid, info.resources);
     }
 
-    infos.removeItemsAt(index);
+    infos.erase(foundClient);
     return Status::ok();
 }
 
 void ResourceManagerService::getClientForResource_l(int callingPid,
         const MediaResourceParcel *res,
         PidUidVector* idVector,
-        Vector<std::shared_ptr<IResourceManagerClient>> *clients) {
+        std::vector<std::shared_ptr<IResourceManagerClient>>* clients) {
     if (res == NULL) {
         return;
     }
@@ -653,10 +683,10 @@
     mServiceLog->add(log);
     *_aidl_return = false;
 
-    Vector<std::shared_ptr<IResourceManagerClient>> clients;
+    std::vector<std::shared_ptr<IResourceManagerClient>> clients;
     PidUidVector idVector;
     {
-        Mutex::Autolock lock(mLock);
+        std::scoped_lock lock{mLock};
         if (!mProcessInfo->isPidTrusted(callingPid)) {
             pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
             ALOGW("%s called with untrusted pid %d, using actual calling pid %d", __FUNCTION__,
@@ -749,7 +779,7 @@
 }
 
 void ResourceManagerService::pushReclaimAtom(const ClientInfoParcel& clientInfo,
-                        const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
+                        const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
                         const PidUidVector& idVector, bool reclaimed) {
     int32_t callingPid = clientInfo.pid;
     int requesterPriority = -1;
@@ -767,7 +797,7 @@
 }
 
 bool ResourceManagerService::reclaimUnconditionallyFrom(
-        const Vector<std::shared_ptr<IResourceManagerClient>> &clients) {
+        const std::vector<std::shared_ptr<IResourceManagerClient>>& clients) {
     if (clients.size() == 0) {
         return false;
     }
@@ -790,20 +820,18 @@
 
     int failedClientPid = -1;
     {
-        Mutex::Autolock lock(mLock);
+        std::scoped_lock lock{mLock};
         bool found = false;
-        for (size_t i = 0; i < mMap.size(); ++i) {
-            ResourceInfos &infos = mMap.editValueAt(i);
-            for (size_t j = 0; j < infos.size();) {
-                if (infos[j].client == failedClient) {
-                    j = infos.removeItemsAt(j);
+        for (auto& [pid, infos] : mMap) {
+            for (const auto& [id, info] : infos) {
+                if (info.client == failedClient) {
+                    infos.erase(id);
                     found = true;
-                } else {
-                    ++j;
+                    break;
                 }
             }
             if (found) {
-                failedClientPid = mMap.keyAt(i);
+                failedClientPid = pid;
                 break;
             }
         }
@@ -835,7 +863,7 @@
     }
 
     {
-        Mutex::Autolock lock(mLock);
+        std::scoped_lock lock{mLock};
         mOverridePidMap.erase(originalPid);
         if (newPid != -1) {
             mOverridePidMap.emplace(originalPid, newPid);
@@ -865,7 +893,7 @@
         return Status::fromServiceSpecificError(BAD_VALUE);
     }
 
-    Mutex::Autolock lock(mLock);
+    std::scoped_lock lock{mLock};
     removeProcessInfoOverride_l(pid);
 
     if (!mProcessInfo->overrideProcessInfo(pid, procState, oomScore)) {
@@ -877,42 +905,16 @@
                                 .uid = 0,
                                 .id = 0,
                                 .name = "<unknown client>"};
-    uintptr_t cookie = addCookieAndLink_l(client,
-            new OverrideProcessInfoDeathNotifier(ref<ResourceManagerService>(), clientInfo));
+    auto deathNotifier = std::make_shared<OverrideProcessInfoDeathNotifier>(
+            client, ref<ResourceManagerService>(), clientInfo, mDeathRecipient.get());
 
-    mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{cookie, client});
+    mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{deathNotifier, client});
 
     return Status::ok();
 }
 
-uintptr_t ResourceManagerService::addCookieAndLink_l(
-        const std::shared_ptr<IResourceManagerClient>& client, const sp<DeathNotifier>& notifier) {
-    if (client == nullptr) {
-        return 0;
-    }
-    std::scoped_lock lock{sCookieLock};
-
-    uintptr_t cookie;
-    // Need to skip cookie 0 (if it wraps around). ResourceInfo has cookie initialized to 0
-    // indicating the death notifier is not created yet.
-    while ((cookie = ++sCookieCounter) == 0);
-    AIBinder_linkToDeath(client->asBinder().get(), mDeathRecipient.get(), (void*)cookie);
-    sCookieToDeathNotifierMap.emplace(cookie, notifier);
-
-    return cookie;
-}
-
-void ResourceManagerService::removeCookieAndUnlink_l(
-         const std::shared_ptr<IResourceManagerClient>& client, uintptr_t cookie) {
-    std::scoped_lock lock{sCookieLock};
-    if (client != nullptr) {
-        AIBinder_unlinkToDeath(client->asBinder().get(), mDeathRecipient.get(), (void*)cookie);
-    }
-    sCookieToDeathNotifierMap.erase(cookie);
-}
-
 void ResourceManagerService::removeProcessInfoOverride(int pid) {
-    Mutex::Autolock lock(mLock);
+    std::scoped_lock lock{mLock};
 
     removeProcessInfoOverride_l(pid);
 }
@@ -924,9 +926,6 @@
     }
 
     mProcessInfo->removeProcessInfoOverride(pid);
-
-    removeCookieAndUnlink_l(it->second.client, it->second.cookie);
-
     mProcessInfoOverrideMap.erase(pid);
 }
 
@@ -938,28 +937,28 @@
             pid, (long long) clientId);
     mServiceLog->add(log);
 
-    Mutex::Autolock lock(mLock);
+    std::scoped_lock lock{mLock};
     if (!mProcessInfo->isPidTrusted(pid)) {
         pid_t callingPid = IPCThreadState::self()->getCallingPid();
         ALOGW("%s called with untrusted pid %d, using calling pid %d", __FUNCTION__,
                 pid, callingPid);
         pid = callingPid;
     }
-    ssize_t index = mMap.indexOfKey(pid);
-    if (index < 0) {
+    PidResourceInfosMap::iterator found = mMap.find(pid);
+    if (found == mMap.end()) {
         ALOGV("markClientForPendingRemoval: didn't find pid %d for clientId %lld",
               pid, (long long)clientId);
         return Status::ok();
     }
-    ResourceInfos &infos = mMap.editValueAt(index);
+    ResourceInfos& infos = found->second;
 
-    index = infos.indexOfKey(clientId);
-    if (index < 0) {
+    ResourceInfos::iterator foundClient = infos.find(clientId);
+    if (foundClient == infos.end()) {
         ALOGV("markClientForPendingRemoval: didn't find clientId %lld", (long long) clientId);
         return Status::ok();
     }
 
-    ResourceInfo &info = infos.editValueAt(index);
+    ResourceInfo& info = foundClient->second;
     info.pendingRemoval = true;
     return Status::ok();
 }
@@ -968,9 +967,9 @@
     String8 log = String8::format("reclaimResourcesFromClientsPendingRemoval(pid %d)", pid);
     mServiceLog->add(log);
 
-    Vector<std::shared_ptr<IResourceManagerClient>> clients;
+    std::vector<std::shared_ptr<IResourceManagerClient>> clients;
     {
-        Mutex::Autolock lock(mLock);
+        std::scoped_lock lock{mLock};
         if (!mProcessInfo->isPidTrusted(pid)) {
             pid_t callingPid = IPCThreadState::self()->getCallingPid();
             ALOGW("%s called with untrusted pid %d, using calling pid %d", __FUNCTION__,
@@ -992,7 +991,7 @@
                         std::shared_ptr<IResourceManagerClient> client;
                         uid_t uid = 0;
                         if (getBiggestClientPendingRemoval_l(pid, type, subType, uid, &client)) {
-                            clients.add(client);
+                            clients.push_back(client);
                             continue;
                         }
                     }
@@ -1003,7 +1002,7 @@
                     uid_t uid = 0;
                     if (getBiggestClientPendingRemoval_l(pid, type,
                             MediaResource::SubType::kUnspecifiedSubType, uid, &client)) {
-                        clients.add(client);
+                        clients.push_back(client);
                     }
                     break;
             }
@@ -1031,23 +1030,22 @@
 bool ResourceManagerService::getAllClients_l(int callingPid, MediaResource::Type type,
         MediaResource::SubType subType,
         PidUidVector* idVector,
-        Vector<std::shared_ptr<IResourceManagerClient>> *clients) {
-    Vector<std::shared_ptr<IResourceManagerClient>> temp;
+        std::vector<std::shared_ptr<IResourceManagerClient>>* clients) {
+    std::vector<std::shared_ptr<IResourceManagerClient>> temp;
     PidUidVector tempIdList;
 
-    for (size_t i = 0; i < mMap.size(); ++i) {
-        ResourceInfos &infos = mMap.editValueAt(i);
-        for (size_t j = 0; j < infos.size(); ++j) {
-            if (hasResourceType(type, subType, infos[j].resources)) {
-                if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) {
+    for (auto& [pid, infos] : mMap) {
+        for (const auto& [id, info] : infos) {
+            if (hasResourceType(type, subType, info.resources)) {
+                if (!isCallingPriorityHigher_l(callingPid, pid)) {
                     // some higher/equal priority process owns the resource,
                     // this request can't be fulfilled.
                     ALOGE("getAllClients_l: can't reclaim resource %s from pid %d",
-                            asString(type), mMap.keyAt(i));
+                            asString(type), pid);
                     return false;
                 }
-                temp.push_back(infos[j].client);
-                tempIdList.emplace_back(mMap.keyAt(i), infos[j].uid);
+                temp.push_back(info.client);
+                tempIdList.emplace_back(pid, info.uid);
             }
         }
     }
@@ -1055,7 +1053,8 @@
         ALOGV("getAllClients_l: didn't find any resource %s", asString(type));
         return true;
     }
-    clients->appendVector(temp);
+
+    clients->insert(std::end(*clients), std::begin(temp), std::end(temp));
     idVector->insert(std::end(*idVector), std::begin(tempIdList), std::end(tempIdList));
     return true;
 }
@@ -1102,17 +1101,16 @@
         MediaResource::SubType subType, int *lowestPriorityPid, int *lowestPriority) {
     int pid = -1;
     int priority = -1;
-    for (size_t i = 0; i < mMap.size(); ++i) {
-        if (mMap.valueAt(i).size() == 0) {
+    for (auto& [tempPid, infos] : mMap) {
+        if (infos.size() == 0) {
             // no client on this process.
             continue;
         }
-        if (!hasResourceType(type, subType, mMap.valueAt(i))) {
+        if (!hasResourceType(type, subType, infos)) {
             // doesn't have the requested resource type
             continue;
         }
-        int tempPid = mMap.keyAt(i);
-        int tempPriority;
+        int tempPriority = -1;
         if (!getPriority_l(tempPid, &tempPriority)) {
             ALOGV("getLowestPriorityPid_l: can't get priority of pid %d, skipped", tempPid);
             // TODO: remove this pid from mMap?
@@ -1155,8 +1153,8 @@
         MediaResource::SubType subType, uid_t& uid,
         std::shared_ptr<IResourceManagerClient> *client,
         bool pendingRemovalOnly) {
-    ssize_t index = mMap.indexOfKey(pid);
-    if (index < 0) {
+    PidResourceInfosMap::iterator found = mMap.find(pid);
+    if (found == mMap.end()) {
         ALOGE_IF(!pendingRemovalOnly,
                  "getBiggestClient_l: can't find resource info for pid %d", pid);
         return false;
@@ -1164,10 +1162,10 @@
 
     std::shared_ptr<IResourceManagerClient> clientTemp;
     uint64_t largestValue = 0;
-    const ResourceInfos &infos = mMap.valueAt(index);
-    for (size_t i = 0; i < infos.size(); ++i) {
-        const ResourceList &resources = infos[i].resources;
-        if (pendingRemovalOnly && !infos[i].pendingRemoval) {
+    const ResourceInfos& infos = found->second;
+    for (const auto& [id, info] : infos) {
+        const ResourceList& resources = info.resources;
+        if (pendingRemovalOnly && !info.pendingRemoval) {
             continue;
         }
         for (auto it = resources.begin(); it != resources.end(); it++) {
@@ -1175,8 +1173,8 @@
             if (hasResourceType(type, subType, resource)) {
                 if (resource.value > largestValue) {
                     largestValue = resource.value;
-                    clientTemp = infos[i].client;
-                    uid = infos[i].uid;
+                    clientTemp = info.client;
+                    uid = info.uid;
                 }
             }
         }
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 1519e0e..aa88ac6 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -22,15 +22,13 @@
 #include <set>
 #include <mutex>
 #include <string>
+#include <vector>
 
 #include <aidl/android/media/BnResourceManagerService.h>
-#include <arpa/inet.h>
 #include <media/MediaResource.h>
 #include <utils/Errors.h>
-#include <utils/KeyedVector.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
-#include <utils/Vector.h>
 
 namespace android {
 
@@ -58,7 +56,7 @@
     int64_t clientId;
     std::string name;
     std::shared_ptr<IResourceManagerClient> client;
-    uintptr_t cookie{0};
+    std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
     ResourceList resources;
     bool pendingRemoval{false};
 };
@@ -66,9 +64,8 @@
 // vector of <PID, UID>
 typedef std::vector<std::pair<int32_t, uid_t>> PidUidVector;
 
-// TODO: convert these to std::map
-typedef KeyedVector<int64_t, ResourceInfo> ResourceInfos;
-typedef KeyedVector<int, ResourceInfos> PidResourceInfosMap;
+typedef std::map<int64_t, ResourceInfo> ResourceInfos;
+typedef std::map<int, ResourceInfos> PidResourceInfosMap;
 
 class ResourceManagerService : public BnResourceManagerService {
 public:
@@ -136,14 +133,15 @@
 
     // Reclaims resources from |clients|. Returns true if reclaim succeeded
     // for all clients.
-    bool reclaimUnconditionallyFrom(const Vector<std::shared_ptr<IResourceManagerClient>> &clients);
+    bool reclaimUnconditionallyFrom(
+        const std::vector<std::shared_ptr<IResourceManagerClient>>& clients);
 
     // Gets the list of all the clients who own the specified resource type.
     // Returns false if any client belongs to a process with higher priority than the
     // calling process. The clients will remain unchanged if returns false.
     bool getAllClients_l(int callingPid, MediaResource::Type type, MediaResource::SubType subType,
             PidUidVector* idList,
-            Vector<std::shared_ptr<IResourceManagerClient>> *clients);
+            std::vector<std::shared_ptr<IResourceManagerClient>>* clients);
 
     // Gets the client who owns specified resource type from lowest possible priority process.
     // Returns false if the calling process priority is not higher than the lowest process
@@ -174,7 +172,7 @@
     // the result client to the given Vector.
     void getClientForResource_l(int callingPid, const MediaResourceParcel *res,
             PidUidVector* idList,
-            Vector<std::shared_ptr<IResourceManagerClient>> *clients);
+            std::vector<std::shared_ptr<IResourceManagerClient>>* clients);
 
     void onFirstAdded(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
     void onLastRemoved(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
@@ -188,13 +186,9 @@
     void removeProcessInfoOverride(int pid);
 
     void removeProcessInfoOverride_l(int pid);
-    uintptr_t addCookieAndLink_l(const std::shared_ptr<IResourceManagerClient>& client,
-                                 const sp<DeathNotifier>& notifier);
-    void removeCookieAndUnlink_l(const std::shared_ptr<IResourceManagerClient>& client,
-                                 uintptr_t cookie);
 
     void pushReclaimAtom(const ClientInfoParcel& clientInfo,
-                         const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
+                         const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
                          const PidUidVector& idList, bool reclaimed);
 
     // Get the peak concurrent pixel count (associated with the video codecs) for the process.
@@ -202,7 +196,7 @@
     // Get the current concurrent pixel count (associated with the video codecs) for the process.
     long getCurrentConcurrentPixelCount(int pid) const;
 
-    mutable Mutex mLock;
+    mutable std::mutex mLock;
     sp<ProcessInfoInterface> mProcessInfo;
     sp<SystemCallbackInterface> mSystemCB;
     sp<ServiceLog> mServiceLog;
@@ -212,15 +206,11 @@
     int32_t mCpuBoostCount;
     ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
     struct ProcessInfoOverride {
-        uintptr_t cookie;
+        std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
         std::shared_ptr<IResourceManagerClient> client;
     };
     std::map<int, int> mOverridePidMap;
     std::map<pid_t, ProcessInfoOverride> mProcessInfoOverrideMap;
-    static std::mutex sCookieLock;
-    static uintptr_t sCookieCounter GUARDED_BY(sCookieLock);
-    static std::map<uintptr_t, sp<DeathNotifier> > sCookieToDeathNotifierMap
-            GUARDED_BY(sCookieLock);
     std::shared_ptr<ResourceObserverService> mObserverService;
     std::unique_ptr<ResourceManagerMetrics> mResourceManagerMetrics;
 };
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 4e575f0..ae3faea 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -131,18 +131,18 @@
 
         const PidResourceInfosMap &map = mService->mMap;
         EXPECT_EQ(2u, map.size());
-        ssize_t index1 = map.indexOfKey(kTestPid1);
-        ASSERT_GE(index1, 0);
-        const ResourceInfos &infos1 = map[index1];
+        const auto& mapIndex1 = map.find(kTestPid1);
+        EXPECT_TRUE(mapIndex1 != map.end());
+        const ResourceInfos &infos1 = mapIndex1->second;
         EXPECT_EQ(1u, infos1.size());
-        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, resources1);
+        expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, resources1);
 
-        ssize_t index2 = map.indexOfKey(kTestPid2);
-        ASSERT_GE(index2, 0);
-        const ResourceInfos &infos2 = map[index2];
+        const auto& mapIndex2 = map.find(kTestPid2);
+        EXPECT_TRUE(mapIndex2 != map.end());
+        const ResourceInfos &infos2 = mapIndex2->second;
         EXPECT_EQ(2u, infos2.size());
-        expectEqResourceInfo(infos2.valueFor(getId(mTestClient2)), kTestUid2, mTestClient2, resources2);
-        expectEqResourceInfo(infos2.valueFor(getId(mTestClient3)), kTestUid2, mTestClient3, resources3);
+        expectEqResourceInfo(infos2.at(getId(mTestClient2)), kTestUid2, mTestClient2, resources2);
+        expectEqResourceInfo(infos2.at(getId(mTestClient3)), kTestUid2, mTestClient3, resources3);
     }
 
     void testCombineResourceWithNegativeValues() {
@@ -161,12 +161,12 @@
         // 2) both resource entries should have been rejected, resource list should be empty.
         const PidResourceInfosMap &map = mService->mMap;
         EXPECT_EQ(1u, map.size());
-        ssize_t index1 = map.indexOfKey(kTestPid1);
-        ASSERT_GE(index1, 0);
-        const ResourceInfos &infos1 = map[index1];
+        const auto& mapIndex1 = map.find(kTestPid1);
+        EXPECT_TRUE(mapIndex1 != map.end());
+        const ResourceInfos &infos1 = mapIndex1->second;
         EXPECT_EQ(1u, infos1.size());
         std::vector<MediaResourceParcel> expected;
-        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+        expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
 
         resources1.clear();
         resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX));
@@ -181,7 +181,7 @@
         // Both values should saturate to INT64_MAX
         expected.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX));
         expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
-        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+        expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
 
         resources1.clear();
         resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, -10));
@@ -193,7 +193,7 @@
         // 2) Non-drm session resource should ignore negative value addition.
         expected.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX - 10));
         expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
-        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+        expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
 
         resources1.clear();
         resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MIN));
@@ -206,7 +206,7 @@
         expected.clear();
         expected.push_back(MediaResource(MediaResource::Type::kDrmSession, 0));
         expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
-        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+        expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
     }
 
     void testConfig() {
@@ -256,9 +256,9 @@
 
         const PidResourceInfosMap &map = mService->mMap;
         EXPECT_EQ(1u, map.size());
-        ssize_t index1 = map.indexOfKey(kTestPid1);
-        ASSERT_GE(index1, 0);
-        const ResourceInfos &infos1 = map[index1];
+        const auto& mapIndex1 = map.find(kTestPid1);
+        EXPECT_TRUE(mapIndex1 != map.end());
+        const ResourceInfos &infos1 = mapIndex1->second;
         EXPECT_EQ(1u, infos1.size());
 
         // test adding existing types to combine values
@@ -268,7 +268,7 @@
         std::vector<MediaResourceParcel> expected;
         expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 2));
         expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 300));
-        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+        expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
 
         // test adding new types (including types that differs only in subType)
         resources11.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
@@ -280,7 +280,7 @@
         expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
         expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, MediaResource::SubType::kVideoCodec, 1));
         expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 500));
-        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+        expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
     }
 
     void testRemoveResource() {
@@ -299,9 +299,9 @@
 
         const PidResourceInfosMap &map = mService->mMap;
         EXPECT_EQ(1u, map.size());
-        ssize_t index1 = map.indexOfKey(kTestPid1);
-        ASSERT_GE(index1, 0);
-        const ResourceInfos &infos1 = map[index1];
+        const auto& mapIndex1 = map.find(kTestPid1);
+        EXPECT_TRUE(mapIndex1 != map.end());
+        const ResourceInfos &infos1 = mapIndex1->second;
         EXPECT_EQ(1u, infos1.size());
 
         // test partial removal
@@ -311,13 +311,13 @@
         std::vector<MediaResourceParcel> expected;
         expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
         expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
-        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+        expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
 
         // test removal request with negative value, should be ignored
         resources11[0].value = -10000;
         mService->removeResource(client1Info, resources11);
 
-        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+        expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
 
         // test complete removal with overshoot value
         resources11[0].value = 1000;
@@ -325,7 +325,7 @@
 
         expected.clear();
         expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
-        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+        expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
     }
 
     void testOverridePid() {
@@ -466,13 +466,12 @@
 
         const PidResourceInfosMap &map = mService->mMap;
         EXPECT_EQ(2u, map.size());
-        const ResourceInfos &infos1 = map.valueFor(kTestPid1);
-        const ResourceInfos &infos2 = map.valueFor(kTestPid2);
+        const ResourceInfos &infos1 = map.at(kTestPid1);
+        const ResourceInfos &infos2 = map.at(kTestPid2);
         EXPECT_EQ(1u, infos1.size());
         EXPECT_EQ(1u, infos2.size());
         // mTestClient2 has been removed.
-        // (OK to use infos2[0] as there is only 1 entry)
-        EXPECT_EQ(mTestClient3, infos2[0].client);
+        EXPECT_EQ(mTestClient3, infos2.at(getId(mTestClient3)).client);
     }
 
     void testGetAllClients() {
@@ -480,7 +479,7 @@
         MediaResource::Type type = MediaResource::Type::kSecureCodec;
         MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
 
-        Vector<std::shared_ptr<IResourceManagerClient> > clients;
+        std::vector<std::shared_ptr<IResourceManagerClient> > clients;
         PidUidVector idList;
         EXPECT_FALSE(mService->getAllClients_l(kLowPriorityPid, type, subType, &idList, &clients));
         // some higher priority process (e.g. kTestPid2) owns the resource, so getAllClients_l