Merge "Add function for getting LE Audio Broadcast device set"
diff --git a/drm/drmserver/Android.bp b/drm/drmserver/Android.bp
index df3a6a2..ab25c65 100644
--- a/drm/drmserver/Android.bp
+++ b/drm/drmserver/Android.bp
@@ -63,3 +63,39 @@
 
     init_rc: ["drmserver.rc"],
 }
+
+cc_fuzz {
+    name: "drmserver_fuzzer",
+
+    defaults: [
+        "service_fuzzer_defaults",
+    ],
+
+    srcs: [
+        "fuzzer/DrmFuzzer.cpp",
+        "DrmManagerService.cpp",
+        "DrmManager.cpp",
+    ],
+
+    static_libs: [
+        "libmediautils",
+        "liblog",
+        "libdl",
+        "libdrmframeworkcommon",
+        "libselinux",
+        "libstagefright_foundation",
+    ],
+
+     shared_libs: [
+         "libmediametrics",
+     ],
+
+     fuzz_config: {
+         libfuzzer_options: [
+             "max_len=50000",
+         ],
+         cc: [
+             "android-drm-team@google.com",
+         ],
+     },
+}
\ No newline at end of file
diff --git a/drm/drmserver/DrmManagerService.h b/drm/drmserver/DrmManagerService.h
index f9b8bef..56201d9 100644
--- a/drm/drmserver/DrmManagerService.h
+++ b/drm/drmserver/DrmManagerService.h
@@ -141,6 +141,8 @@
 
     virtual status_t dump(int fd, const Vector<String16>& args);
 
+    friend class DrmManagerServiceFuzzer;
+
 private:
     sp<DrmManager> mDrmManager;
 };
diff --git a/drm/drmserver/fuzzer/DrmFuzzer.cpp b/drm/drmserver/fuzzer/DrmFuzzer.cpp
new file mode 100644
index 0000000..4b23679
--- /dev/null
+++ b/drm/drmserver/fuzzer/DrmFuzzer.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fuzzbinder/libbinder_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include "DrmManagerService.h"
+
+namespace android {
+class DrmManagerServiceFuzzer {
+public:
+    DrmManagerServiceFuzzer() {}
+
+    void fuzz(const uint8_t* data, size_t size) {
+          auto drmService = new DrmManagerService();
+          fuzzService(drmService, FuzzedDataProvider(data, size));
+    }
+};
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    android::DrmManagerServiceFuzzer serviceFuzzer;
+    serviceFuzzer.fuzz(data, size);
+    return 0;
+}
\ No newline at end of file
diff --git a/drm/libmediadrm/DrmHalAidl.cpp b/drm/libmediadrm/DrmHalAidl.cpp
index c369529..1844acb 100644
--- a/drm/libmediadrm/DrmHalAidl.cpp
+++ b/drm/libmediadrm/DrmHalAidl.cpp
@@ -393,7 +393,8 @@
 
 // DrmHalAidl methods
 DrmHalAidl::DrmHalAidl()
-    : mListener(::ndk::SharedRefBase::make<DrmHalListener>(&mMetrics)),
+    : mMetrics(std::make_shared<MediaDrmMetrics>()),
+      mListener(::ndk::SharedRefBase::make<DrmHalListener>(mMetrics)),
       mFactories(DrmUtils::makeDrmFactoriesAidl()),
       mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {}
 
@@ -462,8 +463,8 @@
     Uuid uuidAidl = DrmUtils::toAidlUuid(uuid);
     std::string appPackageNameAidl = toStdString(appPackageName);
     std::shared_ptr<IDrmPluginAidl> pluginAidl;
-    mMetrics.SetAppPackageName(appPackageName);
-    mMetrics.SetAppUid(AIBinder_getCallingUid());
+    mMetrics->SetAppPackageName(appPackageName);
+    mMetrics->SetAppUid(AIBinder_getCallingUid());
     for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
         ::ndk::ScopedAStatus status =
                 mFactories[i]->createDrmPlugin(uuidAidl, appPackageNameAidl, &pluginAidl);
@@ -539,10 +540,10 @@
                 AIBinder_getCallingPid(), std::static_pointer_cast<IResourceManagerClient>(client),
                 sessionId);
         mOpenSessions.push_back(client);
-        mMetrics.SetSessionStart(sessionId);
+        mMetrics->SetSessionStart(sessionId);
     }
 
-    mMetrics.mOpenSessionCounter.Increment(err);
+    mMetrics->mOpenSessionCounter.Increment(err);
     return err;
 }
 
@@ -562,10 +563,10 @@
             }
         }
 
-        mMetrics.SetSessionEnd(sessionId);
+        mMetrics->SetSessionEnd(sessionId);
     }
 
-    mMetrics.mCloseSessionCounter.Increment(response);
+    mMetrics->mCloseSessionCounter.Increment(response);
     return response;
 }
 
@@ -577,7 +578,7 @@
                                     DrmPlugin::KeyRequestType* keyRequestType) {
     Mutex::Autolock autoLock(mLock);
     INIT_CHECK();
-    EventTimer<status_t> keyRequestTimer(&mMetrics.mGetKeyRequestTimeUs);
+    EventTimer<status_t> keyRequestTimer(&mMetrics->mGetKeyRequestTimeUs);
 
     DrmSessionManager::Instance()->useSession(sessionId);
 
@@ -618,7 +619,7 @@
                                          Vector<uint8_t>& keySetId) {
     Mutex::Autolock autoLock(mLock);
     INIT_CHECK();
-    EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
+    EventTimer<status_t> keyResponseTimer(&mMetrics->mProvideKeyResponseTimeUs);
 
     DrmSessionManager::Instance()->useSession(sessionId);
 
@@ -687,7 +688,7 @@
     defaultUrl = toString8(requestAidl.defaultUrl);
 
     err = statusAidlToDrmStatus(status);
-    mMetrics.mGetProvisionRequestCounter.Increment(err);
+    mMetrics->mGetProvisionRequestCounter.Increment(err);
     return err;
 }
 
@@ -704,7 +705,7 @@
     certificate = toVector(result.certificate);
     wrappedKey = toVector(result.wrappedKey);
     err = statusAidlToDrmStatus(status);
-    mMetrics.mProvideProvisionResponseCounter.Increment(err);
+    mMetrics->mProvideProvisionResponseCounter.Increment(err);
     return err;
 }
 
@@ -914,7 +915,7 @@
     value = toVector(result);
     err = statusAidlToDrmStatus(status);
     if (name == kPropertyDeviceUniqueId) {
-        mMetrics.mGetDeviceUniqueIdCounter.Increment(err);
+        mMetrics->mGetDeviceUniqueIdCounter.Increment(err);
     }
     return err;
 }
@@ -940,7 +941,7 @@
     if (consumer == nullptr) {
         return DrmStatus(UNEXPECTED_NULL);
     }
-    consumer->consumeFrameworkMetrics(mMetrics);
+    consumer->consumeFrameworkMetrics(*mMetrics.get());
 
     // Append vendor metrics if they are supported.
 
@@ -1146,7 +1147,7 @@
         getPropertyByteArrayInternal(String8("metrics"), metricsVector) == OK) {
         metricsString = toBase64StringNoPad(metricsVector.array(), metricsVector.size());
         status_t res = android::reportDrmPluginMetrics(metricsString, vendor, description,
-                                                       mMetrics.GetAppUid());
+                                                       mMetrics->GetAppUid());
         if (res != OK) {
             ALOGE("Metrics were retrieved but could not be reported: %d", res);
         }
@@ -1156,7 +1157,7 @@
 
 std::string DrmHalAidl::reportFrameworkMetrics(const std::string& pluginMetrics) const {
     mediametrics_handle_t item(mediametrics_create("mediadrm"));
-    mediametrics_setUid(item, mMetrics.GetAppUid());
+    mediametrics_setUid(item, mMetrics->GetAppUid());
     String8 vendor;
     String8 description;
     status_t result = getPropertyStringInternal(String8("vendor"), vendor);
@@ -1173,7 +1174,7 @@
     }
 
     std::string serializedMetrics;
-    result = mMetrics.GetSerializedMetrics(&serializedMetrics);
+    result = mMetrics->GetSerializedMetrics(&serializedMetrics);
     if (result != OK) {
         ALOGE("Failed to serialize framework metrics: %d", result);
     }
diff --git a/drm/libmediadrm/DrmHalListener.cpp b/drm/libmediadrm/DrmHalListener.cpp
index cfcf475..4e868ac 100644
--- a/drm/libmediadrm/DrmHalListener.cpp
+++ b/drm/libmediadrm/DrmHalListener.cpp
@@ -37,12 +37,12 @@
     return vec;
 }
 
-DrmHalListener::DrmHalListener(MediaDrmMetrics* metrics)
+DrmHalListener::DrmHalListener(const std::shared_ptr<MediaDrmMetrics>& metrics)
     : mMetrics(metrics) {}
 
 DrmHalListener::~DrmHalListener() {}
 
-void DrmHalListener::setListener(sp<IDrmClient> listener) {
+void DrmHalListener::setListener(const sp<IDrmClient>& listener) {
     Mutex::Autolock lock(mEventLock);
     mListener = listener;
 }
diff --git a/drm/libmediadrm/include/mediadrm/DrmHalAidl.h b/drm/libmediadrm/include/mediadrm/DrmHalAidl.h
index e0b8341..a81b312 100644
--- a/drm/libmediadrm/include/mediadrm/DrmHalAidl.h
+++ b/drm/libmediadrm/include/mediadrm/DrmHalAidl.h
@@ -123,7 +123,7 @@
     ::ndk::ScopedAStatus onSessionLostState(const std::vector<uint8_t>& in_sessionId);
   private:
     static Mutex mLock;
-    mutable MediaDrmMetrics mMetrics;
+    std::shared_ptr<MediaDrmMetrics> mMetrics;
     std::shared_ptr<DrmHalListener> mListener;
     const std::vector<std::shared_ptr<IDrmFactoryAidl>> mFactories;
     std::shared_ptr<IDrmPluginAidl> mPlugin;
diff --git a/drm/libmediadrm/include/mediadrm/DrmHalListener.h b/drm/libmediadrm/include/mediadrm/DrmHalListener.h
index 22361ad..0eed929 100644
--- a/drm/libmediadrm/include/mediadrm/DrmHalListener.h
+++ b/drm/libmediadrm/include/mediadrm/DrmHalListener.h
@@ -27,7 +27,7 @@
 
 namespace android {
 struct DrmHalListener : public BnDrmPluginListener {
-    explicit DrmHalListener(MediaDrmMetrics* mMetrics);
+    explicit DrmHalListener(const std::shared_ptr<MediaDrmMetrics>& in_metrics);
     ~DrmHalListener();
     ::ndk::ScopedAStatus onEvent(EventTypeAidl in_eventType,
                                  const std::vector<uint8_t>& in_sessionId,
@@ -38,9 +38,9 @@
                                       const std::vector<KeyStatusAidl>& in_keyStatusList,
                                       bool in_hasNewUsableKey);
     ::ndk::ScopedAStatus onSessionLostState(const std::vector<uint8_t>& in_sessionId);
-    void setListener(sp<IDrmClient> listener);
+    void setListener(const sp<IDrmClient>& listener);
 private:
-    mutable MediaDrmMetrics* mMetrics;
+    std::shared_ptr<MediaDrmMetrics> mMetrics;
     sp<IDrmClient> mListener;
     mutable Mutex mEventLock;
     mutable Mutex mNotifyLock;
diff --git a/media/audioaidlconversion/AidlConversionEffect.cpp b/media/audioaidlconversion/AidlConversionEffect.cpp
index ad27c64..2df97d1 100644
--- a/media/audioaidlconversion/AidlConversionEffect.cpp
+++ b/media/audioaidlconversion/AidlConversionEffect.cpp
@@ -30,7 +30,7 @@
 namespace android {
 
 using ::aidl::android::hardware::audio::effect::AcousticEchoCanceler;
-using ::aidl::android::hardware::audio::effect::AutomaticGainControl;
+using ::aidl::android::hardware::audio::effect::AutomaticGainControlV2;
 using ::aidl::android::hardware::audio::effect::BassBoost;
 using ::aidl::android::hardware::audio::effect::Descriptor;
 using ::aidl::android::hardware::audio::effect::Downmix;
@@ -260,46 +260,47 @@
 ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_fixedDigitalGain(
         const Parameter& aidl) {
     int gain = VALUE_OR_RETURN(
-            GET_PARAMETER_SPECIFIC_FIELD(aidl, AutomaticGainControl, automaticGainControl,
-                                         AutomaticGainControl::fixedDigitalGainMb, int));
+            GET_PARAMETER_SPECIFIC_FIELD(aidl, AutomaticGainControlV2, automaticGainControlV2,
+                                         AutomaticGainControlV2::fixedDigitalGainMb, int));
     return VALUE_OR_RETURN(convertReinterpret<uint32_t>(gain));
 }
 
 ConversionResult<Parameter> legacy2aidl_uint32_fixedDigitalGain_Parameter_agc(uint32_t legacy) {
     int gain = VALUE_OR_RETURN(convertReinterpret<int>(legacy));
-    return MAKE_SPECIFIC_PARAMETER(AutomaticGainControl, automaticGainControl, fixedDigitalGainMb,
-                                   gain);
+    return MAKE_SPECIFIC_PARAMETER(AutomaticGainControlV2, automaticGainControlV2,
+                                   fixedDigitalGainMb, gain);
 }
 
 ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_levelEstimator(
         const Parameter& aidl) {
     const auto& le = VALUE_OR_RETURN(GET_PARAMETER_SPECIFIC_FIELD(
-            aidl, AutomaticGainControl, automaticGainControl, AutomaticGainControl::levelEstimator,
-            AutomaticGainControl::LevelEstimator));
+            aidl, AutomaticGainControlV2, automaticGainControlV2,
+            AutomaticGainControlV2::levelEstimator, AutomaticGainControlV2::LevelEstimator));
     return static_cast<uint32_t>(le);
 }
 
 ConversionResult<Parameter> legacy2aidl_uint32_levelEstimator_Parameter_agc(uint32_t legacy) {
-    if (legacy > (uint32_t) AutomaticGainControl::LevelEstimator::PEAK) {
+    if (legacy > (uint32_t)AutomaticGainControlV2::LevelEstimator::PEAK) {
         return unexpected(BAD_VALUE);
     }
-    AutomaticGainControl::LevelEstimator le =
-            static_cast<AutomaticGainControl::LevelEstimator>(legacy);
-    return MAKE_SPECIFIC_PARAMETER(AutomaticGainControl, automaticGainControl, levelEstimator, le);
+    AutomaticGainControlV2::LevelEstimator le =
+            static_cast<AutomaticGainControlV2::LevelEstimator>(legacy);
+    return MAKE_SPECIFIC_PARAMETER(AutomaticGainControlV2, automaticGainControlV2, levelEstimator,
+                                   le);
 }
 
 ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_saturationMargin(
         const Parameter& aidl) {
     int saturationMargin = VALUE_OR_RETURN(
-            GET_PARAMETER_SPECIFIC_FIELD(aidl, AutomaticGainControl, automaticGainControl,
-                                         AutomaticGainControl::saturationMarginMb, int));
+            GET_PARAMETER_SPECIFIC_FIELD(aidl, AutomaticGainControlV2, automaticGainControlV2,
+                                         AutomaticGainControlV2::saturationMarginMb, int));
     return VALUE_OR_RETURN(convertIntegral<uint32_t>(saturationMargin));
 }
 
 ConversionResult<Parameter> legacy2aidl_uint32_saturationMargin_Parameter_agc(uint32_t legacy) {
     int saturationMargin = VALUE_OR_RETURN(convertIntegral<int>(legacy));
-    return MAKE_SPECIFIC_PARAMETER(AutomaticGainControl, automaticGainControl, saturationMarginMb,
-                                   saturationMargin);
+    return MAKE_SPECIFIC_PARAMETER(AutomaticGainControlV2, automaticGainControlV2,
+                                   saturationMarginMb, saturationMargin);
 }
 
 ConversionResult<uint16_t> aidl2legacy_Parameter_BassBoost_uint16_strengthPm(
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 6c882a6..32ebe36 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -20,6 +20,8 @@
 #include <algorithm>
 #include <forward_list>
 
+#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
+#include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
 #include <aidl/android/hardware/audio/core/StreamDescriptor.h>
 #include <error/expected_utils.h>
 #include <media/AidlConversionCppNdk.h>
@@ -37,6 +39,7 @@
 using aidl::android::media::audio::common::AudioDeviceType;
 using aidl::android::media::audio::common::AudioInputFlags;
 using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioLatencyMode;
 using aidl::android::media::audio::common::AudioMode;
 using aidl::android::media::audio::common::AudioOutputFlags;
 using aidl::android::media::audio::common::AudioPort;
@@ -298,6 +301,123 @@
     return OK;
 }
 
+namespace {
+
+class StreamCallbackBase {
+  protected:
+    explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
+  public:
+    void* getCookie() const { return mCookie; }
+    void setCookie(void* cookie) { mCookie = cookie; }
+    sp<CallbackBroker> getBroker() const {
+        if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
+        return nullptr;
+    }
+  private:
+    const wp<CallbackBroker> mBroker;
+    std::atomic<void*> mCookie;
+};
+
+template<class C>
+class StreamCallbackBaseHelper {
+  protected:
+    explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
+    sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
+    using CbRef = const sp<C>&;
+    ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
+        if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
+        return ndk::ScopedAStatus::ok();
+    }
+  private:
+    const StreamCallbackBase& mBase;
+};
+
+template<>
+sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
+        const sp<CallbackBroker>& broker, void* cookie) {
+    if (broker != nullptr) return broker->getStreamOutCallback(cookie);
+    return nullptr;
+}
+
+template<>
+sp<StreamOutHalInterfaceEventCallback>
+StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
+        const sp<CallbackBroker>& broker, void* cookie) {
+    if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
+    return nullptr;
+}
+
+template<>
+sp<StreamOutHalInterfaceLatencyModeCallback>
+StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
+        const sp<CallbackBroker>& broker, void* cookie) {
+    if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
+    return nullptr;
+}
+
+/*
+Note on the callback ownership.
+
+In the Binder ownership model, the server implementation is kept alive
+as long as there is any client (proxy object) alive. This is done by
+incrementing the refcount of the server-side object by the Binder framework.
+When it detects that the last client is gone, it decrements the refcount back.
+
+Thus, it is not needed to keep any references to StreamCallback on our
+side (after we have sent an instance to the client), because we are
+the server-side. The callback object will be kept alive as long as the HAL server
+holds a strong ref to IStreamCallback proxy.
+*/
+
+class OutputStreamCallbackAidl : public StreamCallbackBase,
+                             public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
+                             public ::aidl::android::hardware::audio::core::BnStreamCallback {
+  public:
+    explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
+            : StreamCallbackBase(broker),
+              StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
+                      *static_cast<StreamCallbackBase*>(this)) {}
+    ndk::ScopedAStatus onTransferReady() override {
+        return runCb([](CbRef cb) { cb->onWriteReady(); });
+    }
+    ndk::ScopedAStatus onError() override {
+        return runCb([](CbRef cb) { cb->onError(); });
+    }
+    ndk::ScopedAStatus onDrainReady() override {
+        return runCb([](CbRef cb) { cb->onDrainReady(); });
+    }
+};
+
+class OutputStreamEventCallbackAidl :
+            public StreamCallbackBase,
+            public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
+            public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
+            public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
+  public:
+    explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
+            : StreamCallbackBase(broker),
+              StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
+                      *static_cast<StreamCallbackBase*>(this)),
+              StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
+                      *static_cast<StreamCallbackBase*>(this)) {}
+    ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
+        std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
+        return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
+                [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
+    }
+    ndk::ScopedAStatus onRecommendedLatencyModeChanged(
+            const std::vector<AudioLatencyMode>& in_modes) override {
+        auto halModes = VALUE_OR_FATAL(
+                ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
+                        in_modes,
+                        ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
+        return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
+                [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
+    }
+};
+
+}  // namespace
+
 status_t DeviceHalAidl::openOutputStream(
         audio_io_handle_t handle, audio_devices_t devices,
         audio_output_flags_t flags, struct audio_config* config,
@@ -325,8 +445,19 @@
                     &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
     ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
     args.portConfigId = mixPortConfig.id;
-    args.offloadInfo = aidlConfig.offloadInfo;
+    const bool isOffload = isBitPositionFlagSet(
+            aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
+    std::shared_ptr<OutputStreamCallbackAidl> streamCb;
+    if (isOffload) {
+        streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
+    }
+    auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
+    if (isOffload) {
+        args.offloadInfo = aidlConfig.offloadInfo;
+        args.callback = streamCb;
+    }
     args.bufferSizeFrames = aidlConfig.frameCount;
+    args.eventCallback = eventCb;
     ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
     StreamContextAidl context(ret.desc);
@@ -336,7 +467,14 @@
         return NO_INIT;
     }
     *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), nominalLatency,
-            std::move(ret.stream));
+            std::move(ret.stream), this /*callbackBroker*/);
+    void* cbCookie = (*outStream).get();
+    {
+        std::lock_guard l(mLock);
+        mCallbacks.emplace(cbCookie, Callbacks{});
+    }
+    if (streamCb) streamCb->setCookie(cbCookie);
+    eventCb->setCookie(cbCookie);
     cleanups.disarmAll();
     return OK;
 }
@@ -862,4 +1000,55 @@
     ALOGE("%s: port config id %d not found", __func__, portConfigId);
 }
 
+void DeviceHalAidl::clearCallbacks(void* cookie) {
+    std::lock_guard l(mLock);
+    mCallbacks.erase(cookie);
+}
+
+sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
+    return getCallbackImpl(cookie, &Callbacks::out);
+}
+
+void DeviceHalAidl::setStreamOutCallback(
+        void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
+    setCallbackImpl(cookie, &Callbacks::out, cb);
+}
+
+sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
+        void* cookie) {
+    return getCallbackImpl(cookie, &Callbacks::event);
+}
+
+void DeviceHalAidl::setStreamOutEventCallback(
+        void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
+    setCallbackImpl(cookie, &Callbacks::event, cb);
+}
+
+sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
+        void* cookie) {
+    return getCallbackImpl(cookie, &Callbacks::latency);
+}
+
+void DeviceHalAidl::setStreamOutLatencyModeCallback(
+        void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
+    setCallbackImpl(cookie, &Callbacks::latency, cb);
+}
+
+template<class C>
+sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
+    std::lock_guard l(mLock);
+    if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
+        return ((it->second).*field).promote();
+    }
+    return nullptr;
+}
+template<class C>
+void DeviceHalAidl::setCallbackImpl(
+        void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
+    std::lock_guard l(mLock);
+    if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
+        (it->second).*field = cb;
+    }
+}
+
 } // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
index 4d711ea..6f16daf 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.h
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -21,6 +21,7 @@
 #include <vector>
 
 #include <aidl/android/hardware/audio/core/BpModule.h>
+#include <android-base/thread_annotations.h>
 #include <media/audiohal/DeviceHalInterface.h>
 #include <media/audiohal/EffectHalInterface.h>
 
@@ -28,7 +29,35 @@
 
 namespace android {
 
-class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl {
+class StreamOutHalInterfaceCallback;
+class StreamOutHalInterfaceEventCallback;
+class StreamOutHalInterfaceLatencyModeCallback;
+
+// The role of the broker is to connect AIDL callback interface implementations
+// with StreamOut callback implementations. Since AIDL requires all callbacks
+// to be provided upfront, while libaudiohal interfaces allow late registration,
+// there is a need to coordinate the matching process.
+class CallbackBroker : public virtual RefBase {
+  public:
+    virtual ~CallbackBroker() = default;
+    // The cookie is always the stream instance pointer. We don't use weak pointers to avoid extra
+    // costs on reference counting. The stream cleans up related entries on destruction. Since
+    // access to the callbacks map is synchronized, the possibility for pointer aliasing due to
+    // allocation of a new stream at the address of previously deleted stream is avoided.
+    virtual void clearCallbacks(void* cookie) = 0;
+    virtual sp<StreamOutHalInterfaceCallback> getStreamOutCallback(void* cookie) = 0;
+    virtual void setStreamOutCallback(void* cookie, const sp<StreamOutHalInterfaceCallback>&) = 0;
+    virtual sp<StreamOutHalInterfaceEventCallback> getStreamOutEventCallback(void* cookie) = 0;
+    virtual void setStreamOutEventCallback(void* cookie,
+            const sp<StreamOutHalInterfaceEventCallback>&) = 0;
+    virtual sp<StreamOutHalInterfaceLatencyModeCallback> getStreamOutLatencyModeCallback(
+            void* cookie) = 0;
+    virtual void setStreamOutLatencyModeCallback(
+            void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>&) = 0;
+};
+
+class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl,
+                      public CallbackBroker {
   public:
     // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
     status_t getSupportedDevices(uint32_t *devices) override;
@@ -123,6 +152,12 @@
 
   private:
     friend class sp<DeviceHalAidl>;
+
+    struct Callbacks {  // No need to use `atomic_wp` because access is serialized.
+        wp<StreamOutHalInterfaceCallback> out;
+        wp<StreamOutHalInterfaceEventCallback> event;
+        wp<StreamOutHalInterfaceLatencyModeCallback> latency;
+    };
     using Patches = std::map<int32_t /*patch ID*/,
             ::aidl::android::hardware::audio::core::AudioPatch>;
     using PortConfigs = std::map<int32_t /*port config ID*/,
@@ -191,6 +226,21 @@
     void resetPatch(int32_t patchId);
     void resetPortConfig(int32_t portConfigId);
 
+    // CallbackBroker implementation
+    void clearCallbacks(void* cookie) override;
+    sp<StreamOutHalInterfaceCallback> getStreamOutCallback(void* cookie) override;
+    void setStreamOutCallback(void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) override;
+    sp<StreamOutHalInterfaceEventCallback> getStreamOutEventCallback(void* cookie) override;
+    void setStreamOutEventCallback(void* cookie,
+            const sp<StreamOutHalInterfaceEventCallback>& cb) override;
+    sp<StreamOutHalInterfaceLatencyModeCallback> getStreamOutLatencyModeCallback(
+            void* cookie) override;
+    void setStreamOutLatencyModeCallback(
+            void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) override;
+    // Implementation helpers.
+    template<class C> sp<C> getCallbackImpl(void* cookie, wp<C> Callbacks::* field);
+    template<class C> void setCallbackImpl(void* cookie, wp<C> Callbacks::* field, const sp<C>& cb);
+
     const std::string mInstance;
     const std::shared_ptr<::aidl::android::hardware::audio::core::IModule> mModule;
     Ports mPorts;
@@ -198,7 +248,9 @@
     int32_t mDefaultOutputPortId = -1;
     PortConfigs mPortConfigs;
     Patches mPatches;
-    std::map<audio_patch_handle_t, int32_t /* patch ID */> mFwkHandles;
+    std::map<audio_patch_handle_t, int32_t /*patch ID*/> mFwkHandles;
+    std::mutex mLock;
+    std::map<void*, Callbacks> mCallbacks GUARDED_BY(mLock);
 };
 
 } // namespace android
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
index 6190596..7e25b04 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -136,29 +136,15 @@
     return ret;
 }
 
-status_t EffectConversionHelperAidl::handleSetConfig(uint32_t cmdSize, const void* pCmdData,
+status_t EffectConversionHelperAidl::handleSetConfig(uint32_t cmdSize,
+                                                     const void* pCmdData __unused,
                                                      uint32_t* replySize, void* pReplyData) {
     if (!replySize || *replySize != sizeof(int) || !pReplyData ||
         cmdSize != sizeof(effect_config_t)) {
         return BAD_VALUE;
     }
 
-    return *static_cast<int32_t*>(pReplyData) = OK;
-    const auto& legacyConfig = static_cast<const effect_config_t*>(pCmdData);
-    // already open, apply latest settings
-    Parameter::Common common;
-    common.input.base =
-            VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_buffer_config_t_AudioConfigBase(
-                    legacyConfig->inputCfg, true /* isInput */));
-    common.output.base =
-            VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_buffer_config_t_AudioConfigBase(
-                    legacyConfig->outputCfg, false /* isInput */));
-    common.session = mSessionId;
-    common.ioHandle = mIoId;
-    // TODO: add access mode support
-    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
-            mEffect->setParameter(Parameter::make<Parameter::common>(common))));
-    mCommon = common;
+    // TODO: need to implement setConfig with setParameter(common)
     return *static_cast<int32_t*>(pReplyData) = OK;
 }
 
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index 2b85f97..17b3c2e 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -20,7 +20,6 @@
 #include <algorithm>
 #include <cstdint>
 
-#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
 #include <audio_utils/clock.h>
 #include <mediautils/TimeCheck.h>
 #include <utils/Log.h>
@@ -287,12 +286,13 @@
     if (status_t status = sendCommand(burst, &reply); status != OK) {
         return status;
     }
+    *transferred = reply.fmqByteCount;
     if (mIsInput) {
-        *transferred = reply.fmqByteCount;
         LOG_ALWAYS_FATAL_IF(*transferred > bytes,
                 "%s: HAL module read %zu bytes, which exceeds requested count %zu",
                 __func__, *transferred, bytes);
-        if (!mContext.getDataMQ()->read(static_cast<int8_t*>(buffer), *transferred)) {
+        if (!mContext.getDataMQ()->read(static_cast<int8_t*>(buffer),
+                                        mContext.getDataMQ()->availableToRead())) {
             ALOGE("%s: failed to read %zu bytes to data MQ", __func__, *transferred);
             return NOT_ENOUGH_DATA;
         }
@@ -448,43 +448,18 @@
     return OK;
 }
 
-namespace {
-
-/* Notes on callback ownership.
-
-This is how Binder ownership model looks like. The server implementation
-is owned by Binder framework (via sp<>). Proxies are owned by clients.
-When the last proxy disappears, Binder framework releases the server impl.
-
-Thus, it is not needed to keep any references to StreamCallback (this is
-the server impl) -- it will live as long as HAL server holds a strong ref to
-IStreamCallback proxy.
-
-The callback only keeps a weak reference to the stream. The stream is owned
-by AudioFlinger.
-
-*/
-
-class StreamCallback : public ::aidl::android::hardware::audio::core::BnStreamCallback {
-    ndk::ScopedAStatus onTransferReady() override {
-        return ndk::ScopedAStatus::ok();
-    }
-    ndk::ScopedAStatus onError() override {
-        return ndk::ScopedAStatus::ok();
-    }
-    ndk::ScopedAStatus onDrainReady() override {
-        return ndk::ScopedAStatus::ok();
-    }
-};
-
-}  // namespace
-
 StreamOutHalAidl::StreamOutHalAidl(
         const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
-        const std::shared_ptr<IStreamOut>& stream)
+        const std::shared_ptr<IStreamOut>& stream, const sp<CallbackBroker>& callbackBroker)
         : StreamHalAidl("StreamOutHalAidl", false /*isInput*/, config, nominalLatency,
                 std::move(context), getStreamCommon(stream)),
-          mStream(stream) {}
+          mStream(stream), mCallbackBroker(callbackBroker) {}
+
+StreamOutHalAidl::~StreamOutHalAidl() {
+    if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
+        broker->clearCallbacks(this);
+    }
+}
 
 status_t StreamOutHalAidl::getLatency(uint32_t *latency) {
     return StreamHalAidl::getLatency(latency);
@@ -529,10 +504,18 @@
     return INVALID_OPERATION;
 }
 
-status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback __unused) {
+status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
     TIME_CHECK();
     if (!mStream) return NO_INIT;
-    ALOGE("%s not implemented yet", __func__);
+    if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
+        if (auto cb = callback.promote(); cb != nullptr) {
+            broker->setStreamOutCallback(this, cb);
+        } else {
+            // It is expected that the framework never passes a null pointer.
+            // In the AIDL model callbacks can't be "unregistered".
+            LOG_ALWAYS_FATAL("%s: received an expired or null callback pointer", __func__);
+        }
+    }
     return OK;
 }
 
@@ -639,23 +622,15 @@
 }
 
 status_t StreamOutHalAidl::setEventCallback(
-        const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
+        const sp<StreamOutHalInterfaceEventCallback>& callback) {
     TIME_CHECK();
     if (!mStream) return NO_INIT;
-    ALOGE("%s not implemented yet", __func__);
+    if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
+        broker->setStreamOutEventCallback(this, callback);
+    }
     return OK;
 }
 
-namespace {
-
-struct StreamOutEventCallback {
-    StreamOutEventCallback(const wp<StreamOutHalAidl>& stream) : mStream(stream) {}
-  private:
-    wp<StreamOutHalAidl> mStream;
-};
-
-}  // namespace
-
 status_t StreamOutHalAidl::setLatencyMode(audio_latency_mode_t mode __unused) {
     TIME_CHECK();
     if (!mStream) return NO_INIT;
@@ -672,48 +647,15 @@
 };
 
 status_t StreamOutHalAidl::setLatencyModeCallback(
-        const sp<StreamOutHalInterfaceLatencyModeCallback>& callback __unused) {
+        const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
     TIME_CHECK();
     if (!mStream) return NO_INIT;
-    ALOGE("%s not implemented yet", __func__);
+    if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
+        broker->setStreamOutLatencyModeCallback(this, callback);
+    }
     return OK;
 };
 
-void StreamOutHalAidl::onWriteReady() {
-    sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
-    if (callback == 0) return;
-    ALOGV("asyncCallback onWriteReady");
-    callback->onWriteReady();
-}
-
-void StreamOutHalAidl::onDrainReady() {
-    sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
-    if (callback == 0) return;
-    ALOGV("asyncCallback onDrainReady");
-    callback->onDrainReady();
-}
-
-void StreamOutHalAidl::onError() {
-    sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
-    if (callback == 0) return;
-    ALOGV("asyncCallback onError");
-    callback->onError();
-}
-
-void StreamOutHalAidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs __unused) {
-    sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
-    if (callback == nullptr) return;
-    ALOGV("asyncCodecFormatCallback %s", __func__);
-    callback->onCodecFormatChanged(metadataBs);
-}
-
-void StreamOutHalAidl::onRecommendedLatencyModeChanged(
-        const std::vector<audio_latency_mode_t>& modes __unused) {
-    sp<StreamOutHalInterfaceLatencyModeCallback> callback = mLatencyModeCallback.load().promote();
-    if (callback == nullptr) return;
-    callback->onRecommendedLatencyModeChanged(modes);
-}
-
 status_t StreamOutHalAidl::exit() {
     return StreamHalAidl::exit();
 }
diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h
index ce6c31c..162c7bc 100644
--- a/media/libaudiohal/impl/StreamHalAidl.h
+++ b/media/libaudiohal/impl/StreamHalAidl.h
@@ -27,7 +27,6 @@
 #include <fmq/AidlMessageQueue.h>
 #include <media/audiohal/EffectHalInterface.h>
 #include <media/audiohal/StreamHalInterface.h>
-#include <mediautils/Synchronization.h>
 
 #include "ConversionHelperAidl.h"
 #include "StreamPowerLog.h"
@@ -221,6 +220,8 @@
     std::atomic<pid_t> mWorkerTid = -1;
 };
 
+class CallbackBroker;
+
 class StreamOutHalAidl : public StreamOutHalInterface, public StreamHalAidl {
   public:
     // Return the audio hardware driver estimated latency in milliseconds.
@@ -294,33 +295,21 @@
     status_t setLatencyModeCallback(
             const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) override;
 
-    void onRecommendedLatencyModeChanged(const std::vector<audio_latency_mode_t>& modes);
-
     status_t exit() override;
 
-    void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs);
-
-    // Methods used by StreamOutCallback ().
-    // FIXME: Consider the required visibility.
-    void onWriteReady();
-    void onDrainReady();
-    void onError();
-
   private:
     friend class sp<StreamOutHalAidl>;
 
-    mediautils::atomic_wp<StreamOutHalInterfaceCallback> mCallback;
-    mediautils::atomic_wp<StreamOutHalInterfaceEventCallback> mEventCallback;
-    mediautils::atomic_wp<StreamOutHalInterfaceLatencyModeCallback> mLatencyModeCallback;
-
     const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut> mStream;
+    const wp<CallbackBroker> mCallbackBroker;
 
     // Can not be constructed directly by clients.
     StreamOutHalAidl(
             const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
-            const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut>& stream);
+            const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut>& stream,
+            const sp<CallbackBroker>& callbackBroker);
 
-    ~StreamOutHalAidl() override = default;
+    ~StreamOutHalAidl() override;
 };
 
 class StreamInHalAidl : public StreamInHalInterface, public StreamHalAidl {
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc2.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc2.cpp
index 80df2b8..b736936 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc2.cpp
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc2.cpp
@@ -34,7 +34,7 @@
 namespace effect {
 
 using ::aidl::android::aidl_utils::statusTFromBinderStatus;
-using ::aidl::android::hardware::audio::effect::AutomaticGainControl;
+using ::aidl::android::hardware::audio::effect::AutomaticGainControlV2;
 using ::aidl::android::hardware::audio::effect::Parameter;
 using ::android::status_t;
 using utils::EffectParamReader;
@@ -84,8 +84,8 @@
     switch (type) {
         case AGC2_PARAM_FIXED_DIGITAL_GAIN: {
             Parameter::Id id =
-                    MAKE_SPECIFIC_PARAMETER_ID(AutomaticGainControl, automaticGainControlTag,
-                                               AutomaticGainControl::fixedDigitalGainMb);
+                    MAKE_SPECIFIC_PARAMETER_ID(AutomaticGainControlV2, automaticGainControlV2Tag,
+                                               AutomaticGainControlV2::fixedDigitalGainMb);
             RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
             value = VALUE_OR_RETURN_STATUS(
                     aidl::android::aidl2legacy_Parameter_agc_uint32_fixedDigitalGain(aidlParam));
@@ -93,8 +93,8 @@
         }
         case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR: {
             Parameter::Id id =
-                    MAKE_SPECIFIC_PARAMETER_ID(AutomaticGainControl, automaticGainControlTag,
-                                               AutomaticGainControl::levelEstimator);
+                    MAKE_SPECIFIC_PARAMETER_ID(AutomaticGainControlV2, automaticGainControlV2Tag,
+                                               AutomaticGainControlV2::levelEstimator);
             RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
             value = VALUE_OR_RETURN_STATUS(
                     aidl::android::aidl2legacy_Parameter_agc_uint32_levelEstimator(aidlParam));
@@ -102,8 +102,8 @@
         }
         case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN: {
             Parameter::Id id =
-                    MAKE_SPECIFIC_PARAMETER_ID(AutomaticGainControl, automaticGainControlTag,
-                                               AutomaticGainControl::saturationMarginMb);
+                    MAKE_SPECIFIC_PARAMETER_ID(AutomaticGainControlV2, automaticGainControlV2Tag,
+                                               AutomaticGainControlV2::saturationMarginMb);
             RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
             value = VALUE_OR_RETURN_STATUS(
                     aidl::android::aidl2legacy_Parameter_agc_uint32_saturationMargin(aidlParam));
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionBassBoost.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionBassBoost.cpp
index 038b7df..91c3dea 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionBassBoost.cpp
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionBassBoost.cpp
@@ -24,6 +24,7 @@
 #include <media/AidlConversionNdk.h>
 #include <media/AidlConversionEffect.h>
 #include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effects/aidl_effects_utils.h>
 #include <system/audio_effects/effect_bassboost.h>
 
 #include <utils/Log.h>
@@ -37,6 +38,7 @@
 using ::aidl::android::aidl_utils::statusTFromBinderStatus;
 using ::aidl::android::hardware::audio::effect::BassBoost;
 using ::aidl::android::hardware::audio::effect::Parameter;
+using ::aidl::android::hardware::audio::effect::Range;
 using ::android::status_t;
 using utils::EffectParamReader;
 using utils::EffectParamWriter;
@@ -89,10 +91,10 @@
             return param.writeToValue(&value);
         }
         case BASSBOOST_PARAM_STRENGTH_SUPPORTED: {
-            uint16_t value;
-            const auto& cap =
-                    VALUE_OR_RETURN_STATUS(aidl::android::UNION_GET(mDesc.capability, bassBoost));
-            value = VALUE_OR_RETURN_STATUS(convertIntegral<uint32_t>(cap.strengthSupported));
+            // an invalid range indicates not setting support for this parameter
+            uint16_t value =
+                    ::aidl::android::hardware::audio::effect::isRangeValid<Range::Tag::bassBoost>(
+                            BassBoost::strengthPm, mDesc.capability);
             return param.writeToValue(&value);
         }
         default: {
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDynamicsProcessing.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDynamicsProcessing.cpp
index 4ecaa07..4555c9f 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDynamicsProcessing.cpp
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDynamicsProcessing.cpp
@@ -147,8 +147,6 @@
                                                           DynamicsProcessing::inputGain);
             RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
 
-            DynamicsProcessing::Capability cap =
-                    mDesc.capability.get<Capability::dynamicsProcessing>();
             std::vector<DynamicsProcessing::InputGain> gains =
                     VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
                             aidlParam, DynamicsProcessing, dynamicsProcessing,
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp
index efa9e89..a10d271 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp
@@ -69,25 +69,7 @@
             break;
         }
         case EQ_PARAM_PROPERTIES: {
-            if (value >= 0) {
-                aidlParam = MAKE_SPECIFIC_PARAMETER(Equalizer, equalizer, preset, (int)value);
-            } else {
-                std::vector<Equalizer::BandLevel> bandLevels;
-                uint16_t numBands;
-                if (OK != param.readFromValue(&numBands)) {
-                    ALOGE("%s invalid bandLevel param %s", __func__, param.toString().c_str());
-                    return BAD_VALUE;
-                }
-                for (int i = 0; i < numBands; i++) {
-                    uint16_t level;
-                    if (OK != param.readFromValue(&level)) {
-                        ALOGE("%s invalid property param %s", __func__, param.toString().c_str());
-                        return BAD_VALUE;
-                    }
-                    bandLevels.push_back({.index = i, .levelMb = level});
-                }
-                aidlParam = MAKE_SPECIFIC_PARAMETER(Equalizer, equalizer, bandLevels, bandLevels);
-            }
+            // TODO: handle properties setting
             break;
         }
         default: {
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionHapticGenerator.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionHapticGenerator.cpp
index 814b58f..9575e7d 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionHapticGenerator.cpp
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionHapticGenerator.cpp
@@ -34,6 +34,7 @@
 namespace effect {
 
 using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::HapticGenerator;
 using ::aidl::android::hardware::audio::effect::Parameter;
 using ::android::status_t;
 using utils::EffectParamReader;
@@ -41,27 +42,52 @@
 
 status_t AidlConversionHapticGenerator::setParameter(EffectParamReader& param) {
     uint32_t type = 0;
-    uint16_t value = 0;
     if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
-        OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+        OK != param.readFromParameter(&type)) {
         ALOGE("%s invalid param %s", __func__, param.toString().c_str());
         return BAD_VALUE;
     }
     Parameter aidlParam;
-    // TODO
+    switch (type) {
+        case HG_PARAM_HAPTIC_INTENSITY: {
+            int32_t id = 0, scale;
+            if (OK != param.readFromValue(&id) || OK != param.readFromValue(&scale)) {
+                ALOGE("%s invalid intensity %s", __func__, param.toString().c_str());
+                return BAD_VALUE;
+            }
+            HapticGenerator::HapticScale hpScale(
+                    {.id = id, .scale = (HapticGenerator::VibratorScale)(scale)});
+            aidlParam = MAKE_SPECIFIC_PARAMETER(HapticGenerator, hapticGenerator, hapticScales,
+                                                {hpScale});
+            break;
+        }
+        case HG_PARAM_VIBRATOR_INFO: {
+            float resonantFrequencyHz, qFactor, maxAmplitude;
+            if (OK != param.readFromValue(&resonantFrequencyHz) ||
+                OK != param.readFromValue(&qFactor) || OK != param.readFromValue(&maxAmplitude)) {
+                ALOGE("%s invalid vibrator info %s", __func__, param.toString().c_str());
+                return BAD_VALUE;
+            }
+            HapticGenerator::VibratorInformation info({.resonantFrequencyHz = resonantFrequencyHz,
+                                                       .qFactor = qFactor,
+                                                       .maxAmplitude = maxAmplitude});
+            aidlParam =
+                    MAKE_SPECIFIC_PARAMETER(HapticGenerator, hapticGenerator, vibratorInfo, info);
+            break;
+        }
+        default: {
+            // TODO: implement vendor extension parameters
+            ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+            return BAD_VALUE;
+        }
+    }
+
     return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
 }
 
-status_t AidlConversionHapticGenerator::getParameter(EffectParamWriter& param) {
-    uint32_t type = 0, value = 0;
-    if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
-        OK != param.readFromParameter(&type)) {
-        ALOGE("%s invalid param %s", __func__, param.toString().c_str());
-        param.setStatus(BAD_VALUE);
-        return BAD_VALUE;
-    }
-    // TODO
-    return param.writeToValue(&value);
+// No parameter to get for HapticGenerator
+status_t AidlConversionHapticGenerator::getParameter(EffectParamWriter& param __unused) {
+    return OK;
 }
 
 } // namespace effect
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionLoudnessEnhancer.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionLoudnessEnhancer.cpp
index 70e0428..e3c898f 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionLoudnessEnhancer.cpp
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionLoudnessEnhancer.cpp
@@ -34,6 +34,8 @@
 namespace effect {
 
 using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::getParameterSpecificField;
+using ::aidl::android::hardware::audio::effect::LoudnessEnhancer;
 using ::aidl::android::hardware::audio::effect::Parameter;
 using ::android::status_t;
 using utils::EffectParamReader;
@@ -41,27 +43,52 @@
 
 status_t AidlConversionLoudnessEnhancer::setParameter(EffectParamReader& param) {
     uint32_t type = 0;
-    uint16_t value = 0;
+    int32_t gain = 0;
     if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
-        OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+        OK != param.readFromParameter(&type) || OK != param.readFromValue(&gain)) {
         ALOGE("%s invalid param %s", __func__, param.toString().c_str());
         return BAD_VALUE;
     }
     Parameter aidlParam;
-    // TODO
+    switch (type) {
+        case LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB: {
+            aidlParam = MAKE_SPECIFIC_PARAMETER(LoudnessEnhancer, loudnessEnhancer, gainMb, gain);
+            break;
+        }
+        default: {
+            // TODO: implement vendor extension parameters
+            ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+            return BAD_VALUE;
+        }
+    }
     return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
 }
 
 status_t AidlConversionLoudnessEnhancer::getParameter(EffectParamWriter& param) {
-    uint32_t type = 0, value = 0;
+    uint32_t type = 0;
     if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
         OK != param.readFromParameter(&type)) {
         ALOGE("%s invalid param %s", __func__, param.toString().c_str());
         param.setStatus(BAD_VALUE);
         return BAD_VALUE;
     }
-    // TODO
-    return param.writeToValue(&value);
+    switch (type) {
+        case LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB: {
+            Parameter aidlParam;
+            Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(LoudnessEnhancer, loudnessEnhancerTag,
+                                                        LoudnessEnhancer::gainMb);
+            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+            int32_t gain = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
+                    aidlParam, LoudnessEnhancer, loudnessEnhancer, LoudnessEnhancer::gainMb,
+                    std::decay_t<decltype(gain)>));
+            return param.writeToValue(&gain);
+        }
+        default: {
+            // TODO: implement vendor extension parameters
+            ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+            return BAD_VALUE;
+        }
+    }
 }
 
 } // namespace effect
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionNoiseSuppression.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionNoiseSuppression.cpp
index 5faf645..69184cf 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionNoiseSuppression.cpp
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionNoiseSuppression.cpp
@@ -34,33 +34,77 @@
 namespace effect {
 
 using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::getParameterSpecificField;
 using ::aidl::android::hardware::audio::effect::Parameter;
+using ::aidl::android::hardware::audio::effect::NoiseSuppression;
 using ::android::status_t;
 using utils::EffectParamReader;
 using utils::EffectParamWriter;
 
 status_t AidlConversionNoiseSuppression::setParameter(EffectParamReader& param) {
-    uint32_t type = 0;
-    uint16_t value = 0;
+    uint32_t type = 0, value = 0;
     if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
         OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
         ALOGE("%s invalid param %s", __func__, param.toString().c_str());
         return BAD_VALUE;
     }
     Parameter aidlParam;
-    // TODO
+    switch (type) {
+        case NS_PARAM_LEVEL: {
+            aidlParam = MAKE_SPECIFIC_PARAMETER(NoiseSuppression, noiseSuppression, level,
+                                                static_cast<NoiseSuppression::Level>(value));
+            break;
+        }
+        case NS_PARAM_TYPE: {
+            aidlParam = MAKE_SPECIFIC_PARAMETER(NoiseSuppression, noiseSuppression, type,
+                                                static_cast<NoiseSuppression::Type>(value));
+            break;
+        }
+        default: {
+            // TODO: implement vendor extension parameters
+            ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+            return BAD_VALUE;
+        }
+    }
     return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
 }
 
 status_t AidlConversionNoiseSuppression::getParameter(EffectParamWriter& param) {
-    uint32_t type = 0, value = 0;
+    uint32_t paramType = 0, value = 0;
     if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
-        OK != param.readFromParameter(&type)) {
+        OK != param.readFromParameter(&paramType)) {
         ALOGE("%s invalid param %s", __func__, param.toString().c_str());
         param.setStatus(BAD_VALUE);
         return BAD_VALUE;
     }
-    // TODO
+    Parameter aidlParam;
+    switch (paramType) {
+        case NS_PARAM_LEVEL: {
+            Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(NoiseSuppression, noiseSuppressionTag,
+                                                        NoiseSuppression::level);
+            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+            NoiseSuppression::Level level = VALUE_OR_RETURN_STATUS(
+                    GET_PARAMETER_SPECIFIC_FIELD(aidlParam, NoiseSuppression, noiseSuppression,
+                                                 NoiseSuppression::level, NoiseSuppression::Level));
+            value = static_cast<uint32_t>(level);
+            break;
+        }
+        case NS_PARAM_TYPE: {
+            Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(NoiseSuppression, noiseSuppressionTag,
+                                                        NoiseSuppression::type);
+            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+            NoiseSuppression::Type nsType = VALUE_OR_RETURN_STATUS(
+                    GET_PARAMETER_SPECIFIC_FIELD(aidlParam, NoiseSuppression, noiseSuppression,
+                                                 NoiseSuppression::type, NoiseSuppression::Type));
+            value = static_cast<uint32_t>(nsType);
+            break;
+        }
+        default: {
+            // TODO: implement vendor extension parameters
+            ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+            return BAD_VALUE;
+        }
+    }
     return param.writeToValue(&value);
 }
 
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVendorExtension.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVendorExtension.cpp
index a035614..3baf72e 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVendorExtension.cpp
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVendorExtension.cpp
@@ -17,9 +17,11 @@
 #include <cstdint>
 #include <cstring>
 #include <optional>
+#include <type_traits>
 #define LOG_TAG "AidlConversionVendorExtension"
 //#define LOG_NDEBUG 0
 
+#include <aidl/android/hardware/audio/effect/DefaultExtension.h>
 #include <error/expected_utils.h>
 #include <media/AidlConversionNdk.h>
 #include <media/AidlConversionEffect.h>
@@ -32,34 +34,64 @@
 namespace effect {
 
 using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::DefaultExtension;
 using ::aidl::android::hardware::audio::effect::Parameter;
+using ::aidl::android::hardware::audio::effect::VendorExtension;
 using ::android::status_t;
 using utils::EffectParamReader;
 using utils::EffectParamWriter;
 
+/**
+ * For all effect types we currently don't support, add a default extension implementation to use
+ * std::vector<uint8_t> to pass through all data in the format of effect_param_t (the data we got
+ * from libaudioclient for now).
+ * This logic will be removed after we adopt to same AIDL parameter union AIDL in libaudioclient,
+ * after that framework doesn't need to do any AIDL conversion, and the vendor extension can be
+ * pass down in Parameter as is.
+ */
 status_t AidlConversionVendorExtension::setParameter(EffectParamReader& param) {
-    uint32_t type = 0;
-    uint16_t value = 0;
-    if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
-        OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
-        ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+    size_t len = param.getValueSize();
+    DefaultExtension ext;
+    ext.bytes.resize(len);
+    if (OK != param.readFromValue(ext.bytes.data(), len)) {
+        ALOGE("%s read value from param %s failed", __func__, param.toString().c_str());
         return BAD_VALUE;
     }
-    Parameter aidlParam;
-    // TODO
+    VendorExtension effectParam;
+    effectParam.extension.setParcelable(ext);
+    Parameter aidlParam = UNION_MAKE(Parameter, specific,
+                                     UNION_MAKE(Parameter::Specific, vendorEffect, effectParam));
     return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
 }
 
 status_t AidlConversionVendorExtension::getParameter(EffectParamWriter& param) {
-    uint32_t type = 0, value = 0;
-    if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
-        OK != param.readFromParameter(&type)) {
+    int32_t tag;
+    if (OK != param.readFromParameter(&tag)) {
         ALOGE("%s invalid param %s", __func__, param.toString().c_str());
         param.setStatus(BAD_VALUE);
         return BAD_VALUE;
     }
-    // TODO
-    return param.writeToValue(&value);
+
+    Parameter aidlParam;
+    Parameter::Id id = UNION_MAKE(Parameter::Id, vendorEffectTag, tag /* parameter tag */);
+    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+    VendorExtension effectParam = VALUE_OR_RETURN_STATUS(
+            (::aidl::android::getParameterSpecific<Parameter, VendorExtension,
+                                                   Parameter::Specific::vendorEffect>(aidlParam)));
+    std::optional<DefaultExtension> ext;
+    if (STATUS_OK != effectParam.extension.getParcelable(&ext) || !ext.has_value()) {
+        ALOGE("%s get extension parcelable failed", __func__);
+        param.setStatus(BAD_VALUE);
+        return BAD_VALUE;
+    }
+    const auto& extBytes = ext.value().bytes;
+    if (param.getValueSize() < extBytes.size()) {
+        ALOGE("%s extension return data %zu exceed vsize %zu", __func__, extBytes.size(),
+              param.getValueSize());
+        param.setStatus(BAD_VALUE);
+        return BAD_VALUE;
+    }
+    return param.writeToValue(extBytes.data(), extBytes.size());
 }
 
 } // namespace effect
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index 094b415..c685345 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -31,7 +31,7 @@
 class StreamInHalInterface;
 class StreamOutHalInterface;
 
-class DeviceHalInterface : public RefBase
+class DeviceHalInterface : public virtual RefBase
 {
   public:
     // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
diff --git a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
index 1d52b7d..a651d9b 100644
--- a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
@@ -110,8 +110,8 @@
     virtual void onError() {}
 
   protected:
-    StreamOutHalInterfaceCallback() {}
-    virtual ~StreamOutHalInterfaceCallback() {}
+    StreamOutHalInterfaceCallback() = default;
+    virtual ~StreamOutHalInterfaceCallback() = default;
 };
 
 class StreamOutHalInterfaceEventCallback : public virtual RefBase {
@@ -119,8 +119,8 @@
     virtual void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) = 0;
 
 protected:
-    StreamOutHalInterfaceEventCallback() {}
-    virtual ~StreamOutHalInterfaceEventCallback() {}
+    StreamOutHalInterfaceEventCallback() = default;
+    virtual ~StreamOutHalInterfaceEventCallback() = default;
 };
 
 class StreamOutHalInterfaceLatencyModeCallback : public virtual RefBase {
@@ -131,8 +131,8 @@
     virtual void onRecommendedLatencyModeChanged(std::vector<audio_latency_mode_t> modes) = 0;
 
 protected:
-    StreamOutHalInterfaceLatencyModeCallback() {}
-    virtual ~StreamOutHalInterfaceLatencyModeCallback() {}
+    StreamOutHalInterfaceLatencyModeCallback() = default;
+    virtual ~StreamOutHalInterfaceLatencyModeCallback() = default;
 };
 
 class StreamOutHalInterface : public virtual StreamHalInterface {
diff --git a/media/libaudiohal/tests/Android.bp b/media/libaudiohal/tests/Android.bp
index 6600713..2f78dd0 100644
--- a/media/libaudiohal/tests/Android.bp
+++ b/media/libaudiohal/tests/Android.bp
@@ -46,6 +46,7 @@
         "libaudiohal",
         "liblog",
         "libutils",
+        "libvibrator",
     ],
 
     header_libs: [
diff --git a/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp b/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp
index b7742e4..71c7586 100644
--- a/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp
+++ b/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp
@@ -31,10 +31,14 @@
 #include <system/audio_effects/effect_bassboost.h>
 #include <system/audio_effects/effect_downmix.h>
 #include <system/audio_effects/effect_dynamicsprocessing.h>
+#include <system/audio_effects/effect_hapticgenerator.h>
+#include <system/audio_effects/effect_loudnessenhancer.h>
+#include <system/audio_effects/effect_ns.h>
 #include <system/audio_effect.h>
 
 #include <gtest/gtest.h>
 #include <utils/RefBase.h>
+#include <vibrator/ExternalVibrationUtils.h>
 
 namespace android {
 
@@ -146,6 +150,9 @@
 using EffectParamTestTuple =
         std::tuple<const effect_uuid_t* /* type UUID */, std::shared_ptr<EffectParamCombination>>;
 
+static const effect_uuid_t EXTEND_EFFECT_TYPE_UUID = {
+        0xfa81dbde, 0x588b, 0x11ed, 0x9b6a, {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+
 std::vector<EffectParamTestTuple> testPairs = {
         std::make_tuple(FX_IID_AEC,
                         createEffectParamCombination(AEC_PARAM_ECHO_DELAY, 0xff /* echoDelayMs */,
@@ -162,7 +169,23 @@
         std::make_tuple(SL_IID_DYNAMICSPROCESSING,
                         createEffectParamCombination(
                                 std::array<uint32_t, 2>({DP_PARAM_INPUT_GAIN, 0 /* channel */}),
-                                30 /* gainDb */, sizeof(int32_t) /* returnValueSize */))};
+                                30 /* gainDb */, sizeof(int32_t) /* returnValueSize */)),
+        std::make_tuple(
+                FX_IID_HAPTICGENERATOR,
+                createEffectParamCombination(
+                        HG_PARAM_HAPTIC_INTENSITY,
+                        std::array<uint32_t, 2>(
+                                {1, uint32_t(::android::os::HapticScale::HIGH) /* scale */}),
+                        0 /* returnValueSize */)),
+        std::make_tuple(
+                FX_IID_LOUDNESS_ENHANCER,
+                createEffectParamCombination(LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB, 5 /* gain */,
+                                             sizeof(int32_t) /* returnValueSize */)),
+        std::make_tuple(FX_IID_NS,
+                        createEffectParamCombination(NS_PARAM_LEVEL, 1 /* level */,
+                                                     sizeof(int32_t) /* returnValueSize */)),
+        std::make_tuple(&EXTEND_EFFECT_TYPE_UUID,
+                        createEffectParamCombination(1, 0xbead, sizeof(int32_t)))};
 
 class libAudioHalEffectParamTest : public ::testing::TestWithParam<EffectParamTestTuple> {
   public:
@@ -186,6 +209,7 @@
           }()) {}
 
     void SetUp() override {
+        ASSERT_NE(0ul, mDescs.size());
         for (const auto& desc : mDescs) {
             sp<EffectHalInterface> interface = createEffectHal(desc);
             ASSERT_NE(nullptr, interface);
@@ -237,10 +261,12 @@
                                      &replySize, getParam));
         EffectParamReader parameterGet(*getParam);
         EXPECT_EQ(replySize, parameterGet.getTotalSize()) << parameterGet.toString();
-        std::vector<uint8_t> response(mCombination->valueSize);
-        EXPECT_EQ(OK, parameterGet.readFromValue(response.data(), mCombination->valueSize))
+        if (mCombination->valueSize) {
+            std::vector<uint8_t> response(mCombination->valueSize);
+            EXPECT_EQ(OK, parameterGet.readFromValue(response.data(), mCombination->valueSize))
                 << parameterGet.toString();
-        EXPECT_EQ(response, mExpectedValue);
+            EXPECT_EQ(response, mExpectedValue);
+        }
     }
 
     const EffectParamTestTuple mParamTuple;
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
index 203a27b..4af5fd8 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
@@ -59,8 +59,34 @@
 namespace aidl::android::hardware::audio::effect {
 
 const std::string DynamicsProcessingImpl::kEffectName = "DynamicsProcessing";
-const DynamicsProcessing::Capability DynamicsProcessingImpl::kCapability = {.minCutOffFreq = 220,
-                                                                            .maxCutOffFreq = 20000};
+
+const DynamicsProcessing::EqBandConfig DynamicsProcessingImpl::kEqBandConfigMin =
+        DynamicsProcessing::EqBandConfig({.channel = 0,
+                                          .band = 0,
+                                          .enable = false,
+                                          .cutoffFrequencyHz = 220,
+                                          .gainDb = std::numeric_limits<float>::min()});
+const DynamicsProcessing::EqBandConfig DynamicsProcessingImpl::kEqBandConfigMax =
+        DynamicsProcessing::EqBandConfig({.channel = std::numeric_limits<int>::max(),
+                                          .band = std::numeric_limits<int>::max(),
+                                          .enable = true,
+                                          .cutoffFrequencyHz = 20000,
+                                          .gainDb = std::numeric_limits<float>::max()});
+const Range::DynamicsProcessingRange DynamicsProcessingImpl::kPreEqBandRange = {
+        .min = DynamicsProcessing::make<DynamicsProcessing::preEqBand>(
+                {DynamicsProcessingImpl::kEqBandConfigMin}),
+        .max = DynamicsProcessing::make<DynamicsProcessing::preEqBand>(
+                {DynamicsProcessingImpl::kEqBandConfigMax})};
+const Range::DynamicsProcessingRange DynamicsProcessingImpl::kPostEqBandRange = {
+        .min = DynamicsProcessing::make<DynamicsProcessing::postEqBand>(
+                {DynamicsProcessingImpl::kEqBandConfigMin}),
+        .max = DynamicsProcessing::make<DynamicsProcessing::postEqBand>(
+                {DynamicsProcessingImpl::kEqBandConfigMax})};
+const Range DynamicsProcessingImpl::kRange =
+        Range::make<Range::dynamicsProcessing>({DynamicsProcessingImpl::kPreEqBandRange});
+
+const Capability DynamicsProcessingImpl::kCapability = {.range = {DynamicsProcessingImpl::kRange}};
+
 const Descriptor DynamicsProcessingImpl::kDescriptor = {
         .common = {.id = {.type = kDynamicsProcessingTypeUUID,
                           .uuid = kDynamicsProcessingImplUUID,
@@ -70,8 +96,7 @@
                              .volume = Flags::Volume::CTRL},
                    .name = DynamicsProcessingImpl::kEffectName,
                    .implementor = "The Android Open Source Project"},
-        .capability = Capability::make<Capability::dynamicsProcessing>(
-                DynamicsProcessingImpl::kCapability)};
+        .capability = DynamicsProcessingImpl::kCapability};
 
 ndk::ScopedAStatus DynamicsProcessingImpl::open(const Parameter::Common& common,
                                                 const std::optional<Parameter::Specific>& specific,
@@ -138,6 +163,7 @@
     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
     auto& param = specific.get<Parameter::Specific::dynamicsProcessing>();
+    // TODO: check range here, dynamicsProcessing need customized method for nested parameters.
     auto tag = param.getTag();
 
     switch (tag) {
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
index 824ebea..26b6ead 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
@@ -28,7 +28,7 @@
   public:
     static const std::string kEffectName;
     static const Descriptor kDescriptor;
-    static const DynamicsProcessing::Capability kCapability;
+    static const Capability kCapability;
 
     DynamicsProcessingImpl() { LOG(DEBUG) << __func__; }
     ~DynamicsProcessingImpl() {
@@ -52,6 +52,11 @@
     std::string getEffectName() override { return kEffectName; }
 
   private:
+    static const DynamicsProcessing::EqBandConfig kEqBandConfigMin;
+    static const DynamicsProcessing::EqBandConfig kEqBandConfigMax;
+    static const Range::DynamicsProcessingRange kPreEqBandRange;
+    static const Range::DynamicsProcessingRange kPostEqBandRange;
+    static const Range kRange;
     std::shared_ptr<DynamicsProcessingContext> mContext;
     ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
                                                       Parameter::Specific* specific);
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
index 57a2be9..7978cc5 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
@@ -420,24 +420,18 @@
            validateStageEnablement(engine.postEqStage) && validateStageEnablement(engine.mbcStage);
 }
 
-inline bool DynamicsProcessingContext::validateCutoffFrequency(float freq) {
-    return freq >= DynamicsProcessingImpl::kCapability.minCutOffFreq &&
-            freq <= DynamicsProcessingImpl::kCapability.maxCutOffFreq;
-}
-
 bool DynamicsProcessingContext::validateEqBandConfig(const DynamicsProcessing::EqBandConfig& band,
                                                      int maxChannel, int maxBand) {
-    return validateChannel(band.channel, maxChannel) && validateBand(band.band, maxBand) &&
-           validateCutoffFrequency(band.cutoffFrequencyHz);
+    return validateChannel(band.channel, maxChannel) && validateBand(band.band, maxBand);
 }
 
 bool DynamicsProcessingContext::validateMbcBandConfig(const DynamicsProcessing::MbcBandConfig& band,
                                                       int maxChannel, int maxBand) {
     return validateChannel(band.channel, maxChannel) && validateBand(band.band, maxBand) &&
-           validateCutoffFrequency(band.cutoffFrequencyHz) && validateTime(band.attackTimeMs) &&
-           validateTime(band.releaseTimeMs) && validateRatio(band.ratio) &&
-           validateBandDb(band.thresholdDb) && validateBandDb(band.kneeWidthDb) &&
-           validateBandDb(band.noiseGateThresholdDb) && validateRatio(band.expanderRatio);
+           validateTime(band.attackTimeMs) && validateTime(band.releaseTimeMs) &&
+           validateRatio(band.ratio) && validateBandDb(band.thresholdDb) &&
+           validateBandDb(band.kneeWidthDb) && validateBandDb(band.noiseGateThresholdDb) &&
+           validateRatio(band.expanderRatio);
 }
 
 bool DynamicsProcessingContext::validateLimiterConfig(
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
index e303efd..6124356 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
@@ -531,11 +531,6 @@
 }
 
 RetCode BundleContext::setBassBoostStrength(int strength) {
-    if (strength < 0 || strength > lvm::kBassBoostCap.maxStrengthPm) {
-        LOG(ERROR) << __func__ << " invalid strength: " << strength;
-        return RetCode::ERROR_ILLEGAL_PARAMETER;
-    }
-
     // Update Control Parameter
     LVM_ControlParams_t params;
     {
@@ -555,10 +550,6 @@
 }
 
 RetCode BundleContext::setVolumeLevel(int level) {
-    if (level < lvm::kVolumeCap.minLevelDb || level > lvm::kVolumeCap.maxLevelDb) {
-        return RetCode::ERROR_ILLEGAL_PARAMETER;
-    }
-
     if (mMuteEnabled) {
         mLevelSaved = level / 100;
     } else {
@@ -584,10 +575,6 @@
 }
 
 RetCode BundleContext::setVirtualizerStrength(int strength) {
-    if (strength < 0 || strength > lvm::kVirtualizerCap.maxStrengthPm) {
-        return RetCode::ERROR_ILLEGAL_PARAMETER;
-    }
-
     // Update Control Parameter
     LVM_ControlParams_t params;
     {
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
index 1996240..4652d8d 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
@@ -67,46 +67,53 @@
         {0, "Normal"},      {1, "Classical"}, {2, "Dance"}, {3, "Flat"}, {4, "Folk"},
         {5, "Heavy Metal"}, {6, "Hip Hop"},   {7, "Jazz"},  {8, "Pop"},  {9, "Rock"}};
 
-static const Equalizer::Capability kEqCap = {.bandFrequencies = kEqBandFrequency,
-                                             .presets = kEqPresets};
 
+const std::vector<Range::EqualizerRange> kEqRanges = {
+        MAKE_RANGE(Equalizer, preset, 0, MAX_NUM_PRESETS - 1),
+        MAKE_RANGE(
+                Equalizer, bandLevels,
+                std::vector<Equalizer::BandLevel>{Equalizer::BandLevel(
+                        {.index = 0, .levelMb = std::numeric_limits<int>::min()})},
+                std::vector<Equalizer::BandLevel>{Equalizer::BandLevel(
+                        {.index = MAX_NUM_BANDS - 1, .levelMb = std::numeric_limits<int>::max()})}),
+        /* capability definition */
+        MAKE_RANGE(Equalizer, bandFrequencies, kEqBandFrequency, kEqBandFrequency),
+        MAKE_RANGE(Equalizer, presets, kEqPresets, kEqPresets),
+        /* get only parameters with range min > max */
+        MAKE_RANGE(Equalizer, centerFreqMh, std::vector<int>({1}), std::vector<int>({}))};
+static const Capability kEqCap = {.range = kEqRanges};
 static const std::string kEqualizerEffectName = "EqualizerBundle";
+static const Descriptor kEqualizerDesc = {.common = {.id = {.type = kEqualizerTypeUUID,
+                                                            .uuid = kEqualizerBundleImplUUID,
+                                                            .proxy = kEqualizerProxyUUID},
+                                                     .flags = {.type = Flags::Type::INSERT,
+                                                               .insert = Flags::Insert::FIRST,
+                                                               .volume = Flags::Volume::CTRL},
+                                                     .name = kEqualizerEffectName,
+                                                     .implementor = "NXP Software Ltd."},
+                                          .capability = kEqCap};
 
-static const Descriptor kEqualizerDesc = {
-        .common = {.id = {.type = kEqualizerTypeUUID,
-                          .uuid = kEqualizerBundleImplUUID,
-                          .proxy = kEqualizerProxyUUID},
-                   .flags = {.type = Flags::Type::INSERT,
-                             .insert = Flags::Insert::FIRST,
-                             .volume = Flags::Volume::CTRL},
-                   .name = kEqualizerEffectName,
-                   .implementor = "NXP Software Ltd."},
-        .capability = Capability::make<Capability::equalizer>(kEqCap)};
-
-static const bool mStrengthSupported = true;
-
-static const BassBoost::Capability kBassBoostCap = {.maxStrengthPm = 1000,
-                                                    .strengthSupported = mStrengthSupported};
-
+static const int mMaxStrengthSupported = 1000;
+static const std::vector<Range::BassBoostRange> kBassBoostRanges = {
+        MAKE_RANGE(BassBoost, strengthPm, 0, mMaxStrengthSupported)};
+static const Capability kBassBoostCap = {.range = kBassBoostRanges};
 static const std::string kBassBoostEffectName = "Dynamic Bass Boost";
+static const Descriptor kBassBoostDesc = {.common = {.id = {.type = kBassBoostTypeUUID,
+                                                            .uuid = kBassBoostBundleImplUUID,
+                                                            .proxy = kBassBoostProxyUUID},
+                                                     .flags = {.type = Flags::Type::INSERT,
+                                                               .insert = Flags::Insert::FIRST,
+                                                               .volume = Flags::Volume::CTRL,
+                                                               .deviceIndication = true},
+                                                     .cpuLoad = BASS_BOOST_CUP_LOAD_ARM9E,
+                                                     .memoryUsage = BUNDLE_MEM_USAGE,
+                                                     .name = kBassBoostEffectName,
+                                                     .implementor = "NXP Software Ltd."},
+                                          .capability = kBassBoostCap};
 
-static const Descriptor kBassBoostDesc = {
-        .common = {.id = {.type = kBassBoostTypeUUID,
-                          .uuid = kBassBoostBundleImplUUID,
-                          .proxy = kBassBoostProxyUUID},
-                   .flags = {.type = Flags::Type::INSERT,
-                             .insert = Flags::Insert::FIRST,
-                             .volume = Flags::Volume::CTRL,
-                             .deviceIndication = true},
-                   .cpuLoad = BASS_BOOST_CUP_LOAD_ARM9E,
-                   .memoryUsage = BUNDLE_MEM_USAGE,
-                   .name = kBassBoostEffectName,
-                   .implementor = "NXP Software Ltd."},
-        .capability = Capability::make<Capability::bassBoost>(kBassBoostCap)};
-
-static const Virtualizer::Capability kVirtualizerCap = {.maxStrengthPm = 1000,
-                                                        .strengthSupported = mStrengthSupported};
-
+static const std::vector<Range::VirtualizerRange> kVirtualizerRanges = {
+        MAKE_RANGE(Virtualizer, strengthPm, 0, mMaxStrengthSupported)};
+static const Capability kVirtualizerCap = {.range = kVirtualizerRanges};
 static const std::string kVirtualizerEffectName = "Virtualizer";
 
 static const Descriptor kVirtualizerDesc = {
@@ -121,24 +128,23 @@
                    .memoryUsage = BUNDLE_MEM_USAGE,
                    .name = kVirtualizerEffectName,
                    .implementor = "NXP Software Ltd."},
-        .capability = Capability::make<Capability::virtualizer>(kVirtualizerCap)};
+        .capability = kVirtualizerCap};
 
-static const Volume::Capability kVolumeCap = {.minLevelDb = -9600, .maxLevelDb = 0};
-
+static const std::vector<Range::VolumeRange> kVolumeRanges = {
+        MAKE_RANGE(Volume, levelDb, -9600, 0)};
+static const Capability kVolumeCap = {.range = kVolumeRanges};
 static const std::string kVolumeEffectName = "Volume";
-
-static const Descriptor kVolumeDesc = {
-        .common = {.id = {.type = kVolumeTypeUUID,
-                          .uuid = kVolumeBundleImplUUID,
-                          .proxy = std::nullopt},
-                   .flags = {.type = Flags::Type::INSERT,
-                             .insert = Flags::Insert::LAST,
-                             .volume = Flags::Volume::CTRL},
-                   .cpuLoad = VOLUME_CUP_LOAD_ARM9E,
-                   .memoryUsage = BUNDLE_MEM_USAGE,
-                   .name = kVolumeEffectName,
-                   .implementor = "NXP Software Ltd."},
-        .capability = Capability::make<Capability::volume>(kVolumeCap)};
+static const Descriptor kVolumeDesc = {.common = {.id = {.type = kVolumeTypeUUID,
+                                                         .uuid = kVolumeBundleImplUUID,
+                                                         .proxy = std::nullopt},
+                                                  .flags = {.type = Flags::Type::INSERT,
+                                                            .insert = Flags::Insert::LAST,
+                                                            .volume = Flags::Volume::CTRL},
+                                                  .cpuLoad = VOLUME_CUP_LOAD_ARM9E,
+                                                  .memoryUsage = BUNDLE_MEM_USAGE,
+                                                  .name = kVolumeEffectName,
+                                                  .implementor = "NXP Software Ltd."},
+                                       .capability = kVolumeCap};
 
 /* The following tables have been computed using the actual levels measured by the output of
  * white noise or pink noise (IEC268-1) for the EQ and BassBoost Effects. These are estimates of
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
index fd9f3dc..dc52c16 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "BundleTypes.h"
 #define LOG_TAG "EffectBundleAidl"
 #include <Utils.h>
 #include <algorithm>
@@ -173,6 +174,7 @@
 
 ndk::ScopedAStatus EffectBundleAidl::setParameterEqualizer(const Parameter::Specific& specific) {
     auto& eq = specific.get<Parameter::Specific::equalizer>();
+    RETURN_IF(!inRange(eq, lvm::kEqRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
     auto eqTag = eq.getTag();
     switch (eqTag) {
         case Equalizer::preset:
@@ -193,6 +195,7 @@
 
 ndk::ScopedAStatus EffectBundleAidl::setParameterBassBoost(const Parameter::Specific& specific) {
     auto& bb = specific.get<Parameter::Specific::bassBoost>();
+    RETURN_IF(!inRange(bb, lvm::kBassBoostRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
     auto bbTag = bb.getTag();
     switch (bbTag) {
         case BassBoost::strengthPm: {
@@ -210,6 +213,7 @@
 
 ndk::ScopedAStatus EffectBundleAidl::setParameterVirtualizer(const Parameter::Specific& specific) {
     auto& vr = specific.get<Parameter::Specific::virtualizer>();
+    RETURN_IF(!inRange(vr, lvm::kVirtualizerRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
     auto vrTag = vr.getTag();
     switch (vrTag) {
         case Virtualizer::strengthPm: {
@@ -235,6 +239,7 @@
 
 ndk::ScopedAStatus EffectBundleAidl::setParameterVolume(const Parameter::Specific& specific) {
     auto& vol = specific.get<Parameter::Specific::volume>();
+    RETURN_IF(!inRange(vol, lvm::kVolumeRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
     auto volTag = vol.getTag();
     switch (volTag) {
         case Volume::levelDb: {
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
index 51825ca..018f3bc 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "ReverbTypes.h"
 #define LOG_TAG "EffectReverb"
 #include <Utils.h>
 #include <algorithm>
@@ -132,6 +133,7 @@
 
 ndk::ScopedAStatus EffectReverb::setParameterPresetReverb(const Parameter::Specific& specific) {
     auto& prParam = specific.get<Parameter::Specific::presetReverb>();
+    RETURN_IF(!inRange(prParam, lvm::kPresetReverbRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
     auto tag = prParam.getTag();
 
     switch (tag) {
@@ -152,6 +154,7 @@
 ndk::ScopedAStatus EffectReverb::setParameterEnvironmentalReverb(
         const Parameter::Specific& specific) {
     auto& erParam = specific.get<Parameter::Specific::environmentalReverb>();
+    RETURN_IF(!inRange(erParam, lvm::kEnvReverbRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
     auto tag = erParam.getTag();
 
     switch (tag) {
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp
index d35c22b..87aa12b 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp
@@ -139,12 +139,6 @@
 }
 
 RetCode ReverbContext::setEnvironmentalReverbRoomLevel(int roomLevel) {
-    if (roomLevel < lvm::kEnvReverbCap.minRoomLevelMb ||
-        roomLevel > lvm::kEnvReverbCap.maxRoomLevelMb) {
-        LOG(ERROR) << __func__ << " invalid roomLevel: " << roomLevel;
-        return RetCode::ERROR_ILLEGAL_PARAMETER;
-    }
-
     // Update Control Parameter
     LVREV_ControlParams_st params;
     {
@@ -165,12 +159,6 @@
 }
 
 RetCode ReverbContext::setEnvironmentalReverbRoomHfLevel(int roomHfLevel) {
-    if (roomHfLevel < lvm::kEnvReverbCap.minRoomHfLevelMb ||
-        roomHfLevel > lvm::kEnvReverbCap.maxRoomHfLevelMb) {
-        LOG(ERROR) << __func__ << " invalid roomHfLevel: " << roomHfLevel;
-        return RetCode::ERROR_ILLEGAL_PARAMETER;
-    }
-
     // Update Control Parameter
     LVREV_ControlParams_st params;
     {
@@ -188,10 +176,6 @@
 }
 
 RetCode ReverbContext::setEnvironmentalReverbDecayTime(int decayTime) {
-    if (decayTime < 0 || decayTime > lvm::kEnvReverbCap.maxDecayTimeMs) {
-        LOG(ERROR) << __func__ << " invalid decayTime: " << decayTime;
-        return RetCode::ERROR_ILLEGAL_PARAMETER;
-    }
     int time = decayTime;
     if (time > lvm::kMaxT60) {
         time = lvm::kMaxT60;
@@ -215,12 +199,6 @@
 }
 
 RetCode ReverbContext::setEnvironmentalReverbDecayHfRatio(int decayHfRatio) {
-    if (decayHfRatio < lvm::kEnvReverbCap.minDecayHfRatioPm ||
-        decayHfRatio > lvm::kEnvReverbCap.maxDecayHfRatioPm) {
-        LOG(ERROR) << __func__ << " invalid decayHfRatio: " << decayHfRatio;
-        return RetCode::ERROR_ILLEGAL_PARAMETER;
-    }
-
     // Update Control Parameter
     LVREV_ControlParams_st params;
     {
@@ -238,11 +216,6 @@
 }
 
 RetCode ReverbContext::setEnvironmentalReverbLevel(int level) {
-    if (level < lvm::kEnvReverbCap.minLevelMb || level > lvm::kEnvReverbCap.maxLevelMb) {
-        LOG(ERROR) << __func__ << " invalid level: " << level;
-        return RetCode::ERROR_ILLEGAL_PARAMETER;
-    }
-
     // Update Control Parameter
     LVREV_ControlParams_st params;
     {
@@ -263,20 +236,11 @@
 }
 
 RetCode ReverbContext::setEnvironmentalReverbDelay(int delay) {
-    if (delay < 0 || delay > lvm::kEnvReverbCap.maxDelayMs) {
-        LOG(ERROR) << __func__ << " invalid delay: " << delay;
-        return RetCode::ERROR_ILLEGAL_PARAMETER;
-    }
     mDelay = delay;
     return RetCode::SUCCESS;
 }
 
 RetCode ReverbContext::setEnvironmentalReverbDiffusion(int diffusion) {
-    if (diffusion < 0 || diffusion > lvm::kEnvReverbCap.maxDiffusionPm) {
-        LOG(ERROR) << __func__ << " invalid diffusion: " << diffusion;
-        return RetCode::ERROR_ILLEGAL_PARAMETER;
-    }
-
     // Update Control Parameter
     LVREV_ControlParams_st params;
     {
@@ -294,11 +258,6 @@
 }
 
 RetCode ReverbContext::setEnvironmentalReverbDensity(int density) {
-    if (density < 0 || density > lvm::kEnvReverbCap.maxDensityPm) {
-        LOG(ERROR) << __func__ << " invalid density: " << density;
-        return RetCode::ERROR_ILLEGAL_PARAMETER;
-    }
-
     // Update Control Parameter
     LVREV_ControlParams_st params;
     {
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbTypes.h b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbTypes.h
index e37602c..8dcda87 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbTypes.h
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbTypes.h
@@ -21,6 +21,7 @@
 #include <audio_effects/effect_environmentalreverb.h>
 #include <audio_effects/effect_presetreverb.h>
 #include "effect-impl/EffectUUID.h"
+#include "effect-impl/EffectTypes.h"
 // from Reverb/lib
 #include "LVREV.h"
 
@@ -35,51 +36,51 @@
 constexpr inline int kCpuLoadARM9E = 470;                      // Expressed in 0.1 MIPS
 constexpr inline int kMemUsage = (71 + (kMaxFrameSize >> 7));  // Expressed in kB
 
-static const EnvironmentalReverb::Capability kEnvReverbCap = {.minRoomLevelMb = lvm::kMinLevel,
-                                                              .maxRoomLevelMb = 0,
-                                                              .minRoomHfLevelMb = -4000,
-                                                              .maxRoomHfLevelMb = 0,
-                                                              .maxDecayTimeMs = lvm::kMaxT60,
-                                                              .minDecayHfRatioPm = 100,
-                                                              .maxDecayHfRatioPm = 2000,
-                                                              .minLevelMb = lvm::kMinLevel,
-                                                              .maxLevelMb = 0,
-                                                              .maxDelayMs = 65,
-                                                              .maxDiffusionPm = 1000,
-                                                              .maxDensityPm = 1000};
+static const std::vector<Range::EnvironmentalReverbRange> kEnvReverbRanges = {
+        MAKE_RANGE(EnvironmentalReverb, roomLevelMb, lvm::kMinLevel, 0),
+        MAKE_RANGE(EnvironmentalReverb, roomHfLevelMb, -4000, 0),
+        MAKE_RANGE(EnvironmentalReverb, decayTimeMs, 0, lvm::kMaxT60),
+        MAKE_RANGE(EnvironmentalReverb, decayHfRatioPm, 100, 2000),
+        MAKE_RANGE(EnvironmentalReverb, levelMb, lvm::kMinLevel, 0),
+        MAKE_RANGE(EnvironmentalReverb, delayMs, 0, 65),
+        MAKE_RANGE(EnvironmentalReverb, diffusionPm, 0, 1000),
+        MAKE_RANGE(EnvironmentalReverb, densityPm, 0, 1000)};
+static const Capability kEnvReverbCap = {
+        .range = Range::make<Range::environmentalReverb>(kEnvReverbRanges)};
 
 // NXP SW auxiliary environmental reverb
 static const std::string kAuxEnvReverbEffectName = "Auxiliary Environmental Reverb";
-static const Descriptor kAuxEnvReverbDesc = {
-        .common = {.id = {.type = kEnvReverbTypeUUID,
-                          .uuid = kAuxEnvReverbImplUUID,
-                          .proxy = std::nullopt},
-                   .flags = {.type = Flags::Type::AUXILIARY},
-                   .cpuLoad = kCpuLoadARM9E,
-                   .memoryUsage = kMemUsage,
-                   .name = kAuxEnvReverbEffectName,
-                   .implementor = "NXP Software Ltd."},
-        .capability = Capability::make<Capability::environmentalReverb>(kEnvReverbCap)};
+static const Descriptor kAuxEnvReverbDesc = {.common = {.id = {.type = kEnvReverbTypeUUID,
+                                                               .uuid = kAuxEnvReverbImplUUID,
+                                                               .proxy = std::nullopt},
+                                                        .flags = {.type = Flags::Type::AUXILIARY},
+                                                        .cpuLoad = kCpuLoadARM9E,
+                                                        .memoryUsage = kMemUsage,
+                                                        .name = kAuxEnvReverbEffectName,
+                                                        .implementor = "NXP Software Ltd."},
+                                             .capability = kEnvReverbCap};
 
 // NXP SW insert environmental reverb
 static const std::string kInsertEnvReverbEffectName = "Insert Environmental Reverb";
-static const Descriptor kInsertEnvReverbDesc = {
-        .common = {.id = {.type = kEnvReverbTypeUUID,
-                          .uuid = kInsertEnvReverbImplUUID,
-                          .proxy = std::nullopt},
-                   .flags = {.type = Flags::Type::INSERT,
-                             .insert = Flags::Insert::FIRST,
-                             .volume = Flags::Volume::CTRL},
-                   .cpuLoad = kCpuLoadARM9E,
-                   .memoryUsage = kMemUsage,
-                   .name = kInsertEnvReverbEffectName,
-                   .implementor = "NXP Software Ltd."},
-        .capability = Capability::make<Capability::environmentalReverb>(kEnvReverbCap)};
+static const Descriptor kInsertEnvReverbDesc = {.common = {.id = {.type = kEnvReverbTypeUUID,
+                                                                  .uuid = kInsertEnvReverbImplUUID,
+                                                                  .proxy = std::nullopt},
+                                                           .flags = {.type = Flags::Type::INSERT,
+                                                                     .insert = Flags::Insert::FIRST,
+                                                                     .volume = Flags::Volume::CTRL},
+                                                           .cpuLoad = kCpuLoadARM9E,
+                                                           .memoryUsage = kMemUsage,
+                                                           .name = kInsertEnvReverbEffectName,
+                                                           .implementor = "NXP Software Ltd."},
+                                                .capability = kEnvReverbCap};
 
 static const std::vector<PresetReverb::Presets> kSupportedPresets{
         ndk::enum_range<PresetReverb::Presets>().begin(),
         ndk::enum_range<PresetReverb::Presets>().end()};
-static const PresetReverb::Capability kPresetReverbCap = {.supportedPresets = kSupportedPresets};
+static const std::vector<Range::PresetReverbRange> kPresetReverbRanges = {
+        MAKE_RANGE(PresetReverb, supportedPresets, kSupportedPresets, kSupportedPresets)};
+static const Capability kPresetReverbCap = {
+        .range = Range::make<Range::presetReverb>(kPresetReverbRanges)};
 
 // NXP SW auxiliary preset reverb
 static const std::string kAuxPresetReverbEffectName = "Auxiliary Preset Reverb";
@@ -92,7 +93,7 @@
                    .memoryUsage = kMemUsage,
                    .name = kAuxPresetReverbEffectName,
                    .implementor = "NXP Software Ltd."},
-        .capability = Capability::make<Capability::presetReverb>(kPresetReverbCap)};
+        .capability = kPresetReverbCap};
 
 // NXP SW insert preset reverb
 static const std::string kInsertPresetReverbEffectName = "Insert Preset Reverb";
@@ -107,7 +108,7 @@
                    .memoryUsage = kMemUsage,
                    .name = kInsertPresetReverbEffectName,
                    .implementor = "NXP Software Ltd."},
-        .capability = Capability::make<Capability::presetReverb>(kPresetReverbCap)};
+        .capability = kPresetReverbCap};
 
 enum class ReverbEffectType {
     AUX_ENV,
diff --git a/media/libeffects/visualizer/aidl/Visualizer.cpp b/media/libeffects/visualizer/aidl/Visualizer.cpp
index 28a7287..6e7833c 100644
--- a/media/libeffects/visualizer/aidl/Visualizer.cpp
+++ b/media/libeffects/visualizer/aidl/Visualizer.cpp
@@ -54,9 +54,16 @@
 namespace aidl::android::hardware::audio::effect {
 
 const std::string VisualizerImpl::kEffectName = "Visualizer";
-const Visualizer::Capability VisualizerImpl::kCapability = {
-        .maxLatencyMs = VisualizerContext::kMaxLatencyMs,
-        .captureSampleRange = {.min = 0, .max = VisualizerContext::kMaxCaptureBufSize}};
+const std::vector<Range::VisualizerRange> VisualizerImpl::kRanges = {
+        MAKE_RANGE(Visualizer, latencyMs, 0, VisualizerContext::kMaxLatencyMs),
+        MAKE_RANGE(Visualizer, captureSamples, 0, VisualizerContext::kMaxCaptureBufSize),
+        /* get only parameters, set invalid range (min > max) to indicate not support set */
+        MAKE_RANGE(Visualizer, measurement, Visualizer::Measurement({.peak = 1, .rms = 1}),
+                   Visualizer::Measurement({.peak = 0, .rms = 0})),
+        MAKE_RANGE(Visualizer, captureSampleBuffer, std::vector<uint8_t>({1}),
+                   std::vector<uint8_t>({0}))};
+const Capability VisualizerImpl::kCapability = {
+        .range = Range::make<Range::visualizer>(VisualizerImpl::kRanges)};
 const Descriptor VisualizerImpl::kDescriptor = {
         .common = {.id = {.type = kVisualizerTypeUUID,
                           .uuid = kVisualizerImplUUID,
@@ -66,7 +73,7 @@
                              .volume = Flags::Volume::CTRL},
                    .name = VisualizerImpl::kEffectName,
                    .implementor = "The Android Open Source Project"},
-        .capability = Capability::make<Capability::visualizer>(VisualizerImpl::kCapability)};
+        .capability = VisualizerImpl::kCapability};
 
 ndk::ScopedAStatus VisualizerImpl::getDescriptor(Descriptor* _aidl_return) {
     RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
@@ -96,32 +103,13 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus VisualizerImpl::setOnlyParameter(
-        const Visualizer::SetOnlyParameters& param) {
-    auto tag = param.getTag();
-    switch (tag) {
-        case Visualizer::SetOnlyParameters::latencyMs: {
-            RETURN_IF(mContext->setDownstreamLatency(
-                              param.get<Visualizer::SetOnlyParameters::latencyMs>()) !=
-                              RetCode::SUCCESS,
-                      EX_ILLEGAL_ARGUMENT, "setLatencyFailed");
-            break;
-        }
-        default: {
-            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
-            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
-                    EX_ILLEGAL_ARGUMENT, "setOnlyParameterTagNotSupported");
-        }
-    }
-    return ndk::ScopedAStatus::ok();
-}
-
 ndk::ScopedAStatus VisualizerImpl::setParameterSpecific(const Parameter::Specific& specific) {
     RETURN_IF(Parameter::Specific::visualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
     auto& param = specific.get<Parameter::Specific::visualizer>();
+    RETURN_IF(!inRange(param, kRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
     const auto tag = param.getTag();
     switch (tag) {
         case Visualizer::captureSamples: {
@@ -142,8 +130,11 @@
                       EX_ILLEGAL_ARGUMENT, "setMeasurementModeFailed");
             return ndk::ScopedAStatus::ok();
         }
-        case Visualizer::setOnlyParameters: {
-            return setOnlyParameter(param.get<Visualizer::setOnlyParameters>());
+        case Visualizer::latencyMs: {
+            RETURN_IF(mContext->setDownstreamLatency(param.get<Visualizer::latencyMs>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setLatencyFailed");
+            return ndk::ScopedAStatus::ok();
         }
         default: {
             LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
@@ -153,30 +144,6 @@
     }
 }
 
-ndk::ScopedAStatus VisualizerImpl::getOnlyParameter(const Visualizer::GetOnlyParameters::Tag tag,
-                                                    Parameter::Specific* specific) {
-    Visualizer visualizer;
-    Visualizer::GetOnlyParameters param;
-    switch (tag) {
-        case Visualizer::GetOnlyParameters::measurement: {
-            param.set<Visualizer::GetOnlyParameters::measurement>(mContext->getMeasure());
-            break;
-        }
-        case Visualizer::GetOnlyParameters::captureSampleBuffer: {
-            param.set<Visualizer::GetOnlyParameters::captureSampleBuffer>(mContext->capture());
-            break;
-        }
-        default: {
-            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
-            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
-                    EX_ILLEGAL_ARGUMENT, "setOnlyParameterTagNotSupported");
-        }
-    }
-    visualizer.set<Visualizer::getOnlyParameters>(param);
-    specific->set<Parameter::Specific::visualizer>(visualizer);
-    return ndk::ScopedAStatus::ok();
-}
-
 ndk::ScopedAStatus VisualizerImpl::getParameterSpecific(const Parameter::Id& id,
                                                         Parameter::Specific* specific) {
     RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
@@ -188,9 +155,6 @@
         case Visualizer::Id::commonTag: {
             return getParameterVisualizer(specificId.get<Visualizer::Id::commonTag>(), specific);
         }
-        case Visualizer::Id::getOnlyParamTag: {
-            return getOnlyParameter(specificId.get<Visualizer::Id::getOnlyParamTag>(), specific);
-        }
         default: {
             LOG(ERROR) << __func__ << " unsupported tag: " << toString(specificTag);
             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
@@ -218,6 +182,18 @@
             param.set<Visualizer::measurementMode>(mContext->getMeasurementMode());
             break;
         }
+        case Visualizer::measurement: {
+            param.set<Visualizer::measurement>(mContext->getMeasure());
+            break;
+        }
+        case Visualizer::captureSampleBuffer: {
+            param.set<Visualizer::captureSampleBuffer>(mContext->capture());
+            break;
+        }
+        case Visualizer::latencyMs: {
+            param.set<Visualizer::latencyMs>(mContext->getDownstreamLatency());
+            break;
+        }
         default: {
             LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
diff --git a/media/libeffects/visualizer/aidl/Visualizer.h b/media/libeffects/visualizer/aidl/Visualizer.h
index 5908d9a..f6e1d6d 100644
--- a/media/libeffects/visualizer/aidl/Visualizer.h
+++ b/media/libeffects/visualizer/aidl/Visualizer.h
@@ -28,7 +28,7 @@
 class VisualizerImpl final : public EffectImpl {
   public:
     static const std::string kEffectName;
-    static const Visualizer::Capability kCapability;
+    static const Capability kCapability;
     static const Descriptor kDescriptor;
     VisualizerImpl() { LOG(DEBUG) << __func__; }
     ~VisualizerImpl() {
@@ -49,12 +49,10 @@
     std::string getEffectName() override { return kEffectName; }
 
   private:
+    static const std::vector<Range::VisualizerRange> kRanges;
     std::shared_ptr<VisualizerContext> mContext;
     ndk::ScopedAStatus getParameterVisualizer(const Visualizer::Tag& tag,
                                                     Parameter::Specific* specific);
-    ndk::ScopedAStatus setOnlyParameter(const Visualizer::SetOnlyParameters& param);
-    ndk::ScopedAStatus getOnlyParameter(const Visualizer::GetOnlyParameters::Tag tag,
-                                        Parameter::Specific* specific);
 };
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/visualizer/aidl/VisualizerContext.cpp b/media/libeffects/visualizer/aidl/VisualizerContext.cpp
index 1965e0e..4405407 100644
--- a/media/libeffects/visualizer/aidl/VisualizerContext.cpp
+++ b/media/libeffects/visualizer/aidl/VisualizerContext.cpp
@@ -88,11 +88,6 @@
 
 RetCode VisualizerContext::setCaptureSamples(int samples) {
     std::lock_guard lg(mMutex);
-    if (samples < 0 || (unsigned)samples > kMaxCaptureBufSize) {
-        LOG(ERROR) << __func__ << " captureSamples " << samples << " exceed valid range: 0 - "
-                   << kMaxCaptureBufSize;
-        return RetCode::ERROR_ILLEGAL_PARAMETER;
-    }
     mCaptureSamples = samples;
     return RetCode::SUCCESS;
 }
@@ -122,16 +117,16 @@
 }
 
 RetCode VisualizerContext::setDownstreamLatency(int latency) {
-    if (latency < 0 || (unsigned)latency > kMaxLatencyMs) {
-        LOG(ERROR) << __func__ << " latency " << latency << " exceed valid range: 0 - "
-                   << kMaxLatencyMs;
-        return RetCode::ERROR_ILLEGAL_PARAMETER;
-    }
     std::lock_guard lg(mMutex);
     mDownstreamLatency = latency;
     return RetCode::SUCCESS;
 }
 
+int VisualizerContext::getDownstreamLatency() {
+    std::lock_guard lg(mMutex);
+    return mDownstreamLatency;
+}
+
 uint32_t VisualizerContext::getDeltaTimeMsFromUpdatedTime_l() {
     uint32_t deltaMs = 0;
     if (mBufferUpdateTime.tv_sec != 0) {
@@ -149,7 +144,7 @@
     return deltaMs;
 }
 
-Visualizer::GetOnlyParameters::Measurement VisualizerContext::getMeasure() {
+Visualizer::Measurement VisualizerContext::getMeasure() {
     uint16_t peakU16 = 0;
     float sumRmsSquared = 0.0f;
     uint8_t nbValidMeasurements = 0;
@@ -184,7 +179,7 @@
     }
 
     float rms = nbValidMeasurements == 0 ? 0.0f : sqrtf(sumRmsSquared / nbValidMeasurements);
-    Visualizer::GetOnlyParameters::Measurement measure;
+    Visualizer::Measurement measure;
     // convert from I16 sample values to mB and write results
     measure.rms = (rms < 0.000016f) ? -9600 : (int32_t)(2000 * log10(rms / 32767.0f));
     measure.peak = (peakU16 == 0) ? -9600 : (int32_t)(2000 * log10(peakU16 / 32767.0f));
diff --git a/media/libeffects/visualizer/aidl/VisualizerContext.h b/media/libeffects/visualizer/aidl/VisualizerContext.h
index bfda0b9..3cb711e 100644
--- a/media/libeffects/visualizer/aidl/VisualizerContext.h
+++ b/media/libeffects/visualizer/aidl/VisualizerContext.h
@@ -45,10 +45,11 @@
     RetCode setScalingMode(Visualizer::ScalingMode mode);
     Visualizer::ScalingMode getScalingMode();
     RetCode setDownstreamLatency(int latency);
+    int getDownstreamLatency();
 
     IEffect::Status process(float* in, float* out, int samples);
     // Gets the current measurements, measured by process() and consumed by getParameter()
-    Visualizer::GetOnlyParameters::Measurement getMeasure();
+    Visualizer::Measurement getMeasure();
     // Gets the latest PCM capture, data captured by process() and consumed by getParameter()
     std::vector<uint8_t> capture();
 
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index cf4b849..ebbbb5f 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -863,6 +863,9 @@
             return NAME_NOT_FOUND;
         };
     }
+
+    // we want an empty metrics record for any early getMetrics() call
+    // this should be the *only* initMediametrics() call that's not on the Looper thread
     initMediametrics();
 }
 
@@ -871,8 +874,17 @@
     mResourceManagerProxy->removeClient();
 
     flushMediametrics();
+
+    // clean any saved metrics info we stored as part of configure()
+    if (mConfigureMsg != nullptr) {
+        mediametrics_handle_t metricsHandle;
+        if (mConfigureMsg->findInt64("metrics", &metricsHandle)) {
+            mediametrics_delete(metricsHandle);
+        }
+    }
 }
 
+// except for in constructor, called from the looper thread (and therefore mutexed)
 void MediaCodec::initMediametrics() {
     if (mMetricsHandle == 0) {
         mMetricsHandle = mediametrics_create(kCodecKeyName);
@@ -902,11 +914,12 @@
 }
 
 void MediaCodec::updateMediametrics() {
-    ALOGV("MediaCodec::updateMediametrics");
     if (mMetricsHandle == 0) {
         return;
     }
 
+    Mutex::Autolock _lock(mMetricsLock);
+
     if (mLatencyHist.getCount() != 0 ) {
         mediametrics_setInt64(mMetricsHandle, kCodecLatencyMax, mLatencyHist.getMax());
         mediametrics_setInt64(mMetricsHandle, kCodecLatencyMin, mLatencyHist.getMin());
@@ -1019,6 +1032,8 @@
 }
 
 
+// called to update info being passed back via getMetrics(), which is a
+// unique copy for that call, no concurrent access worries.
 void MediaCodec::updateEphemeralMediametrics(mediametrics_handle_t item) {
     ALOGD("MediaCodec::updateEphemeralMediametrics()");
 
@@ -1058,7 +1073,13 @@
 }
 
 void MediaCodec::flushMediametrics() {
+    ALOGD("flushMediametrics");
+
+    // update does its own mutex locking
     updateMediametrics();
+
+    // ensure mutex while we do our own work
+    Mutex::Autolock _lock(mMetricsLock);
     if (mMetricsHandle != 0) {
         if (mediametrics_count(mMetricsHandle) > 0) {
             mediametrics_selfRecord(mMetricsHandle);
@@ -1572,6 +1593,8 @@
     }
     msg->setString("name", name);
 
+    // initial naming setup covers the period before the first call to ::configure().
+    // after that, we manage this through ::configure() and the setup message.
     if (mMetricsHandle != 0) {
         mediametrics_setCString(mMetricsHandle, kCodecCodec, name.c_str());
         mediametrics_setCString(mMetricsHandle, kCodecMode, toCodecMode(mDomain));
@@ -1644,23 +1667,28 @@
         const sp<IDescrambler> &descrambler,
         uint32_t flags) {
     sp<AMessage> msg = new AMessage(kWhatConfigure, this);
+    mediametrics_handle_t nextMetricsHandle = mediametrics_create(kCodecKeyName);
 
     // TODO: validity check log-session-id: it should be a 32-hex-digit.
     format->findString("log-session-id", &mLogSessionId);
 
-    if (mMetricsHandle != 0) {
+    if (nextMetricsHandle != 0) {
         int32_t profile = 0;
         if (format->findInt32("profile", &profile)) {
-            mediametrics_setInt32(mMetricsHandle, kCodecProfile, profile);
+            mediametrics_setInt32(nextMetricsHandle, kCodecProfile, profile);
         }
         int32_t level = 0;
         if (format->findInt32("level", &level)) {
-            mediametrics_setInt32(mMetricsHandle, kCodecLevel, level);
+            mediametrics_setInt32(nextMetricsHandle, kCodecLevel, level);
         }
-        mediametrics_setInt32(mMetricsHandle, kCodecEncoder,
+        mediametrics_setInt32(nextMetricsHandle, kCodecEncoder,
                               (flags & CONFIGURE_FLAG_ENCODE) ? 1 : 0);
 
-        mediametrics_setCString(mMetricsHandle, kCodecLogSessionId, mLogSessionId.c_str());
+        mediametrics_setCString(nextMetricsHandle, kCodecLogSessionId, mLogSessionId.c_str());
+
+        // moved here from ::init()
+        mediametrics_setCString(nextMetricsHandle, kCodecCodec, mInitName.c_str());
+        mediametrics_setCString(nextMetricsHandle, kCodecMode, toCodecMode(mDomain));
     }
 
     if (mDomain == DOMAIN_VIDEO || mDomain == DOMAIN_IMAGE) {
@@ -1670,38 +1698,38 @@
             mRotationDegrees = 0;
         }
 
-        if (mMetricsHandle != 0) {
-            mediametrics_setInt32(mMetricsHandle, kCodecWidth, mWidth);
-            mediametrics_setInt32(mMetricsHandle, kCodecHeight, mHeight);
-            mediametrics_setInt32(mMetricsHandle, kCodecRotation, mRotationDegrees);
+        if (nextMetricsHandle != 0) {
+            mediametrics_setInt32(nextMetricsHandle, kCodecWidth, mWidth);
+            mediametrics_setInt32(nextMetricsHandle, kCodecHeight, mHeight);
+            mediametrics_setInt32(nextMetricsHandle, kCodecRotation, mRotationDegrees);
             int32_t maxWidth = 0;
             if (format->findInt32("max-width", &maxWidth)) {
-                mediametrics_setInt32(mMetricsHandle, kCodecMaxWidth, maxWidth);
+                mediametrics_setInt32(nextMetricsHandle, kCodecMaxWidth, maxWidth);
             }
             int32_t maxHeight = 0;
             if (format->findInt32("max-height", &maxHeight)) {
-                mediametrics_setInt32(mMetricsHandle, kCodecMaxHeight, maxHeight);
+                mediametrics_setInt32(nextMetricsHandle, kCodecMaxHeight, maxHeight);
             }
             int32_t colorFormat = -1;
             if (format->findInt32("color-format", &colorFormat)) {
-                mediametrics_setInt32(mMetricsHandle, kCodecColorFormat, colorFormat);
+                mediametrics_setInt32(nextMetricsHandle, kCodecColorFormat, colorFormat);
             }
             if (mDomain == DOMAIN_VIDEO) {
                 float frameRate = -1.0;
                 if (format->findFloat("frame-rate", &frameRate)) {
-                    mediametrics_setDouble(mMetricsHandle, kCodecFrameRate, frameRate);
+                    mediametrics_setDouble(nextMetricsHandle, kCodecFrameRate, frameRate);
                 }
                 float captureRate = -1.0;
                 if (format->findFloat("capture-rate", &captureRate)) {
-                    mediametrics_setDouble(mMetricsHandle, kCodecCaptureRate, captureRate);
+                    mediametrics_setDouble(nextMetricsHandle, kCodecCaptureRate, captureRate);
                 }
                 float operatingRate = -1.0;
                 if (format->findFloat("operating-rate", &operatingRate)) {
-                    mediametrics_setDouble(mMetricsHandle, kCodecOperatingRate, operatingRate);
+                    mediametrics_setDouble(nextMetricsHandle, kCodecOperatingRate, operatingRate);
                 }
                 int32_t priority = -1;
                 if (format->findInt32("priority", &priority)) {
-                    mediametrics_setInt32(mMetricsHandle, kCodecPriority, priority);
+                    mediametrics_setInt32(nextMetricsHandle, kCodecPriority, priority);
                 }
             }
             int32_t colorStandard = -1;
@@ -1732,14 +1760,14 @@
         }
 
     } else {
-        if (mMetricsHandle != 0) {
+        if (nextMetricsHandle != 0) {
             int32_t channelCount;
             if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)) {
-                mediametrics_setInt32(mMetricsHandle, kCodecChannelCount, channelCount);
+                mediametrics_setInt32(nextMetricsHandle, kCodecChannelCount, channelCount);
             }
             int32_t sampleRate;
             if (format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
-                mediametrics_setInt32(mMetricsHandle, kCodecSampleRate, sampleRate);
+                mediametrics_setInt32(nextMetricsHandle, kCodecSampleRate, sampleRate);
             }
         }
     }
@@ -1749,41 +1777,41 @@
                                                  enableMediaFormatShapingDefault);
         if (!enableShaping) {
             ALOGI("format shaping disabled, property '%s'", enableMediaFormatShapingProperty);
-            if (mMetricsHandle != 0) {
-                mediametrics_setInt32(mMetricsHandle, kCodecShapingEnhanced, -1);
+            if (nextMetricsHandle != 0) {
+                mediametrics_setInt32(nextMetricsHandle, kCodecShapingEnhanced, -1);
             }
         } else {
-            (void) shapeMediaFormat(format, flags);
+            (void) shapeMediaFormat(format, flags, nextMetricsHandle);
             // XXX: do we want to do this regardless of shaping enablement?
             mapFormat(mComponentName, format, nullptr, false);
         }
     }
 
     // push min/max QP to MediaMetrics after shaping
-    if (mDomain == DOMAIN_VIDEO && mMetricsHandle != 0) {
+    if (mDomain == DOMAIN_VIDEO && nextMetricsHandle != 0) {
         int32_t qpIMin = -1;
         if (format->findInt32("video-qp-i-min", &qpIMin)) {
-            mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMin, qpIMin);
+            mediametrics_setInt32(nextMetricsHandle, kCodecRequestedVideoQPIMin, qpIMin);
         }
         int32_t qpIMax = -1;
         if (format->findInt32("video-qp-i-max", &qpIMax)) {
-            mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMax, qpIMax);
+            mediametrics_setInt32(nextMetricsHandle, kCodecRequestedVideoQPIMax, qpIMax);
         }
         int32_t qpPMin = -1;
         if (format->findInt32("video-qp-p-min", &qpPMin)) {
-            mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMin, qpPMin);
+            mediametrics_setInt32(nextMetricsHandle, kCodecRequestedVideoQPPMin, qpPMin);
         }
         int32_t qpPMax = -1;
         if (format->findInt32("video-qp-p-max", &qpPMax)) {
-            mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMax, qpPMax);
+            mediametrics_setInt32(nextMetricsHandle, kCodecRequestedVideoQPPMax, qpPMax);
         }
         int32_t qpBMin = -1;
         if (format->findInt32("video-qp-b-min", &qpBMin)) {
-            mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMin, qpBMin);
+            mediametrics_setInt32(nextMetricsHandle, kCodecRequestedVideoQPBMin, qpBMin);
         }
         int32_t qpBMax = -1;
         if (format->findInt32("video-qp-b-max", &qpBMax)) {
-            mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMax, qpBMax);
+            mediametrics_setInt32(nextMetricsHandle, kCodecRequestedVideoQPBMax, qpBMax);
         }
     }
 
@@ -1799,13 +1827,23 @@
         } else {
             msg->setPointer("descrambler", descrambler.get());
         }
-        if (mMetricsHandle != 0) {
-            mediametrics_setInt32(mMetricsHandle, kCodecCrypto, 1);
+        if (nextMetricsHandle != 0) {
+            mediametrics_setInt32(nextMetricsHandle, kCodecCrypto, 1);
         }
     } else if (mFlags & kFlagIsSecure) {
         ALOGW("Crypto or descrambler should be given for secure codec");
     }
 
+    if (mConfigureMsg != nullptr) {
+        // if re-configuring, we have one of these from before.
+        // Recover the space before we discard the old mConfigureMsg
+        mediametrics_handle_t metricsHandle;
+        if (mConfigureMsg->findInt64("metrics", &metricsHandle)) {
+            mediametrics_delete(metricsHandle);
+        }
+    }
+    msg->setInt64("metrics", nextMetricsHandle);
+
     // save msg for reset
     mConfigureMsg = msg;
 
@@ -2132,7 +2170,8 @@
 
 status_t MediaCodec::shapeMediaFormat(
             const sp<AMessage> &format,
-            uint32_t flags) {
+            uint32_t flags,
+            mediametrics_handle_t metricsHandle) {
     ALOGV("shapeMediaFormat entry");
 
     if (!(flags & CONFIGURE_FLAG_ENCODE)) {
@@ -2188,39 +2227,39 @@
         sp<AMessage> deltas = updatedFormat->changesFrom(format, false /* deep */);
         size_t changeCount = deltas->countEntries();
         ALOGD("shapeMediaFormat: deltas(%zu): %s", changeCount, deltas->debugString(2).c_str());
-        if (mMetricsHandle != 0) {
-            mediametrics_setInt32(mMetricsHandle, kCodecShapingEnhanced, changeCount);
+        if (metricsHandle != 0) {
+            mediametrics_setInt32(metricsHandle, kCodecShapingEnhanced, changeCount);
         }
         if (changeCount > 0) {
-            if (mMetricsHandle != 0) {
+            if (metricsHandle != 0) {
                 // save some old properties before we fold in the new ones
                 int32_t bitrate;
                 if (format->findInt32(KEY_BIT_RATE, &bitrate)) {
-                    mediametrics_setInt32(mMetricsHandle, kCodecOriginalBitrate, bitrate);
+                    mediametrics_setInt32(metricsHandle, kCodecOriginalBitrate, bitrate);
                 }
                 int32_t qpIMin = -1;
                 if (format->findInt32("original-video-qp-i-min", &qpIMin)) {
-                    mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPIMin, qpIMin);
+                    mediametrics_setInt32(metricsHandle, kCodecOriginalVideoQPIMin, qpIMin);
                 }
                 int32_t qpIMax = -1;
                 if (format->findInt32("original-video-qp-i-max", &qpIMax)) {
-                    mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPIMax, qpIMax);
+                    mediametrics_setInt32(metricsHandle, kCodecOriginalVideoQPIMax, qpIMax);
                 }
                 int32_t qpPMin = -1;
                 if (format->findInt32("original-video-qp-p-min", &qpPMin)) {
-                    mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPPMin, qpPMin);
+                    mediametrics_setInt32(metricsHandle, kCodecOriginalVideoQPPMin, qpPMin);
                 }
                 int32_t qpPMax = -1;
                 if (format->findInt32("original-video-qp-p-max", &qpPMax)) {
-                    mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPPMax, qpPMax);
+                    mediametrics_setInt32(metricsHandle, kCodecOriginalVideoQPPMax, qpPMax);
                 }
                  int32_t qpBMin = -1;
                 if (format->findInt32("original-video-qp-b-min", &qpBMin)) {
-                    mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPBMin, qpBMin);
+                    mediametrics_setInt32(metricsHandle, kCodecOriginalVideoQPBMin, qpBMin);
                 }
                 int32_t qpBMax = -1;
                 if (format->findInt32("original-video-qp-b-max", &qpBMax)) {
-                    mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPBMax, qpBMax);
+                    mediametrics_setInt32(metricsHandle, kCodecOriginalVideoQPBMax, qpBMax);
                 }
             }
             // NB: for any field in both format and deltas, the deltas copy wins
@@ -2806,26 +2845,44 @@
     return OK;
 }
 
+// this is the user-callable entry point
 status_t MediaCodec::getMetrics(mediametrics_handle_t &reply) {
 
     reply = 0;
 
-    // shouldn't happen, but be safe
-    if (mMetricsHandle == 0) {
-        return UNKNOWN_ERROR;
+    sp<AMessage> msg = new AMessage(kWhatGetMetrics, this);
+    sp<AMessage> response;
+    status_t err;
+    if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
+        return err;
     }
 
-    // update any in-flight data that's not carried within the record
-    updateMediametrics();
-
-    // send it back to the caller.
-    reply = mediametrics_dup(mMetricsHandle);
-
-    updateEphemeralMediametrics(reply);
+    CHECK(response->findInt64("metrics", &reply));
 
     return OK;
 }
 
+// runs on the looper thread (for mutex purposes)
+void MediaCodec::onGetMetrics(const sp<AMessage>& msg) {
+
+    mediametrics_handle_t results = 0;
+
+    sp<AReplyToken> replyID;
+    CHECK(msg->senderAwaitsResponse(&replyID));
+
+    if (mMetricsHandle != 0) {
+        updateMediametrics();
+        results = mediametrics_dup(mMetricsHandle);
+        updateEphemeralMediametrics(results);
+    } else {
+        results = mediametrics_dup(mMetricsHandle);
+    }
+
+    sp<AMessage> response = new AMessage;
+    response->setInt64("metrics", results);
+    response->postReply(replyID);
+}
+
 status_t MediaCodec::getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
     sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
     msg->setInt32("portIndex", kPortIndexInput);
@@ -3887,6 +3944,13 @@
             break;
         }
 
+        case kWhatGetMetrics:
+        {
+            onGetMetrics(msg);
+            break;
+        }
+
+
         case kWhatConfigure:
         {
             if (mState != INITIALIZED) {
@@ -3907,6 +3971,18 @@
             sp<AMessage> format;
             CHECK(msg->findMessage("format", &format));
 
+            // start with a copy of the passed metrics info for use in this run
+            mediametrics_handle_t handle;
+            CHECK(msg->findInt64("metrics", &handle));
+            if (handle != 0) {
+                if (mMetricsHandle != 0) {
+                    flushMediametrics();
+                }
+                mMetricsHandle = mediametrics_dup(handle);
+                // and set some additional metrics values
+                initMediametrics();
+            }
+
             int32_t push;
             if (msg->findInt32("push-blank-buffers-on-shutdown", &push) && push != 0) {
                 mFlags |= kFlagPushBlankBuffersOnShutdown;
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
index 1f569ef..f26311d 100644
--- a/media/libstagefright/SurfaceUtils.cpp
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -193,10 +193,38 @@
 
 status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */) {
     status_t err = NO_ERROR;
-    ANativeWindowBuffer* anb = NULL;
+    ANativeWindowBuffer* anb = nullptr;
     int numBufs = 0;
     int minUndequeuedBufs = 0;
 
+    auto handleError = [](ANativeWindow *nativeWindow, ANativeWindowBuffer* anb, status_t err)
+    {
+        if (anb != nullptr) {
+            nativeWindow->cancelBuffer(nativeWindow, anb, -1);
+            anb = nullptr;
+        }
+
+        // Clean up after success or error.
+        status_t err2 = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_CPU);
+        if (err2 != NO_ERROR) {
+            ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
+                    strerror(-err2), -err2);
+            if (err == NO_ERROR) {
+                err = err2;
+            }
+        }
+
+        err2 = nativeWindowConnect(nativeWindow, "pushBlankBuffersToNativeWindow(err2)");
+        if (err2 != NO_ERROR) {
+            ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err);
+            if (err == NO_ERROR) {
+                err = err2;
+            }
+        }
+
+        return err;
+    };
+
     // We need to reconnect to the ANativeWindow as a CPU client to ensure that
     // no frames get dropped by SurfaceFlinger assuming that these are video
     // frames.
@@ -217,7 +245,7 @@
             nativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
             false /* reconnect */);
     if (err != NO_ERROR) {
-        goto error;
+        return handleError(nativeWindow, anb, err);
     }
 
     static_cast<Surface*>(nativeWindow)->getIGraphicBufferProducer()->allowAllocation(true);
@@ -227,14 +255,14 @@
     if (err != NO_ERROR) {
         ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query "
                 "failed: %s (%d)", strerror(-err), -err);
-        goto error;
+        return handleError(nativeWindow, anb, err);
     }
 
     numBufs = minUndequeuedBufs + 1;
     err = native_window_set_buffer_count(nativeWindow, numBufs);
     if (err != NO_ERROR) {
         ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)", strerror(-err), -err);
-        goto error;
+        return handleError(nativeWindow, anb, err);
     }
 
     // We push numBufs + 1 buffers to ensure that we've drawn into the same
@@ -252,7 +280,7 @@
         sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
         // Fill the buffer with the a 1x1 checkerboard pattern ;)
-        uint32_t *img = NULL;
+        uint32_t *img = nullptr;
         err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
         if (err != NO_ERROR) {
             ALOGE("error pushing blank frames: lock failed: %s (%d)", strerror(-err), -err);
@@ -273,34 +301,10 @@
             break;
         }
 
-        anb = NULL;
+        anb = nullptr;
     }
 
-error:
-
-    if (anb != NULL) {
-        nativeWindow->cancelBuffer(nativeWindow, anb, -1);
-        anb = NULL;
-    }
-
-    // Clean up after success or error.
-    status_t err2 = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_CPU);
-    if (err2 != NO_ERROR) {
-        ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err2), -err2);
-        if (err == NO_ERROR) {
-            err = err2;
-        }
-    }
-
-    err2 = nativeWindowConnect(nativeWindow, "pushBlankBuffersToNativeWindow(err2)");
-    if (err2 != NO_ERROR) {
-        ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err);
-        if (err == NO_ERROR) {
-            err = err2;
-        }
-    }
-
-    return err;
+    return handleError(nativeWindow, anb, err);
 }
 
 status_t nativeWindowConnect(ANativeWindow *surface, const char *reason) {
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 6f6a4e6..703f7ad 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -357,6 +357,7 @@
         kWhatSetNotification                = 'setN',
         kWhatDrmReleaseCrypto               = 'rDrm',
         kWhatCheckBatteryStats              = 'chkB',
+        kWhatGetMetrics                     = 'getM',
     };
 
     enum {
@@ -427,6 +428,7 @@
     sp<Surface> mSurface;
     SoftwareRenderer *mSoftRenderer;
 
+    Mutex mMetricsLock;
     mediametrics_handle_t mMetricsHandle = 0;
     nsecs_t mLifetimeStartNs = 0;
     void initMediametrics();
@@ -434,6 +436,7 @@
     void flushMediametrics();
     void updateEphemeralMediametrics(mediametrics_handle_t item);
     void updateLowLatency(const sp<AMessage> &msg);
+    void onGetMetrics(const sp<AMessage>& msg);
     constexpr const char *asString(TunnelPeekState state, const char *default_string="?");
     void updateTunnelPeek(const sp<AMessage> &msg);
     void updatePlaybackDuration(const sp<AMessage> &msg);
@@ -472,7 +475,8 @@
     // the (possibly) updated format is returned in place.
     status_t shapeMediaFormat(
             const sp<AMessage> &format,
-            uint32_t flags);
+            uint32_t flags,
+            mediametrics_handle_t handle);
 
     // populate the format shaper library with information for this codec encoding
     // for the indicated media type
diff --git a/media/libstagefright/rtsp/AAVCAssembler.cpp b/media/libstagefright/rtsp/AAVCAssembler.cpp
index ddf797c..88f7be7 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AAVCAssembler.cpp
@@ -332,6 +332,11 @@
 }
 
 bool AAVCAssembler::dropFramesUntilIframe(const sp<ABuffer> &buffer) {
+    if (buffer->size() == 0) {
+        ALOGE("b/230630526 buffer->size() == 0");
+        android_errorWriteLog(0x534e4554, "230630526");
+        return false;
+    }
     const uint8_t *data = buffer->data();
     unsigned nalType = data[0] & 0x1f;
     if (!mFirstIFrameProvided && nalType < 0x5) {
@@ -624,8 +629,7 @@
     int32_t firstSeqNo = buffer->int32Data();
 
     // This only works for FU-A type & non-start sequence
-    int32_t nalType = buffer->size() >= 1 ? buffer->data()[0] & 0x1f : -1;
-    if (nalType != 28 || (buffer->size() >= 2 && buffer->data()[1] & 0x80)) {
+    if (buffer->size() < 2 || (buffer->data()[0] & 0x1f) != 28 || buffer->data()[1] & 0x80) {
         return firstSeqNo;
     }
 
diff --git a/media/libstagefright/rtsp/AHEVCAssembler.cpp b/media/libstagefright/rtsp/AHEVCAssembler.cpp
index bb42d1f..72dd981 100644
--- a/media/libstagefright/rtsp/AHEVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AHEVCAssembler.cpp
@@ -629,13 +629,13 @@
 
 int32_t AHEVCAssembler::pickStartSeq(const Queue *queue,
         uint32_t first, int64_t play, int64_t jit) {
+    CHECK(!queue->empty());
     // pick the first sequence number has the start bit.
     sp<ABuffer> buffer = *(queue->begin());
     int32_t firstSeqNo = buffer->int32Data();
 
     // This only works for FU-A type & non-start sequence
-    unsigned nalType = buffer->data()[0] & 0x1f;
-    if (nalType != 28 || buffer->data()[2] & 0x80) {
+    if (buffer->size() < 3 || (buffer->data()[0] & 0x1f) != 28 || buffer->data()[2] & 0x80) {
         return firstSeqNo;
     }
 
@@ -645,7 +645,7 @@
         if (rtpTime + jit >= play) {
             break;
         }
-        if ((data[2] & 0x80)) {
+        if (it->size() >= 3 && (data[2] & 0x80)) {
             const int32_t seqNo = it->int32Data();
             ALOGE("finding [HEAD] pkt. \t Seq# (%d ~ )[%d", firstSeqNo, seqNo);
             firstSeqNo = seqNo;
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index a38ef57..fddbece 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -69,6 +69,7 @@
         "-Wall",
         "-Wextra",
         "-Werror",
+        "-Wthread-safety",
     ],
 
     header_libs: [
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 07f4529..83b84e3 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -103,11 +103,10 @@
     AttributionSourceState myAttributionSource;
     myAttributionSource.uid = VALUE_OR_FATAL(android::legacy2aidl_uid_t_int32_t(getuid()));
     myAttributionSource.pid = VALUE_OR_FATAL(android::legacy2aidl_pid_t_int32_t(getpid()));
-    if (callerAttributionSource.token != nullptr) {
-        myAttributionSource.token = callerAttributionSource.token;
-    } else {
-        myAttributionSource.token = sp<BBinder>::make();
-    }
+    // Create a static token for audioserver requests, which identifies the
+    // audioserver to the app ops system
+    static sp<BBinder> appOpsToken = sp<BBinder>::make();
+    myAttributionSource.token = appOpsToken;
     myAttributionSource.next.push_back(nextAttributionSource);
 
     return std::optional<AttributionSourceState>{myAttributionSource};
diff --git a/media/utils/TimerThread.cpp b/media/utils/TimerThread.cpp
index 5e58a3d..d4da28f 100644
--- a/media/utils/TimerThread.cpp
+++ b/media/utils/TimerThread.cpp
@@ -292,6 +292,7 @@
 
 void TimerThread::MonitorThread::threadFunc() {
     std::unique_lock _l(mMutex);
+    ::android::base::ScopedLockAssertion lock_assertion(mMutex);
     while (!mShouldExit) {
         Handle nextDeadline = INVALID_HANDLE;
         Handle now = INVALID_HANDLE;
@@ -385,6 +386,7 @@
 std::shared_ptr<const TimerThread::Request> TimerThread::MonitorThread::remove(Handle handle) {
     std::pair<std::shared_ptr<const Request>, TimerCallback> data;
     std::unique_lock ul(mMutex);
+    ::android::base::ScopedLockAssertion lock_assertion(mMutex);
     if (const auto it = mMonitorRequests.find(handle);
         it != mMonitorRequests.end()) {
         data = std::move(it->second);
diff --git a/media/utils/include/mediautils/TimerThread.h b/media/utils/include/mediautils/TimerThread.h
index c76fa7d..1e0d8c2 100644
--- a/media/utils/include/mediautils/TimerThread.h
+++ b/media/utils/include/mediautils/TimerThread.h
@@ -297,7 +297,7 @@
                 std::pair<std::shared_ptr<const Request>, TimerCallback>>
                         mSecondChanceRequests GUARDED_BY(mMutex);
 
-        RequestQueue& mTimeoutQueue; // locked internally, added to when request times out.
+        RequestQueue& mTimeoutQueue GUARDED_BY(mMutex); // added to when request times out.
 
         // Worker thread variables
         bool mShouldExit GUARDED_BY(mMutex) = false;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e4c4107..f1f8a8f 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -288,7 +288,6 @@
                 return opPackageLegacy == package; }) == packages.end()) {
             ALOGW("The package name(%s) provided does not correspond to the uid %d",
                     attributionSource.packageName.value_or("").c_str(), attributionSource.uid);
-            checkedAttributionSource.packageName = std::optional<std::string>();
         }
     }
     return checkedAttributionSource;
@@ -588,6 +587,33 @@
     audio_io_handle_t io = AUDIO_IO_HANDLE_NONE;
     audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
     audio_attributes_t localAttr = *attr;
+
+    // TODO b/182392553: refactor or make clearer
+    pid_t clientPid =
+        VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(client.attributionSource.pid));
+    bool updatePid = (clientPid == (pid_t)-1);
+    const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+
+    AttributionSourceState adjAttributionSource = client.attributionSource;
+    if (!isAudioServerOrMediaServerOrSystemServerOrRootUid(callingUid)) {
+        uid_t clientUid =
+            VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(client.attributionSource.uid));
+        ALOGW_IF(clientUid != callingUid,
+                "%s uid %d tried to pass itself off as %d",
+                __FUNCTION__, callingUid, clientUid);
+        adjAttributionSource.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
+        updatePid = true;
+    }
+    if (updatePid) {
+        const pid_t callingPid = IPCThreadState::self()->getCallingPid();
+        ALOGW_IF(clientPid != (pid_t)-1 && clientPid != callingPid,
+                 "%s uid %d pid %d tried to pass itself off as pid %d",
+                 __func__, callingUid, callingPid, clientPid);
+        adjAttributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
+    }
+    adjAttributionSource = AudioFlinger::checkAttributionSourcePackage(
+            adjAttributionSource);
+
     if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
         audio_config_t fullConfig = AUDIO_CONFIG_INITIALIZER;
         fullConfig.sample_rate = config->sample_rate;
@@ -597,7 +623,7 @@
         bool isSpatialized;
         ret = AudioSystem::getOutputForAttr(&localAttr, &io,
                                             actualSessionId,
-                                            &streamType, client.attributionSource,
+                                            &streamType, adjAttributionSource,
                                             &fullConfig,
                                             (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ |
                                                     AUDIO_OUTPUT_FLAG_DIRECT),
@@ -608,7 +634,7 @@
         ret = AudioSystem::getInputForAttr(&localAttr, &io,
                                               RECORD_RIID_INVALID,
                                               actualSessionId,
-                                              client.attributionSource,
+                                              adjAttributionSource,
                                               config,
                                               AUDIO_INPUT_FLAG_MMAP_NOIRQ, deviceId, &portId);
     }
@@ -1057,7 +1083,7 @@
     audio_attributes_t localAttr = input.attr;
 
     AttributionSourceState adjAttributionSource = input.clientInfo.attributionSource;
-    if (!isAudioServerOrMediaServerUid(callingUid)) {
+    if (!isAudioServerOrMediaServerOrSystemServerOrRootUid(callingUid)) {
         ALOGW_IF(clientUid != callingUid,
                 "%s uid %d tried to pass itself off as %d",
                 __FUNCTION__, callingUid, clientUid);
@@ -1073,6 +1099,8 @@
         clientPid = callingPid;
         adjAttributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
     }
+    adjAttributionSource = AudioFlinger::checkAttributionSourcePackage(
+            adjAttributionSource);
 
     audio_session_t sessionId = input.sessionId;
     if (sessionId == AUDIO_SESSION_ALLOCATE) {
@@ -2317,7 +2345,7 @@
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
     const uid_t currentUid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(
            adjAttributionSource.uid));
-    if (!isAudioServerOrMediaServerUid(callingUid)) {
+    if (!isAudioServerOrMediaServerOrSystemServerOrRootUid(callingUid)) {
         ALOGW_IF(currentUid != callingUid,
                 "%s uid %d tried to pass itself off as %d",
                 __FUNCTION__, callingUid, currentUid);
@@ -2333,7 +2361,8 @@
                  __func__, callingUid, callingPid, currentPid);
         adjAttributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
     }
-
+    adjAttributionSource = AudioFlinger::checkAttributionSourcePackage(
+            adjAttributionSource);
     // we don't yet support anything other than linear PCM
     if (!audio_is_valid_format(input.config.format) || !audio_is_linear_pcm(input.config.format)) {
         ALOGE("createRecord() invalid format %#x", input.config.format);
@@ -3967,7 +3996,7 @@
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
     adjAttributionSource.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
     pid_t currentPid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(adjAttributionSource.pid));
-    if (currentPid == -1 || !isAudioServerOrMediaServerUid(callingUid)) {
+    if (currentPid == -1 || !isAudioServerOrMediaServerOrSystemServerOrRootUid(callingUid)) {
         const pid_t callingPid = IPCThreadState::self()->getCallingPid();
         ALOGW_IF(currentPid != -1 && currentPid != callingPid,
                  "%s uid %d pid %d tried to pass itself off as pid %d",
@@ -3975,6 +4004,7 @@
         adjAttributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
         currentPid = callingPid;
     }
+    adjAttributionSource = AudioFlinger::checkAttributionSourcePackage(adjAttributionSource);
 
     ALOGV("createEffect pid %d, effectClient %p, priority %d, sessionId %d, io %d, factory %p",
           adjAttributionSource.pid, effectClient.get(), priority, sessionId, io,
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 9837574..355f411 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -8369,8 +8369,6 @@
     audio_input_flags_t inputFlags = mInput->flags;
     audio_input_flags_t requestedFlags = *flags;
     uint32_t sampleRate;
-    AttributionSourceState checkedAttributionSource = AudioFlinger::checkAttributionSourcePackage(
-            attributionSource);
 
     lStatus = initCheck();
     if (lStatus != NO_ERROR) {
@@ -8385,7 +8383,7 @@
     }
 
     if (maxSharedAudioHistoryMs != 0) {
-        if (!captureHotwordAllowed(checkedAttributionSource)) {
+        if (!captureHotwordAllowed(attributionSource)) {
             lStatus = PERMISSION_DENIED;
             goto Exit;
         }
@@ -8506,16 +8504,16 @@
         Mutex::Autolock _l(mLock);
         int32_t startFrames = -1;
         if (!mSharedAudioPackageName.empty()
-                && mSharedAudioPackageName == checkedAttributionSource.packageName
+                && mSharedAudioPackageName == attributionSource.packageName
                 && mSharedAudioSessionId == sessionId
-                && captureHotwordAllowed(checkedAttributionSource)) {
+                && captureHotwordAllowed(attributionSource)) {
             startFrames = mSharedAudioStartFrames;
         }
 
         track = new RecordTrack(this, client, attr, sampleRate,
                       format, channelMask, frameCount,
                       nullptr /* buffer */, (size_t)0 /* bufferSize */, sessionId, creatorPid,
-                      checkedAttributionSource, *flags, TrackBase::TYPE_DEFAULT, portId,
+                      attributionSource, *flags, TrackBase::TYPE_DEFAULT, portId,
                       startFrames);
 
         lStatus = track->initCheck();
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 02c4aaf..58f99e8 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -531,10 +531,7 @@
             id, attr.flags);
         return nullptr;
     }
-
-    AttributionSourceState checkedAttributionSource = AudioFlinger::checkAttributionSourcePackage(
-            attributionSource);
-    return new OpPlayAudioMonitor(checkedAttributionSource, attr.usage, id);
+    return new OpPlayAudioMonitor(attributionSource, attr.usage, id);
 }
 
 AudioFlinger::PlaybackThread::OpPlayAudioMonitor::OpPlayAudioMonitor(
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 4212c1c..fdf5787 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -352,31 +352,20 @@
     ALOGV("%s()", __func__);
     Mutex::Autolock _l(mLock);
 
-    // TODO b/182392553: refactor or remove
-    AttributionSourceState adjAttributionSource = attributionSource;
-    const uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    if (!isAudioServerOrMediaServerUid(callingUid) || attributionSource.uid == -1) {
-        int32_t callingUidAidl = VALUE_OR_RETURN_BINDER_STATUS(
-            legacy2aidl_uid_t_int32_t(callingUid));
-        ALOGW_IF(attributionSource.uid != -1 && attributionSource.uid != callingUidAidl,
-                "%s uid %d tried to pass itself off as %d", __func__,
-                callingUidAidl, attributionSource.uid);
-        adjAttributionSource.uid = callingUidAidl;
-    }
     if (!mPackageManager.allowPlaybackCapture(VALUE_OR_RETURN_BINDER_STATUS(
-        aidl2legacy_int32_t_uid_t(adjAttributionSource.uid)))) {
+        aidl2legacy_int32_t_uid_t(attributionSource.uid)))) {
         attr.flags = static_cast<audio_flags_mask_t>(attr.flags | AUDIO_FLAG_NO_MEDIA_PROJECTION);
     }
     if (((attr.flags & (AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE)) != 0)
-            && !bypassInterruptionPolicyAllowed(adjAttributionSource)) {
+            && !bypassInterruptionPolicyAllowed(attributionSource)) {
         attr.flags = static_cast<audio_flags_mask_t>(
                 attr.flags & ~(AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE));
     }
 
     if (attr.content_type == AUDIO_CONTENT_TYPE_ULTRASOUND) {
-        if (!accessUltrasoundAllowed(adjAttributionSource)) {
+        if (!accessUltrasoundAllowed(attributionSource)) {
             ALOGE("%s: permission denied: ultrasound not allowed for uid %d pid %d",
-                    __func__, adjAttributionSource.uid, adjAttributionSource.pid);
+                    __func__, attributionSource.uid, attributionSource.pid);
             return binderStatusFromStatusT(PERMISSION_DENIED);
         }
     }
@@ -386,7 +375,7 @@
     bool isSpatialized = false;
     status_t result = mAudioPolicyManager->getOutputForAttr(&attr, &output, session,
                                                             &stream,
-                                                            adjAttributionSource,
+                                                            attributionSource,
                                                             &config,
                                                             &flags, &selectedDeviceId, &portId,
                                                             &secondaryOutputs,
@@ -401,20 +390,20 @@
             break;
         case AudioPolicyInterface::API_OUTPUT_TELEPHONY_TX:
             if (((attr.flags & AUDIO_FLAG_CALL_REDIRECTION) != 0)
-                && !callAudioInterceptionAllowed(adjAttributionSource)) {
+                && !callAudioInterceptionAllowed(attributionSource)) {
                 ALOGE("%s() permission denied: call redirection not allowed for uid %d",
-                    __func__, adjAttributionSource.uid);
+                    __func__, attributionSource.uid);
                 result = PERMISSION_DENIED;
-            } else if (!modifyPhoneStateAllowed(adjAttributionSource)) {
+            } else if (!modifyPhoneStateAllowed(attributionSource)) {
                 ALOGE("%s() permission denied: modify phone state not allowed for uid %d",
-                    __func__, adjAttributionSource.uid);
+                    __func__, attributionSource.uid);
                 result = PERMISSION_DENIED;
             }
             break;
         case AudioPolicyInterface::API_OUT_MIX_PLAYBACK:
-            if (!modifyAudioRoutingAllowed(adjAttributionSource)) {
+            if (!modifyAudioRoutingAllowed(attributionSource)) {
                 ALOGE("%s() permission denied: modify audio routing not allowed for uid %d",
-                    __func__, adjAttributionSource.uid);
+                    __func__, attributionSource.uid);
                 result = PERMISSION_DENIED;
             }
             break;
@@ -427,7 +416,7 @@
 
     if (result == NO_ERROR) {
         sp<AudioPlaybackClient> client =
-                new AudioPlaybackClient(attr, output, adjAttributionSource, session,
+                new AudioPlaybackClient(attr, output, attributionSource, session,
                     portId, selectedDeviceId, stream, isSpatialized);
         mAudioPlaybackClients.add(portId, client);
 
@@ -613,33 +602,8 @@
         return binderStatusFromStatusT(BAD_VALUE);
     }
 
-    // Make sure attribution source represents the current caller
-    AttributionSourceState adjAttributionSource = attributionSource;
-    // TODO b/182392553: refactor or remove
-    bool updatePid = (attributionSource.pid == -1);
-    const uid_t callingUid =IPCThreadState::self()->getCallingUid();
-    const uid_t currentUid = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_int32_t_uid_t(
-            attributionSource.uid));
-    if (!isAudioServerOrMediaServerUid(callingUid)) {
-        ALOGW_IF(currentUid != (uid_t)-1 && currentUid != callingUid,
-                "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid,
-                currentUid);
-        adjAttributionSource.uid = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_uid_t_int32_t(
-                callingUid));
-        updatePid = true;
-    }
-
-    if (updatePid) {
-        const int32_t callingPid = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_pid_t_int32_t(
-            IPCThreadState::self()->getCallingPid()));
-        ALOGW_IF(attributionSource.pid != -1 && attributionSource.pid != callingPid,
-                 "%s uid %d pid %d tried to pass itself off as pid %d",
-                 __func__, adjAttributionSource.uid, callingPid, attributionSource.pid);
-        adjAttributionSource.pid = callingPid;
-    }
-
     RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(validateUsage(attr,
-            adjAttributionSource)));
+            attributionSource)));
 
     // check calling permissions.
     // Capturing from the following sources does not require permission RECORD_AUDIO
@@ -650,17 +614,17 @@
     // type is API_INPUT_MIX_EXT_POLICY_REROUTE and by AudioService if a media projection
     // is used and input type is API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK
     // - ECHO_REFERENCE source is controlled by captureAudioOutputAllowed()
-    if (!(recordingAllowed(adjAttributionSource, inputSource)
+    if (!(recordingAllowed(attributionSource, inputSource)
             || inputSource == AUDIO_SOURCE_FM_TUNER
             || inputSource == AUDIO_SOURCE_REMOTE_SUBMIX
             || inputSource == AUDIO_SOURCE_ECHO_REFERENCE)) {
         ALOGE("%s permission denied: recording not allowed for %s",
-                __func__, adjAttributionSource.toString().c_str());
+                __func__, attributionSource.toString().c_str());
         return binderStatusFromStatusT(PERMISSION_DENIED);
     }
 
-    bool canCaptureOutput = captureAudioOutputAllowed(adjAttributionSource);
-    bool canInterceptCallAudio = callAudioInterceptionAllowed(adjAttributionSource);
+    bool canCaptureOutput = captureAudioOutputAllowed(attributionSource);
+    bool canInterceptCallAudio = callAudioInterceptionAllowed(attributionSource);
     bool isCallAudioSource = inputSource == AUDIO_SOURCE_VOICE_UPLINK
              || inputSource == AUDIO_SOURCE_VOICE_DOWNLINK
              || inputSource == AUDIO_SOURCE_VOICE_CALL;
@@ -674,11 +638,11 @@
     }
     if (inputSource == AUDIO_SOURCE_FM_TUNER
         && !canCaptureOutput
-        && !captureTunerAudioInputAllowed(adjAttributionSource)) {
+        && !captureTunerAudioInputAllowed(attributionSource)) {
         return binderStatusFromStatusT(PERMISSION_DENIED);
     }
 
-    bool canCaptureHotword = captureHotwordAllowed(adjAttributionSource);
+    bool canCaptureHotword = captureHotwordAllowed(attributionSource);
     if ((inputSource == AUDIO_SOURCE_HOTWORD) && !canCaptureHotword) {
         return binderStatusFromStatusT(PERMISSION_DENIED);
     }
@@ -686,14 +650,14 @@
     if (((flags & AUDIO_INPUT_FLAG_HW_HOTWORD) != 0)
             && !canCaptureHotword) {
         ALOGE("%s: permission denied: hotword mode not allowed"
-              " for uid %d pid %d", __func__, adjAttributionSource.uid, adjAttributionSource.pid);
+              " for uid %d pid %d", __func__, attributionSource.uid, attributionSource.pid);
         return binderStatusFromStatusT(PERMISSION_DENIED);
     }
 
     if (attr.source == AUDIO_SOURCE_ULTRASOUND) {
-        if (!accessUltrasoundAllowed(adjAttributionSource)) {
+        if (!accessUltrasoundAllowed(attributionSource)) {
             ALOGE("%s: permission denied: ultrasound not allowed for uid %d pid %d",
-                    __func__, adjAttributionSource.uid, adjAttributionSource.pid);
+                    __func__, attributionSource.uid, attributionSource.pid);
             return binderStatusFromStatusT(PERMISSION_DENIED);
         }
     }
@@ -708,7 +672,7 @@
             AutoCallerClear acc;
             // the audio_in_acoustics_t parameter is ignored by get_input()
             status = mAudioPolicyManager->getInputForAttr(&attr, &input, riid, session,
-                                                          adjAttributionSource, &config,
+                                                          attributionSource, &config,
                                                           flags, &selectedDeviceId,
                                                           &inputType, &portId);
 
@@ -737,7 +701,7 @@
                 }
                 break;
             case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE:
-                if (!(modifyAudioRoutingAllowed(adjAttributionSource)
+                if (!(modifyAudioRoutingAllowed(attributionSource)
                         || ((attr.flags & AUDIO_FLAG_CALL_REDIRECTION) != 0
                             && canInterceptCallAudio))) {
                     ALOGE("%s permission denied for remote submix capture", __func__);
@@ -760,7 +724,7 @@
         }
 
         sp<AudioRecordClient> client = new AudioRecordClient(attr, input, session, portId,
-                                                             selectedDeviceId, adjAttributionSource,
+                                                             selectedDeviceId, attributionSource,
                                                              canCaptureOutput, canCaptureHotword,
                                                              mOutputCommandThread);
         mAudioRecordClients.add(portId, client);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 7dff809..78f3e25 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -1018,7 +1018,7 @@
 
         wp<NotificationListener> mListener;
 
-        const String8&     mId;       // The camera ID
+        const String8      mId;       // The camera ID
         int                mStatusId; // The RequestThread's component ID for
                                       // status tracking
 
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
index 2e98fe0..d56ff53 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
@@ -81,9 +81,6 @@
             const hardware::hidl_vec<
                     hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
 
-    // Handle one notify message
-    void notify(const hardware::camera::device::V3_2::NotifyMsg& msg);
-
     status_t switchToOffline(const std::vector<int32_t>& streamsToKeep,
             /*out*/ sp<CameraOfflineSessionBase>* session) override;