Merge "Camera: do not register empty buffer as inflight"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 793cbf4..e584ffb 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -81,6 +81,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libstagefright_xmlparser@1.0.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libstagefright_soft_*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk/libstagefright_soft_*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libaudiopolicyengineconfig*)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 0e969c7..3e8992a 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -108,7 +108,7 @@
      *
      * Also returns the set of currently-known camera IDs and state of each device.
      * Adding a listener will trigger the torch status listener to fire for all
-     * devices that have a flash unit
+     * devices that have a flash unit.
      */
     CameraStatus[] addListener(ICameraServiceListener listener);
 
diff --git a/camera/aidl/android/hardware/ICameraServiceListener.aidl b/camera/aidl/android/hardware/ICameraServiceListener.aidl
index f871ce4..e9dcbdb 100644
--- a/camera/aidl/android/hardware/ICameraServiceListener.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceListener.aidl
@@ -76,4 +76,11 @@
     const int TORCH_STATUS_UNKNOWN = -1;
 
     oneway void onTorchStatusChanged(int status, String cameraId);
+
+    /**
+     * Notify registered clients about camera access priority changes.
+     * Clients which were previously unable to open a certain camera device
+     * can retry after receiving this callback.
+     */
+    oneway void onCameraAccessPrioritiesChanged();
 }
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index 55bfa7e..c3407f0 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -86,6 +86,11 @@
             return binder::Status::ok();
         }
 
+        // Access priority API not implemented yet
+        virtual binder::Status onCameraAccessPrioritiesChanged() {
+            return binder::Status::ok();
+        }
+
       private:
         const wp<CameraManagerGlobal> mCameraManager;
     };
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index de40990..359eaed 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -38,6 +38,8 @@
         filterDurations(ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
         filterDurations(ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS);
         filterDurations(ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS);
+        filterDurations(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS);
+        filterDurations(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS);
     }
     // TODO: filter request/result keys
 }
@@ -186,6 +188,16 @@
                     filteredDurations.push_back(duration);
                 }
                 break;
+            case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS:
+            case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS:
+                if (format == HAL_PIXEL_FORMAT_BLOB) {
+                    format = AIMAGE_FORMAT_DEPTH_JPEG;
+                    filteredDurations.push_back(format);
+                    filteredDurations.push_back(width);
+                    filteredDurations.push_back(height);
+                    filteredDurations.push_back(duration);
+                }
+                break;
             default:
                 // Should not reach here
                 ALOGE("%s: Unkown tag 0x%x", __FUNCTION__, tag);
@@ -284,6 +296,32 @@
         filteredHeicStreamConfigs.push_back(isInput);
     }
     mData.update(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS, filteredHeicStreamConfigs);
+
+    entry = mData.find(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS);
+    Vector<int32_t> filteredDynamicDepthStreamConfigs;
+    filteredDynamicDepthStreamConfigs.setCapacity(entry.count);
+
+    for (size_t i = 0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+        int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+        int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+        int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+        int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+        if (isInput == ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_INPUT) {
+            // Hide input streams
+            continue;
+        }
+        // Translate HAL formats to NDK format
+        if (format == HAL_PIXEL_FORMAT_BLOB) {
+            format = AIMAGE_FORMAT_DEPTH_JPEG;
+        }
+
+        filteredDynamicDepthStreamConfigs.push_back(format);
+        filteredDynamicDepthStreamConfigs.push_back(width);
+        filteredDynamicDepthStreamConfigs.push_back(height);
+        filteredDynamicDepthStreamConfigs.push_back(isInput);
+    }
+    mData.update(ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS,
+            filteredDynamicDepthStreamConfigs);
 }
 
 bool
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 8c19e1d..b200abf 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -5688,13 +5688,17 @@
      *
      * <p>The ID of the active physical camera that's backing the logical camera. All camera
      * streams and metadata that are not physical camera specific will be originating from this
-     * physical camera. This must be one of valid physical IDs advertised in the physicalIds
-     * static tag.</p>
+     * physical camera.</p>
      * <p>For a logical camera made up of physical cameras where each camera's lenses have
      * different characteristics, the camera device may choose to switch between the physical
      * cameras when application changes FOCAL_LENGTH or SCALER_CROP_REGION.
      * At the time of lens switch, this result metadata reflects the new active physical camera
      * ID.</p>
+     * <p>This key will be available if the camera device advertises this key via {@link ACAMERA_REQUEST_AVAILABLE_RESULT_KEYS }.
+     * When available, this must be one of valid physical IDs backing this logical multi-camera.
+     * If this key is not available for a logical multi-camera, the camera device implementation
+     * may still switch between different active physical cameras based on use case, but the
+     * current active physical camera information won't be available to the application.</p>
      */
     ACAMERA_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID =           // byte
             ACAMERA_LOGICAL_MULTI_CAMERA_START + 2,
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 8534b28..8fe029a 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -90,6 +90,11 @@
         return binder::Status::ok();
     };
 
+    virtual binder::Status onCameraAccessPrioritiesChanged() {
+        // No op
+        return binder::Status::ok();
+    }
+
     bool waitForNumCameras(size_t num) const {
         Mutex::Autolock l(mLock);
 
diff --git a/include/media/AudioVolumeGroup.h b/include/media/AudioVolumeGroup.h
new file mode 120000
index 0000000..d6f1c99
--- /dev/null
+++ b/include/media/AudioVolumeGroup.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/media/AudioVolumeGroup.h
\ No newline at end of file
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index 10d8b13..1f24413 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -16,6 +16,7 @@
 	libhwbinder \
 	libmedia \
 	libmedialogservice \
+	libmediautils \
 	libnbaio \
 	libnblog \
 	libsoundtriggerservice \
diff --git a/media/bufferpool/2.0/Android.bp b/media/bufferpool/2.0/Android.bp
index cd4e06e..c71ac17 100644
--- a/media/bufferpool/2.0/Android.bp
+++ b/media/bufferpool/2.0/Android.bp
@@ -1,6 +1,9 @@
 cc_library {
     name: "libstagefright_bufferpool@2.0",
     vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
     srcs: [
         "Accessor.cpp",
         "AccessorImpl.cpp",
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.cpp b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
index 2c0a7a0..7045b6a 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -39,7 +39,7 @@
 namespace android {
 
 class C2SoftHevcEnc::IntfImpl : public C2InterfaceHelper {
-   public:
+  public:
     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper>& helper)
         : C2InterfaceHelper(helper) {
         setDerivedInstance(this);
@@ -73,6 +73,7 @@
                              0u, (uint64_t)C2MemoryUsage::CPU_READ))
                          .build());
 
+        // matches size limits in codec library
         addParameter(
             DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
                 .withDefault(new C2StreamPictureSizeInfo::input(0u, 320, 240))
@@ -91,6 +92,7 @@
                     Setter<decltype(*mFrameRate)>::StrictValueWithNoDeps)
                 .build());
 
+        // matches limits in codec library
         addParameter(
             DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
                 .withDefault(new C2StreamBitrateInfo::output(0u, 64000))
@@ -98,6 +100,7 @@
                 .withSetter(BitrateSetter)
                 .build());
 
+        // matches levels allowed within codec library
         addParameter(
             DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
                 .withDefault(new C2StreamProfileLevelInfo::output(
@@ -137,7 +140,7 @@
                              C2P<C2StreamBitrateInfo::output>& me) {
         (void)mayBlock;
         C2R res = C2R::Ok();
-        if (me.v.value <= 4096) {
+        if (me.v.value < 4096) {
             me.set().value = 4096;
         }
         return res;
@@ -278,7 +281,7 @@
         return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.);
     }
 
-   std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const {
+    std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const {
         return mSize;
     }
     std::shared_ptr<C2StreamFrameRateInfo::output> getFrameRate_l() const {
@@ -304,18 +307,21 @@
     std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
     std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
 };
+
 constexpr char COMPONENT_NAME[] = "c2.android.hevc.encoder";
 
 static size_t GetCPUCoreCount() {
-    long cpuCoreCount = 1;
+    long cpuCoreCount = 0;
+
 #if defined(_SC_NPROCESSORS_ONLN)
     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
 #else
     // _SC_NPROC_ONLN must be defined...
     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
 #endif
-    CHECK(cpuCoreCount >= 1);
-    ALOGV("Number of CPU cores: %ld", cpuCoreCount);
+
+    if (cpuCoreCount < 1)
+        cpuCoreCount = 1;
     return (size_t)cpuCoreCount;
 }
 
@@ -383,7 +389,7 @@
 
 c2_status_t C2SoftHevcEnc::initEncParams() {
     mCodecCtx = nullptr;
-    mNumCores = MIN(GetCPUCoreCount(), CODEC_MAX_CORES);
+    mNumCores = std::min(GetCPUCoreCount(), (size_t) CODEC_MAX_CORES);
     memset(&mEncParams, 0, sizeof(ihevce_static_cfg_params_t));
 
     // default configuration
@@ -397,7 +403,8 @@
     mEncParams.s_src_prms.i4_width = mSize->width;
     mEncParams.s_src_prms.i4_height = mSize->height;
     mEncParams.s_src_prms.i4_frm_rate_denom = 1000;
-    mEncParams.s_src_prms.i4_frm_rate_num = mFrameRate->value * mEncParams.s_src_prms.i4_frm_rate_denom;
+    mEncParams.s_src_prms.i4_frm_rate_num =
+        mFrameRate->value * mEncParams.s_src_prms.i4_frm_rate_denom;
     mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P5;
     mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_tgt_bitrate[0] =
         mBitrate->value;
@@ -470,7 +477,7 @@
                                          const C2GraphicView* const input,
                                          uint64_t timestamp) {
     ihevce_static_cfg_params_t* params = &mEncParams;
-    memset(ps_encode_ip, 0, sizeof(ihevce_inp_buf_t));
+    memset(ps_encode_ip, 0, sizeof(*ps_encode_ip));
 
     if (!input) {
         return C2_OK;
@@ -495,13 +502,14 @@
     int32_t uStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
     int32_t vStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
 
-    uint32_t width = mSize->width;
-    uint32_t height = mSize->height;
+    const uint32_t width = mSize->width;
+    const uint32_t height = mSize->height;
 
-    // width and height are always even
-    // width and height are always even (as block size is 16x16)
-    CHECK_EQ((width & 1u), 0u);
-    CHECK_EQ((height & 1u), 0u);
+    // width and height must be even
+    if (width & 1u || height & 1u) {
+        ALOGW("height(%u) and width(%u) must both be even", height, width);
+        return C2_BAD_VALUE;
+    }
 
     size_t yPlaneSize = width * height;
 
@@ -650,6 +658,7 @@
         if (view->error() != C2_OK) {
             ALOGE("graphic view map err = %d", view->error());
             mSignalledError = true;
+            work->result = C2_CORRUPTED;
             return;
         }
     }
@@ -687,8 +696,8 @@
 
     status = setEncodeArgs(&s_encode_ip, view.get(), timestamp);
     if (C2_OK != status) {
-        mSignalledError = true;
         ALOGE("setEncodeArgs failed : 0x%x", status);
+        mSignalledError = true;
         work->result = status;
         return;
     }
@@ -761,8 +770,9 @@
         : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
               GetCodec2PlatformComponentStore()->getParamReflector())) {}
 
-    virtual c2_status_t createComponent(
-        c2_node_id_t id, std::shared_ptr<C2Component>* const component,
+    c2_status_t createComponent(
+        c2_node_id_t id,
+        std::shared_ptr<C2Component>* const component,
         std::function<void(C2Component*)> deleter) override {
         *component = std::shared_ptr<C2Component>(
             new C2SoftHevcEnc(
@@ -772,8 +782,9 @@
         return C2_OK;
     }
 
-    virtual c2_status_t createInterface(
-        c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
+    c2_status_t createInterface(
+        c2_node_id_t id,
+        std::shared_ptr<C2ComponentInterface>* const interface,
         std::function<void(C2ComponentInterface*)> deleter) override {
         *interface = std::shared_ptr<C2ComponentInterface>(
             new SimpleInterface<C2SoftHevcEnc::IntfImpl>(
@@ -783,7 +794,7 @@
         return C2_OK;
     }
 
-    virtual ~C2SoftHevcEncFactory() override = default;
+    ~C2SoftHevcEncFactory() override = default;
 
    private:
     std::shared_ptr<C2ReflectorHelper> mHelper;
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.h b/media/codec2/components/hevc/C2SoftHevcEnc.h
index c22fea2..9d90b95 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.h
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -17,18 +17,18 @@
 #ifndef ANDROID_C2_SOFT_HEVC_ENC_H_
 #define ANDROID_C2_SOFT_HEVC_ENC_H_
 
-#include <map>
-#include <utils/Vector.h>
-#include <media/stagefright/foundation/ColorUtils.h>
 #include <SimpleC2Component.h>
+#include <algorithm>
+#include <map>
+#include <media/stagefright/foundation/ColorUtils.h>
+#include <utils/Vector.h>
 
 #include "ihevc_typedefs.h"
 
 namespace android {
-#define MIN(a, b) ((a) < (b)) ? (a) : (b)
 
 /** Get time */
-#define GETTIME(a, b) gettimeofday(a, b);
+#define GETTIME(a, b) gettimeofday(a, b)
 
 /** Compute difference between start and end */
 #define TIME_DIFF(start, end, diff)                      \
@@ -55,7 +55,7 @@
                       const std::shared_ptr<C2BlockPool>& pool) override;
 
    protected:
-    virtual ~C2SoftHevcEnc();
+    ~C2SoftHevcEnc() override;
 
    private:
     std::shared_ptr<IntfImpl> mIntf;
diff --git a/media/codec2/components/opus/C2SoftOpusDec.cpp b/media/codec2/components/opus/C2SoftOpusDec.cpp
index 680712e..7dcd53d 100644
--- a/media/codec2/components/opus/C2SoftOpusDec.cpp
+++ b/media/codec2/components/opus/C2SoftOpusDec.cpp
@@ -252,20 +252,25 @@
     const uint8_t *data = rView.data() + inOffset;
     if (mInputBufferCount < 3) {
         if (mInputBufferCount == 0) {
-            size_t opusHeadSize = inSize;
+            size_t opusHeadSize = 0;
             size_t codecDelayBufSize = 0;
             size_t seekPreRollBufSize = 0;
-            void *opusHeadBuf = (void *)data;
+            void *opusHeadBuf = NULL;
             void *codecDelayBuf = NULL;
             void *seekPreRollBuf = NULL;
 
-            GetOpusHeaderBuffers(data, inSize, &opusHeadBuf,
-                                &opusHeadSize, &codecDelayBuf,
-                                &codecDelayBufSize, &seekPreRollBuf,
-                                &seekPreRollBufSize);
+            if (!GetOpusHeaderBuffers(data, inSize, &opusHeadBuf,
+                                     &opusHeadSize, &codecDelayBuf,
+                                     &codecDelayBufSize, &seekPreRollBuf,
+                                     &seekPreRollBufSize)) {
+                ALOGE("%s encountered error in GetOpusHeaderBuffers", __func__);
+                mSignalledError = true;
+                work->result = C2_CORRUPTED;
+                return;
+            }
 
             if (!ParseOpusHeader((uint8_t *)opusHeadBuf, opusHeadSize, &mHeader)) {
-                ALOGE("Encountered error while Parsing Opus Header.");
+                ALOGE("%s Encountered error while Parsing Opus Header.", __func__);
                 mSignalledError = true;
                 work->result = C2_CORRUPTED;
                 return;
@@ -304,16 +309,16 @@
                 return;
             }
 
-            if (codecDelayBuf && codecDelayBufSize == 8) {
+            if (codecDelayBuf && codecDelayBufSize == sizeof(uint64_t)) {
                 uint64_t value;
                 memcpy(&value, codecDelayBuf, sizeof(uint64_t));
                 mCodecDelay = ns_to_samples(value, kRate);
                 mSamplesToDiscard = mCodecDelay;
                 ++mInputBufferCount;
             }
-            if (seekPreRollBuf && seekPreRollBufSize == 8) {
+            if (seekPreRollBuf && seekPreRollBufSize == sizeof(uint64_t)) {
                 uint64_t value;
-                memcpy(&value, codecDelayBuf, sizeof(uint64_t));
+                memcpy(&value, seekPreRollBuf, sizeof(uint64_t));
                 mSeekPreRoll = ns_to_samples(value, kRate);
                 ++mInputBufferCount;
             }
diff --git a/media/codec2/components/xaac/C2SoftXaacDec.cpp b/media/codec2/components/xaac/C2SoftXaacDec.cpp
index 86739c2..ed730c3 100644
--- a/media/codec2/components/xaac/C2SoftXaacDec.cpp
+++ b/media/codec2/components/xaac/C2SoftXaacDec.cpp
@@ -1067,6 +1067,8 @@
     int i_loud_norm;
     int i_target_loudness;
     unsigned int i_sbr_mode;
+    uint32_t ui_proc_mem_tabs_size = 0;
+    pVOID pv_alloc_ptr = NULL;
 
     /* Sampling Frequency */
     err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
@@ -1115,6 +1117,24 @@
                                 IA_ENHAACPLUS_DEC_CONFIG_PARAM_SBR_MODE, &i_sbr_mode);
     RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_SBR_MODE");
 
+    /* Get memory info tables size */
+    err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEMTABS_SIZE, 0,
+                              &ui_proc_mem_tabs_size);
+    RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEMTABS_SIZE");
+
+    pv_alloc_ptr = memalign(4, ui_proc_mem_tabs_size);
+    if (pv_alloc_ptr == NULL) {
+        ALOGE(" Cannot create requested memory  %d", ui_proc_mem_tabs_size);
+        return IA_FATAL_ERROR;
+    }
+    memset(pv_alloc_ptr, 0, ui_proc_mem_tabs_size);
+    mMemoryVec.push(pv_alloc_ptr);
+
+    /* Set pointer for process memory tables */
+    err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEMTABS_PTR, 0,
+                              pv_alloc_ptr);
+    RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEMTABS_PTR");
+
     err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
                               IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS, nullptr);
 
diff --git a/media/codec2/core/Android.bp b/media/codec2/core/Android.bp
index b723755..a7e8997 100644
--- a/media/codec2/core/Android.bp
+++ b/media/codec2/core/Android.bp
@@ -7,6 +7,9 @@
 cc_library_shared {
     name: "libcodec2",
     vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
 
     srcs: ["C2.cpp"],
 
diff --git a/media/codec2/hidl/1.0/utils/Android.bp b/media/codec2/hidl/1.0/utils/Android.bp
index d0296a5..f5aa65b 100644
--- a/media/codec2/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hidl/1.0/utils/Android.bp
@@ -3,6 +3,9 @@
 cc_library {
     name: "libcodec2_hidl@1.0",
     vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
 
     defaults: ["hidl_defaults"],
 
diff --git a/media/codec2/hidl/1.0/utils/Component.cpp b/media/codec2/hidl/1.0/utils/Component.cpp
index 0473b57..f3bf6f7 100644
--- a/media/codec2/hidl/1.0/utils/Component.cpp
+++ b/media/codec2/hidl/1.0/utils/Component.cpp
@@ -22,7 +22,6 @@
 #include <codec2/hidl/1.0/ComponentStore.h>
 #include <codec2/hidl/1.0/InputBufferManager.h>
 
-#include <android/hardware/media/c2/1.0/IInputSink.h>
 #include <hidl/HidlBinderSupport.h>
 #include <utils/Timers.h>
 
@@ -298,19 +297,12 @@
 Return<void> Component::connectToInputSurface(
         const sp<IInputSurface>& inputSurface,
         connectToInputSurface_cb _hidl_cb) {
-    sp<Sink> sink;
-    {
-        std::lock_guard<std::mutex> lock(mSinkMutex);
-        if (!mSink) {
-            mSink = new Sink(shared_from_this());
-        }
-        sink = mSink;
-    }
     Status status;
     sp<IInputSurfaceConnection> connection;
-    auto transStatus = inputSurface->connect(sink,
-            [&status, &connection](Status s,
-                                   const sp<IInputSurfaceConnection>& c) {
+    auto transStatus = inputSurface->connect(
+            asInputSink(),
+            [&status, &connection](
+                    Status s, const sp<IInputSurfaceConnection>& c) {
                 status = s;
                 connection = c;
             }
@@ -454,6 +446,14 @@
     return sp<IComponentInterface>(mInterface);
 }
 
+Return<sp<IInputSink>> Component::asInputSink() {
+    std::lock_guard<std::mutex> lock(mSinkMutex);
+    if (!mSink) {
+        mSink = new Sink(shared_from_this());
+    }
+    return {mSink};
+}
+
 std::shared_ptr<C2Component> Component::findLocalComponent(
         const sp<IInputSink>& sink) {
     return Component::Sink::findLocalComponent(sink);
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
index 4ac95c5..e444013 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
@@ -26,6 +26,7 @@
 #include <android/hardware/media/c2/1.0/IComponentInterface.h>
 #include <android/hardware/media/c2/1.0/IComponentListener.h>
 #include <android/hardware/media/c2/1.0/IComponentStore.h>
+#include <android/hardware/media/c2/1.0/IInputSink.h>
 #include <hidl/Status.h>
 #include <hwbinder/IBinder.h>
 
@@ -94,6 +95,7 @@
     virtual Return<Status> reset() override;
     virtual Return<Status> release() override;
     virtual Return<sp<IComponentInterface>> getInterface() override;
+    virtual Return<sp<IInputSink>> asInputSink() override;
 
     // Returns a C2Component associated to the given sink if the sink is indeed
     // a local component. Returns nullptr otherwise.
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index dce3222..2d10c67 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -709,6 +709,49 @@
         Mutexed<Config>::Locked config(mConfig);
         config->mUsingSurface = surface != nullptr;
 
+        // Enforce required parameters
+        int32_t i32;
+        float flt;
+        if (config->mDomain & Config::IS_AUDIO) {
+            if (!msg->findInt32(KEY_SAMPLE_RATE, &i32)) {
+                ALOGD("sample rate is missing, which is required for audio components.");
+                return BAD_VALUE;
+            }
+            if (!msg->findInt32(KEY_CHANNEL_COUNT, &i32)) {
+                ALOGD("channel count is missing, which is required for audio components.");
+                return BAD_VALUE;
+            }
+            if ((config->mDomain & Config::IS_ENCODER)
+                    && !mime.equalsIgnoreCase(MEDIA_MIMETYPE_AUDIO_FLAC)
+                    && !msg->findInt32(KEY_BIT_RATE, &i32)
+                    && !msg->findFloat(KEY_BIT_RATE, &flt)) {
+                ALOGD("bitrate is missing, which is required for audio encoders.");
+                return BAD_VALUE;
+            }
+        }
+        if (config->mDomain & (Config::IS_IMAGE | Config::IS_VIDEO)) {
+            if (!msg->findInt32(KEY_WIDTH, &i32)) {
+                ALOGD("width is missing, which is required for image/video components.");
+                return BAD_VALUE;
+            }
+            if (!msg->findInt32(KEY_HEIGHT, &i32)) {
+                ALOGD("height is missing, which is required for image/video components.");
+                return BAD_VALUE;
+            }
+            if ((config->mDomain & Config::IS_ENCODER) && (config->mDomain & Config::IS_VIDEO)) {
+                if (!msg->findInt32(KEY_BIT_RATE, &i32)
+                        && !msg->findFloat(KEY_BIT_RATE, &flt)) {
+                    ALOGD("bitrate is missing, which is required for video encoders.");
+                    return BAD_VALUE;
+                }
+                if (!msg->findInt32(KEY_I_FRAME_INTERVAL, &i32)
+                        && !msg->findFloat(KEY_I_FRAME_INTERVAL, &flt)) {
+                    ALOGD("I frame interval is missing, which is required for video encoders.");
+                    return BAD_VALUE;
+                }
+            }
+        }
+
         /*
          * Handle input surface configuration
          */
@@ -718,13 +761,14 @@
             {
                 config->mISConfig->mMinFps = 0;
                 int64_t value;
-                if (msg->findInt64("repeat-previous-frame-after", &value) && value > 0) {
+                if (msg->findInt64(KEY_REPEAT_PREVIOUS_FRAME_AFTER, &value) && value > 0) {
                     config->mISConfig->mMinFps = 1e6 / value;
                 }
-                (void)msg->findFloat("max-fps-to-encoder", &config->mISConfig->mMaxFps);
+                (void)msg->findFloat(
+                        KEY_MAX_FPS_TO_ENCODER, &config->mISConfig->mMaxFps);
                 config->mISConfig->mMinAdjustedFps = 0;
                 config->mISConfig->mFixedAdjustedFps = 0;
-                if (msg->findInt64("max-pts-gap-to-encoder", &value)) {
+                if (msg->findInt64(KEY_MAX_PTS_GAP_TO_ENCODER, &value)) {
                     if (value < 0 && value >= INT32_MIN) {
                         config->mISConfig->mFixedAdjustedFps = -1e6 / value;
                     } else if (value > 0 && value <= INT32_MAX) {
@@ -745,7 +789,7 @@
                 config->mISConfig->mSuspended = false;
                 config->mISConfig->mSuspendAtUs = -1;
                 int32_t value;
-                if (msg->findInt32("create-input-buffers-suspended", &value) && value) {
+                if (msg->findInt32(KEY_CREATE_INPUT_SURFACE_SUSPENDED, &value) && value) {
                     config->mISConfig->mSuspended = true;
                 }
             }
@@ -1453,7 +1497,7 @@
      */
     if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))
             && (config->mDomain & Config::IS_ENCODER) && config->mInputSurface && config->mISConfig) {
-        (void)params->findInt64("time-offset-us", &config->mISConfig->mTimeOffsetUs);
+        (void)params->findInt64(PARAMETER_KEY_OFFSET_TIME, &config->mISConfig->mTimeOffsetUs);
 
         if (params->findInt64("skip-frames-before", &config->mISConfig->mStartAtUs)) {
             config->mISConfig->mStopped = false;
@@ -1462,10 +1506,10 @@
         }
 
         int32_t value;
-        if (params->findInt32("drop-input-frames", &value)) {
+        if (params->findInt32(PARAMETER_KEY_SUSPEND, &value)) {
             config->mISConfig->mSuspended = value;
             config->mISConfig->mSuspendAtUs = -1;
-            (void)params->findInt64("drop-start-time-us", &config->mISConfig->mSuspendAtUs);
+            (void)params->findInt64(PARAMETER_KEY_SUSPEND_TIME, &config->mISConfig->mSuspendAtUs);
         }
 
         (void)config->mInputSurface->configure(*config->mISConfig);
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 7a444a3..fb6af93 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -99,6 +99,34 @@
      */
     virtual size_t numClientBuffers() const = 0;
 
+    void handleImageData(const sp<Codec2Buffer> &buffer) {
+        sp<ABuffer> imageDataCandidate = buffer->getImageData();
+        if (imageDataCandidate == nullptr) {
+            return;
+        }
+        sp<ABuffer> imageData;
+        if (!mFormat->findBuffer("image-data", &imageData)
+                || imageDataCandidate->size() != imageData->size()
+                || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
+            ALOGD("[%s] updating image-data", mName);
+            sp<AMessage> newFormat = dupFormat();
+            newFormat->setBuffer("image-data", imageDataCandidate);
+            MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
+            if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
+                int32_t stride = img->mPlane[0].mRowInc;
+                newFormat->setInt32(KEY_STRIDE, stride);
+                ALOGD("[%s] updating stride = %d", mName, stride);
+                if (img->mNumPlanes > 1 && stride > 0) {
+                    int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
+                    newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
+                    ALOGD("[%s] updating vstride = %d", mName, vstride);
+                }
+            }
+            setFormat(newFormat);
+            buffer->setFormat(newFormat);
+        }
+    }
+
 protected:
     std::string mComponentName; ///< name of component for debugging
     std::string mChannelName; ///< name of channel for debugging
@@ -255,34 +283,6 @@
         mSkipCutBuffer = scb;
     }
 
-    void handleImageData(const sp<Codec2Buffer> &buffer) {
-        sp<ABuffer> imageDataCandidate = buffer->getImageData();
-        if (imageDataCandidate == nullptr) {
-            return;
-        }
-        sp<ABuffer> imageData;
-        if (!mFormat->findBuffer("image-data", &imageData)
-                || imageDataCandidate->size() != imageData->size()
-                || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
-            ALOGD("[%s] updating image-data", mName);
-            sp<AMessage> newFormat = dupFormat();
-            newFormat->setBuffer("image-data", imageDataCandidate);
-            MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
-            if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
-                int32_t stride = img->mPlane[0].mRowInc;
-                newFormat->setInt32(KEY_STRIDE, stride);
-                ALOGD("[%s] updating stride = %d", mName, stride);
-                if (img->mNumPlanes > 1 && stride > 0) {
-                    int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
-                    newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
-                    ALOGD("[%s] updating vstride = %d", mName, vstride);
-                }
-            }
-            setFormat(newFormat);
-            buffer->setFormat(newFormat);
-        }
-    }
-
 protected:
     sp<SkipCutBuffer> mSkipCutBuffer;
 
@@ -783,6 +783,7 @@
         status_t err = mImpl.grabBuffer(index, &c2Buffer);
         if (err == OK) {
             c2Buffer->setFormat(mFormat);
+            handleImageData(c2Buffer);
             *buffer = c2Buffer;
             return true;
         }
@@ -1053,6 +1054,7 @@
             return false;
         }
         *index = mImpl.assignSlot(newBuffer);
+        handleImageData(newBuffer);
         *buffer = newBuffer;
         return true;
     }
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index e0b1355..ab6a105 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -14,6 +14,9 @@
 cc_library_shared {
     name: "libcodec2_vndk",
     vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
 
     srcs: [
         "C2AllocatorIon.cpp",
diff --git a/media/codec2/vndk/C2AllocatorIon.cpp b/media/codec2/vndk/C2AllocatorIon.cpp
index 736aac5..d22153d 100644
--- a/media/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/codec2/vndk/C2AllocatorIon.cpp
@@ -140,6 +140,7 @@
 
 protected:
     class Impl;
+    class ImplV2;
     Impl *mImpl;
 
     // TODO: we could make this encapsulate shared_ptr and copiable
@@ -147,7 +148,7 @@
 };
 
 class C2AllocationIon::Impl {
-private:
+protected:
     /**
      * Constructs an ion allocation.
      *
@@ -191,11 +192,7 @@
      * \return created ion allocation (implementation) which may be invalid if the
      * import failed.
      */
-    static Impl *Import(int ionFd, size_t capacity, int bufferFd, C2Allocator::id_t id) {
-        ion_user_handle_t buffer = -1;
-        int ret = ion_import(ionFd, bufferFd, &buffer);
-        return new Impl(ionFd, capacity, bufferFd, buffer, id, ret);
-    }
+    static Impl *Import(int ionFd, size_t capacity, int bufferFd, C2Allocator::id_t id);
 
     /**
      * Constructs an ion allocation by allocating an ion buffer.
@@ -209,24 +206,7 @@
      * \return created ion allocation (implementation) which may be invalid if the
      * allocation failed.
      */
-    static Impl *Alloc(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags, C2Allocator::id_t id) {
-        int bufferFd = -1;
-        ion_user_handle_t buffer = -1;
-        size_t alignedSize = align == 0 ? size : (size + align - 1) & ~(align - 1);
-        int ret = ion_alloc(ionFd, alignedSize, align, heapMask, flags, &buffer);
-        ALOGV("ion_alloc(ionFd = %d, size = %zu, align = %zu, prot = %d, flags = %d) "
-              "returned (%d) ; buffer = %d",
-              ionFd, alignedSize, align, heapMask, flags, ret, buffer);
-        if (ret == 0) {
-            // get buffer fd for native handle constructor
-            ret = ion_share(ionFd, buffer, &bufferFd);
-            if (ret != 0) {
-                ion_free(ionFd, buffer);
-                buffer = -1;
-            }
-        }
-        return new Impl(ionFd, alignedSize, bufferFd, buffer, id, ret);
-    }
+    static Impl *Alloc(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags, C2Allocator::id_t id);
 
     c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
         (void)fence; // TODO: wait for fence
@@ -256,32 +236,7 @@
         size_t mapSize = size + alignmentBytes;
         Mapping map = { nullptr, alignmentBytes, mapSize };
 
-        c2_status_t err = C2_OK;
-        if (mMapFd == -1) {
-            int ret = ion_map(mIonFd, mBuffer, mapSize, prot,
-                              flags, mapOffset, (unsigned char**)&map.addr, &mMapFd);
-            ALOGV("ion_map(ionFd = %d, handle = %d, size = %zu, prot = %d, flags = %d, "
-                  "offset = %zu) returned (%d)",
-                  mIonFd, mBuffer, mapSize, prot, flags, mapOffset, ret);
-            if (ret) {
-                mMapFd = -1;
-                map.addr = *addr = nullptr;
-                err = c2_map_errno<EINVAL>(-ret);
-            } else {
-                *addr = (uint8_t *)map.addr + alignmentBytes;
-            }
-        } else {
-            map.addr = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
-            ALOGV("mmap(size = %zu, prot = %d, flags = %d, mapFd = %d, offset = %zu) "
-                  "returned (%d)",
-                  mapSize, prot, flags, mMapFd, mapOffset, errno);
-            if (map.addr == MAP_FAILED) {
-                map.addr = *addr = nullptr;
-                err = c2_map_errno<EINVAL>(errno);
-            } else {
-                *addr = (uint8_t *)map.addr + alignmentBytes;
-            }
-        }
+        c2_status_t err = mapInternal(mapSize, mapOffset, alignmentBytes, prot, flags, &(map.addr), addr);
         if (map.addr) {
             mMappings.push_back(map);
         }
@@ -289,7 +244,7 @@
     }
 
     c2_status_t unmap(void *addr, size_t size, C2Fence *fence) {
-        if (mMapFd < 0 || mMappings.empty()) {
+        if (mMappings.empty()) {
             ALOGD("tried to unmap unmapped buffer");
             return C2_NOT_FOUND;
         }
@@ -307,14 +262,14 @@
                 *fence = C2Fence(); // not using fences
             }
             (void)mMappings.erase(it);
-            ALOGV("successfully unmapped: %d", mBuffer);
+            ALOGV("successfully unmapped: %d", mHandle.bufferFd());
             return C2_OK;
         }
         ALOGD("unmap failed to find specified map");
         return C2_BAD_VALUE;
     }
 
-    ~Impl() {
+    virtual ~Impl() {
         if (!mMappings.empty()) {
             ALOGD("Dangling mappings!");
             for (const Mapping &map : mMappings) {
@@ -326,7 +281,9 @@
             mMapFd = -1;
         }
         if (mInit == C2_OK) {
-            (void)ion_free(mIonFd, mBuffer);
+            if (mBuffer >= 0) {
+                (void)ion_free(mIonFd, mBuffer);
+            }
             native_handle_close(&mHandle);
         }
         if (mIonFd >= 0) {
@@ -346,11 +303,42 @@
         return mId;
     }
 
-    ion_user_handle_t ionHandle() const {
+    virtual ion_user_handle_t ionHandle() const {
         return mBuffer;
     }
 
-private:
+protected:
+    virtual c2_status_t mapInternal(size_t mapSize, size_t mapOffset, size_t alignmentBytes,
+            int prot, int flags, void** base, void** addr) {
+        c2_status_t err = C2_OK;
+        if (mMapFd == -1) {
+            int ret = ion_map(mIonFd, mBuffer, mapSize, prot,
+                              flags, mapOffset, (unsigned char**)base, &mMapFd);
+            ALOGV("ion_map(ionFd = %d, handle = %d, size = %zu, prot = %d, flags = %d, "
+                  "offset = %zu) returned (%d)",
+                  mIonFd, mBuffer, mapSize, prot, flags, mapOffset, ret);
+            if (ret) {
+                mMapFd = -1;
+                *base = *addr = nullptr;
+                err = c2_map_errno<EINVAL>(-ret);
+            } else {
+                *addr = (uint8_t *)*base + alignmentBytes;
+            }
+        } else {
+            *base = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
+            ALOGV("mmap(size = %zu, prot = %d, flags = %d, mapFd = %d, offset = %zu) "
+                  "returned (%d)",
+                  mapSize, prot, flags, mMapFd, mapOffset, errno);
+            if (*base == MAP_FAILED) {
+                *base = *addr = nullptr;
+                err = c2_map_errno<EINVAL>(errno);
+            } else {
+                *addr = (uint8_t *)*base + alignmentBytes;
+            }
+        }
+        return err;
+    }
+
     int mIonFd;
     C2HandleIon mHandle;
     ion_user_handle_t mBuffer;
@@ -365,6 +353,93 @@
     std::list<Mapping> mMappings;
 };
 
+class C2AllocationIon::ImplV2 : public C2AllocationIon::Impl {
+public:
+    /**
+     * Constructs an ion allocation for platforms with new (ion_4.12.h) api
+     *
+     * \note We always create an ion allocation, even if the allocation or import fails
+     * so that we can capture the error.
+     *
+     * \param ionFd     ion client (ownership transferred to created object)
+     * \param capacity  size of allocation
+     * \param bufferFd  buffer handle (ownership transferred to created object). Must be
+     *                  invalid if err is not 0.
+     * \param err       errno during buffer allocation or import
+     */
+    ImplV2(int ionFd, size_t capacity, int bufferFd, C2Allocator::id_t id, int err)
+        : Impl(ionFd, capacity, bufferFd, -1 /*buffer*/, id, err) {
+    }
+
+    virtual ~ImplV2() = default;
+
+    virtual ion_user_handle_t ionHandle() const {
+        return mHandle.bufferFd();
+    }
+
+protected:
+    virtual c2_status_t mapInternal(size_t mapSize, size_t mapOffset, size_t alignmentBytes,
+            int prot, int flags, void** base, void** addr) {
+        c2_status_t err = C2_OK;
+        *base = mmap(nullptr, mapSize, prot, flags, mHandle.bufferFd(), mapOffset);
+        ALOGV("mmapV2(size = %zu, prot = %d, flags = %d, mapFd = %d, offset = %zu) "
+              "returned (%d)",
+              mapSize, prot, flags, mHandle.bufferFd(), mapOffset, errno);
+        if (*base == MAP_FAILED) {
+            *base = *addr = nullptr;
+            err = c2_map_errno<EINVAL>(errno);
+        } else {
+            *addr = (uint8_t *)*base + alignmentBytes;
+        }
+        return err;
+    }
+
+};
+
+C2AllocationIon::Impl *C2AllocationIon::Impl::Import(int ionFd, size_t capacity, int bufferFd,
+        C2Allocator::id_t id) {
+    int ret = 0;
+    if (ion_is_legacy(ionFd)) {
+        ion_user_handle_t buffer = -1;
+        ret = ion_import(ionFd, bufferFd, &buffer);
+        return new Impl(ionFd, capacity, bufferFd, buffer, id, ret);
+    } else {
+        return new ImplV2(ionFd, capacity, bufferFd, id, ret);
+    }
+}
+
+C2AllocationIon::Impl *C2AllocationIon::Impl::Alloc(int ionFd, size_t size, size_t align,
+        unsigned heapMask, unsigned flags, C2Allocator::id_t id) {
+    int bufferFd = -1;
+    ion_user_handle_t buffer = -1;
+    size_t alignedSize = align == 0 ? size : (size + align - 1) & ~(align - 1);
+    int ret;
+
+    if (ion_is_legacy(ionFd)) {
+        ret = ion_alloc(ionFd, alignedSize, align, heapMask, flags, &buffer);
+        ALOGV("ion_alloc(ionFd = %d, size = %zu, align = %zu, prot = %d, flags = %d) "
+              "returned (%d) ; buffer = %d",
+              ionFd, alignedSize, align, heapMask, flags, ret, buffer);
+        if (ret == 0) {
+            // get buffer fd for native handle constructor
+            ret = ion_share(ionFd, buffer, &bufferFd);
+            if (ret != 0) {
+                ion_free(ionFd, buffer);
+                buffer = -1;
+            }
+        }
+        return new Impl(ionFd, alignedSize, bufferFd, buffer, id, ret);
+
+    } else {
+        ret = ion_alloc_fd(ionFd, alignedSize, align, heapMask, flags, &bufferFd);
+        ALOGV("ion_alloc_fd(ionFd = %d, size = %zu, align = %zu, prot = %d, flags = %d) "
+              "returned (%d) ; bufferFd = %d",
+              ionFd, alignedSize, align, heapMask, flags, ret, bufferFd);
+
+        return new ImplV2(ionFd, alignedSize, bufferFd, id, ret);
+    }
+}
+
 c2_status_t C2AllocationIon::map(
     size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
     return mImpl->map(offset, size, usage, fence, addr);
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 4200a46..7239302 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -1557,6 +1557,21 @@
                 } else if (!strcmp("A_FLAC", codecID)) {
                     AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_FLAC);
                     err = addFlacMetadata(meta, codecPrivate, codecPrivateSize);
+                } else if ((!strcmp("A_MS/ACM", codecID))) {
+                    if ((NULL == codecPrivate) || (codecPrivateSize < 30)) {
+                        ALOGW("unsupported audio: A_MS/ACM has no valid private data: %s, size: %zu",
+                               codecPrivate == NULL ? "null" : "non-null", codecPrivateSize);
+                        continue;
+                    } else {
+                        uint16_t ID = *(uint16_t *)codecPrivate;
+                        if (ID == 0x0055) {
+                            AMediaFormat_setString(meta,
+                                    AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG);
+                        } else {
+                            ALOGW("A_MS/ACM unsupported type , continue");
+                            continue;
+                        }
+                    }
                 } else {
                     ALOGW("%s is not supported.", codecID);
                     continue;
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 4b4d767..4298b57 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -142,6 +142,7 @@
     uint8_t *mSrcBuffer;
 
     bool mIsHeif;
+    bool mIsAudio;
     sp<ItemTable> mItemTable;
 
     // Start offset from composition time to presentation time.
@@ -3021,8 +3022,10 @@
         }
 
         unsigned bsid = br.getBits(5);
-        if (bsid < 8) {
-            ALOGW("Incorrect bsid in EAC3 header. Possibly AC-3?");
+        if (bsid == 9 || bsid == 10) {
+            ALOGW("EAC3 stream (bsid=%d) may be silenced by the decoder", bsid);
+        } else if (bsid > 16) {
+            ALOGE("EAC3 stream (bsid=%d) is not compatible with ETSI TS 102 366 v1.4.1", bsid);
             delete[] chunk;
             return ERROR_MALFORMED;
         }
@@ -4528,6 +4531,7 @@
     }
 
     mIsPcm = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW);
+    mIsAudio = !strncasecmp(mime, "audio/", 6);
 
     if (mIsPcm) {
         int32_t numChannels = 0;
@@ -5414,8 +5418,11 @@
                 findFlags = SampleTable::kFlagBefore;
             }
 
-            uint32_t syncSampleIndex;
-            if (err == OK) {
+            uint32_t syncSampleIndex = sampleIndex;
+            // assume every audio sample is a sync sample. This works around
+            // seek issues with files that were incorrectly written with an
+            // empty or single-sample stss block for the audio track
+            if (err == OK && !mIsAudio) {
                 err = mSampleTable->findSyncSampleNear(
                         sampleIndex, &syncSampleIndex, findFlags);
             }
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index b111b78..e9b6fb1 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -10,6 +10,7 @@
         "AudioAttributes.cpp",
         "AudioPolicy.cpp",
         "AudioProductStrategy.cpp",
+        "AudioVolumeGroup.cpp",
     ],
     shared_libs: [
         "libaudioutils",
diff --git a/media/libaudioclient/AudioAttributes.cpp b/media/libaudioclient/AudioAttributes.cpp
index 0f327cf..1ee6930 100644
--- a/media/libaudioclient/AudioAttributes.cpp
+++ b/media/libaudioclient/AudioAttributes.cpp
@@ -43,7 +43,7 @@
         strcpy(mAttributes.tags, "");
     }
     mStreamType = static_cast<audio_stream_type_t>(parcel->readInt32());
-    mGroupId = parcel->readUint32();
+    mGroupId = static_cast<volume_group_t>(parcel->readUint32());
     return NO_ERROR;
 }
 
@@ -60,7 +60,7 @@
         parcel->writeUtf8AsUtf16(mAttributes.tags);
     }
     parcel->writeInt32(static_cast<int32_t>(mStreamType));
-    parcel->writeUint32(mGroupId);
+    parcel->writeUint32(static_cast<uint32_t>(mGroupId));
     return NO_ERROR;
 }
 
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index baa1469..9daa299 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -1426,8 +1426,10 @@
 
 // =========================================================================
 
-AudioRecord::AudioRecordThread::AudioRecordThread(AudioRecord& receiver, bool bCanCallJava)
-    : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
+AudioRecord::AudioRecordThread::AudioRecordThread(AudioRecord& receiver,
+        bool bCanCallJava __unused)
+    : Thread(true /* bCanCallJava */)  // binder recursion on restoreRecord_l() may call Java.
+    , mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
       mIgnoreNextPausedInt(false)
 {
 }
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 01d9b3d..0ce2513 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -792,6 +792,7 @@
         int64_t token = IPCThreadState::self()->clearCallingIdentity();
         ap->registerClient(apc);
         ap->setAudioPortCallbacksEnabled(apc->isAudioPortCbEnabled());
+        ap->setAudioVolumeGroupCallbacksEnabled(apc->isAudioVolumeGroupCbEnabled());
         IPCThreadState::self()->restoreCallingIdentity(token);
     }
 
@@ -987,6 +988,38 @@
     return aps->getStreamVolumeIndex(stream, index, device);
 }
 
+status_t AudioSystem::setVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                  int index,
+                                                  audio_devices_t device)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->setVolumeIndexForAttributes(attr, index, device);
+}
+
+status_t AudioSystem::getVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                  int &index,
+                                                  audio_devices_t device)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->getVolumeIndexForAttributes(attr, index, device);
+}
+
+status_t AudioSystem::getMaxVolumeIndexForAttributes(const audio_attributes_t &attr, int &index)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->getMaxVolumeIndexForAttributes(attr, index);
+}
+
+status_t AudioSystem::getMinVolumeIndexForAttributes(const audio_attributes_t &attr, int &index)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->getMinVolumeIndexForAttributes(attr, index);
+}
+
 uint32_t AudioSystem::getStrategyForStream(audio_stream_type_t stream)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
@@ -1190,6 +1223,38 @@
     return (ret < 0) ? INVALID_OPERATION : NO_ERROR;
 }
 
+status_t AudioSystem::addAudioVolumeGroupCallback(const sp<AudioVolumeGroupCallback>& callback)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+
+    Mutex::Autolock _l(gLockAPS);
+    if (gAudioPolicyServiceClient == 0) {
+        return NO_INIT;
+    }
+    int ret = gAudioPolicyServiceClient->addAudioVolumeGroupCallback(callback);
+    if (ret == 1) {
+        aps->setAudioVolumeGroupCallbacksEnabled(true);
+    }
+    return (ret < 0) ? INVALID_OPERATION : NO_ERROR;
+}
+
+status_t AudioSystem::removeAudioVolumeGroupCallback(const sp<AudioVolumeGroupCallback>& callback)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+
+    Mutex::Autolock _l(gLockAPS);
+    if (gAudioPolicyServiceClient == 0) {
+        return NO_INIT;
+    }
+    int ret = gAudioPolicyServiceClient->removeAudioVolumeGroupCallback(callback);
+    if (ret == 0) {
+        aps->setAudioVolumeGroupCallbacksEnabled(false);
+    }
+    return (ret < 0) ? INVALID_OPERATION : NO_ERROR;
+}
+
 status_t AudioSystem::addAudioDeviceCallback(
         const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
@@ -1403,12 +1468,16 @@
 
 audio_stream_type_t AudioSystem::attributesToStreamType(const audio_attributes_t &attr)
 {
-    product_strategy_t strategyId =
-            AudioSystem::getProductStrategyFromAudioAttributes(AudioAttributes(attr));
+    product_strategy_t psId;
+    status_t ret = AudioSystem::getProductStrategyFromAudioAttributes(AudioAttributes(attr), psId);
+    if (ret != NO_ERROR) {
+        ALOGE("no strategy found for attributes %s",  toString(attr).c_str());
+        return AUDIO_STREAM_MUSIC;
+    }
     AudioProductStrategyVector strategies;
     listAudioProductStrategies(strategies);
     for (const auto &strategy : strategies) {
-        if (strategy.getId() == strategyId) {
+        if (strategy.getId() == psId) {
             auto attrVect = strategy.getAudioAttributes();
             auto iter = std::find_if(begin(attrVect), end(attrVect), [&attr](const auto &refAttr) {
                              return AudioProductStrategy::attributesMatches(
@@ -1422,11 +1491,27 @@
     return AUDIO_STREAM_MUSIC;
 }
 
-product_strategy_t AudioSystem::getProductStrategyFromAudioAttributes(const AudioAttributes &aa)
+status_t AudioSystem::getProductStrategyFromAudioAttributes(const AudioAttributes &aa,
+                                                            product_strategy_t &productStrategy)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
-    if (aps == 0) return PRODUCT_STRATEGY_NONE;
-    return aps->getProductStrategyFromAudioAttributes(aa);
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->getProductStrategyFromAudioAttributes(aa,productStrategy);
+}
+
+status_t AudioSystem::listAudioVolumeGroups(AudioVolumeGroupVector &groups)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->listAudioVolumeGroups(groups);
+}
+
+status_t AudioSystem::getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
+                                                        volume_group_t &volumeGroup)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->getVolumeGroupFromAudioAttributes(aa, volumeGroup);
 }
 
 // ---------------------------------------------------------------------------
@@ -1478,6 +1563,47 @@
     }
 }
 
+// ----------------------------------------------------------------------------
+int AudioSystem::AudioPolicyServiceClient::addAudioVolumeGroupCallback(
+        const sp<AudioVolumeGroupCallback>& callback)
+{
+    Mutex::Autolock _l(mLock);
+    for (size_t i = 0; i < mAudioVolumeGroupCallback.size(); i++) {
+        if (mAudioVolumeGroupCallback[i] == callback) {
+            return -1;
+        }
+    }
+    mAudioVolumeGroupCallback.add(callback);
+    return mAudioVolumeGroupCallback.size();
+}
+
+int AudioSystem::AudioPolicyServiceClient::removeAudioVolumeGroupCallback(
+        const sp<AudioVolumeGroupCallback>& callback)
+{
+    Mutex::Autolock _l(mLock);
+    size_t i;
+    for (i = 0; i < mAudioVolumeGroupCallback.size(); i++) {
+        if (mAudioVolumeGroupCallback[i] == callback) {
+            break;
+        }
+    }
+    if (i == mAudioVolumeGroupCallback.size()) {
+        return -1;
+    }
+    mAudioVolumeGroupCallback.removeAt(i);
+    return mAudioVolumeGroupCallback.size();
+}
+
+void AudioSystem::AudioPolicyServiceClient::onAudioVolumeGroupChanged(volume_group_t group,
+                                                                      int flags)
+{
+    Mutex::Autolock _l(mLock);
+    for (size_t i = 0; i < mAudioVolumeGroupCallback.size(); i++) {
+        mAudioVolumeGroupCallback[i]->onAudioVolumeGroupChanged(group, flags);
+    }
+}
+// ----------------------------------------------------------------------------
+
 void AudioSystem::AudioPolicyServiceClient::onDynamicPolicyMixStateUpdate(
         String8 regId, int32_t state)
 {
@@ -1521,6 +1647,9 @@
         for (size_t i = 0; i < mAudioPortCallbacks.size(); i++) {
             mAudioPortCallbacks[i]->onServiceDied();
         }
+        for (size_t i = 0; i < mAudioVolumeGroupCallback.size(); i++) {
+            mAudioVolumeGroupCallback[i]->onServiceDied();
+        }
     }
     {
         Mutex::Autolock _l(gLockAPS);
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 7881bb8..670a200 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -3127,8 +3127,9 @@
 
 // =========================================================================
 
-AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
-    : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
+AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava __unused)
+    : Thread(true /* bCanCallJava */)  // binder recursion on restoreTrack_l() may call Java.
+    , mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
       mIgnoreNextPausedInt(false)
 {
 }
diff --git a/media/libaudioclient/AudioVolumeGroup.cpp b/media/libaudioclient/AudioVolumeGroup.cpp
new file mode 100644
index 0000000..e79a362
--- /dev/null
+++ b/media/libaudioclient/AudioVolumeGroup.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioVolumeGroup"
+
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+
+#include <media/AudioVolumeGroup.h>
+#include <media/AudioAttributes.h>
+
+namespace android {
+
+status_t AudioVolumeGroup::readFromParcel(const Parcel *parcel)
+{
+    status_t ret = parcel->readUtf8FromUtf16(&mName);
+    if (ret != NO_ERROR) {
+        return ret;
+    }
+    mGroupId = static_cast<volume_group_t>(parcel->readInt32());
+    size_t size = static_cast<size_t>(parcel->readInt32());
+    for (size_t i = 0; i < size; i++) {
+        AudioAttributes attribute;
+        attribute.readFromParcel(parcel);
+        if (ret != NO_ERROR) {
+            mAudioAttributes.clear();
+            return ret;
+        }
+        mAudioAttributes.push_back(attribute.getAttributes());
+    }
+    size = static_cast<size_t>(parcel->readInt32());
+    for (size_t i = 0; i < size; i++) {
+        audio_stream_type_t stream = static_cast<audio_stream_type_t>(parcel->readInt32());
+        mStreams.push_back(stream);
+    }
+    return NO_ERROR;
+}
+
+status_t AudioVolumeGroup::writeToParcel(Parcel *parcel) const
+{
+    parcel->writeUtf8AsUtf16(mName);
+    parcel->writeInt32(static_cast<int32_t>(mGroupId));
+    size_t size = mAudioAttributes.size();
+    size_t sizePosition = parcel->dataPosition();
+    parcel->writeInt32(size);
+    size_t finalSize = size;
+    for (const auto &attributes : mAudioAttributes) {
+        size_t position = parcel->dataPosition();
+        AudioAttributes attribute(attributes);
+        status_t ret = attribute.writeToParcel(parcel);
+        if (ret != NO_ERROR) {
+            parcel->setDataPosition(position);
+            finalSize--;
+        }
+    }
+    if (size != finalSize) {
+        size_t position = parcel->dataPosition();
+        parcel->setDataPosition(sizePosition);
+        parcel->writeInt32(finalSize);
+        parcel->setDataPosition(position);
+    }
+    parcel->writeInt32(mStreams.size());
+    for (const auto &stream : mStreams) {
+        parcel->writeInt32(static_cast<int32_t>(stream));
+    }
+    return NO_ERROR;
+}
+
+} // namespace android
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 1bce16f..3bac44f 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -51,6 +51,10 @@
     INIT_STREAM_VOLUME,
     SET_STREAM_VOLUME,
     GET_STREAM_VOLUME,
+    SET_VOLUME_ATTRIBUTES,
+    GET_VOLUME_ATTRIBUTES,
+    GET_MIN_VOLUME_FOR_ATTRIBUTES,
+    GET_MAX_VOLUME_FOR_ATTRIBUTES,
     GET_STRATEGY_FOR_STREAM,
     GET_OUTPUT_FOR_EFFECT,
     REGISTER_EFFECT,
@@ -78,6 +82,7 @@
     START_AUDIO_SOURCE,
     STOP_AUDIO_SOURCE,
     SET_AUDIO_PORT_CALLBACK_ENABLED,
+    SET_AUDIO_VOLUME_GROUP_CALLBACK_ENABLED,
     SET_MASTER_MONO,
     GET_MASTER_MONO,
     GET_STREAM_VOLUME_DB,
@@ -95,6 +100,8 @@
     GET_OFFLOAD_FORMATS_A2DP,
     LIST_AUDIO_PRODUCT_STRATEGIES,
     GET_STRATEGY_FOR_ATTRIBUTES,
+    LIST_AUDIO_VOLUME_GROUPS,
+    GET_VOLUME_GROUP_FOR_ATTRIBUTES
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -415,6 +422,70 @@
         return static_cast <status_t> (reply.readInt32());
     }
 
+    virtual status_t setVolumeIndexForAttributes(const audio_attributes_t &attr, int index,
+                                                 audio_devices_t device)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(&attr, sizeof(audio_attributes_t));
+        data.writeInt32(index);
+        data.writeInt32(static_cast <uint32_t>(device));
+        status_t status = remote()->transact(SET_VOLUME_ATTRIBUTES, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        return static_cast <status_t> (reply.readInt32());
+    }
+    virtual status_t getVolumeIndexForAttributes(const audio_attributes_t &attr, int &index,
+                                                 audio_devices_t device)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(&attr, sizeof(audio_attributes_t));
+        data.writeInt32(static_cast <uint32_t>(device));
+        status_t status = remote()->transact(GET_VOLUME_ATTRIBUTES, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = static_cast <status_t> (reply.readInt32());
+        if (status != NO_ERROR) {
+            return status;
+        }
+        index = reply.readInt32();
+        return NO_ERROR;
+    }
+    virtual status_t getMinVolumeIndexForAttributes(const audio_attributes_t &attr, int &index)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(&attr, sizeof(audio_attributes_t));
+        status_t status = remote()->transact(GET_MIN_VOLUME_FOR_ATTRIBUTES, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = static_cast <status_t> (reply.readInt32());
+        if (status != NO_ERROR) {
+            return status;
+        }
+        index = reply.readInt32();
+        return NO_ERROR;
+    }
+    virtual status_t getMaxVolumeIndexForAttributes(const audio_attributes_t &attr, int &index)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(&attr, sizeof(audio_attributes_t));
+        status_t status = remote()->transact(GET_MAX_VOLUME_FOR_ATTRIBUTES, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = static_cast <status_t> (reply.readInt32());
+        if (status != NO_ERROR) {
+            return status;
+        }
+        index = reply.readInt32();
+        return NO_ERROR;
+    }
     virtual uint32_t getStrategyForStream(audio_stream_type_t stream)
     {
         Parcel data, reply;
@@ -692,6 +763,14 @@
         remote()->transact(SET_AUDIO_PORT_CALLBACK_ENABLED, data, &reply);
     }
 
+    virtual void setAudioVolumeGroupCallbacksEnabled(bool enabled)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(enabled ? 1 : 0);
+        remote()->transact(SET_AUDIO_VOLUME_GROUP_CALLBACK_ENABLED, data, &reply);
+    }
+
     virtual status_t acquireSoundTriggerSession(audio_session_t *session,
                                             audio_io_handle_t *ioHandle,
                                             audio_devices_t *device)
@@ -1085,35 +1164,90 @@
             return status;
         }
         status = static_cast<status_t>(reply.readInt32());
-        if (status == NO_ERROR) {
-            uint32_t numStrategies = static_cast<uint32_t>(reply.readInt32());
-            for (size_t i = 0; i < numStrategies; i++) {
-                AudioProductStrategy strategy;
-                status = strategy.readFromParcel(&reply);
-                if (status != NO_ERROR) {
-                    ALOGE("%s: failed to read strategies", __FUNCTION__);
-                    strategies.clear();
-                    return status;
-                }
-                strategies.push_back(strategy);
-            }
+        if (status != NO_ERROR) {
+            return status;
         }
-        return status;
+        uint32_t numStrategies = static_cast<uint32_t>(reply.readInt32());
+        for (size_t i = 0; i < numStrategies; i++) {
+            AudioProductStrategy strategy;
+            status = strategy.readFromParcel(&reply);
+            if (status != NO_ERROR) {
+                ALOGE("%s: failed to read strategies", __FUNCTION__);
+                strategies.clear();
+                return status;
+            }
+            strategies.push_back(strategy);
+        }
+        return NO_ERROR;
     }
 
-    virtual product_strategy_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa)
+    virtual status_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa,
+                                                           product_strategy_t &productStrategy)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
         status_t status = aa.writeToParcel(&data);
         if (status != NO_ERROR) {
-            return PRODUCT_STRATEGY_NONE;
+            return status;
         }
         status = remote()->transact(GET_STRATEGY_FOR_ATTRIBUTES, data, &reply);
-        if (status == NO_ERROR) {
-            return static_cast<product_strategy_t>(reply.readInt32());
+        if (status != NO_ERROR) {
+            return status;
         }
-        return PRODUCT_STRATEGY_NONE;
+        status = static_cast<status_t>(reply.readInt32());
+        if (status != NO_ERROR) {
+            return status;
+        }
+        productStrategy = static_cast<product_strategy_t>(reply.readInt32());
+        return NO_ERROR;
+    }
+
+    virtual status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+
+        status_t status = remote()->transact(LIST_AUDIO_VOLUME_GROUPS, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = static_cast<status_t>(reply.readInt32());
+        if (status != NO_ERROR) {
+            return status;
+        }
+        uint32_t numGroups = static_cast<uint32_t>(reply.readInt32());
+        for (size_t i = 0; i < numGroups; i++) {
+            AudioVolumeGroup group;
+            status = group.readFromParcel(&reply);
+            if (status != NO_ERROR) {
+                ALOGE("%s: failed to read volume groups", __FUNCTION__);
+                groups.clear();
+                return status;
+            }
+            groups.push_back(group);
+        }
+        return NO_ERROR;
+    }
+
+    virtual status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
+                                                       volume_group_t &volumeGroup)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        status_t status = aa.writeToParcel(&data);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = remote()->transact(GET_VOLUME_GROUP_FOR_ATTRIBUTES, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = static_cast<status_t>(reply.readInt32());
+        if (status != NO_ERROR) {
+            return status;
+        }
+        volumeGroup = static_cast<volume_group_t>(reply.readInt32());
+        return NO_ERROR;
     }
 };
 
@@ -1173,7 +1307,9 @@
         case SET_A11Y_SERVICES_UIDS:
         case SET_UID_DEVICE_AFFINITY:
         case REMOVE_UID_DEVICE_AFFINITY:
-        case GET_OFFLOAD_FORMATS_A2DP: {
+        case GET_OFFLOAD_FORMATS_A2DP:
+        case LIST_AUDIO_VOLUME_GROUPS:
+        case GET_VOLUME_GROUP_FOR_ATTRIBUTES: {
             if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
@@ -1433,6 +1569,73 @@
             return NO_ERROR;
         } break;
 
+        case SET_VOLUME_ATTRIBUTES: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_attributes_t attributes = {};
+            status_t status = data.read(&attributes, sizeof(audio_attributes_t));
+            if (status != NO_ERROR) {
+                return status;
+            }
+            int index = data.readInt32();
+            audio_devices_t device = static_cast <audio_devices_t>(data.readInt32());
+
+            reply->writeInt32(static_cast <uint32_t>(setVolumeIndexForAttributes(attributes,
+                                                                                 index, device)));
+            return NO_ERROR;
+        } break;
+
+        case GET_VOLUME_ATTRIBUTES: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_attributes_t attributes = {};
+            status_t status = data.read(&attributes, sizeof(audio_attributes_t));
+            if (status != NO_ERROR) {
+                return status;
+            }
+            audio_devices_t device = static_cast <audio_devices_t>(data.readInt32());
+
+            int index = 0;
+            status = getVolumeIndexForAttributes(attributes, index, device);
+            reply->writeInt32(static_cast <uint32_t>(status));
+            if (status == NO_ERROR) {
+                reply->writeInt32(index);
+            }
+            return NO_ERROR;
+        } break;
+
+        case GET_MIN_VOLUME_FOR_ATTRIBUTES: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_attributes_t attributes = {};
+            status_t status = data.read(&attributes, sizeof(audio_attributes_t));
+            if (status != NO_ERROR) {
+                return status;
+            }
+
+            int index = 0;
+            status = getMinVolumeIndexForAttributes(attributes, index);
+            reply->writeInt32(static_cast <uint32_t>(status));
+            if (status == NO_ERROR) {
+                reply->writeInt32(index);
+            }
+            return NO_ERROR;
+        } break;
+
+        case GET_MAX_VOLUME_FOR_ATTRIBUTES: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_attributes_t attributes = {};
+            status_t status = data.read(&attributes, sizeof(audio_attributes_t));
+            if (status != NO_ERROR) {
+                return status;
+            }
+
+            int index = 0;
+            status = getMaxVolumeIndexForAttributes(attributes, index);
+            reply->writeInt32(static_cast <uint32_t>(status));
+            if (status == NO_ERROR) {
+                reply->writeInt32(index);
+            }
+            return NO_ERROR;
+        } break;
+
         case GET_DEVICES_FOR_STREAM: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             audio_stream_type_t stream =
@@ -1681,6 +1884,12 @@
             return NO_ERROR;
         } break;
 
+        case SET_AUDIO_VOLUME_GROUP_CALLBACK_ENABLED: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            setAudioVolumeGroupCallbacksEnabled(data.readInt32() == 1);
+            return NO_ERROR;
+        } break;
+
         case ACQUIRE_SOUNDTRIGGER_SESSION: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             sp<IAudioPolicyServiceClient> client = interface_cast<IAudioPolicyServiceClient>(
@@ -1992,7 +2201,7 @@
             status_t status = listAudioProductStrategies(strategies);
             reply->writeInt32(status);
             if (status != NO_ERROR) {
-                return status;
+                return NO_ERROR;
             }
             size_t size = strategies.size();
             size_t sizePosition = reply->dataPosition();
@@ -2021,11 +2230,61 @@
             if (status != NO_ERROR) {
                 return status;
             }
-            product_strategy_t strategy = getProductStrategyFromAudioAttributes(attributes);
+            product_strategy_t strategy;
+            status = getProductStrategyFromAudioAttributes(attributes, strategy);
+            reply->writeInt32(status);
+            if (status != NO_ERROR) {
+                return NO_ERROR;
+            }
             reply->writeUint32(static_cast<int>(strategy));
             return NO_ERROR;
         }
 
+        case LIST_AUDIO_VOLUME_GROUPS: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            AudioVolumeGroupVector groups;
+            status_t status = listAudioVolumeGroups(groups);
+            reply->writeInt32(status);
+            if (status != NO_ERROR) {
+                return NO_ERROR;
+            }
+            size_t size = groups.size();
+            size_t sizePosition = reply->dataPosition();
+            reply->writeInt32(size);
+            size_t finalSize = size;
+            for (size_t i = 0; i < size; i++) {
+                size_t position = reply->dataPosition();
+                if (groups[i].writeToParcel(reply) != NO_ERROR) {
+                    reply->setDataPosition(position);
+                    finalSize--;
+                }
+            }
+            if (size != finalSize) {
+                size_t position = reply->dataPosition();
+                reply->setDataPosition(sizePosition);
+                reply->writeInt32(finalSize);
+                reply->setDataPosition(position);
+            }
+            return NO_ERROR;
+        }
+
+        case GET_VOLUME_GROUP_FOR_ATTRIBUTES: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            AudioAttributes attributes;
+            status_t status = attributes.readFromParcel(&data);
+            if (status != NO_ERROR) {
+                return status;
+            }
+            volume_group_t group;
+            status = getVolumeGroupFromAudioAttributes(attributes, group);
+            reply->writeInt32(status);
+            if (status != NO_ERROR) {
+                return NO_ERROR;
+            }
+            reply->writeUint32(static_cast<int>(group));
+            return NO_ERROR;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libaudioclient/IAudioPolicyServiceClient.cpp b/media/libaudioclient/IAudioPolicyServiceClient.cpp
index 1f9eab7..52d8ccd 100644
--- a/media/libaudioclient/IAudioPolicyServiceClient.cpp
+++ b/media/libaudioclient/IAudioPolicyServiceClient.cpp
@@ -31,7 +31,8 @@
     PORT_LIST_UPDATE = IBinder::FIRST_CALL_TRANSACTION,
     PATCH_LIST_UPDATE,
     MIX_STATE_UPDATE,
-    RECORDING_CONFIGURATION_UPDATE
+    RECORDING_CONFIGURATION_UPDATE,
+    VOLUME_GROUP_CHANGED,
 };
 
 // ----------------------------------------------------------------------
@@ -108,6 +109,15 @@
         remote()->transact(PATCH_LIST_UPDATE, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
+    void onAudioVolumeGroupChanged(volume_group_t group, int flags)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyServiceClient::getInterfaceDescriptor());
+        data.writeUint32(group);
+        data.writeInt32(flags);
+        remote()->transact(VOLUME_GROUP_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
     void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state)
     {
         Parcel data, reply;
@@ -157,6 +167,13 @@
             onAudioPatchListUpdate();
             return NO_ERROR;
         } break;
+    case VOLUME_GROUP_CHANGED: {
+            CHECK_INTERFACE(IAudioPolicyServiceClient, data, reply);
+            volume_group_t group = static_cast<volume_group_t>(data.readUint32());
+            int flags = data.readInt32();
+            onAudioVolumeGroupChanged(group, flags);
+            return NO_ERROR;
+        } break;
     case MIX_STATE_UPDATE: {
             CHECK_INTERFACE(IAudioPolicyServiceClient, data, reply);
             String8 regId = data.readString8();
diff --git a/media/libaudioclient/include/media/AudioAttributes.h b/media/libaudioclient/include/media/AudioAttributes.h
index edf26eb..0a35e9e 100644
--- a/media/libaudioclient/include/media/AudioAttributes.h
+++ b/media/libaudioclient/include/media/AudioAttributes.h
@@ -17,6 +17,7 @@
 
 #pragma once
 
+#include <media/AudioCommonTypes.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
 #include <binder/Parcelable.h>
@@ -28,7 +29,7 @@
 public:
     AudioAttributes() = default;
     AudioAttributes(const audio_attributes_t &attributes) : mAttributes(attributes) {}
-    AudioAttributes(uint32_t groupId,
+    AudioAttributes(volume_group_t groupId,
                     audio_stream_type_t stream,
                     const audio_attributes_t &attributes) :
          mAttributes(attributes), mStreamType(stream), mGroupId(groupId) {}
@@ -39,7 +40,7 @@
     status_t writeToParcel(Parcel *parcel) const override;
 
     audio_stream_type_t getStreamType() const { return mStreamType; }
-    uint32_t getGroupId() const { return mGroupId; }
+    volume_group_t getGroupId() const { return mGroupId; }
 
 private:
     audio_attributes_t mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
@@ -53,7 +54,7 @@
      * @brief mGroupId: for future volume management, define groups within a strategy that follows
      * the same curves of volume (extension of stream types to manage volume)
      */
-    uint32_t mGroupId = 0;
+    volume_group_t mGroupId = VOLUME_GROUP_NONE;
 };
 
 } // namespace android
diff --git a/media/libaudioclient/include/media/AudioCommonTypes.h b/media/libaudioclient/include/media/AudioCommonTypes.h
index 5188da1..8e446ea 100644
--- a/media/libaudioclient/include/media/AudioCommonTypes.h
+++ b/media/libaudioclient/include/media/AudioCommonTypes.h
@@ -27,7 +27,7 @@
 const product_strategy_t PRODUCT_STRATEGY_NONE = static_cast<product_strategy_t>(-1);
 
 using AttributesVector = std::vector<audio_attributes_t>;
-using StreamTypes = std::vector<audio_stream_type_t>;
+using StreamTypeVector = std::vector<audio_stream_type_t>;
 
 constexpr bool operator==(const audio_attributes_t &lhs, const audio_attributes_t &rhs)
 {
@@ -38,5 +38,9 @@
 {
     return !(lhs==rhs);
 }
+
+enum volume_group_t : uint32_t;
+static const volume_group_t VOLUME_GROUP_NONE = static_cast<volume_group_t>(-1);
+
 } // namespace android
 
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index b9ee24a..e64f285 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -21,6 +21,7 @@
 
 #include <media/AudioPolicy.h>
 #include <media/AudioProductStrategy.h>
+#include <media/AudioVolumeGroup.h>
 #include <media/AudioIoDescriptor.h>
 #include <media/IAudioFlingerClient.h>
 #include <media/IAudioPolicyServiceClient.h>
@@ -263,6 +264,17 @@
                                          int *index,
                                          audio_devices_t device);
 
+    static status_t setVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                int index,
+                                                audio_devices_t device);
+    static status_t getVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                int &index,
+                                                audio_devices_t device);
+
+    static status_t getMaxVolumeIndexForAttributes(const audio_attributes_t &attr, int &index);
+
+    static status_t getMinVolumeIndexForAttributes(const audio_attributes_t &attr, int &index);
+
     static uint32_t getStrategyForStream(audio_stream_type_t stream);
     static audio_devices_t getDevicesForStream(audio_stream_type_t stream);
 
@@ -367,13 +379,34 @@
     static bool     isHapticPlaybackSupported();
 
     static status_t listAudioProductStrategies(AudioProductStrategyVector &strategies);
-    static product_strategy_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa);
+    static status_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa,
+                                                        product_strategy_t &productStrategy);
 
     static audio_attributes_t streamTypeToAttributes(audio_stream_type_t stream);
     static audio_stream_type_t attributesToStreamType(const audio_attributes_t &attr);
 
+    static status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups);
+
+    static status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
+                                                      volume_group_t &volumeGroup);
+
     // ----------------------------------------------------------------------------
 
+    class AudioVolumeGroupCallback : public RefBase
+    {
+    public:
+
+        AudioVolumeGroupCallback() {}
+        virtual ~AudioVolumeGroupCallback() {}
+
+        virtual void onAudioVolumeGroupChanged(volume_group_t group, int flags) = 0;
+        virtual void onServiceDied() = 0;
+
+    };
+
+    static status_t addAudioVolumeGroupCallback(const sp<AudioVolumeGroupCallback>& callback);
+    static status_t removeAudioVolumeGroupCallback(const sp<AudioVolumeGroupCallback>& callback);
+
     class AudioPortCallback : public RefBase
     {
     public:
@@ -506,12 +539,17 @@
         int removeAudioPortCallback(const sp<AudioPortCallback>& callback);
         bool isAudioPortCbEnabled() const { return (mAudioPortCallbacks.size() != 0); }
 
+        int addAudioVolumeGroupCallback(const sp<AudioVolumeGroupCallback>& callback);
+        int removeAudioVolumeGroupCallback(const sp<AudioVolumeGroupCallback>& callback);
+        bool isAudioVolumeGroupCbEnabled() const { return (mAudioVolumeGroupCallback.size() != 0); }
+
         // DeathRecipient
         virtual void binderDied(const wp<IBinder>& who);
 
         // IAudioPolicyServiceClient
         virtual void onAudioPortListUpdate();
         virtual void onAudioPatchListUpdate();
+        virtual void onAudioVolumeGroupChanged(volume_group_t group, int flags);
         virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
         virtual void onRecordingConfigurationUpdate(int event,
                                                     const record_client_info_t *clientInfo,
@@ -525,6 +563,7 @@
     private:
         Mutex                               mLock;
         Vector <sp <AudioPortCallback> >    mAudioPortCallbacks;
+        Vector <sp <AudioVolumeGroupCallback> > mAudioVolumeGroupCallback;
     };
 
     static audio_io_handle_t getOutput(audio_stream_type_t stream);
diff --git a/media/libaudioclient/include/media/AudioVolumeGroup.h b/media/libaudioclient/include/media/AudioVolumeGroup.h
new file mode 100644
index 0000000..9a6ea07
--- /dev/null
+++ b/media/libaudioclient/include/media/AudioVolumeGroup.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#pragma once
+
+#include <media/AudioProductStrategy.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <binder/Parcelable.h>
+
+namespace android {
+
+class AudioVolumeGroup : public Parcelable
+{
+public:
+    AudioVolumeGroup() {}
+    AudioVolumeGroup(const std::string &name,
+                     volume_group_t group,
+                     const AttributesVector &attributes,
+                     const StreamTypeVector &streams) :
+        mName(name), mGroupId(group), mAudioAttributes(attributes), mStreams(streams) {}
+
+    const std::string &getName() const { return mName; }
+    volume_group_t getId() const { return mGroupId; }
+    AttributesVector getAudioAttributes() const { return mAudioAttributes; }
+    StreamTypeVector getStreamTypes() const { return mStreams; }
+
+    status_t readFromParcel(const Parcel *parcel) override;
+    status_t writeToParcel(Parcel *parcel) const override;
+
+private:
+    std::string mName;
+    volume_group_t mGroupId = VOLUME_GROUP_NONE;
+    AttributesVector mAudioAttributes;
+    StreamTypeVector mStreams;
+};
+
+using AudioVolumeGroupVector = std::vector<AudioVolumeGroup>;
+
+} // namespace android
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index e89a55d..35540f0 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -93,6 +93,17 @@
     virtual status_t getStreamVolumeIndex(audio_stream_type_t stream,
                                           int *index,
                                           audio_devices_t device) = 0;
+
+    virtual status_t setVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                 int index,
+                                                 audio_devices_t device) = 0;
+    virtual status_t getVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                 int &index,
+                                                 audio_devices_t device) = 0;
+    virtual status_t getMaxVolumeIndexForAttributes(const audio_attributes_t &attr, int &index) = 0;
+
+    virtual status_t getMinVolumeIndexForAttributes(const audio_attributes_t &attr, int &index) = 0;
+
     virtual uint32_t getStrategyForStream(audio_stream_type_t stream) = 0;
     virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream) = 0;
     virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc) = 0;
@@ -160,6 +171,8 @@
 
     virtual void setAudioPortCallbacksEnabled(bool enabled) = 0;
 
+    virtual void setAudioVolumeGroupCallbacksEnabled(bool enabled) = 0;
+
     virtual status_t acquireSoundTriggerSession(audio_session_t *session,
                                            audio_io_handle_t *ioHandle,
                                            audio_devices_t *device) = 0;
@@ -198,7 +211,12 @@
 
     virtual bool     isHapticPlaybackSupported() = 0;
     virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies) = 0;
-    virtual product_strategy_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa) = 0;
+    virtual status_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa,
+                                                           product_strategy_t &productStrategy) = 0;
+
+    virtual status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) = 0;
+    virtual status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
+                                                       volume_group_t &volumeGroup) = 0;
 };
 
 
diff --git a/media/libaudioclient/include/media/IAudioPolicyServiceClient.h b/media/libaudioclient/include/media/IAudioPolicyServiceClient.h
index b3c0381..79008c3 100644
--- a/media/libaudioclient/include/media/IAudioPolicyServiceClient.h
+++ b/media/libaudioclient/include/media/IAudioPolicyServiceClient.h
@@ -23,6 +23,8 @@
 #include <binder/IInterface.h>
 #include <system/audio.h>
 #include <system/audio_effect.h>
+#include <media/AudioPolicy.h>
+#include <media/AudioVolumeGroup.h>
 
 namespace android {
 
@@ -45,6 +47,8 @@
 public:
     DECLARE_META_INTERFACE(AudioPolicyServiceClient);
 
+    // Notifies a change of volume group
+    virtual void onAudioVolumeGroupChanged(volume_group_t group, int flags) = 0;
     // Notifies a change of audio port configuration.
     virtual void onAudioPortListUpdate() = 0;
     // Notifies a change of audio patch configuration.
diff --git a/media/libaudiohal/impl/EffectHalHidl.cpp b/media/libaudiohal/impl/EffectHalHidl.cpp
index b0597b3..caf575c 100644
--- a/media/libaudiohal/impl/EffectHalHidl.cpp
+++ b/media/libaudiohal/impl/EffectHalHidl.cpp
@@ -18,6 +18,7 @@
 //#define LOG_NDEBUG 0
 
 #include <common/all-versions/VersionUtils.h>
+#include <cutils/native_handle.h>
 #include <hwbinder/IPCThreadState.h>
 #include <media/EffectsFactoryApi.h>
 #include <utils/Log.h>
@@ -280,6 +281,15 @@
     return ret.isOk() ? analyzeResult(ret) : FAILED_TRANSACTION;
 }
 
+status_t EffectHalHidl::dump(int fd) {
+    if (mEffect == 0) return NO_INIT;
+    native_handle_t* hidlHandle = native_handle_create(1, 0);
+    hidlHandle->data[0] = fd;
+    Return<void> ret = mEffect->debug(hidlHandle, {} /* options */);
+    native_handle_delete(hidlHandle);
+    return ret.isOk() ? OK : FAILED_TRANSACTION;
+}
+
 status_t EffectHalHidl::getConfigImpl(
         uint32_t cmdCode, uint32_t *replySize, void *pReplyData) {
     if (replySize == NULL || *replySize != sizeof(effect_config_t) || pReplyData == NULL) {
diff --git a/media/libaudiohal/impl/EffectHalHidl.h b/media/libaudiohal/impl/EffectHalHidl.h
index 9d9f707..1f238c0 100644
--- a/media/libaudiohal/impl/EffectHalHidl.h
+++ b/media/libaudiohal/impl/EffectHalHidl.h
@@ -61,6 +61,8 @@
     // Whether it's a local implementation.
     virtual bool isLocal() const { return false; }
 
+    virtual status_t dump(int fd);
+
     uint64_t effectId() const { return mEffectId; }
 
     static void effectDescriptorToHal(
diff --git a/media/libaudiohal/include/media/audiohal/EffectHalInterface.h b/media/libaudiohal/include/media/audiohal/EffectHalInterface.h
index 92622aa..03165bd 100644
--- a/media/libaudiohal/include/media/audiohal/EffectHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/EffectHalInterface.h
@@ -55,6 +55,8 @@
     // Whether it's a local implementation.
     virtual bool isLocal() const = 0;
 
+    virtual status_t dump(int fd) = 0;
+
   protected:
     // Subclasses can not be constructed directly by clients.
     EffectHalInterface() {}
diff --git a/media/libeffects/downmix/tests/Android.bp b/media/libeffects/downmix/tests/Android.bp
index e2e7dbd..63afc54 100644
--- a/media/libeffects/downmix/tests/Android.bp
+++ b/media/libeffects/downmix/tests/Android.bp
@@ -24,7 +24,6 @@
     ],
 
     cflags: [
-        "-v",
         "-Werror",
         "-Wextra",
     ],
diff --git a/media/libeffects/lvm/tests/lvmtest.cpp b/media/libeffects/lvm/tests/lvmtest.cpp
index fe47d0b..416bdaa 100644
--- a/media/libeffects/lvm/tests/lvmtest.cpp
+++ b/media/libeffects/lvm/tests/lvmtest.cpp
@@ -15,6 +15,7 @@
  */
 #include <assert.h>
 #include <inttypes.h>
+#include <iterator>
 #include <math.h>
 #include <stdlib.h>
 #include <string.h>
@@ -102,20 +103,15 @@
   printf("\n     -M");
   printf("\n           Mono mode (force all input audio channels to be identical)");
   printf("\n     -basslvl:<effect_level>");
-  printf("\n           A value that ranges between 0 - 15 default 0");
+  printf("\n           A value that ranges between %d - %d default 0", LVM_BE_MIN_EFFECTLEVEL,
+    LVM_BE_MAX_EFFECTLEVEL);
   printf("\n");
   printf("\n     -eqPreset:<preset Value>");
-  printf("\n           0 - Normal");
-  printf("\n           1 - Classical");
-  printf("\n           2 - Dance");
-  printf("\n           3 - Flat");
-  printf("\n           4 - Folk");
-  printf("\n           5 - Heavy Metal");
-  printf("\n           6 - Hip Hop");
-  printf("\n           7 - Jazz");
-  printf("\n           8 - Pop");
-  printf("\n           9 - Rock");
-  printf("\n           default 0");
+  const size_t numPresetLvls  = std::size(gEqualizerPresets);
+  for (size_t i = 0; i < numPresetLvls; ++i) {
+    printf("\n           %zu - %s", i, gEqualizerPresets[i].name);
+  }
+  printf("\n           default - 0");
   printf("\n     -bE ");
   printf("\n           Enable Dynamic Bass Enhancement");
   printf("\n");
@@ -619,7 +615,7 @@
             std::fill(fp + 1, fp + channelCount, *fp); // replicate ch 0
         }
     }
-#if 1
+#ifndef BYPASS_EXEC
     errCode = lvmExecute(floatIn.data(), floatOut.data(), pContext, plvmConfigParams);
     if (errCode) {
       printf("\nError: lvmExecute returned with %d\n", errCode);
@@ -689,7 +685,7 @@
           lvmConfigParams.monoMode = true;
     } else if (!strncmp(argv[i], "-basslvl:", 9)) {
       const int bassEffectLevel = atoi(argv[i] + 9);
-      if (bassEffectLevel > 15 || bassEffectLevel < 0) {
+      if (bassEffectLevel > LVM_BE_MAX_EFFECTLEVEL || bassEffectLevel < LVM_BE_MIN_EFFECTLEVEL) {
         printf("Error: Unsupported Bass Effect Level : %d\n",
                bassEffectLevel);
         printUsage();
@@ -698,7 +694,8 @@
       lvmConfigParams.bassEffectLevel = bassEffectLevel;
     } else if (!strncmp(argv[i], "-eqPreset:", 10)) {
       const int eqPresetLevel = atoi(argv[i] + 10);
-      if (eqPresetLevel > 9 || eqPresetLevel < 0) {
+      const int numPresetLvls = std::size(gEqualizerPresets);
+      if (eqPresetLevel >= numPresetLvls || eqPresetLevel < 0) {
         printf("Error: Unsupported Equalizer Preset : %d\n", eqPresetLevel);
         printUsage();
         return -1;
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 5853e4b..9799cad 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -259,6 +259,7 @@
     name: "libmedia_player2_util",
 
     srcs: [
+        "AudioParameter.cpp",
         "BufferingSettings.cpp",
         "DataSourceDesc.cpp",
         "MediaCodecBuffer.cpp",
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
index cbd64bb..ea0547c 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -96,6 +96,7 @@
 
 static const char *AMediaFormatKeyGroupInt64[] = {
     AMEDIAFORMAT_KEY_DURATION,
+    AMEDIAFORMAT_KEY_MAX_PTS_GAP_TO_ENCODER,
     AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER,
     AMEDIAFORMAT_KEY_TIME_US,
 };
@@ -127,6 +128,7 @@
 static const char *AMediaFormatKeyGroupFloatInt32[] = {
     AMEDIAFORMAT_KEY_FRAME_RATE,
     AMEDIAFORMAT_KEY_I_FRAME_INTERVAL,
+    AMEDIAFORMAT_KEY_MAX_FPS_TO_ENCODER,
     AMEDIAFORMAT_KEY_OPERATING_RATE,
 };
 
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmedia/TypeConverter.cpp
index 8dac91a..0301b21 100644
--- a/media/libmedia/TypeConverter.cpp
+++ b/media/libmedia/TypeConverter.cpp
@@ -415,14 +415,6 @@
             OutputDeviceConverter::fromString(literalDevice, device);
 }
 
-bool deviceToString(audio_devices_t device, std::string& literalDevice) {
-    if (device & AUDIO_DEVICE_BIT_IN) {
-        return InputDeviceConverter::toString(device, literalDevice);
-    } else {
-        return OutputDeviceConverter::toString(device, literalDevice);
-    }
-}
-
 SampleRateTraits::Collection samplingRatesFromString(
         const std::string &samplingRates, const char *del)
 {
diff --git a/media/libmedia/include/media/TypeConverter.h b/media/libmedia/include/media/TypeConverter.h
index 418e09c..3acfe98 100644
--- a/media/libmedia/include/media/TypeConverter.h
+++ b/media/libmedia/include/media/TypeConverter.h
@@ -233,8 +233,6 @@
 
 bool deviceFromString(const std::string& literalDevice, audio_devices_t& device);
 
-bool deviceToString(audio_devices_t device, std::string& literalDevice);
-
 SampleRateTraits::Collection samplingRatesFromString(
         const std::string &samplingRates, const char *del = AudioParameter::valueListSeparator);
 
@@ -255,47 +253,53 @@
 OutputChannelTraits::Collection outputChannelMasksFromString(
         const std::string &outChannels, const char *del = AudioParameter::valueListSeparator);
 
-static inline std::string toString(audio_usage_t usage)
+// counting enumerations
+template <typename T, std::enable_if_t<std::is_same<T, audio_content_type_t>::value
+                                    || std::is_same<T, audio_mode_t>::value
+                                    || std::is_same<T, audio_source_t>::value
+                                    || std::is_same<T, audio_stream_type_t>::value
+                                    || std::is_same<T, audio_usage_t>::value
+                                    , int> = 0>
+static inline std::string toString(const T& value)
 {
-    std::string usageLiteral;
-    if (!android::UsageTypeConverter::toString(usage, usageLiteral)) {
-        ALOGV("failed to convert usage: %d", usage);
-        return "AUDIO_USAGE_UNKNOWN";
-    }
-    return usageLiteral;
+    std::string result;
+    return TypeConverter<DefaultTraits<T>>::toString(value, result)
+            ? result : std::to_string(static_cast<int>(value));
+
 }
 
-static inline std::string toString(audio_content_type_t content)
+// flag enumerations
+template <typename T, std::enable_if_t<std::is_same<T, audio_gain_mode_t>::value
+                                    || std::is_same<T, audio_input_flags_t>::value
+                                    || std::is_same<T, audio_output_flags_t>::value
+                                    , int> = 0>
+static inline std::string toString(const T& value)
 {
-    std::string contentLiteral;
-    if (!android::AudioContentTypeConverter::toString(content, contentLiteral)) {
-        ALOGV("failed to convert content type: %d", content);
-        return "AUDIO_CONTENT_TYPE_UNKNOWN";
-    }
-    return contentLiteral;
+    std::string result;
+    TypeConverter<DefaultTraits<T>>::maskToString(value, result);
+    return result;
 }
 
-static inline std::string toString(audio_stream_type_t stream)
+static inline std::string toString(const audio_devices_t& devices)
 {
-    std::string streamLiteral;
-    if (!android::StreamTypeConverter::toString(stream, streamLiteral)) {
-        ALOGV("failed to convert stream: %d", stream);
-        return "AUDIO_STREAM_DEFAULT";
+    std::string result;
+    if ((devices & AUDIO_DEVICE_BIT_IN) != 0) {
+        InputDeviceConverter::maskToString(devices, result);
+    } else {
+        OutputDeviceConverter::maskToString(devices, result);
     }
-    return streamLiteral;
+    return result;
 }
 
-static inline std::string toString(audio_source_t source)
+// TODO: Remove when FormatTraits uses DefaultTraits.
+static inline std::string toString(const audio_format_t& format)
 {
-    std::string sourceLiteral;
-    if (!android::SourceTypeConverter::toString(source, sourceLiteral)) {
-        ALOGV("failed to convert source: %d", source);
-        return "AUDIO_SOURCE_DEFAULT";
-    }
-    return sourceLiteral;
+    std::string result;
+    return TypeConverter<VectorTraits<audio_format_t>>::toString(format, result)
+            ? result : std::to_string(static_cast<int>(format));
 }
 
-static inline std::string toString(const audio_attributes_t &attributes)
+static inline std::string toString(const audio_attributes_t& attributes)
 {
     std::ostringstream result;
     result << "{ Content type: " << toString(attributes.content_type)
@@ -308,16 +312,6 @@
     return result.str();
 }
 
-static inline std::string toString(audio_mode_t mode)
-{
-    std::string modeLiteral;
-    if (!android::AudioModeConverter::toString(mode, modeLiteral)) {
-        ALOGV("failed to convert mode: %d", mode);
-        return "AUDIO_MODE_INVALID";
-    }
-    return modeLiteral;
-}
-
 }; // namespace android
 
 #endif  /*ANDROID_TYPE_CONVERTER_H_*/
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 22fa495..46a1c24 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -64,8 +64,6 @@
 
     name: "libmediaplayerservice",
 
-    compile_multilib: "32",
-
     sanitize: {
         cfi: true,
     },
diff --git a/media/libmediaplayerservice/tests/Android.bp b/media/libmediaplayerservice/tests/Android.bp
index 4749a8b..f8c89e5 100644
--- a/media/libmediaplayerservice/tests/Android.bp
+++ b/media/libmediaplayerservice/tests/Android.bp
@@ -14,8 +14,6 @@
         "android.hardware.drm@1.2",
     ],
 
-    compile_multilib: "32",
-
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 2ea5fcd..9eba7e9 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -85,7 +85,7 @@
     CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC));
     CHECK(meta->findInt32(kKeyChannelCount, &mChannelCount));
     CHECK(meta->findInt32(kKeySampleRate, &mSampleRate));
-    CHECK(mChannelCount >= 1 && mChannelCount <= 2);
+    CHECK(mChannelCount >= 1 && mChannelCount <= 7);
 
     // Optionally, we want to check whether AACProfile is also set.
     if (meta->findInt32(kKeyAACProfile, &mAACProfile)) {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 9d3338b..1dee4f7 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -37,6 +37,7 @@
 
 #include <media/stagefright/BufferProducerWrapper.h>
 #include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/OMXClient.h>
 #include <media/stagefright/PersistentSurface.h>
@@ -1817,20 +1818,19 @@
         }
 
         if (!msg->findInt64(
-                    "repeat-previous-frame-after",
-                    &mRepeatFrameDelayUs)) {
+                KEY_REPEAT_PREVIOUS_FRAME_AFTER, &mRepeatFrameDelayUs)) {
             mRepeatFrameDelayUs = -1LL;
         }
 
         // only allow 32-bit value, since we pass it as U32 to OMX.
-        if (!msg->findInt64("max-pts-gap-to-encoder", &mMaxPtsGapUs)) {
+        if (!msg->findInt64(KEY_MAX_PTS_GAP_TO_ENCODER, &mMaxPtsGapUs)) {
             mMaxPtsGapUs = 0LL;
         } else if (mMaxPtsGapUs > INT32_MAX || mMaxPtsGapUs < INT32_MIN) {
             ALOGW("Unsupported value for max pts gap %lld", (long long) mMaxPtsGapUs);
             mMaxPtsGapUs = 0LL;
         }
 
-        if (!msg->findFloat("max-fps-to-encoder", &mMaxFps)) {
+        if (!msg->findFloat(KEY_MAX_FPS_TO_ENCODER, &mMaxFps)) {
             mMaxFps = -1;
         }
 
@@ -1844,8 +1844,8 @@
         }
 
         if (!msg->findInt32(
-                    "create-input-buffers-suspended",
-                    (int32_t*)&mCreateInputBuffersSuspended)) {
+                KEY_CREATE_INPUT_SURFACE_SUSPENDED,
+                (int32_t*)&mCreateInputBuffersSuspended)) {
             mCreateInputBuffersSuspended = false;
         }
     }
@@ -7431,7 +7431,7 @@
     }
 
     int64_t timeOffsetUs;
-    if (params->findInt64("time-offset-us", &timeOffsetUs)) {
+    if (params->findInt64(PARAMETER_KEY_OFFSET_TIME, &timeOffsetUs)) {
         if (mGraphicBufferSource == NULL) {
             ALOGE("[%s] Invalid to set input buffer time offset without surface",
                     mComponentName.c_str());
@@ -7467,7 +7467,7 @@
     }
 
     int32_t dropInputFrames;
-    if (params->findInt32("drop-input-frames", &dropInputFrames)) {
+    if (params->findInt32(PARAMETER_KEY_SUSPEND, &dropInputFrames)) {
         if (mGraphicBufferSource == NULL) {
             ALOGE("[%s] Invalid to set suspend without surface",
                     mComponentName.c_str());
@@ -7475,7 +7475,7 @@
         }
 
         int64_t suspendStartTimeUs = -1;
-        (void) params->findInt64("drop-start-time-us", &suspendStartTimeUs);
+        (void) params->findInt64(PARAMETER_KEY_SUSPEND_TIME, &suspendStartTimeUs);
         status_t err = statusFromBinderStatus(
                 mGraphicBufferSource->setSuspend(dropInputFrames != 0, suspendStartTimeUs));
 
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 488890d..d8b825d 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -199,7 +199,6 @@
         "libhidlallocatorutils",
         "libhidlbase",
         "libhidlmemory",
-        "libziparchive",
         "android.hidl.allocator@1.0",
         "android.hardware.cas.native@1.0",
         "android.hardware.media.omx@1.0",
@@ -265,9 +264,11 @@
     srcs: [
         "ClearFileSource.cpp",
         "DataURISource.cpp",
+        "DataSourceBase.cpp",
         "HTTPBase.cpp",
         "HevcUtils.cpp",
         "MediaClock.cpp",
+        "MediaSource.cpp",
         "NdkUtils.cpp",
         "Utils.cpp",
         "VideoFrameSchedulerBase.cpp",
diff --git a/media/libstagefright/HevcUtils.cpp b/media/libstagefright/HevcUtils.cpp
index f152a38..0c38f2e 100644
--- a/media/libstagefright/HevcUtils.cpp
+++ b/media/libstagefright/HevcUtils.cpp
@@ -457,8 +457,8 @@
         if (numNalus == 0) {
             continue;
         }
-        // array_completeness set to 0.
-        header[0] = type;
+        // array_completeness set to 1.
+        header[0] = type | 0x80;
         header[1] = (numNalus >> 8) & 0xff;
         header[2] = numNalus & 0xff;
         header += 3;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 6259b15..f6ed0f1 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -3128,8 +3128,8 @@
         if (!mIsHeic) {
             if (mStszTableEntries->count() == 0) {
                 mFirstSampleTimeRealUs = systemTime() / 1000;
+                mOwner->setStartTimestampUs(timestampUs);
                 mStartTimestampUs = timestampUs;
-                mOwner->setStartTimestampUs(mStartTimestampUs);
                 previousPausedDurationUs = mStartTimestampUs;
             }
 
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 9c58e05..d4e4000 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1973,10 +1973,11 @@
 
                 case kWhatComponentConfigured:
                 {
-                    if (mState == UNINITIALIZED || mState == INITIALIZED) {
-                        // In case a kWhatError message came in and replied with error,
+                    if (mState == RELEASING || mState == UNINITIALIZED || mState == INITIALIZED) {
+                        // In case a kWhatError or kWhatRelease message came in and replied,
                         // we log a warning and ignore.
-                        ALOGW("configure interrupted by error, current state %d", mState);
+                        ALOGW("configure interrupted by error or release, current state %d",
+                              mState);
                         break;
                     }
                     CHECK_EQ(mState, CONFIGURING);
@@ -2067,6 +2068,13 @@
 
                 case kWhatStartCompleted:
                 {
+                    if (mState == RELEASING || mState == UNINITIALIZED) {
+                        // In case a kWhatRelease message came in and replied,
+                        // we log a warning and ignore.
+                        ALOGW("start interrupted by release, current state %d", mState);
+                        break;
+                    }
+
                     CHECK_EQ(mState, STARTING);
                     if (mIsVideo) {
                         addResource(
@@ -2632,11 +2640,12 @@
                 break;
             }
 
-            // If we're flushing, or we're stopping but received a release
-            // request, post the reply for the pending call first, and consider
-            // it done. The reply token will be replaced after this, and we'll
-            // no longer be able to reply.
-            if (mState == FLUSHING || mState == STOPPING) {
+            // If we're flushing, stopping, configuring or starting  but
+            // received a release request, post the reply for the pending call
+            // first, and consider it done. The reply token will be replaced
+            // after this, and we'll no longer be able to reply.
+            if (mState == FLUSHING || mState == STOPPING
+                    || mState == CONFIGURING || mState == STARTING) {
                 (new AMessage)->postReply(mReplyID);
             }
 
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 5d2291f..c3d85ee 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -32,6 +32,7 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaCodecSource.h>
 #include <media/stagefright/MediaErrors.h>
@@ -362,7 +363,7 @@
 
 status_t MediaCodecSource::setInputBufferTimeOffset(int64_t timeOffsetUs) {
     sp<AMessage> msg = new AMessage(kWhatSetInputBufferTimeOffset, mReflector);
-    msg->setInt64("time-offset-us", timeOffsetUs);
+    msg->setInt64(PARAMETER_KEY_OFFSET_TIME, timeOffsetUs);
     return postSynchronouslyAndReturnError(msg);
 }
 
@@ -490,7 +491,7 @@
     mCodecLooper->start();
 
     if (mFlags & FLAG_USE_SURFACE_INPUT) {
-        mOutputFormat->setInt32("create-input-buffers-suspended", 1);
+        mOutputFormat->setInt32(KEY_CREATE_INPUT_SURFACE_SUSPENDED, 1);
     }
 
     AString outputMIME;
@@ -677,9 +678,9 @@
     CHECK(mFlags & FLAG_USE_SURFACE_INPUT);
     if (mEncoder != NULL) {
         sp<AMessage> params = new AMessage;
-        params->setInt32("drop-input-frames", false);
+        params->setInt32(PARAMETER_KEY_SUSPEND, false);
         if (resumeStartTimeUs > 0) {
-            params->setInt64("drop-start-time-us", resumeStartTimeUs);
+            params->setInt64(PARAMETER_KEY_SUSPEND_TIME, resumeStartTimeUs);
         }
         mEncoder->setParameters(params);
     }
@@ -799,7 +800,7 @@
     if (mFlags & FLAG_USE_SURFACE_INPUT) {
         if (mEncoder != NULL) {
             sp<AMessage> params = new AMessage;
-            params->setInt32("drop-input-frames", false);
+            params->setInt32(PARAMETER_KEY_SUSPEND, false);
             if (startTimeUs >= 0) {
                 params->setInt64("skip-frames-before", startTimeUs);
             }
@@ -832,8 +833,8 @@
 void MediaCodecSource::onPause(int64_t pauseStartTimeUs) {
     if ((mFlags & FLAG_USE_SURFACE_INPUT) && (mEncoder != NULL)) {
         sp<AMessage> params = new AMessage;
-        params->setInt32("drop-input-frames", true);
-        params->setInt64("drop-start-time-us", pauseStartTimeUs);
+        params->setInt32(PARAMETER_KEY_SUSPEND, true);
+        params->setInt64(PARAMETER_KEY_SUSPEND_TIME, pauseStartTimeUs);
         mEncoder->setParameters(params);
     } else {
         CHECK(mPuller != NULL);
@@ -1096,12 +1097,12 @@
         sp<AReplyToken> replyID;
         CHECK(msg->senderAwaitsResponse(&replyID));
         status_t err = OK;
-        CHECK(msg->findInt64("time-offset-us", &mInputBufferTimeOffsetUs));
+        CHECK(msg->findInt64(PARAMETER_KEY_OFFSET_TIME, &mInputBufferTimeOffsetUs));
 
         // Propagate the timestamp offset to GraphicBufferSource.
         if (mFlags & FLAG_USE_SURFACE_INPUT) {
             sp<AMessage> params = new AMessage;
-            params->setInt64("time-offset-us", mInputBufferTimeOffsetUs);
+            params->setInt64(PARAMETER_KEY_OFFSET_TIME, mInputBufferTimeOffsetUs);
             err = mEncoder->setParameters(params);
         }
 
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index a938d51..a309ee4 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -23,8 +23,6 @@
 #include <binder/PermissionCache.h>
 #include <binder/IServiceManager.h>
 #include <media/DataSource.h>
-#include <media/MediaAnalyticsItem.h>
-#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaExtractorFactory.h>
@@ -34,7 +32,6 @@
 #include <private/android_filesystem_config.h>
 #include <cutils/properties.h>
 #include <utils/String8.h>
-#include <ziparchive/zip_archive.h>
 
 #include <dirent.h>
 #include <dlfcn.h>
@@ -130,13 +127,6 @@
 std::shared_ptr<std::list<sp<ExtractorPlugin>>> MediaExtractorFactory::gPlugins;
 bool MediaExtractorFactory::gPluginsRegistered = false;
 bool MediaExtractorFactory::gIgnoreVersion = false;
-std::string MediaExtractorFactory::gLinkedLibraries;
-
-// static
-void MediaExtractorFactory::SetLinkedLibraries(const std::string& linkedLibraries) {
-    Mutex::Autolock autoLock(gPluginMutex);
-    gLinkedLibraries = linkedLibraries;
-}
 
 // static
 void *MediaExtractorFactory::sniff(
@@ -235,9 +225,11 @@
 }
 
 //static
-void MediaExtractorFactory::RegisterExtractorsInSystem(
-        const char *libDirPath, std::list<sp<ExtractorPlugin>> &pluginList) {
+void MediaExtractorFactory::RegisterExtractors(
+        const char *libDirPath, const android_dlextinfo* dlextinfo,
+        std::list<sp<ExtractorPlugin>> &pluginList) {
     ALOGV("search for plugins at %s", libDirPath);
+
     DIR *libDir = opendir(libDirPath);
     if (libDir) {
         struct dirent* libEntry;
@@ -246,73 +238,12 @@
                 continue;
             }
             String8 libPath = String8(libDirPath) + "/" + libEntry->d_name;
-            void *libHandle = dlopen(libPath.string(), RTLD_NOW | RTLD_LOCAL);
-            if (libHandle) {
-                GetExtractorDef getDef =
-                    (GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
-                if (getDef) {
-                    ALOGV("registering sniffer for %s", libPath.string());
-                    RegisterExtractor(
-                            new ExtractorPlugin(getDef(), libHandle, libPath), pluginList);
-                } else {
-                    ALOGW("%s does not contain sniffer", libPath.string());
-                    dlclose(libHandle);
-                }
-            } else {
-                ALOGW("couldn't dlopen(%s) %s", libPath.string(), strerror(errno));
-            }
-        }
-
-        closedir(libDir);
-    } else {
-        ALOGE("couldn't opendir(%s)", libDirPath);
-    }
-}
-
-//static
-void MediaExtractorFactory::RegisterExtractorsInApex(
-        const char *libDirPath, std::list<sp<ExtractorPlugin>> &pluginList) {
-    ALOGV("search for plugins at %s", libDirPath);
-    ALOGV("linked libs %s", gLinkedLibraries.c_str());
-
-    std::string libDirPathEx = libDirPath;
-    libDirPathEx += "/extractors";
-    android_namespace_t *extractorNs = android_create_namespace("extractor",
-            nullptr,  // ld_library_path
-            libDirPath,  // default_library_path
-            ANDROID_NAMESPACE_TYPE_ISOLATED,
-            libDirPathEx.c_str(),  // permitted_when_isolated_path
-            nullptr); // parent
-    if (!android_link_namespaces(extractorNs, nullptr, gLinkedLibraries.c_str())) {
-        ALOGE("Failed to link namespace. Failed to load extractor plug-ins in apex.");
-        return;
-    }
-    const android_dlextinfo dlextinfo = {
-        .flags = ANDROID_DLEXT_USE_NAMESPACE,
-        .library_namespace = extractorNs,
-    };
-
-    // try extractors subfolder first
-    DIR *libDir = opendir(libDirPathEx.c_str());
-
-    if (libDir) {
-        libDirPath = libDirPathEx.c_str();
-    } else {
-        libDir = opendir(libDirPath);
-    }
-    if (libDir) {
-        struct dirent* libEntry;
-        while ((libEntry = readdir(libDir))) {
-            if (libEntry->d_name[0] == '.') {
-                continue;
-            }
-            String8 libPath = String8(libDirPath) + "/" + libEntry->d_name;
             if (!libPath.contains("extractor.so")) {
                 continue;
             }
             void *libHandle = android_dlopen_ext(
                     libPath.string(),
-                    RTLD_NOW | RTLD_LOCAL, &dlextinfo);
+                    RTLD_NOW | RTLD_LOCAL, dlextinfo);
             if (libHandle) {
                 GetExtractorDef getDef =
                     (GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
@@ -352,17 +283,27 @@
 
     std::shared_ptr<std::list<sp<ExtractorPlugin>>> newList(new std::list<sp<ExtractorPlugin>>());
 
-    RegisterExtractorsInApex("/apex/com.android.media/lib"
+    android_namespace_t *mediaNs = android_get_exported_namespace("media");
+    if (mediaNs != NULL) {
+        const android_dlextinfo dlextinfo = {
+            .flags = ANDROID_DLEXT_USE_NAMESPACE,
+            .library_namespace = mediaNs,
+        };
+        RegisterExtractors("/apex/com.android.media/lib"
 #ifdef __LP64__
-            "64"
+                "64"
 #endif
-            , *newList);
+                "/extractors", &dlextinfo, *newList);
 
-    RegisterExtractorsInSystem("/system/lib"
+    } else {
+        ALOGE("couldn't find media namespace.");
+    }
+
+    RegisterExtractors("/system/lib"
 #ifdef __LP64__
             "64"
 #endif
-            "/extractors", *newList);
+            "/extractors", NULL, *newList);
 
     newList->sort(compareFunc);
     gPlugins = newList;
diff --git a/media/libstagefright/OggWriter.cpp b/media/libstagefright/OggWriter.cpp
index 5c13983..cb87b55 100644
--- a/media/libstagefright/OggWriter.cpp
+++ b/media/libstagefright/OggWriter.cpp
@@ -295,6 +295,18 @@
                   mEstimatedSizeBytes, mMaxFileSizeLimitBytes);
             break;
         }
+
+        int32_t isCodecSpecific;
+        if ((buffer->meta_data().findInt32(kKeyIsCodecConfig, &isCodecSpecific)
+             && isCodecSpecific)
+            || IsOpusHeader((uint8_t*)buffer->data() + buffer->range_offset(),
+                         buffer->range_length())) {
+            ALOGV("Drop codec specific info buffer");
+            buffer->release();
+            buffer = nullptr;
+            continue;
+        }
+
         int64_t timestampUs;
         CHECK(buffer->meta_data().findInt64(kKeyTime, &timestampUs));
         if (timestampUs > mEstimatedDurationUs) {
diff --git a/media/libstagefright/codecs/raw/SoftRaw.cpp b/media/libstagefright/codecs/raw/SoftRaw.cpp
index 1a527b3..0e31804 100644
--- a/media/libstagefright/codecs/raw/SoftRaw.cpp
+++ b/media/libstagefright/codecs/raw/SoftRaw.cpp
@@ -60,7 +60,7 @@
     def.eDir = OMX_DirInput;
     def.nBufferCountMin = kNumBuffers;
     def.nBufferCountActual = def.nBufferCountMin;
-    def.nBufferSize = 64 * 1024;
+    def.nBufferSize = 192 * 1024;
     def.bEnabled = OMX_TRUE;
     def.bPopulated = OMX_FALSE;
     def.eDomain = OMX_PortDomainAudio;
@@ -78,7 +78,7 @@
     def.eDir = OMX_DirOutput;
     def.nBufferCountMin = kNumBuffers;
     def.nBufferCountActual = def.nBufferCountMin;
-    def.nBufferSize = 64 * 1024;
+    def.nBufferSize = 192 * 1024;
     def.bEnabled = OMX_TRUE;
     def.bPopulated = OMX_FALSE;
     def.eDomain = OMX_PortDomainAudio;
diff --git a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
index 8a86a0d..da86758 100644
--- a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
+++ b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
@@ -1178,6 +1178,8 @@
     int i_target_loudness;
     unsigned int i_sbr_mode;
     int i;
+    int ui_proc_mem_tabs_size = 0;
+    pVOID pv_alloc_ptr = NULL;
 
 #ifdef ENABLE_MPEG_D_DRC
     {
@@ -1228,6 +1230,29 @@
                                     IA_ENHAACPLUS_DEC_CONFIG_PARAM_SBR_MODE, &i_sbr_mode);
         RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_SBR_MODE");
 
+        /* Get memory info tables size */
+        err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEMTABS_SIZE, 0,
+                                  &ui_proc_mem_tabs_size);
+
+        RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEMTABS_SIZE");
+
+        pv_alloc_ptr = memalign(4, ui_proc_mem_tabs_size);
+
+        if (pv_alloc_ptr == NULL) {
+            ALOGE("Cannot create requested memory  %d", ui_proc_mem_tabs_size);
+            return IA_FATAL_ERROR;
+        }
+
+        memset(pv_alloc_ptr, 0, ui_proc_mem_tabs_size);
+
+        mMemoryVec.push(pv_alloc_ptr);
+
+        /* Set pointer for process memory tables */
+        err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEMTABS_PTR, 0,
+                                  pv_alloc_ptr);
+
+        RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEMTABS_PTR");
+
         err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
                                   IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS, NULL);
 
diff --git a/media/libstagefright/foundation/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
index 9faede1..acb9ccf 100644
--- a/media/libstagefright/foundation/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -15,9 +15,9 @@
  */
 
 //#define LOG_NDEBUG 0
-#define LOG_TAG "SoftOpus"
-#include <algorithm>
+#define LOG_TAG "OpusHeader"
 #include <cstring>
+#include <inttypes.h>
 #include <stdint.h>
 
 #include <log/log.h>
@@ -91,6 +91,9 @@
 
 // Parses Opus Header. Header spec: http://wiki.xiph.org/OggOpus#ID_Header
 bool ParseOpusHeader(const uint8_t* data, size_t data_size, OpusHeader* header) {
+    if (data == NULL) {
+        return false;
+    }
     if (data_size < kOpusHeaderSize) {
         ALOGV("Header size is too small.");
         return false;
@@ -183,53 +186,88 @@
         ALOGD("Buffer not large enough to hold unified OPUS CSD");
         return -1;
     }
+    int headerLen = 0;
 
-    int headerLen = WriteOpusHeader(header, inputSampleRate, output,
+    // Add opus header
+    /*
+      Following is the CSD syntax for signalling OpusHeader
+      (http://wiki.xiph.org/OggOpus#ID_Header)
+
+      Marker (8 bytes) | Length (8 bytes) | OpusHeader
+
+      Markers supported:
+      AOPUS_CSD_OPUS_HEADER_MARKER - Signals Opus Header
+
+      Length should be a value within AOPUS_OPUSHEAD_MINSIZE and AOPUS_OPUSHEAD_MAXSIZE.
+    */
+
+    memcpy(output + headerLen, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE);
+    headerLen += AOPUS_MARKER_SIZE;
+
+    // Place holder for opusHeader Size
+    headerLen += AOPUS_LENGTH_SIZE;
+
+    int headerSize = WriteOpusHeader(header, inputSampleRate, output + headerLen,
         outputSize);
-    if (headerLen < 0) {
-        ALOGD("WriteOpusHeader failed");
+    if (headerSize < 0) {
+        ALOGD("%s: WriteOpusHeader failed", __func__);
         return -1;
     }
-    if (headerLen >= (outputSize - 2 * AOPUS_TOTAL_CSD_SIZE)) {
-        ALOGD("Buffer not large enough to hold codec delay and seek pre roll");
-        return -1;
-    }
+    headerLen += headerSize;
 
-    uint64_t length = AOPUS_LENGTH;
+    // Update opus headerSize after AOPUS_CSD_OPUS_HEADER_MARKER
+    uint64_t length = headerSize;
+    memcpy(output + AOPUS_MARKER_SIZE, &length, AOPUS_LENGTH_SIZE);
 
     /*
       Following is the CSD syntax for signalling codec delay and
       seek pre-roll which is to be appended after OpusHeader
 
-      Marker (8 bytes) | Length (8 bytes) | Samples (8 bytes)
+      Marker (8 bytes) | Length (8 bytes) | Samples in ns (8 bytes)
 
       Markers supported:
-      AOPUSDLY - Signals Codec Delay
-      AOPUSPRL - Signals seek pre roll
+      AOPUS_CSD_CODEC_DELAY_MARKER - codec delay as samples in ns, represented in 8 bytes
+      AOPUS_CSD_SEEK_PREROLL_MARKER - preroll adjustment as samples in ns, represented in 8 bytes
 
-      Length should be 8.
     */
-
+    length = sizeof(codecDelay);
+    if (headerLen > (outputSize - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE - length)) {
+        ALOGD("Buffer not large enough to hold codec delay");
+        return -1;
+    }
     // Add codec delay
     memcpy(output + headerLen, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE);
     headerLen += AOPUS_MARKER_SIZE;
     memcpy(output + headerLen, &length, AOPUS_LENGTH_SIZE);
     headerLen += AOPUS_LENGTH_SIZE;
-    memcpy(output + headerLen, &codecDelay, AOPUS_CSD_SIZE);
-    headerLen += AOPUS_CSD_SIZE;
+    memcpy(output + headerLen, &codecDelay, length);
+    headerLen += length;
 
+    length = sizeof(seekPreRoll);
+    if (headerLen > (outputSize - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE - length)) {
+        ALOGD("Buffer not large enough to hold seek pre roll");
+        return -1;
+    }
     // Add skip pre roll
     memcpy(output + headerLen, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE);
     headerLen += AOPUS_MARKER_SIZE;
     memcpy(output + headerLen, &length, AOPUS_LENGTH_SIZE);
     headerLen += AOPUS_LENGTH_SIZE;
-    memcpy(output + headerLen, &seekPreRoll, AOPUS_CSD_SIZE);
-    headerLen += AOPUS_CSD_SIZE;
+    memcpy(output + headerLen, &seekPreRoll, length);
+    headerLen += length;
 
     return headerLen;
 }
 
-void GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
+bool IsOpusHeader(const uint8_t *data, size_t data_size) {
+    if (data_size < AOPUS_MARKER_SIZE) {
+        return false;
+    }
+
+    return !memcmp(data, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE);
+}
+
+bool GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
                           void **opusHeadBuf, size_t *opusHeadSize,
                           void **codecDelayBuf, size_t *codecDelaySize,
                           void **seekPreRollBuf, size_t *seekPreRollSize) {
@@ -237,26 +275,77 @@
     *codecDelaySize = 0;
     *seekPreRollBuf = NULL;
     *seekPreRollSize = 0;
-    *opusHeadBuf = (void *)data;
-    *opusHeadSize = data_size;
-    if (data_size >= AOPUS_UNIFIED_CSD_MINSIZE) {
+    *opusHeadBuf = NULL;
+    *opusHeadSize = 0;
+
+    // AOPUS_MARKER_SIZE is 8 "OpusHead" is of size 8
+    if (data_size < 8)
+        return false;
+
+    // Check if the CSD is in legacy format
+    if (!memcmp("OpusHead", data, 8)) {
+        if (data_size < AOPUS_OPUSHEAD_MINSIZE || data_size > AOPUS_OPUSHEAD_MAXSIZE) {
+            ALOGD("Unexpected size for opusHeadSize %zu", data_size);
+            return false;
+        }
+        *opusHeadBuf = (void *)data;
+        *opusHeadSize = data_size;
+        return true;
+    } else if (memcmp(AOPUS_CSD_MARKER_PREFIX, data, AOPUS_CSD_MARKER_PREFIX_SIZE) == 0) {
         size_t i = 0;
-        while (i < data_size - AOPUS_TOTAL_CSD_SIZE) {
+        bool found = false;
+        while (i <= data_size - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE) {
             uint8_t *csdBuf = (uint8_t *)data + i;
-            if (!memcmp(csdBuf, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE)) {
-                *opusHeadSize = std::min(*opusHeadSize, i);
+            if (!memcmp(csdBuf, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE)) {
+                uint64_t value;
+                memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
+                if (value < AOPUS_OPUSHEAD_MINSIZE || value > AOPUS_OPUSHEAD_MAXSIZE) {
+                    ALOGD("Unexpected size for opusHeadSize %" PRIu64, value);
+                    return false;
+                }
+                i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
+                if (i > data_size) {
+                    ALOGD("Marker signals a header that is larger than input");
+                    return false;
+                }
+                *opusHeadBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
+                *opusHeadSize = value;
+                found = true;
+            } else if (!memcmp(csdBuf, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE)) {
+                uint64_t value;
+                memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
+                if (value != sizeof(uint64_t)) {
+                    ALOGD("Unexpected size for codecDelay %" PRIu64, value);
+                    return false;
+                }
+                i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
+                if (i > data_size) {
+                    ALOGD("Marker signals a header that is larger than input");
+                    return false;
+                }
                 *codecDelayBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
-                *codecDelaySize = AOPUS_CSD_SIZE;
-                i += AOPUS_TOTAL_CSD_SIZE;
+                *codecDelaySize = value;
             } else if (!memcmp(csdBuf, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE)) {
-                *opusHeadSize = std::min(*opusHeadSize, i);
+                uint64_t value;
+                memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
+                if (value != sizeof(uint64_t)) {
+                    ALOGD("Unexpected size for seekPreRollSize %" PRIu64, value);
+                    return false;
+                }
+                i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
+                if (i > data_size) {
+                    ALOGD("Marker signals a header that is larger than input");
+                    return false;
+                }
                 *seekPreRollBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
-                *seekPreRollSize = AOPUS_CSD_SIZE;
-                i += AOPUS_TOTAL_CSD_SIZE;
+                *seekPreRollSize = value;
             } else {
                 i++;
             }
         }
+        return found;
+    } else {
+        return false;  // it isn't in either format
     }
 }
 
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h b/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h
index 9bffccb..29037af 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h
@@ -25,22 +25,37 @@
 namespace android {
 
 /* Constants used for delimiting Opus CSD */
-#define AOPUS_CSD_CODEC_DELAY_MARKER "AOPUSDLY"
-#define AOPUS_CSD_SEEK_PREROLL_MARKER "AOPUSPRL"
-#define AOPUS_CSD_SIZE 8
-#define AOPUS_LENGTH 8
+#define AOPUS_CSD_MARKER_PREFIX "AOPUS"
+#define AOPUS_CSD_MARKER_PREFIX_SIZE (sizeof(AOPUS_CSD_MARKER_PREFIX) - 1)
+#define AOPUS_CSD_OPUS_HEADER_MARKER AOPUS_CSD_MARKER_PREFIX "HDR"
+#define AOPUS_CSD_CODEC_DELAY_MARKER AOPUS_CSD_MARKER_PREFIX "DLY"
+#define AOPUS_CSD_SEEK_PREROLL_MARKER AOPUS_CSD_MARKER_PREFIX "PRL"
 #define AOPUS_MARKER_SIZE 8
-#define AOPUS_LENGTH_SIZE 8
-#define AOPUS_TOTAL_CSD_SIZE \
-    ((AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + (AOPUS_CSD_SIZE))
-#define AOPUS_CSD0_MINSIZE 19
-#define AOPUS_UNIFIED_CSD_MINSIZE \
-    ((AOPUS_CSD0_MINSIZE) + 2 * (AOPUS_TOTAL_CSD_SIZE))
+#define AOPUS_LENGTH_SIZE sizeof(uint64_t)
+#define AOPUS_CSD_CODEC_DELAY_SIZE \
+     (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + sizeof(uint64_t)
+#define AOPUS_CSD_SEEK_PREROLL_SIZE \
+     (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + sizeof(uint64_t)
 
-/* CSD0 at max can be 22 bytes + max number of channels (255) */
-#define AOPUS_CSD0_MAXSIZE 277
+/* OpusHead csd minimum size is 19 */
+#define AOPUS_OPUSHEAD_MINSIZE 19
+#define AOPUS_CSD_OPUSHEAD_MINSIZE \
+    (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + (AOPUS_OPUSHEAD_MINSIZE)
+
+#define AOPUS_UNIFIED_CSD_MINSIZE \
+    ((AOPUS_CSD_OPUSHEAD_MINSIZE) + \
+     (AOPUS_CSD_CODEC_DELAY_SIZE) + \
+     (AOPUS_CSD_SEEK_PREROLL_SIZE))
+
+/* OpusHead csd at max can be AOPUS_CSD_OPUSHEAD_MINSIZE + 2 + max number of channels (255) */
+#define AOPUS_OPUSHEAD_MAXSIZE ((AOPUS_OPUSHEAD_MINSIZE) + 2 + 255)
+#define AOPUS_CSD_OPUSHEAD_MAXSIZE \
+    (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + (AOPUS_OPUSHEAD_MAXSIZE)
+
 #define AOPUS_UNIFIED_CSD_MAXSIZE \
-    ((AOPUS_CSD0_MAXSIZE) + 2 * (AOPUS_TOTAL_CSD_SIZE))
+    ((AOPUS_CSD_OPUSHEAD_MAXSIZE) + \
+     (AOPUS_CSD_CODEC_DELAY_SIZE) + \
+     (AOPUS_CSD_SEEK_PREROLL_SIZE))
 
 struct OpusHeader {
     int channels;
@@ -54,13 +69,14 @@
 
 bool ParseOpusHeader(const uint8_t* data, size_t data_size, OpusHeader* header);
 int WriteOpusHeader(const OpusHeader &header, int input_sample_rate, uint8_t* output, size_t output_size);
-void GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
+bool GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
                           void **opusHeadBuf, size_t *opusHeadSize,
                           void **codecDelayBuf, size_t *codecDelaySize,
                           void **seekPreRollBuf, size_t *seekPreRollSize);
 int WriteOpusHeaders(const OpusHeader &header, int inputSampleRate,
                      uint8_t* output, size_t outputSize, uint64_t codecDelay,
                      uint64_t seekPreRoll);
+bool IsOpusHeader(const uint8_t *data, size_t data_size);
 }  // namespace android
 
 #endif  // OPUS_HEADER_H_
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
index 4358aac..ea87948 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <unordered_set>
 
+#include <android/dlext.h>
 #include <media/IMediaExtractor.h>
 
 namespace android {
@@ -36,19 +37,16 @@
             const sp<DataSource> &source, const char *mime = NULL);
     static status_t dump(int fd, const Vector<String16>& args);
     static std::unordered_set<std::string> getSupportedTypes();
-    static void SetLinkedLibraries(const std::string& linkedLibraries);
 
 private:
     static Mutex gPluginMutex;
     static std::shared_ptr<std::list<sp<ExtractorPlugin>>> gPlugins;
     static bool gPluginsRegistered;
     static bool gIgnoreVersion;
-    static std::string gLinkedLibraries;
 
-    static void RegisterExtractorsInSystem(
-            const char *libDirPath, std::list<sp<ExtractorPlugin>> &pluginList);
-    static void RegisterExtractorsInApex(
-            const char *libDirPath, std::list<sp<ExtractorPlugin>> &pluginList);
+    static void RegisterExtractors(
+            const char *libDirPath, const android_dlextinfo* dlextinfo,
+            std::list<sp<ExtractorPlugin>> &pluginList);
     static void RegisterExtractor(
             const sp<ExtractorPlugin> &plugin, std::list<sp<ExtractorPlugin>> &pluginList);
 
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
index 82a0631..4302aee 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
@@ -423,6 +423,11 @@
             CHECK_LE(offset + (mOtherDataLenBits / 8), buffer->size());
             offset += mOtherDataLenBits / 8;
         }
+
+        if (i < mNumSubFrames && offset >= buffer->size()) {
+            ALOGW("Skip subframes after %d, total %d", (int)i, (int)mNumSubFrames);
+            break;
+        }
     }
 
     if (offset < buffer->size()) {
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
index 16c7be9..8377723 100644
--- a/media/mediaserver/Android.bp
+++ b/media/mediaserver/Android.bp
@@ -34,6 +34,7 @@
         "frameworks/av/services/mediaresourcemanager",
     ],
 
+    // back to 32-bit, b/126502613
     compile_multilib: "32",
 
     init_rc: ["mediaserver.rc"],
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index ad3c068..bd6a6c6 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -47,6 +47,9 @@
 constexpr unsigned MAX_FILE_CHUNK_SIZE = AIO_BUFS_MAX * AIO_BUF_LEN;
 
 constexpr uint32_t MAX_MTP_FILE_SIZE = 0xFFFFFFFF;
+// Note: POLL_TIMEOUT_MS = 0 means return immediately i.e. no sleep.
+// And this will cause high CPU usage.
+constexpr int32_t POLL_TIMEOUT_MS = 500;
 
 struct timespec ZERO_TIMEOUT = { 0, 0 };
 
@@ -305,7 +308,7 @@
     int error = 0;
 
     while (num_events < min_events) {
-        if (poll(mPollFds, 2, 0) == -1) {
+        if (poll(mPollFds, 2, POLL_TIMEOUT_MS) == -1) {
             PLOG(ERROR) << "Mtp error during poll()";
             return -1;
         }
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 339f622..f9f1acc 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -76,7 +76,7 @@
         "libbinder",
         "libmedia",
         "libmedia_omx",
-        "libmedia_jni",
+        "libmedia_jni_utils",
         "libmediadrm",
         "libstagefright",
         "libstagefright_foundation",
@@ -84,8 +84,7 @@
         "liblog",
         "libutils",
         "libcutils",
-        "libandroid",
-        "libandroid_runtime",
+        "libnativewindow",
         "libbinder",
         "libhidlbase",
         "libgui",
@@ -94,6 +93,12 @@
         "libmediandk_utils",
     ],
 
+    required: [
+        // libmediandk may be used by Java and non-Java things. When lower-level things use it,
+        // they shouldn't have to take on the cost of loading libandroid_runtime.
+        "libandroid_runtime",
+    ],
+
     export_include_dirs: ["include"],
 
     product_variables: {
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
index 20b1667..1883f63 100644
--- a/media/ndk/NdkImage.cpp
+++ b/media/ndk/NdkImage.cpp
@@ -23,7 +23,7 @@
 #include "NdkImageReaderPriv.h"
 
 #include <android_media_Utils.h>
-#include <android_runtime/android_hardware_HardwareBuffer.h>
+#include <private/android/AHardwareBufferHelpers.h>
 #include <utils/Log.h>
 #include "hardware/camera3.h"
 
@@ -190,7 +190,7 @@
 
     auto lockedBuffer = std::make_unique<CpuConsumer::LockedBuffer>();
 
-    uint64_t grallocUsage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(mUsage);
+    uint64_t grallocUsage = AHardwareBuffer_convertToGrallocUsageBits(mUsage);
 
     status_t ret =
             lockImageFromBuffer(mBuffer, grallocUsage, mBuffer->mFence->dup(), lockedBuffer.get());
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index c3eb437..bcc7ff3 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -25,8 +25,8 @@
 #include <cutils/atomic.h>
 #include <utils/Log.h>
 #include <android_media_Utils.h>
-#include <android_runtime/android_view_Surface.h>
-#include <android_runtime/android_hardware_HardwareBuffer.h>
+#include <ui/PublicFormat.h>
+#include <private/android/AHardwareBufferHelpers.h>
 #include <grallocusage/GrallocUsageConversion.h>
 #include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
 
@@ -70,6 +70,7 @@
         case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
         case AIMAGE_FORMAT_Y8:
         case AIMAGE_FORMAT_HEIC:
+        case AIMAGE_FORMAT_DEPTH_JPEG:
             return true;
         case AIMAGE_FORMAT_PRIVATE:
             // For private format, cpu usage is prohibited.
@@ -98,6 +99,7 @@
         case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
         case AIMAGE_FORMAT_Y8:
         case AIMAGE_FORMAT_HEIC:
+        case AIMAGE_FORMAT_DEPTH_JPEG:
             return 1;
         case AIMAGE_FORMAT_PRIVATE:
             return 0;
@@ -270,9 +272,9 @@
 media_status_t
 AImageReader::init() {
     PublicFormat publicFormat = static_cast<PublicFormat>(mFormat);
-    mHalFormat = android_view_Surface_mapPublicFormatToHalFormat(publicFormat);
-    mHalDataSpace = android_view_Surface_mapPublicFormatToHalDataspace(publicFormat);
-    mHalUsage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(mUsage);
+    mHalFormat = mapPublicFormatToHalFormat(publicFormat);
+    mHalDataSpace = mapPublicFormatToHalDataspace(publicFormat);
+    mHalUsage = AHardwareBuffer_convertToGrallocUsageBits(mUsage);
 
     sp<IGraphicBufferProducer> gbProducer;
     sp<IGraphicBufferConsumer> gbConsumer;
diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp
index b8af5ff..ce2c660 100644
--- a/media/ndk/NdkMediaCrypto.cpp
+++ b/media/ndk/NdkMediaCrypto.cpp
@@ -29,7 +29,6 @@
 #include <binder/IServiceManager.h>
 #include <media/ICrypto.h>
 #include <media/IMediaDrmService.h>
-#include <android_runtime/AndroidRuntime.h>
 #include <android_util_Binder.h>
 
 #include <jni.h>
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 1abee93..0891f2a 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -23,9 +23,7 @@
 #include <jni.h>
 #include <unistd.h>
 
-#include <android_runtime/AndroidRuntime.h>
-#include <android_util_Binder.h>
-#include <binder/IServiceManager.h>
+#include <binder/IBinder.h>
 #include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
@@ -41,8 +39,67 @@
 #include "../../libstagefright/include/NuCachedSource2.h"
 #include "NdkMediaDataSourceCallbacksPriv.h"
 
+#include <mutex> // std::call_once,once_flag
+#include <dlfcn.h> // dlopen
+
 using namespace android;
 
+// load libandroid_runtime.so lazily.
+// A vendor process may use libmediandk but should not depend on libandroid_runtime.
+// TODO(jooyung): remove duplicate (b/125550121)
+// frameworks/native/libs/binder/ndk/ibinder_jni.cpp
+namespace {
+
+typedef JNIEnv* (*getJNIEnv_t)();
+typedef sp<IBinder> (*ibinderForJavaObject_t)(JNIEnv* env, jobject obj);
+
+getJNIEnv_t getJNIEnv_;
+ibinderForJavaObject_t ibinderForJavaObject_;
+
+std::once_flag mLoadFlag;
+
+void load() {
+    std::call_once(mLoadFlag, []() {
+        void* handle = dlopen("libandroid_runtime.so", RTLD_LAZY);
+        if (handle == nullptr) {
+            ALOGE("Could not open libandroid_runtime.");
+            return;
+        }
+
+        getJNIEnv_ = reinterpret_cast<getJNIEnv_t>(
+                dlsym(handle, "_ZN7android14AndroidRuntime9getJNIEnvEv"));
+        if (getJNIEnv_ == nullptr) {
+            ALOGE("Could not find AndroidRuntime::getJNIEnv.");
+            // no return
+        }
+
+        ibinderForJavaObject_ = reinterpret_cast<ibinderForJavaObject_t>(
+                dlsym(handle, "_ZN7android20ibinderForJavaObjectEP7_JNIEnvP8_jobject"));
+        if (ibinderForJavaObject_ == nullptr) {
+            ALOGE("Could not find ibinderForJavaObject.");
+            // no return
+        }
+    });
+}
+
+JNIEnv* getJNIEnv() {
+    load();
+    if (getJNIEnv_ == nullptr) {
+        return nullptr;
+    }
+    return (getJNIEnv_)();
+}
+
+sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj) {
+    load();
+    if (ibinderForJavaObject_ == nullptr) {
+        return nullptr;
+    }
+    return (ibinderForJavaObject_)(env, obj);
+}
+
+} // namespace
+
 struct AMediaDataSource {
     void *userdata;
     AMediaDataSourceReadAt readAt;
@@ -124,9 +181,14 @@
     if (obj == NULL) {
         return NULL;
     }
+    sp<IBinder> binder;
     switch (version) {
         case 1:
-            return interface_cast<IMediaHTTPService>(ibinderForJavaObject(env, obj));
+            binder = ibinderForJavaObject(env, obj);
+            if (binder == NULL) {
+                return NULL;
+            }
+            return interface_cast<IMediaHTTPService>(binder);
         case 2:
             return new JMedia2HTTPService(env, obj);
         default:
@@ -179,7 +241,7 @@
 
     switch (version) {
         case 1:
-            env = AndroidRuntime::getJNIEnv();
+            env = getJNIEnv();
             clazz = "android/media/MediaHTTPService";
             method = "createHttpServiceBinderIfNecessary";
             signature = "(Ljava/lang/String;)Landroid/os/IBinder;";
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 28e4f12..c83b255 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -34,7 +34,6 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/NuMediaExtractor.h>
 #include <media/IMediaHTTPService.h>
-#include <android_runtime/AndroidRuntime.h>
 #include <android_util_Binder.h>
 
 #include <jni.h>
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 26a6238..768a7a9 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -26,7 +26,6 @@
 #include <utils/StrongPointer.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <android_runtime/AndroidRuntime.h>
 #include <android_util_Binder.h>
 
 #include <jni.h>
@@ -344,8 +343,10 @@
 EXPORT const char* AMEDIAFORMAT_KEY_LYRICIST = "lyricist";
 EXPORT const char* AMEDIAFORMAT_KEY_MANUFACTURER = "manufacturer";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_BIT_RATE = "max-bitrate";
+EXPORT const char* AMEDIAFORMAT_KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
+EXPORT const char* AMEDIAFORMAT_KEY_MAX_PTS_GAP_TO_ENCODER = "max-pts-gap-to-encoder";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";
 EXPORT const char* AMEDIAFORMAT_KEY_MIME = "mime";
 EXPORT const char* AMEDIAFORMAT_KEY_MPEG_USER_DATA = "mpeg-user-data";
diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp
index e79926d..d1992bf 100644
--- a/media/ndk/NdkMediaMuxer.cpp
+++ b/media/ndk/NdkMediaMuxer.cpp
@@ -30,7 +30,6 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaMuxer.h>
 #include <media/IMediaHTTPService.h>
-#include <android_runtime/AndroidRuntime.h>
 #include <android_util_Binder.h>
 
 #include <jni.h>
diff --git a/media/ndk/include/media/NdkImage.h b/media/ndk/include/media/NdkImage.h
index 14d88cb..3e60de0 100644
--- a/media/ndk/include/media/NdkImage.h
+++ b/media/ndk/include/media/NdkImage.h
@@ -535,6 +535,15 @@
      * Format as described in ISO/IEC 23008-12.</p>
      */
     AIMAGE_FORMAT_HEIC = 0x48454946,
+
+    /**
+     * Depth augmented compressed JPEG format.
+     *
+     * <p>JPEG compressed main image along with XMP embedded depth metadata
+     * following ISO 16684-1:2011(E).</p>
+     */
+    AIMAGE_FORMAT_DEPTH_JPEG = 0x69656963,
+
 };
 
 /**
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index ddf5291..56bcaab 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -216,6 +216,8 @@
 extern const char* AMEDIAFORMAT_KEY_LYRICIST __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_MANUFACTURER __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_MAX_BIT_RATE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_MAX_FPS_TO_ENCODER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_MAX_PTS_GAP_TO_ENCODER __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_MPEG2_STREAM_HEADER __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_PSSH __INTRODUCED_IN(29);
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 7bdd3ad..9756926 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -107,8 +107,10 @@
     AMEDIAFORMAT_KEY_LYRICIST; # var introduced=29
     AMEDIAFORMAT_KEY_MANUFACTURER; # var introduced=29
     AMEDIAFORMAT_KEY_MAX_BIT_RATE; # var introduced=29
+    AMEDIAFORMAT_KEY_MAX_FPS_TO_ENCODER; # var introduced=29
     AMEDIAFORMAT_KEY_MAX_HEIGHT; # var introduced=21
     AMEDIAFORMAT_KEY_MAX_INPUT_SIZE; # var introduced=21
+    AMEDIAFORMAT_KEY_MAX_PTS_GAP_TO_ENCODER; # var introduced=29
     AMEDIAFORMAT_KEY_MAX_WIDTH; # var introduced=21
     AMEDIAFORMAT_KEY_MIME; # var introduced=21
     AMEDIAFORMAT_KEY_MPEG_USER_DATA; # var introduced=28
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 599c446..2fb24f5 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -22,6 +22,9 @@
 #include <binder/PermissionCache.h>
 #include "mediautils/ServiceUtilities.h"
 
+#include <iterator>
+#include <algorithm>
+
 /* When performing permission checks we do not use permission cache for
  * runtime permissions (protection level dangerous) as they may change at
  * runtime. All other permissions (protection level normal and dangerous)
@@ -220,4 +223,85 @@
     return NO_ERROR;
 }
 
+sp<content::pm::IPackageManagerNative> MediaPackageManager::retreivePackageManager() {
+    const sp<IServiceManager> sm = defaultServiceManager();
+    if (sm == nullptr) {
+        ALOGW("%s: failed to retrieve defaultServiceManager", __func__);
+        return nullptr;
+    }
+    sp<IBinder> packageManager = sm->checkService(String16(nativePackageManagerName));
+    if (packageManager == nullptr) {
+        ALOGW("%s: failed to retrieve native package manager", __func__);
+        return nullptr;
+    }
+    return interface_cast<content::pm::IPackageManagerNative>(packageManager);
+}
+
+std::optional<bool> MediaPackageManager::doIsAllowed(uid_t uid) {
+    if (mPackageManager == nullptr) {
+        /** Can not fetch package manager at construction it may not yet be registered. */
+        mPackageManager = retreivePackageManager();
+        if (mPackageManager == nullptr) {
+            ALOGW("%s: Playback capture is denied as package manager is not reachable", __func__);
+            return std::nullopt;
+        }
+    }
+
+    std::vector<std::string> packageNames;
+    auto status = mPackageManager->getNamesForUids({(int32_t)uid}, &packageNames);
+    if (!status.isOk()) {
+        ALOGW("%s: Playback capture is denied for uid %u as the package names could not be "
+              "retrieved from the package manager: %s", __func__, uid, status.toString8().c_str());
+        return std::nullopt;
+    }
+    if (packageNames.empty()) {
+        ALOGW("%s: Playback capture for uid %u is denied as no package name could be retrieved "
+              "from the package manager: %s", __func__, uid, status.toString8().c_str());
+        return std::nullopt;
+    }
+    std::vector<bool> isAllowed;
+    status = mPackageManager->isAudioPlaybackCaptureAllowed(packageNames, &isAllowed);
+    if (!status.isOk()) {
+        ALOGW("%s: Playback capture is denied for uid %u as the manifest property could not be "
+              "retrieved from the package manager: %s", __func__, uid, status.toString8().c_str());
+        return std::nullopt;
+    }
+    if (packageNames.size() != isAllowed.size()) {
+        ALOGW("%s: Playback capture is denied for uid %u as the package manager returned incoherent"
+              " response size: %zu != %zu", __func__, uid, packageNames.size(), isAllowed.size());
+        return std::nullopt;
+    }
+
+    // Zip together packageNames and isAllowed for debug logs
+    Packages& packages = mDebugLog[uid];
+    packages.resize(packageNames.size()); // Reuse all objects
+    std::transform(begin(packageNames), end(packageNames), begin(isAllowed),
+                   begin(packages), [] (auto& name, bool isAllowed) -> Package {
+                       return {std::move(name), isAllowed};
+                   });
+
+    // Only allow playback record if all packages in this UID allow it
+    bool playbackCaptureAllowed = std::all_of(begin(isAllowed), end(isAllowed),
+                                                  [](bool b) { return b; });
+
+    return playbackCaptureAllowed;
+}
+
+void MediaPackageManager::dump(int fd, int spaces) const {
+    dprintf(fd, "%*sAllow playback capture log:\n", spaces, "");
+    if (mPackageManager == nullptr) {
+        dprintf(fd, "%*sNo package manager\n", spaces + 2, "");
+    }
+    dprintf(fd, "%*sPackage manager errors: %u\n", spaces + 2, "", mPackageManagerErrors);
+
+    for (const auto& uidCache : mDebugLog) {
+        for (const auto& package : std::get<Packages>(uidCache)) {
+            dprintf(fd, "%*s- uid=%5u, allowPlaybackCapture=%s, packageName=%s\n", spaces + 2, "",
+                    std::get<const uid_t>(uidCache),
+                    package.playbackCaptureAllowed ? "true " : "false",
+                    package.name.c_str());
+        }
+    }
+}
+
 } // namespace android
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 98f54c2..94370ee 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -14,13 +14,22 @@
  * limitations under the License.
  */
 
+#ifndef ANDROID_MEDIAUTILS_SERVICEUTILITIES_H
+#define ANDROID_MEDIAUTILS_SERVICEUTILITIES_H
+
 #include <unistd.h>
 
+#include <android/content/pm/IPackageManagerNative.h>
 #include <binder/IMemory.h>
 #include <binder/PermissionController.h>
 #include <cutils/multiuser.h>
 #include <private/android_filesystem_config.h>
 
+#include <map>
+#include <optional>
+#include <string>
+#include <vector>
+
 namespace android {
 
 // Audio permission utilities
@@ -72,4 +81,31 @@
 bool dumpAllowed();
 bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);
 status_t checkIMemory(const sp<IMemory>& iMemory);
+
+class MediaPackageManager {
+public:
+    /** Query the PackageManager to check if all apps of an UID allow playback capture. */
+    bool allowPlaybackCapture(uid_t uid) {
+        auto result = doIsAllowed(uid);
+        if (!result) {
+            mPackageManagerErrors++;
+        }
+        return result.value_or(false);
+    }
+    void dump(int fd, int spaces = 0) const;
+private:
+    static constexpr const char* nativePackageManagerName = "package_native";
+    std::optional<bool> doIsAllowed(uid_t uid);
+    sp<content::pm::IPackageManagerNative> retreivePackageManager();
+    sp<content::pm::IPackageManagerNative> mPackageManager; // To check apps manifest
+    uint_t mPackageManagerErrors = 0;
+    struct Package {
+        std::string name;
+        bool playbackCaptureAllowed = false;
+    };
+    using Packages = std::vector<Package>;
+    std::map<uid_t, Packages> mDebugLog;
+};
 }
+
+#endif // ANDROID_MEDIAUTILS_SERVICEUTILITIES_H
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 8455e54..ecaeb52 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1500,6 +1500,11 @@
 
     write(fd, result.string(), result.length());
 
+    if (mEffectInterface != 0) {
+        dprintf(fd, "\tEffect ID %d HAL dump:\n", mId);
+        (void)mEffectInterface->dump(fd);
+    }
+
     if (locked) {
         mLock.unlock();
     }
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a8c4bd1..8f181a4 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -457,52 +457,6 @@
     }
 }
 
-std::string devicesToString(audio_devices_t devices)
-{
-    std::string result;
-    if (devices & AUDIO_DEVICE_BIT_IN) {
-        InputDeviceConverter::maskToString(devices, result);
-    } else {
-        OutputDeviceConverter::maskToString(devices, result);
-    }
-    return result;
-}
-
-std::string inputFlagsToString(audio_input_flags_t flags)
-{
-    std::string result;
-    InputFlagConverter::maskToString(flags, result);
-    return result;
-}
-
-std::string outputFlagsToString(audio_output_flags_t flags)
-{
-    std::string result;
-    OutputFlagConverter::maskToString(flags, result);
-    return result;
-}
-
-const char *sourceToString(audio_source_t source)
-{
-    switch (source) {
-    case AUDIO_SOURCE_DEFAULT:              return "default";
-    case AUDIO_SOURCE_MIC:                  return "mic";
-    case AUDIO_SOURCE_VOICE_UPLINK:         return "voice uplink";
-    case AUDIO_SOURCE_VOICE_DOWNLINK:       return "voice downlink";
-    case AUDIO_SOURCE_VOICE_CALL:           return "voice call";
-    case AUDIO_SOURCE_CAMCORDER:            return "camcorder";
-    case AUDIO_SOURCE_VOICE_RECOGNITION:    return "voice recognition";
-    case AUDIO_SOURCE_VOICE_COMMUNICATION:  return "voice communication";
-    case AUDIO_SOURCE_REMOTE_SUBMIX:        return "remote submix";
-    case AUDIO_SOURCE_UNPROCESSED:          return "unprocessed";
-    case AUDIO_SOURCE_VOICE_PERFORMANCE:    return "voice performance";
-    case AUDIO_SOURCE_ECHO_REFERENCE:       return "echo reference";
-    case AUDIO_SOURCE_FM_TUNER:             return "FM tuner";
-    case AUDIO_SOURCE_HOTWORD:              return "hotword";
-    default:                                return "unknown";
-    }
-}
-
 AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
         audio_devices_t outDevice, audio_devices_t inDevice, type_t type, bool systemReady)
     :   Thread(false /*canCallJava*/),
@@ -717,8 +671,8 @@
             event->mStatus = createAudioPatch_l(&data->mPatch, &data->mHandle);
             const audio_devices_t newDevice = getDevice();
             mLocalLog.log("CFG_EVENT_CREATE_AUDIO_PATCH: old device %#x (%s) new device %#x (%s)",
-                    (unsigned)oldDevice, devicesToString(oldDevice).c_str(),
-                    (unsigned)newDevice, devicesToString(newDevice).c_str());
+                    (unsigned)oldDevice, toString(oldDevice).c_str(),
+                    (unsigned)newDevice, toString(newDevice).c_str());
         } break;
         case CFG_EVENT_RELEASE_AUDIO_PATCH: {
             const audio_devices_t oldDevice = getDevice();
@@ -727,8 +681,8 @@
             event->mStatus = releaseAudioPatch_l(data->mHandle);
             const audio_devices_t newDevice = getDevice();
             mLocalLog.log("CFG_EVENT_RELEASE_AUDIO_PATCH: old device %#x (%s) new device %#x (%s)",
-                    (unsigned)oldDevice, devicesToString(oldDevice).c_str(),
-                    (unsigned)newDevice, devicesToString(newDevice).c_str());
+                    (unsigned)oldDevice, toString(oldDevice).c_str(),
+                    (unsigned)newDevice, toString(newDevice).c_str());
         } break;
         default:
             ALOG_ASSERT(false, "processConfigEvents_l() unknown event type %d", event->mType);
@@ -858,9 +812,9 @@
         dprintf(fd, " none\n");
     }
     // Note: output device may be used by capture threads for effects such as AEC.
-    dprintf(fd, "  Output device: %#x (%s)\n", mOutDevice, devicesToString(mOutDevice).c_str());
-    dprintf(fd, "  Input device: %#x (%s)\n", mInDevice, devicesToString(mInDevice).c_str());
-    dprintf(fd, "  Audio source: %d (%s)\n", mAudioSource, sourceToString(mAudioSource));
+    dprintf(fd, "  Output device: %#x (%s)\n", mOutDevice, toString(mOutDevice).c_str());
+    dprintf(fd, "  Input device: %#x (%s)\n", mInDevice, toString(mInDevice).c_str());
+    dprintf(fd, "  Audio source: %d (%s)\n", mAudioSource, toString(mAudioSource).c_str());
 
     // Dump timestamp statistics for the Thread types that support it.
     if (mType == RECORD
@@ -872,6 +826,28 @@
         dprintf(fd, "  Timestamp corrected: %s\n", isTimestampCorrectionEnabled() ? "yes" : "no");
     }
 
+    if (mLastIoBeginNs > 0) { // MMAP may not set this
+        dprintf(fd, "  Last %s occurred (msecs): %lld\n",
+                isOutput() ? "write" : "read",
+                (long long) (systemTime() - mLastIoBeginNs) / NANOS_PER_MILLISECOND);
+    }
+
+    if (mProcessTimeMs.getN() > 0) {
+        dprintf(fd, "  Process time ms stats: %s\n", mProcessTimeMs.toString().c_str());
+    }
+
+    if (mIoJitterMs.getN() > 0) {
+        dprintf(fd, "  Hal %s jitter ms stats: %s\n",
+                isOutput() ? "write" : "read",
+                mIoJitterMs.toString().c_str());
+    }
+
+    if (mLatencyMs.getN() > 0) {
+        dprintf(fd, "  Threadloop %s latency stats: %s\n",
+                isOutput() ? "write" : "read",
+                mLatencyMs.toString().c_str());
+    }
+
     if (locked) {
         mLock.unlock();
     }
@@ -1704,7 +1680,7 @@
         // mStreamTypes[] initialized in constructor body
         mTracks(type == MIXER),
         mOutput(output),
-        mLastWriteTime(-1), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
+        mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
         mMixerStatus(MIXER_IDLE),
         mMixerStatusIgnoringFastTracks(MIXER_IDLE),
         mStandbyDelayNs(AudioFlinger::mStandbyTimeInNsecs),
@@ -1857,8 +1833,6 @@
                 channelMaskToString(mHapticChannelMask, true /* output */).c_str());
     }
     dprintf(fd, "  Normal frame count: %zu\n", mNormalFrameCount);
-    dprintf(fd, "  Last write occurred (msecs): %llu\n",
-            (unsigned long long) ns2ms(systemTime() - mLastWriteTime));
     dprintf(fd, "  Total writes: %d\n", mNumWrites);
     dprintf(fd, "  Delayed writes: %d\n", mNumDelayedWrites);
     dprintf(fd, "  Blocked in write: %s\n", mInWrite ? "yes" : "no");
@@ -1871,7 +1845,7 @@
     AudioStreamOut *output = mOutput;
     audio_output_flags_t flags = output != NULL ? output->flags : AUDIO_OUTPUT_FLAG_NONE;
     dprintf(fd, "  AudioStreamOut: %p flags %#x (%s)\n",
-            output, flags, outputFlagsToString(flags).c_str());
+            output, flags, toString(flags).c_str());
     dprintf(fd, "  Frames written: %lld\n", (long long)mFramesWritten);
     dprintf(fd, "  Suspended frames: %lld\n", (long long)mSuspendedFrames);
     if (mPipeSink.get() != nullptr) {
@@ -3189,8 +3163,8 @@
     Vector< sp<Track> > tracksToRemove;
 
     mStandbyTimeNs = systemTime();
-    nsecs_t lastWriteFinished = -1; // time last server write completed
-    int64_t lastFramesWritten = -1; // track changes in timestamp server frames written
+    int64_t lastLoopCountWritten = -2; // never matches "previous" loop, when loopCount = 0.
+    int64_t lastFramesWritten = -1;    // track changes in timestamp server frames written
 
     // MIXER
     nsecs_t lastWarning = 0;
@@ -3236,7 +3210,8 @@
     }
     audio_patch_handle_t lastDownstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
 
-    while (!exitPending())
+    // loopCount is used for statistics and diagnostics.
+    for (int64_t loopCount = 0; !exitPending(); ++loopCount)
     {
         // Log merge requests are performed during AudioFlinger binder transactions, but
         // that does not cover audio playback. It's requested here for that reason.
@@ -3394,11 +3369,11 @@
                     // use the time before we called the HAL write - it is a bit more accurate
                     // to when the server last read data than the current time here.
                     //
-                    // If we haven't written anything, mLastWriteTime will be -1
+                    // If we haven't written anything, mLastIoBeginNs will be -1
                     // and we use systemTime().
                     mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] = mFramesWritten;
-                    mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = mLastWriteTime == -1
-                            ? systemTime() : mLastWriteTime;
+                    mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = mLastIoBeginNs == -1
+                            ? systemTime() : mLastIoBeginNs;
                 }
 
                 for (const sp<Track> &t : mActiveTracks) {
@@ -3411,6 +3386,14 @@
                     }
                 }
             }
+
+            if (audio_has_proportional_frames(mFormat)) {
+                const double latencyMs = mTimestamp.getOutputServerLatencyMs(mSampleRate);
+                if (latencyMs != 0.) { // note 0. means timestamp is empty.
+                    mLatencyMs.add(latencyMs);
+                }
+            }
+
             } // if (mType ... ) { // no indentation
 #if 0
             // logFormat example
@@ -3635,43 +3618,68 @@
             // mSleepTimeUs == 0 means we must write to audio hardware
             if (mSleepTimeUs == 0) {
                 ssize_t ret = 0;
-                // We save lastWriteFinished here, as previousLastWriteFinished,
-                // for throttling. On thread start, previousLastWriteFinished will be
-                // set to -1, which properly results in no throttling after the first write.
-                nsecs_t previousLastWriteFinished = lastWriteFinished;
-                nsecs_t delta = 0;
+                // writePeriodNs is updated >= 0 when ret > 0.
+                int64_t writePeriodNs = -1;
                 if (mBytesRemaining) {
                     // FIXME rewrite to reduce number of system calls
-                    mLastWriteTime = systemTime();  // also used for dumpsys
+                    const int64_t lastIoBeginNs = systemTime();
                     ret = threadLoop_write();
-                    lastWriteFinished = systemTime();
-                    delta = lastWriteFinished - mLastWriteTime;
+                    const int64_t lastIoEndNs = systemTime();
                     if (ret < 0) {
                         mBytesRemaining = 0;
-                    } else {
+                    } else if (ret > 0) {
                         mBytesWritten += ret;
                         mBytesRemaining -= ret;
-                        mFramesWritten += ret / mFrameSize;
+                        const int64_t frames = ret / mFrameSize;
+                        mFramesWritten += frames;
+
+                        writePeriodNs = lastIoEndNs - mLastIoEndNs;
+                        // process information relating to write time.
+                        if (audio_has_proportional_frames(mFormat)) {
+                            // we are in a continuous mixing cycle
+                            if (mMixerStatus == MIXER_TRACKS_READY &&
+                                    loopCount == lastLoopCountWritten + 1) {
+
+                                const double jitterMs =
+                                        TimestampVerifier<int64_t, int64_t>::computeJitterMs(
+                                                {frames, writePeriodNs},
+                                                {0, 0} /* lastTimestamp */, mSampleRate);
+                                const double processMs =
+                                       (lastIoBeginNs - mLastIoEndNs) * 1e-6;
+
+                                Mutex::Autolock _l(mLock);
+                                mIoJitterMs.add(jitterMs);
+                                mProcessTimeMs.add(processMs);
+                            }
+
+                            // write blocked detection
+                            const int64_t deltaWriteNs = lastIoEndNs - lastIoBeginNs;
+                            if (mType == MIXER && deltaWriteNs > maxPeriod) {
+                                mNumDelayedWrites++;
+                                if ((lastIoEndNs - lastWarning) > kWarningThrottleNs) {
+                                    ATRACE_NAME("underrun");
+                                    ALOGW("write blocked for %lld msecs, "
+                                            "%d delayed writes, thread %d",
+                                            (long long)deltaWriteNs / NANOS_PER_MILLISECOND,
+                                            mNumDelayedWrites, mId);
+                                    lastWarning = lastIoEndNs;
+                                }
+                            }
+                        }
+                        // update timing info.
+                        mLastIoBeginNs = lastIoBeginNs;
+                        mLastIoEndNs = lastIoEndNs;
+                        lastLoopCountWritten = loopCount;
                     }
                 } else if ((mMixerStatus == MIXER_DRAIN_TRACK) ||
                         (mMixerStatus == MIXER_DRAIN_ALL)) {
                     threadLoop_drain();
                 }
                 if (mType == MIXER && !mStandby) {
-                    // write blocked detection
-                    if (delta > maxPeriod) {
-                        mNumDelayedWrites++;
-                        if ((lastWriteFinished - lastWarning) > kWarningThrottleNs) {
-                            ATRACE_NAME("underrun");
-                            ALOGW("write blocked for %llu msecs, %d delayed writes, thread %p",
-                                    (unsigned long long) ns2ms(delta), mNumDelayedWrites, this);
-                            lastWarning = lastWriteFinished;
-                        }
-                    }
 
                     if (mThreadThrottle
                             && mMixerStatus == MIXER_TRACKS_READY // we are mixing (active tracks)
-                            && ret > 0) {                         // we wrote something
+                            && writePeriodNs > 0) {               // we have write period info
                         // Limit MixerThread data processing to no more than twice the
                         // expected processing rate.
                         //
@@ -3690,12 +3698,9 @@
                         // 2. threadLoop_mix (significant for heavy mixing, especially
                         //                    on low tier processors)
 
-                        // it's OK if deltaMs (and deltaNs) is an overestimate.
-                        nsecs_t deltaNs;
-                        // deltaNs = lastWriteFinished - previousLastWriteFinished;
-                        __builtin_sub_overflow(
-                            lastWriteFinished,previousLastWriteFinished, &deltaNs);
-                        const int32_t deltaMs = deltaNs / 1000000;
+                        // it's OK if deltaMs is an overestimate.
+
+                        const int32_t deltaMs = writePeriodNs / NANOS_PER_MILLISECOND;
 
                         const int32_t throttleMs = (int32_t)mHalfBufferMs - deltaMs;
                         if ((signed)mHalfBufferMs >= throttleMs && throttleMs > 0) {
@@ -3708,7 +3713,8 @@
                             mThreadThrottleTimeMs += throttleMs;
                             // Throttle must be attributed to the previous mixer loop's write time
                             // to allow back-to-back throttling.
-                            lastWriteFinished += throttleMs * 1000000;
+                            // This also ensures proper timing statistics.
+                            mLastIoEndNs = systemTime();  // we fetch the write end time again.
                         } else {
                             uint32_t diff = mThreadThrottleTimeMs - mThreadThrottleEndMs;
                             if (diff > 0) {
@@ -5304,13 +5310,6 @@
     dprintf(fd, "  Master balance: %f (%s)\n", mMasterBalance.load(),
             (hasFastMixer() ? std::to_string(mFastMixer->getMasterBalance())
                             : mBalance.toString()).c_str());
-    const double latencyMs = mTimestamp.getOutputServerLatencyMs(mSampleRate);
-    if (latencyMs != 0.) {
-        dprintf(fd, "  NormalMixer latency ms: %.2lf\n", latencyMs);
-    } else {
-        dprintf(fd, "  NormalMixer latency ms: unavail\n");
-    }
-
     if (hasFastMixer()) {
         dprintf(fd, "  FastMixer thread %p tid=%d", mFastMixer.get(), mFastMixer->getTid());
 
@@ -6751,8 +6750,10 @@
     // used to request a deferred sleep, to be executed later while mutex is unlocked
     uint32_t sleepUs = 0;
 
+    int64_t lastLoopCountRead = -2;  // never matches "previous" loop, when loopCount = 0.
+
     // loop while there is work to do
-    for (;;) {
+    for (int64_t loopCount = 0;; ++loopCount) {  // loopCount used for statistics tracking
         Vector< sp<EffectChain> > effectChains;
 
         // activeTracks accumulates a copy of a subset of mActiveTracks
@@ -6951,6 +6952,7 @@
 
         int32_t rear = mRsmpInRear & (mRsmpInFramesP2 - 1);
         ssize_t framesRead;
+        const int64_t lastIoBeginNs = systemTime(); // start IO timing
 
         // If an NBAIO source is present, use it to read the normal capture's data
         if (mPipeSource != 0) {
@@ -7008,10 +7010,12 @@
             }
         }
 
+        const int64_t lastIoEndNs = systemTime(); // end IO timing
+
         // Update server timestamp with server stats
         // systemTime() is optional if the hardware supports timestamps.
         mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] += framesRead;
-        mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = systemTime();
+        mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = lastIoEndNs;
 
         // Update server timestamp with kernel stats
         if (mPipeSource.get() == nullptr /* don't obtain for FastCapture, could block */) {
@@ -7045,6 +7049,15 @@
                 mTimestampVerifier.error();
             }
         }
+
+        // From the timestamp, input read latency is negative output write latency.
+        const audio_input_flags_t flags = mInput != NULL ? mInput->flags : AUDIO_INPUT_FLAG_NONE;
+        const double latencyMs = RecordTrack::checkServerLatencySupported(mFormat, flags)
+                ? - mTimestamp.getOutputServerLatencyMs(mSampleRate) : 0.;
+        if (latencyMs != 0.) { // note 0. means timestamp is empty.
+            mLatencyMs.add(latencyMs);
+        }
+
         // Use this to track timestamp information
         // ALOGD("%s", mTimestamp.toString().c_str());
 
@@ -7060,6 +7073,24 @@
         ALOG_ASSERT(framesRead > 0);
         mFramesRead += framesRead;
 
+        if (audio_has_proportional_frames(mFormat)
+                && loopCount == lastLoopCountRead + 1) {
+            const int64_t readPeriodNs = lastIoEndNs - mLastIoEndNs;
+            const double jitterMs =
+                    TimestampVerifier<int64_t, int64_t>::computeJitterMs(
+                            {framesRead, readPeriodNs},
+                            {0, 0} /* lastTimestamp */, mSampleRate);
+            const double processMs = (lastIoBeginNs - mLastIoEndNs) * 1e-6;
+
+            Mutex::Autolock _l(mLock);
+            mIoJitterMs.add(jitterMs);
+            mProcessTimeMs.add(processMs);
+        }
+        // update timing info.
+        mLastIoBeginNs = lastIoBeginNs;
+        mLastIoEndNs = lastIoEndNs;
+        lastLoopCountRead = loopCount;
+
 #ifdef TEE_SINK
         (void)mTee.write((uint8_t*)mRsmpInBuffer + rear * mFrameSize, framesRead);
 #endif
@@ -7708,7 +7739,7 @@
     AudioStreamIn *input = mInput;
     audio_input_flags_t flags = input != NULL ? input->flags : AUDIO_INPUT_FLAG_NONE;
     dprintf(fd, "  AudioStreamIn: %p flags %#x (%s)\n",
-            input, flags, inputFlagsToString(flags).c_str());
+            input, flags, toString(flags).c_str());
     dprintf(fd, "  Frames read: %lld\n", (long long)mFramesRead);
     if (mActiveTracks.isEmpty()) {
         dprintf(fd, "  No active record clients\n");
@@ -7719,14 +7750,6 @@
         (void)input->stream->dump(fd);
     }
 
-    const double latencyMs = RecordTrack::checkServerLatencySupported(mFormat, flags)
-            ? - mTimestamp.getOutputServerLatencyMs(mSampleRate) : 0.;
-    if (latencyMs != 0.) {
-        dprintf(fd, "  NormalRecord latency ms: %.2lf\n", latencyMs);
-    } else {
-        dprintf(fd, "  NormalRecord latency ms: unavail\n");
-    }
-
     dprintf(fd, "  Fast capture thread: %s\n", hasFastCapture() ? "yes" : "no");
     dprintf(fd, "  Fast track available: %s\n", mFastTrackAvail ? "yes" : "no");
 
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 1131b26..1afea08 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -512,6 +512,16 @@
                 TimestampVerifier< // For timestamp statistics.
                         int64_t /* frame count */, int64_t /* time ns */> mTimestampVerifier;
                 audio_devices_t         mTimestampCorrectedDevices = AUDIO_DEVICE_NONE;
+
+                // ThreadLoop statistics per iteration.
+                int64_t                 mLastIoBeginNs = -1;
+                int64_t                 mLastIoEndNs = -1;
+
+                // This should be read under ThreadBase lock (if not on the threadLoop thread).
+                audio_utils::Statistics<double> mIoJitterMs{0.995 /* alpha */};
+                audio_utils::Statistics<double> mProcessTimeMs{0.995 /* alpha */};
+                audio_utils::Statistics<double> mLatencyMs{0.995 /* alpha */};
+
                 bool                    mIsMsdDevice = false;
                 // A condition that must be evaluated by the thread loop has changed and
                 // we must not wait for async write callback in the thread loop before evaluating it
@@ -1030,7 +1040,6 @@
     float                           mMasterVolume;
     std::atomic<float>              mMasterBalance{};
     audio_utils::Balance            mBalance;
-    nsecs_t                         mLastWriteTime;
     int                             mNumWrites;
     int                             mNumDelayedWrites;
     bool                            mInWrite;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 65f799e..ad78a45 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -700,8 +700,13 @@
         const AudioBufferProvider::Buffer& sourceBuffer) {
     auto start = std::chrono::steady_clock::now();
     const size_t frameCount = sourceBuffer.frameCount;
-    for (auto& sink : mTeePatches) {
-        RecordThread::PatchRecord* patchRecord = sink.patchRecord.get();
+    if (frameCount == 0) {
+        return;  // No audio to intercept.
+        // Additionally PatchProxyBufferProvider::obtainBuffer (called by PathTrack::getNextBuffer)
+        // does not allow 0 frame size request contrary to getNextBuffer
+    }
+    for (auto& teePatch : mTeePatches) {
+        RecordThread::PatchRecord* patchRecord = teePatch.patchRecord.get();
 
         size_t framesWritten = writeFrames(patchRecord, sourceBuffer.i8, frameCount);
         // On buffer wrap, the buffer frame count will be less than requested,
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index f72f44a..9e4eebc 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -90,7 +90,7 @@
 LOCAL_SHARED_LIBRARIES += libmedia_helper
 LOCAL_SHARED_LIBRARIES += libmediametrics
 
-LOCAL_SHARED_LIBRARIES += libhidlbase libxml2
+LOCAL_SHARED_LIBRARIES += libbinder libhidlbase libxml2
 
 ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
 LOCAL_CFLAGS += -DUSE_XML_AUDIO_POLICY_CONF
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index bb5441d..acbfc9e 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -58,10 +58,12 @@
     typedef enum {
         API_INPUT_INVALID = -1,
         API_INPUT_LEGACY  = 0,// e.g. audio recording from a microphone
-        API_INPUT_MIX_CAPTURE,// used for "remote submix", capture of the media to play it remotely
+        API_INPUT_MIX_CAPTURE,// used for "remote submix" legacy mode (no DAP),
+                              // capture of the media to play it remotely
         API_INPUT_MIX_EXT_POLICY_REROUTE,// used for platform audio rerouting, where mixes are
                                          // handled by external and dynamically installed
                                          // policies which reroute audio mixes
+        API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK,  // used for playback capture with a MediaProjection
         API_INPUT_TELEPHONY_RX, // used for capture from telephony RX path
     } input_type_t;
 
@@ -159,6 +161,19 @@
                                           int *index,
                                           audio_devices_t device) = 0;
 
+    virtual status_t setVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                 int index,
+                                                 audio_devices_t device) = 0;
+    virtual status_t getVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                 int &index,
+                                                 audio_devices_t device) = 0;
+
+    virtual status_t getMaxVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                    int &index) = 0;
+
+    virtual status_t getMinVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                    int &index) = 0;
+
     // return the strategy corresponding to a given stream type
     virtual uint32_t getStrategyForStream(audio_stream_type_t stream) = 0;
 
@@ -244,7 +259,13 @@
 
     virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies) = 0;
 
-    virtual product_strategy_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa) = 0;
+    virtual status_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa,
+                                                           product_strategy_t &productStrategy) = 0;
+
+    virtual status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) = 0;
+
+    virtual status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
+                                                       volume_group_t &volumeGroup) = 0;
 };
 
 
@@ -341,6 +362,8 @@
 
     virtual void onAudioPatchListUpdate() = 0;
 
+    virtual void onAudioVolumeGroupChanged(volume_group_t group, int flags) = 0;
+
     virtual audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t use) = 0;
 
     virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index a3b6b36..48b5271 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -21,6 +21,7 @@
 #include <math.h>
 
 namespace android {
+
 /**
  * VolumeSource is the discriminent for volume management on an output.
  * It used to be the stream type by legacy, it may be host volume group or a volume curves if
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
index 996347b..4af93e1 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
@@ -20,6 +20,7 @@
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 #include <system/audio.h>
+#include <vector>
 
 namespace android {
 
@@ -59,12 +60,36 @@
     void getDefaultConfig(struct audio_gain_config *config);
     status_t checkConfig(const struct audio_gain_config *config);
 
+    void setUseForVolume(bool canUseForVolume) { mUseForVolume = canUseForVolume; }
+    bool canUseForVolume() const { return mUseForVolume; }
+
     const struct audio_gain &getGain() const { return mGain; }
 
 private:
     int               mIndex;
     struct audio_gain mGain;
     bool              mUseInChannelMask;
+    bool              mUseForVolume = false;
+};
+
+class AudioGains : public std::vector<sp<AudioGain> >
+{
+public:
+    bool canUseForVolume() const
+    {
+        for (const auto &gain: *this) {
+            if (gain->canUseForVolume()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    int32_t add(const sp<AudioGain> gain)
+    {
+        push_back(gain);
+        return 0;
+    }
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index cf9519b..704f404 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -98,7 +98,7 @@
         ActivityTracking::dump(dst, spaces);
         dst->appendFormat(", Volume: %.03f, MuteCount: %02d\n", mCurVolumeDb, mMuteCount);
     }
-    void setVolume(float volume) { mCurVolumeDb = volume; }
+    void setVolume(float volumeDb) { mCurVolumeDb = volumeDb; }
     float getVolume() const { return mCurVolumeDb; }
 
 private:
@@ -156,7 +156,7 @@
     virtual bool isDuplicated() const { return false; }
     virtual uint32_t latency() { return 0; }
     virtual bool isFixedVolume(audio_devices_t device);
-    virtual bool setVolume(float volume,
+    virtual bool setVolume(float volumeDb,
                            audio_stream_type_t stream,
                            audio_devices_t device,
                            uint32_t delayMs,
@@ -219,10 +219,10 @@
     {
         return mVolumeActivities[vs].decMuteCount();
     }
-    void setCurVolume(VolumeSource vs, float volume)
+    void setCurVolume(VolumeSource vs, float volumeDb)
     {
         // Even if not activity for this group registered, need to create anyway
-        mVolumeActivities[vs].setVolume(volume);
+        mVolumeActivities[vs].setVolume(volumeDb);
     }
     float getCurVolume(VolumeSource vs) const
     {
@@ -327,7 +327,7 @@
             setClientActive(client, false);
         }
     }
-    virtual bool setVolume(float volume,
+    virtual bool setVolume(float volumeDb,
                            audio_stream_type_t stream,
                            audio_devices_t device,
                            uint32_t delayMs,
@@ -401,7 +401,7 @@
 
             void dump(String8 *dst) const override;
 
-    virtual bool setVolume(float volume,
+    virtual bool setVolume(float volumeDb,
                            audio_stream_type_t stream,
                            audio_devices_t device,
                            uint32_t delayMs,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 1b5a2d6..2d182bd 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -18,6 +18,7 @@
 
 #include "AudioCollections.h"
 #include "AudioProfile.h"
+#include "AudioGain.h"
 #include "HandleGenerator.h"
 #include <utils/String8.h>
 #include <utils/Vector.h>
@@ -29,9 +30,7 @@
 namespace android {
 
 class HwModule;
-class AudioGain;
 class AudioRoute;
-typedef Vector<sp<AudioGain> > AudioGainCollection;
 
 class AudioPort : public virtual RefBase, private HandleGenerator<audio_port_handle_t>
 {
@@ -49,8 +48,8 @@
 
     virtual const String8 getTagName() const = 0;
 
-    void setGains(const AudioGainCollection &gains) { mGains = gains; }
-    const AudioGainCollection &getGains() const { return mGains; }
+    void setGains(const AudioGains &gains) { mGains = gains; }
+    const AudioGains &getGains() const { return mGains; }
 
     virtual void setFlags(uint32_t flags)
     {
@@ -138,7 +137,7 @@
 
     void log(const char* indent) const;
 
-    AudioGainCollection mGains; // gain controllers
+    AudioGains mGains; // gain controllers
 
 private:
     void pickChannelMask(audio_channel_mask_t &channelMask, const ChannelsVector &channelMasks) const;
@@ -165,6 +164,8 @@
         return (other != 0) && (other->getAudioPort() != 0) && (getAudioPort() != 0) &&
                 (other->getAudioPort()->getModuleHandle() == getAudioPort()->getModuleHandle());
     }
+    bool hasGainController(bool canUseForVolume = false) const;
+
     unsigned int mSamplingRate = 0u;
     audio_format_t mFormat = AUDIO_FORMAT_INVALID;
     audio_channel_mask_t mChannelMask = AUDIO_CHANNEL_NONE;
diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
index 93022fb..d408446 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
@@ -38,6 +38,8 @@
     virtual float volIndexToDb(device_category device, int indexInUi) const = 0;
     virtual bool hasVolumeIndexForDevice(audio_devices_t device) const = 0;
     virtual status_t initVolume(int indexMin, int indexMax) = 0;
+    virtual std::vector<audio_attributes_t> getAttributes() const = 0;
+    virtual std::vector<audio_stream_type_t> getStreamTypes() const = 0;
     virtual void dump(String8 *dst, int spaces = 0, bool curvePoints = false) const = 0;
 };
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 7293bc4..fd33649 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -149,7 +149,7 @@
     return false;
 }
 
-bool AudioOutputDescriptor::setVolume(float volume,
+bool AudioOutputDescriptor::setVolume(float volumeDb,
                                       audio_stream_type_t stream,
                                       audio_devices_t device __unused,
                                       uint32_t delayMs,
@@ -158,9 +158,9 @@
     // We actually change the volume if:
     // - the float value returned by computeVolume() changed
     // - the force flag is set
-    if (volume != getCurVolume(static_cast<VolumeSource>(stream)) || force) {
-        ALOGV("setVolume() for stream %d, volume %f, delay %d", stream, volume, delayMs);
-        setCurVolume(static_cast<VolumeSource>(stream), volume);
+    if (volumeDb != getCurVolume(static_cast<VolumeSource>(stream)) || force) {
+        ALOGV("setVolume() for stream %d, volume %f, delay %d", stream, volumeDb, delayMs);
+        setCurVolume(static_cast<VolumeSource>(stream), volumeDb);
         return true;
     }
     return false;
@@ -388,15 +388,39 @@
             mFlags & AUDIO_OUTPUT_FLAG_FAST ? AUDIO_LATENCY_LOW : AUDIO_LATENCY_NORMAL;
 }
 
-bool SwAudioOutputDescriptor::setVolume(float volume,
+bool SwAudioOutputDescriptor::setVolume(float volumeDb,
                                         audio_stream_type_t stream,
                                         audio_devices_t device,
                                         uint32_t delayMs,
                                         bool force)
 {
-    if (!AudioOutputDescriptor::setVolume(volume, stream, device, delayMs, force)) {
+    if (!AudioOutputDescriptor::setVolume(volumeDb, stream, device, delayMs, force)) {
         return false;
     }
+    if (!devices().isEmpty()) {
+        // Assume first device to check upon Gain Crontroller availability
+        const auto &devicePort = devices().itemAt(0);
+        ALOGV("%s: device %s hasGC %d", __FUNCTION__,
+            devicePort->toString().c_str(), devices().itemAt(0)->hasGainController(true));
+        if (devicePort->hasGainController(true)) {
+            // @todo: default stream volume to max (0) when using HW Port gain?
+            float volumeAmpl = Volume::DbToAmpl(0);
+            mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+
+            AudioGains gains = devicePort->getGains();
+            int gainMinValueInMb = gains[0]->getMinValueInMb();
+            int gainMaxValueInMb = gains[0]->getMaxValueInMb();
+            int gainStepValueInMb = gains[0]->getStepValueInMb();
+            int gainValueMb = ((volumeDb * 100)/ gainStepValueInMb) * gainStepValueInMb;
+            gainValueMb = std::max(gainMinValueInMb, std::min(gainValueMb, gainMaxValueInMb));
+
+            audio_port_config config = {};
+            devicePort->toAudioPortConfig(&config);
+            config.config_mask = AUDIO_PORT_CONFIG_GAIN;
+            config.gain.values[0] = gainValueMb;
+            return mClientInterface->setAudioPortConfig(&config, 0) == NO_ERROR;
+        }
+    }
     // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is enabled
     float volumeAmpl = Volume::DbToAmpl(getCurVolume(static_cast<VolumeSource>(stream)));
     if (stream == AUDIO_STREAM_BLUETOOTH_SCO) {
@@ -591,13 +615,13 @@
 }
 
 
-bool HwAudioOutputDescriptor::setVolume(float volume,
+bool HwAudioOutputDescriptor::setVolume(float volumeDb,
                                         audio_stream_type_t stream,
                                         audio_devices_t device,
                                         uint32_t delayMs,
                                         bool force)
 {
-    bool changed = AudioOutputDescriptor::setVolume(volume, stream, device, delayMs, force);
+    bool changed = AudioOutputDescriptor::setVolume(volumeDb, stream, device, delayMs, force);
 
     if (changed) {
       // TODO: use gain controller on source device if any to adjust volume
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
index cd1c2f2..3a4db90 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -41,9 +41,7 @@
         const audio_port_config &cfg = cfgs[i];
         dst->appendFormat("%*s  [%s %d] ", spaces, "", prefix, i + 1);
         if (cfg.type == AUDIO_PORT_TYPE_DEVICE) {
-            std::string device;
-            deviceToString(cfg.ext.device.type, device);
-            dst->appendFormat("Device ID %d %s", cfg.id, device.c_str());
+            dst->appendFormat("Device ID %d %s", cfg.id, toString(cfg.ext.device.type).c_str());
         } else {
             dst->appendFormat("Mix ID %d I/O handle %d", cfg.id, cfg.ext.mix.handle);
         }
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 2c4695d..23d764e 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -66,9 +66,7 @@
     RouteFlagTypeConverter::maskToString(mMix.mRouteFlags, routeFlagLiteral);
     dst->appendFormat("%*s- Route Flags: %s\n", spaces, "", routeFlagLiteral.c_str());
 
-    std::string deviceLiteral;
-    deviceToString(mMix.mDeviceType, deviceLiteral);
-    dst->appendFormat("%*s- device type: %s\n", spaces, "", deviceLiteral.c_str());
+    dst->appendFormat("%*s- device type: %s\n", spaces, "", toString(mMix.mDeviceType).c_str());
 
     dst->appendFormat("%*s- device address: %s\n", spaces, "", mMix.mDeviceAddress.string());
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 9fcf5e7..a66c695 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -479,4 +479,14 @@
             dstConfig, srcConfig, AUDIO_PORT_CONFIG_FLAGS, { AUDIO_INPUT_FLAG_NONE });
 }
 
+bool AudioPortConfig::hasGainController(bool canUseForVolume) const
+{
+    sp<AudioPort> audioport = getAudioPort();
+    if (audioport == nullptr) {
+        return false;
+    }
+    return canUseForVolume ? audioport->getGains().canUseForVolume()
+                           : audioport->getGains().size() > 0;
+}
+
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index a3121d1..91961d0 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -18,6 +18,7 @@
 //#define LOG_NDEBUG 0
 
 #include <audio_utils/string.h>
+#include <media/TypeConverter.h>
 #include <set>
 #include "DeviceDescriptor.h"
 #include "TypeConverter.h"
@@ -346,10 +347,9 @@
     if (!mTagName.isEmpty()) {
         dst->appendFormat("%*s- tag name: %s\n", spaces, "", mTagName.string());
     }
-    std::string deviceLiteral;
-    if (deviceToString(mDeviceType, deviceLiteral)) {
-        dst->appendFormat("%*s- type: %-48s\n", spaces, "", deviceLiteral.c_str());
-    }
+
+    dst->appendFormat("%*s- type: %-48s\n", spaces, "", ::android::toString(mDeviceType).c_str());
+
     if (mAddress.size() != 0) {
         dst->appendFormat("%*s- address: %-32s\n", spaces, "", mAddress.string());
     }
@@ -401,9 +401,8 @@
 
 void DeviceDescriptor::log() const
 {
-    std::string device;
-    deviceToString(mDeviceType, device);
-    ALOGI("Device id:%d type:0x%08X:%s, addr:%s", mId,  mDeviceType, device.c_str(),
+    ALOGI("Device id:%d type:0x%08X:%s, addr:%s", mId,  mDeviceType,
+          ::android::toString(mDeviceType).c_str(),
           mAddress.string());
 
     AudioPort::log("  ");
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index e0b233d..ec7ff57 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -341,7 +341,7 @@
         }
     }
     if (!allowToCreate) {
-        ALOGE("%s: could not find HW module for device %s %04x address %s", __FUNCTION__,
+        ALOGV("%s: could not find HW module for device %s %04x address %s", __FUNCTION__,
               name, deviceType, address);
         return nullptr;
     }
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 81d3968..5f820c2 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -64,7 +64,7 @@
     }
 };
 
-struct AudioGainTraits : public AndroidCollectionTraits<AudioGain, AudioGainCollection>
+struct AudioGainTraits : public AndroidCollectionTraits<AudioGain, AudioGains>
 {
     static constexpr const char *tag = "gain";
     static constexpr const char *collectionTag = "gains";
@@ -84,6 +84,9 @@
         static constexpr const char *minRampMs = "minRampMs";
         /** needed if mode AUDIO_GAIN_MODE_RAMP. */
         static constexpr const char *maxRampMs = "maxRampMs";
+        /** needed to allow use setPortGain instead of setStreamVolume. */
+        static constexpr const char *useForVolume = "useForVolume";
+
     };
 
     static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
@@ -375,9 +378,14 @@
     if (!maxRampMsLiteral.empty() && convertTo(maxRampMsLiteral, maxRampMs)) {
         gain->setMaxRampInMs(maxRampMs);
     }
-    ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d", __func__,
-          gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
-          gain->getMaxValueInMb());
+    std::string useForVolumeLiteral = getXmlAttribute(cur, Attributes::useForVolume);
+    bool useForVolume = false;
+    if (!useForVolumeLiteral.empty() && convertTo(useForVolumeLiteral, useForVolume)) {
+        gain->setUseForVolume(useForVolume);
+    }
+    ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d UseForVolume: %d",
+          __func__, gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
+          gain->getMaxValueInMb(), useForVolume);
 
     if (gain->getMode() != 0) {
         return gain;
diff --git a/services/audiopolicy/config/a2dp_in_audio_policy_configuration.xml b/services/audiopolicy/config/a2dp_in_audio_policy_configuration.xml
new file mode 100644
index 0000000..57bd4f8
--- /dev/null
+++ b/services/audiopolicy/config/a2dp_in_audio_policy_configuration.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Bluetooth Input Audio HAL Audio Policy Configuration file -->
+<module name="a2dp" halVersion="2.0">
+    <mixPorts>
+        <mixPort name="a2dp input" role="sink">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100,48000"
+                     channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
+        </mixPort>
+    </mixPorts>
+    <devicePorts>
+        <devicePort tagName="BT A2DP In" type="AUDIO_DEVICE_IN_BLUETOOTH_A2DP" role="source">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100,48000"
+                     channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
+        </devicePort>
+    </devicePorts>
+    <routes>
+        <route type="mix" sink="a2dp input"
+               sources="BT A2DP In"/>
+    </routes>
+</module>
diff --git a/services/audiopolicy/config/audio_policy_configuration.xml b/services/audiopolicy/config/audio_policy_configuration.xml
index b4cc1d3..b28381b 100644
--- a/services/audiopolicy/config/audio_policy_configuration.xml
+++ b/services/audiopolicy/config/audio_policy_configuration.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- Copyright (C) 2019 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.
@@ -173,8 +173,8 @@
 
         </module>
 
-        <!-- A2dp Audio HAL -->
-        <xi:include href="a2dp_audio_policy_configuration.xml"/>
+        <!-- A2dp Input Audio HAL -->
+        <xi:include href="a2dp_in_audio_policy_configuration.xml"/>
 
         <!-- Usb Audio HAL -->
         <xi:include href="usb_audio_policy_configuration.xml"/>
@@ -182,8 +182,8 @@
         <!-- Remote Submix Audio HAL -->
         <xi:include href="r_submix_audio_policy_configuration.xml"/>
 
-        <!-- Hearing aid Audio HAL -->
-        <xi:include href="hearing_aid_audio_policy_configuration.xml"/>
+        <!-- Bluetooth Audio HAL -->
+        <xi:include href="bluetooth_audio_policy_configuration.xml"/>
 
         <!-- MSD Audio HAL (optional) -->
         <xi:include href="msd_audio_policy_configuration.xml"/>
diff --git a/services/audiopolicy/config/audio_policy_configuration_bluetooth_legacy_hal.xml b/services/audiopolicy/config/audio_policy_configuration_bluetooth_legacy_hal.xml
new file mode 100644
index 0000000..b4cc1d3
--- /dev/null
+++ b/services/audiopolicy/config/audio_policy_configuration_bluetooth_legacy_hal.xml
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <!-- version section contains a “version” tag in the form “major.minor” e.g version=”1.0” -->
+
+    <!-- Global configuration Decalaration -->
+    <globalConfiguration speaker_drc_enabled="true"/>
+
+
+    <!-- Modules section:
+        There is one section per audio HW module present on the platform.
+        Each module section will contains two mandatory tags for audio HAL “halVersion” and “name”.
+        The module names are the same as in current .conf file:
+                “primary”, “A2DP”, “remote_submix”, “USB”
+        Each module will contain the following sections:
+        “devicePorts”: a list of device descriptors for all input and output devices accessible via this
+        module.
+        This contains both permanently attached devices and removable devices.
+        “mixPorts”: listing all output and input streams exposed by the audio HAL
+        “routes”: list of possible connections between input and output devices or between stream and
+        devices.
+            "route": is defined by an attribute:
+                -"type": <mux|mix> means all sources are mutual exclusive (mux) or can be mixed (mix)
+                -"sink": the sink involved in this route
+                -"sources": all the sources than can be connected to the sink via vis route
+        “attachedDevices”: permanently attached devices.
+        The attachedDevices section is a list of devices names. The names correspond to device names
+        defined in <devicePorts> section.
+        “defaultOutputDevice”: device to be used by default when no policy rule applies
+    -->
+    <modules>
+        <!-- Primary Audio HAL -->
+        <module name="primary" halVersion="3.0">
+            <attachedDevices>
+                <item>Speaker</item>
+                <item>Built-In Mic</item>
+                <item>Built-In Back Mic</item>
+            </attachedDevices>
+            <defaultOutputDevice>Speaker</defaultOutputDevice>
+            <mixPorts>
+                <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="deep_buffer" role="source"
+                        flags="AUDIO_OUTPUT_FLAG_DEEP_BUFFER">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="compressed_offload" role="source"
+                         flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING">
+                    <profile name="" format="AUDIO_FORMAT_MP3"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
+                    <profile name="" format="AUDIO_FORMAT_AAC"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
+                    <profile name="" format="AUDIO_FORMAT_AAC_LC"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
+                </mixPort>
+                <mixPort name="voice_tx" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+                </mixPort>
+                <mixPort name="primary input" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
+                </mixPort>
+                <mixPort name="voice_rx" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                </mixPort>
+            </mixPorts>
+            <devicePorts>
+                <!-- Output devices declaration, i.e. Sink DEVICE PORT -->
+                <devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
+                   <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                </devicePort>
+                <devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address="">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                    <gains>
+                        <gain name="gain_1" mode="AUDIO_GAIN_MODE_JOINT"
+                              minValueMB="-8400"
+                              maxValueMB="4000"
+                              defaultValueMB="0"
+                              stepValueMB="100"/>
+                    </gains>
+                </devicePort>
+                <devicePort tagName="Wired Headset" type="AUDIO_DEVICE_OUT_WIRED_HEADSET" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </devicePort>
+                <devicePort tagName="Wired Headphones" type="AUDIO_DEVICE_OUT_WIRED_HEADPHONE" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </devicePort>
+                <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+                </devicePort>
+                <devicePort tagName="BT SCO Headset" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+                </devicePort>
+                <devicePort tagName="BT SCO Car Kit" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+                </devicePort>
+                <devicePort tagName="Telephony Tx" type="AUDIO_DEVICE_OUT_TELEPHONY_TX" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+                </devicePort>
+
+                <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
+                </devicePort>
+                <devicePort tagName="Built-In Back Mic" type="AUDIO_DEVICE_IN_BACK_MIC" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
+                </devicePort>
+                <devicePort tagName="Wired Headset Mic" type="AUDIO_DEVICE_IN_WIRED_HEADSET" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
+                </devicePort>
+                <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                </devicePort>
+                <devicePort tagName="Telephony Rx" type="AUDIO_DEVICE_IN_TELEPHONY_RX" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                </devicePort>
+            </devicePorts>
+            <!-- route declaration, i.e. list all available sources for a given sink -->
+            <routes>
+                <route type="mix" sink="Earpiece"
+                       sources="primary output,deep_buffer,BT SCO Headset Mic"/>
+                <route type="mix" sink="Speaker"
+                       sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
+                <route type="mix" sink="Wired Headset"
+                       sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
+                <route type="mix" sink="Wired Headphones"
+                       sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
+                <route type="mix" sink="primary input"
+                       sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic"/>
+                <route type="mix" sink="Telephony Tx"
+                       sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic, voice_tx"/>
+                <route type="mix" sink="voice_rx"
+                       sources="Telephony Rx"/>
+            </routes>
+
+        </module>
+
+        <!-- A2dp Audio HAL -->
+        <xi:include href="a2dp_audio_policy_configuration.xml"/>
+
+        <!-- Usb Audio HAL -->
+        <xi:include href="usb_audio_policy_configuration.xml"/>
+
+        <!-- Remote Submix Audio HAL -->
+        <xi:include href="r_submix_audio_policy_configuration.xml"/>
+
+        <!-- Hearing aid Audio HAL -->
+        <xi:include href="hearing_aid_audio_policy_configuration.xml"/>
+
+        <!-- MSD Audio HAL (optional) -->
+        <xi:include href="msd_audio_policy_configuration.xml"/>
+
+    </modules>
+    <!-- End of Modules section -->
+
+    <!-- Volume section:
+        IMPORTANT NOTE: Volume tables have been moved to engine configuration.
+                        Keep it here for legacy.
+                        Engine will fallback on these files if none are provided by engine.
+     -->
+
+    <xi:include href="audio_policy_volumes.xml"/>
+    <xi:include href="default_volume_tables.xml"/>
+
+    <!-- End of Volume section -->
+
+    <!-- Surround Sound configuration -->
+
+    <xi:include href="surround_sound_configuration_5_0.xml"/>
+
+    <!-- End of Surround Sound configuration -->
+
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/config/bluetooth_audio_policy_configuration.xml b/services/audiopolicy/config/bluetooth_audio_policy_configuration.xml
new file mode 100644
index 0000000..ce78eb0
--- /dev/null
+++ b/services/audiopolicy/config/bluetooth_audio_policy_configuration.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Bluetooth Audio HAL Audio Policy Configuration file -->
+<module name="bluetooth" halVersion="2.0">
+    <mixPorts>
+        <!-- A2DP Audio Ports -->
+        <mixPort name="a2dp output" role="source"/>
+        <!-- Hearing AIDs Audio Ports -->
+        <mixPort name="hearing aid output" role="source">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="24000,16000"
+                     channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+        </mixPort>
+    </mixPorts>
+    <devicePorts>
+        <!-- A2DP Audio Ports -->
+        <devicePort tagName="BT A2DP Out" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" role="sink">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100,48000,88200,96000"
+                     channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+        </devicePort>
+        <devicePort tagName="BT A2DP Headphones" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES" role="sink">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100,48000,88200,96000"
+                     channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+        </devicePort>
+        <devicePort tagName="BT A2DP Speaker" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER" role="sink">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100,48000,88200,96000"
+                     channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+        </devicePort>
+        <!-- Hearing AIDs Audio Ports -->
+        <devicePort tagName="BT Hearing Aid Out" type="AUDIO_DEVICE_OUT_HEARING_AID" role="sink"/>
+    </devicePorts>
+    <routes>
+        <route type="mix" sink="BT A2DP Out"
+               sources="a2dp output"/>
+        <route type="mix" sink="BT A2DP Headphones"
+               sources="a2dp output"/>
+        <route type="mix" sink="BT A2DP Speaker"
+               sources="a2dp output"/>
+        <route type="mix" sink="BT Hearing Aid Out"
+               sources="hearing aid output"/>
+    </routes>
+</module>
diff --git a/services/audiopolicy/engine/common/Android.bp b/services/audiopolicy/engine/common/Android.bp
index e6ede07..d0775ad 100644
--- a/services/audiopolicy/engine/common/Android.bp
+++ b/services/audiopolicy/engine/common/Android.bp
@@ -17,3 +17,31 @@
     host_supported: true,
     export_include_dirs: ["include"],
 }
+
+cc_library_static {
+    name: "libaudiopolicyengine_common",
+    srcs: [
+        "src/EngineBase.cpp",
+        "src/ProductStrategy.cpp",
+        "src/VolumeCurve.cpp",
+        "src/VolumeGroup.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    header_libs: [
+        "libbase_headers",
+        "libaudiopolicycommon",
+        "libaudiopolicyengine_common_headers",
+        "libaudiopolicyengine_interface_headers",
+    ],
+    export_header_lib_headers: [
+        "libaudiopolicyengine_common_headers",
+    ],
+    static_libs: [
+        "libaudiopolicycomponents",
+        "libaudiopolicyengine_config",
+    ],
+}
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
index bc027e2..6ff8512 100644
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -19,7 +19,7 @@
 #include <EngineConfig.h>
 #include <AudioPolicyManagerInterface.h>
 #include <ProductStrategy.h>
-#include <StreamVolumeCurves.h>
+#include <VolumeGroup.h>
 
 namespace android {
 namespace audio_policy {
@@ -68,9 +68,27 @@
 
     status_t listAudioProductStrategies(AudioProductStrategyVector &strategies) const override;
 
-    VolumeCurves *getVolumeCurvesForAttributes(const audio_attributes_t &attr) override;
+    VolumeCurves *getVolumeCurvesForAttributes(const audio_attributes_t &attr) const override;
 
-    VolumeCurves *getVolumeCurvesForStreamType(audio_stream_type_t stream) override;
+    VolumeCurves *getVolumeCurvesForStreamType(audio_stream_type_t stream) const override;
+
+    IVolumeCurves *getVolumeCurvesForVolumeGroup(volume_group_t group) const override
+    {
+       return mVolumeGroups.find(group) != end(mVolumeGroups) ?
+                   mVolumeGroups.at(group)->getVolumeCurves() : nullptr;
+    }
+
+    VolumeGroupVector getVolumeGroups() const override;
+
+    volume_group_t getVolumeGroupForAttributes(const audio_attributes_t &attr) const override;
+
+    volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const override;
+
+    StreamTypeVector getStreamTypesForVolumeGroup(volume_group_t volumeGroup) const override;
+
+    AttributesVector getAllAttributesForVolumeGroup(volume_group_t volumeGroup) const override;
+
+    status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const override;
 
     void dump(String8 *dst) const override;
 
@@ -105,12 +123,11 @@
     AudioPolicyManagerObserver *mApmObserver = nullptr;
 
     ProductStrategyMap mProductStrategies;
+    VolumeGroupMap mVolumeGroups;
     audio_mode_t mPhoneState = AUDIO_MODE_NORMAL;  /**< current phone state. */
 
     /** current forced use configuration. */
     audio_policy_forced_cfg_t mForceUse[AUDIO_POLICY_FORCE_USE_CNT] = {};
-
-    StreamVolumeCurves mStreamVolumeCurves;
 };
 
 } // namespace audio_policy
diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h
index 72505b2..767a8ed 100644
--- a/services/audiopolicy/engine/common/include/ProductStrategy.h
+++ b/services/audiopolicy/engine/common/include/ProductStrategy.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include "VolumeGroup.h"
+
 #include <system/audio.h>
 #include <AudioPolicyManagerInterface.h>
 #include <utils/RefBase.h>
@@ -38,7 +40,7 @@
 private:
     struct AudioAttributes {
         audio_stream_type_t mStream = AUDIO_STREAM_DEFAULT;
-        uint32_t mGroupId = 0;
+        volume_group_t mVolumeGroup = VOLUME_GROUP_NONE;
         audio_attributes_t mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
     };
 
@@ -85,6 +87,12 @@
     audio_attributes_t getAttributesForStreamType(audio_stream_type_t stream) const;
     audio_stream_type_t getStreamTypeForAttributes(const audio_attributes_t &attr) const;
 
+    volume_group_t getVolumeGroupForAttributes(const audio_attributes_t &attr) const;
+
+    volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const;
+
+    volume_group_t getDefaultVolumeGroup() const;
+
     bool isDefault() const;
 
     void dump(String8 *dst, int spaces = 0) const;
@@ -108,6 +116,10 @@
 {
 public:
     /**
+     * @brief initialize: set default product strategy in cache.
+     */
+    void initialize();
+    /**
      * @brief getProductStrategyForAttribute. The order of the vector is dimensionning.
      * @param attr
      * @return applicable product strategy for the given attribute, default if none applicable.
@@ -136,9 +148,16 @@
 
     std::string getDeviceAddressForProductStrategy(product_strategy_t strategy) const;
 
+    volume_group_t getVolumeGroupForAttributes(const audio_attributes_t &attr) const;
+
+    volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const;
+
     product_strategy_t getDefault() const;
 
     void dump(String8 *dst, int spaces = 0) const;
+
+private:
+    product_strategy_t mDefaultStrategy = PRODUCT_STRATEGY_NONE;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/engine/common/include/StreamVolumeCurves.h b/services/audiopolicy/engine/common/include/StreamVolumeCurves.h
deleted file mode 100644
index 5b0b7d6..0000000
--- a/services/audiopolicy/engine/common/include/StreamVolumeCurves.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <VolumeCurve.h>
-#include <map>
-
-namespace android {
-
-class StreamVolumeCurves
-{
-public:
-    StreamVolumeCurves() = default;
-
-    /**
-     * @brief switchVolumeCurve control API for Engine, allows to switch the volume curves
-     * from one stream type to another.
-     * @param src source stream type
-     * @param dst destination stream type
-     */
-    status_t switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst)
-    {
-        if (!hasCurvesFor(streamSrc) || !hasCurvesFor(streamDst)) {
-            ALOGE("%s: No curves defined for streams %d %d", __FUNCTION__, streamSrc, streamDst);
-            return NO_INIT;
-        }
-        const VolumeCurves &sourceCurves = getCurvesFor(streamSrc);
-        VolumeCurves &dstCurves = editCurvesFor(streamDst);
-        return dstCurves.switchCurvesFrom(sourceCurves);
-    }
-    void dump(String8 *dst, int spaces = 0) const;
-
-    void add(const VolumeCurves &curves, audio_stream_type_t streamType)
-    {
-        mCurves.emplace(streamType, curves);
-    }
-
-    bool hasCurvesFor(audio_stream_type_t stream)
-    {
-        return mCurves.find(stream) != end(mCurves);
-    }
-
-    VolumeCurves &editCurvesFor(audio_stream_type_t stream)
-    {
-        ALOG_ASSERT(mCurves.find(stream) != end(mCurves), "Invalid stream type for Volume Curve");
-        return mCurves[stream];
-    }
-    const VolumeCurves &getCurvesFor(audio_stream_type_t stream) const
-    {
-        ALOG_ASSERT(mCurves.find(stream) != end(mCurves), "Invalid stream type for Volume Curve");
-        return mCurves.at(stream);
-    }
-    /**
-     * @brief getVolumeCurvesForStream
-     * @param stream type for which the volume curves interface is requested
-     * @return the VolumeCurves for a given stream type.
-     */
-    VolumeCurves &getVolumeCurvesForStream(audio_stream_type_t stream)
-    {
-        ALOG_ASSERT(mCurves.find(stream) != end(mCurves), "Invalid stream type for Volume Curve");
-        return mCurves[stream];
-    }
-    /**
-     * @brief restoreOriginVolumeCurve helper control API for engine to restore the original volume
-     * curves for a given stream type
-     * @param stream for which the volume curves will be restored.
-     */
-    status_t restoreOriginVolumeCurve(audio_stream_type_t stream)
-    {
-        if (!hasCurvesFor(stream)) {
-            ALOGE("%s: No curves defined for streams", __FUNCTION__);
-            return NO_INIT;
-        }
-        return switchVolumeCurve(stream, stream);
-    }
-
-private:
-    std::map<audio_stream_type_t, VolumeCurves> mCurves;
-};
-
-} // namespace android
diff --git a/services/audiopolicy/engine/common/include/VolumeCurve.h b/services/audiopolicy/engine/common/include/VolumeCurve.h
index 0ec63e1..54314e3 100644
--- a/services/audiopolicy/engine/common/include/VolumeCurve.h
+++ b/services/audiopolicy/engine/common/include/VolumeCurve.h
@@ -18,7 +18,9 @@
 
 #include "IVolumeCurves.h"
 #include <policy.h>
+#include <AudioPolicyManagerInterface.h>
 #include <utils/RefBase.h>
+#include <HandleGenerator.h>
 #include <utils/String8.h>
 #include <utils/SortedVector.h>
 #include <utils/KeyedVector.h>
@@ -71,18 +73,11 @@
 {
 public:
     VolumeCurves(int indexMin = 0, int indexMax = 100) :
-        mIndexMin(indexMin), mIndexMax(indexMax), mStream(AUDIO_STREAM_DEFAULT)
+        mIndexMin(indexMin), mIndexMax(indexMax)
     {
         addCurrentVolumeIndex(AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, 0);
     }
-    VolumeCurves(audio_stream_type_t stream, int indexMin, int indexMax) :
-        mIndexMin(indexMin), mIndexMax(indexMax), mStream(stream)
-    {
-        addCurrentVolumeIndex(AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, 0);
-    }
-
-    // Once XML has been parsed, must be call first to sanity check table and initialize indexes
-    virtual status_t initVolume(int indexMin, int indexMax)
+    status_t initVolume(int indexMin, int indexMax) override
     {
         mIndexMin = indexMin;
         mIndexMax = indexMax;
@@ -174,8 +169,16 @@
             return 0.0f;
         }
     }
-
-    audio_stream_type_t getStreamType() const { return mStream; }
+    void addAttributes(const audio_attributes_t &attr)
+    {
+        mAttributes.push_back(attr);
+    }
+    AttributesVector getAttributes() const override { return mAttributes; }
+    void addStreamType(audio_stream_type_t stream)
+    {
+        mStreams.push_back(stream);
+    }
+    StreamTypeVector getStreamTypes() const override { return mStreams; }
 
     void dump(String8 *dst, int spaces = 0, bool curvePoints = false) const override;
 
@@ -186,7 +189,8 @@
     int mIndexMax; /**< max volume index. */
     const bool mCanBeMuted = true; /**< true is the stream can be muted. */
 
-    const audio_stream_type_t mStream; /**< Keep it for legacy. */
+    AttributesVector mAttributes;
+    StreamTypeVector mStreams; /**< Keep it for legacy. */
 };
 
 } // namespace android
diff --git a/services/audiopolicy/engine/common/include/VolumeGroup.h b/services/audiopolicy/engine/common/include/VolumeGroup.h
new file mode 100644
index 0000000..c34b406
--- /dev/null
+++ b/services/audiopolicy/engine/common/include/VolumeGroup.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <AudioPolicyManagerInterface.h>
+#include <VolumeCurve.h>
+#include <system/audio.h>
+#include <utils/RefBase.h>
+#include <HandleGenerator.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <utils/Errors.h>
+
+namespace android {
+
+class VolumeGroup : public virtual RefBase, private HandleGenerator<uint32_t>
+{
+public:
+    VolumeGroup(const std::string &name, int indexMin, int indexMax);
+    std::string getName() const { return mName; }
+    volume_group_t getId() const { return mId; }
+
+    void add(const sp<VolumeCurve> &curve);
+
+    VolumeCurves *getVolumeCurves() { return &mGroupVolumeCurves; }
+
+    void addSupportedAttributes(const audio_attributes_t &attr);
+    AttributesVector getSupportedAttributes() const { return mGroupVolumeCurves.getAttributes(); }
+
+    void addSupportedStream(audio_stream_type_t stream);
+    StreamTypeVector getStreamTypes() const { return mGroupVolumeCurves.getStreamTypes(); }
+
+    void dump(String8 *dst, int spaces = 0) const;
+
+private:
+    const std::string mName;
+    const volume_group_t mId;
+    VolumeCurves mGroupVolumeCurves;
+};
+
+class VolumeGroupMap : public std::map<volume_group_t, sp<VolumeGroup> >
+{
+public:
+    void dump(String8 *dst, int spaces = 0) const;
+};
+
+} // namespace android
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 6e2ab4c..4fe7b42 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -15,7 +15,7 @@
  */
 
 #define LOG_TAG "APM::AudioPolicyEngine/Base"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include "EngineBase.h"
 #include "EngineDefaultConfig.h"
@@ -96,46 +96,47 @@
 engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
 {
     auto loadProductStrategies =
-            [](auto& strategyConfigs, auto& productStrategies) {
-        uint32_t groupid = 0;
+            [](auto& strategyConfigs, auto& productStrategies, auto& volumeGroups) {
         for (auto& strategyConfig : strategyConfigs) {
             sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name);
             for (const auto &group : strategyConfig.attributesGroups) {
-                for (const auto &attr : group.attributesVect) {
-                    strategy->addAttributes({group.stream, groupid, attr});
+                const auto &iter = std::find_if(begin(volumeGroups), end(volumeGroups),
+                                         [&group](const auto &volumeGroup) {
+                        return group.volumeGroup == volumeGroup.second->getName(); });
+                ALOG_ASSERT(iter != end(volumeGroups), "Invalid Volume Group Name %s",
+                            group.volumeGroup.c_str());
+                if (group.stream != AUDIO_STREAM_DEFAULT) {
+                    iter->second->addSupportedStream(group.stream);
                 }
-                groupid += 1;
+                for (const auto &attr : group.attributesVect) {
+                    strategy->addAttributes({group.stream, iter->second->getId(), attr});
+                    iter->second->addSupportedAttributes(attr);
+                }
             }
             product_strategy_t strategyId = strategy->getId();
             productStrategies[strategyId] = strategy;
         }
     };
-    auto loadVolumeCurves = [](const auto &configVolumes, auto &streamVolumeCollection) {
-        for (auto &configVolume : configVolumes) {
-            audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT;
-            if (configVolume.stream.empty() ||
-                    !StreamTypeConverter::fromString(configVolume.stream, streamType)) {
-                ALOGE("%s: Invalid stream type", __FUNCTION__);
-                continue;
-            }
-            VolumeCurves volumeCurves(streamType, configVolume.indexMin, configVolume.indexMax);
-            for (auto &configCurve : configVolume.volumeCurves) {
-                device_category deviceCategory = DEVICE_CATEGORY_SPEAKER;
-                if (!DeviceCategoryConverter::fromString(configCurve.deviceCategory,
-                                                         deviceCategory)) {
+    auto loadVolumeGroups = [](auto &volumeConfigs, auto &volumeGroups) {
+        for (auto &volumeConfig : volumeConfigs) {
+            sp<VolumeGroup> volumeGroup = new VolumeGroup(volumeConfig.name, volumeConfig.indexMin,
+                                                          volumeConfig.indexMax);
+            volumeGroups[volumeGroup->getId()] = volumeGroup;
+
+            for (auto &configCurve : volumeConfig.volumeCurves) {
+                device_category deviceCat = DEVICE_CATEGORY_SPEAKER;
+                if (!DeviceCategoryConverter::fromString(configCurve.deviceCategory, deviceCat)) {
                     ALOGE("%s: Invalid %s", __FUNCTION__, configCurve.deviceCategory.c_str());
                     continue;
                 }
-                sp<VolumeCurve> curve = new VolumeCurve(deviceCategory);
+                sp<VolumeCurve> curve = new VolumeCurve(deviceCat);
                 for (auto &point : configCurve.curvePoints) {
                     curve->add({point.index, point.attenuationInMb});
                 }
-                volumeCurves.add(curve);
+                volumeGroup->add(curve);
             }
-            streamVolumeCollection.add(volumeCurves, streamType);
         }
     };
-
     auto result = engineConfig::parse();
     if (result.parsedConfig == nullptr) {
         ALOGW("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
@@ -145,8 +146,10 @@
                   static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};
     }
     ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
-    loadProductStrategies(result.parsedConfig->productStrategies, mProductStrategies);
-    loadVolumeCurves(result.parsedConfig->volumeGroups, mStreamVolumeCurves);
+    loadVolumeGroups(result.parsedConfig->volumeGroups, mVolumeGroups);
+    loadProductStrategies(result.parsedConfig->productStrategies, mProductStrategies,
+                          mVolumeGroups);
+    mProductStrategies.initialize();
     return result;
 }
 
@@ -204,30 +207,86 @@
     return NO_ERROR;
 }
 
-VolumeCurves *EngineBase::getVolumeCurvesForAttributes(const audio_attributes_t &attr)
+VolumeCurves *EngineBase::getVolumeCurvesForAttributes(const audio_attributes_t &attr) const
 {
-    return &mStreamVolumeCurves.getVolumeCurvesForStream(getStreamTypeForAttributes(attr));
+    volume_group_t volGr = mProductStrategies.getVolumeGroupForAttributes(attr);
+    const auto &iter = mVolumeGroups.find(volGr);
+    LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s", toString(attr).c_str());
+    return mVolumeGroups.at(volGr)->getVolumeCurves();
 }
 
-VolumeCurves *EngineBase::getVolumeCurvesForStreamType(audio_stream_type_t stream)
+VolumeCurves *EngineBase::getVolumeCurvesForStreamType(audio_stream_type_t stream) const
 {
-    return &mStreamVolumeCurves.getVolumeCurvesForStream(stream);
+    volume_group_t volGr = mProductStrategies.getVolumeGroupForStreamType(stream);
+    const auto &iter = mVolumeGroups.find(volGr);
+    LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s",
+                toString(stream).c_str());
+    return mVolumeGroups.at(volGr)->getVolumeCurves();
 }
 
 status_t EngineBase::switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst)
 {
-    return mStreamVolumeCurves.switchVolumeCurve(streamSrc, streamDst);;
+    auto srcCurves = getVolumeCurvesForStreamType(streamSrc);
+    auto dstCurves = getVolumeCurvesForStreamType(streamDst);
+
+    if (srcCurves == nullptr || dstCurves == nullptr) {
+        return BAD_VALUE;
+    }
+    return dstCurves->switchCurvesFrom(*srcCurves);
 }
 
 status_t EngineBase::restoreOriginVolumeCurve(audio_stream_type_t stream)
 {
-    return mStreamVolumeCurves.restoreOriginVolumeCurve(stream);
+    VolumeCurves *curves = getVolumeCurvesForStreamType(stream);
+    return curves != nullptr ? curves->switchCurvesFrom(*curves) : BAD_VALUE;
+}
+
+VolumeGroupVector EngineBase::getVolumeGroups() const
+{
+    VolumeGroupVector group;
+    for (const auto &iter : mVolumeGroups) {
+        group.push_back(iter.first);
+    }
+    return group;
+}
+
+volume_group_t EngineBase::getVolumeGroupForAttributes(const audio_attributes_t &attr) const
+{
+    return mProductStrategies.getVolumeGroupForAttributes(attr);
+}
+
+volume_group_t EngineBase::getVolumeGroupForStreamType(audio_stream_type_t stream) const
+{
+    return mProductStrategies.getVolumeGroupForStreamType(stream);
+}
+
+StreamTypeVector EngineBase::getStreamTypesForVolumeGroup(volume_group_t volumeGroup) const
+{
+    // @TODO default music stream to control volume if no group?
+    return (mVolumeGroups.find(volumeGroup) != end(mVolumeGroups)) ?
+                mVolumeGroups.at(volumeGroup)->getStreamTypes() :
+                StreamTypeVector(AUDIO_STREAM_MUSIC);
+}
+
+AttributesVector EngineBase::getAllAttributesForVolumeGroup(volume_group_t volumeGroup) const
+{
+    return (mVolumeGroups.find(volumeGroup) != end(mVolumeGroups)) ?
+                mVolumeGroups.at(volumeGroup)->getSupportedAttributes() : AttributesVector();
+}
+
+status_t EngineBase::listAudioVolumeGroups(AudioVolumeGroupVector &groups) const
+{
+    for (const auto &iter : mVolumeGroups) {
+        groups.push_back({iter.second->getName(), iter.second->getId(),
+                          iter.second->getSupportedAttributes(), iter.second->getStreamTypes()});
+    }
+    return NO_ERROR;
 }
 
 void EngineBase::dump(String8 *dst) const
 {
     mProductStrategies.dump(dst, 2);
-    mStreamVolumeCurves.dump(dst, 2);
+    mVolumeGroups.dump(dst, 2);
 }
 
 } // namespace audio_policy
diff --git a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
index f1642c5..fede0d9 100644
--- a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
+++ b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
@@ -25,11 +25,11 @@
 const engineConfig::ProductStrategies gOrderedStrategies = {
     {"STRATEGY_PHONE",
      {
-         {"phone", AUDIO_STREAM_VOICE_CALL,
+         {"phone", AUDIO_STREAM_VOICE_CALL, "AUDIO_STREAM_VOICE_CALL",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_SOURCE_DEFAULT, 0,
             ""}},
          },
-         {"sco", AUDIO_STREAM_BLUETOOTH_SCO,
+         {"sco", AUDIO_STREAM_BLUETOOTH_SCO, "AUDIO_STREAM_BLUETOOTH_SCO",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_SCO,
             ""}},
          }
@@ -37,18 +37,18 @@
     },
     {"STRATEGY_SONIFICATION",
      {
-         {"ring", AUDIO_STREAM_RING,
+         {"ring", AUDIO_STREAM_RING, "AUDIO_STREAM_RING",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
             AUDIO_SOURCE_DEFAULT, 0, ""}}
          },
-         {"alarm", AUDIO_STREAM_ALARM,
+         {"alarm", AUDIO_STREAM_ALARM, "AUDIO_STREAM_ALARM",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ALARM, AUDIO_SOURCE_DEFAULT, 0, ""}},
          }
      },
     },
     {"STRATEGY_ENFORCED_AUDIBLE",
      {
-         {"", AUDIO_STREAM_ENFORCED_AUDIBLE,
+         {"", AUDIO_STREAM_ENFORCED_AUDIBLE, "AUDIO_STREAM_ENFORCED_AUDIBLE",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
             AUDIO_FLAG_AUDIBILITY_ENFORCED, ""}}
          }
@@ -56,7 +56,7 @@
     },
     {"STRATEGY_ACCESSIBILITY",
      {
-         {"", AUDIO_STREAM_ACCESSIBILITY,
+         {"", AUDIO_STREAM_ACCESSIBILITY, "AUDIO_STREAM_ACCESSIBILITY",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
             AUDIO_SOURCE_DEFAULT, 0, ""}}
          }
@@ -64,7 +64,7 @@
     },
     {"STRATEGY_SONIFICATION_RESPECTFUL",
      {
-         {"", AUDIO_STREAM_NOTIFICATION,
+         {"", AUDIO_STREAM_NOTIFICATION, "AUDIO_STREAM_NOTIFICATION",
           {
               {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION, AUDIO_SOURCE_DEFAULT, 0, ""},
               {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
@@ -81,7 +81,7 @@
     },
     {"STRATEGY_MEDIA",
      {
-         {"music", AUDIO_STREAM_MUSIC,
+         {"music", AUDIO_STREAM_MUSIC, "AUDIO_STREAM_MUSIC",
           {
               {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA, AUDIO_SOURCE_DEFAULT, 0, ""},
               {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_GAME, AUDIO_SOURCE_DEFAULT, 0, ""},
@@ -91,7 +91,7 @@
               {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, 0, ""}
           },
          },
-         {"system", AUDIO_STREAM_SYSTEM,
+         {"system", AUDIO_STREAM_SYSTEM, "AUDIO_STREAM_SYSTEM",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ASSISTANCE_SONIFICATION,
             AUDIO_SOURCE_DEFAULT, 0, ""}}
          }
@@ -99,7 +99,7 @@
     },
     {"STRATEGY_DTMF",
      {
-         {"", AUDIO_STREAM_DTMF,
+         {"", AUDIO_STREAM_DTMF, "AUDIO_STREAM_DTMF",
           {
               {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
                AUDIO_SOURCE_DEFAULT, 0, ""}
@@ -109,7 +109,7 @@
     },
     {"STRATEGY_TRANSMITTED_THROUGH_SPEAKER",
      {
-         {"", AUDIO_STREAM_TTS,
+         {"", AUDIO_STREAM_TTS, "AUDIO_STREAM_TTS",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
             AUDIO_FLAG_BEACON, ""}}
          }
@@ -117,14 +117,14 @@
     },
     {"STRATEGY_REROUTING",
      {
-         {"", AUDIO_STREAM_REROUTING,
+         {"", AUDIO_STREAM_REROUTING, "AUDIO_STREAM_REROUTING",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, 0, ""}}
          }
      },
     },
     {"STRATEGY_PATCH",
      {
-         {"", AUDIO_STREAM_PATCH,
+         {"", AUDIO_STREAM_PATCH, "AUDIO_STREAM_PATCH",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, 0, ""}}
          }
      },
diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
index 71607d1..16e6690 100644
--- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp
+++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
@@ -44,7 +44,7 @@
 {
     std::vector<android::AudioAttributes> androidAa;
     for (const auto &attr : mAttributesVector) {
-        androidAa.push_back({attr.mGroupId, attr.mStream, attr.mAttributes});
+        androidAa.push_back({attr.mVolumeGroup, attr.mStream, attr.mAttributes});
     }
     return androidAa;
 }
@@ -69,7 +69,8 @@
     }) != end(mAttributesVector);
 }
 
-audio_stream_type_t ProductStrategy::getStreamTypeForAttributes(const audio_attributes_t &attr) const
+audio_stream_type_t ProductStrategy::getStreamTypeForAttributes(
+        const audio_attributes_t &attr) const
 {
     const auto iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
                                    [&attr](const auto &supportedAttr) {
@@ -110,6 +111,33 @@
         return supportedAttr.mStream == streamType; }) != end(mAttributesVector);
 }
 
+volume_group_t ProductStrategy::getVolumeGroupForAttributes(const audio_attributes_t &attr) const
+{
+    for (const auto &supportedAttr : mAttributesVector) {
+        if (AudioProductStrategy::attributesMatches(supportedAttr.mAttributes, attr)) {
+            return supportedAttr.mVolumeGroup;
+        }
+    }
+    return VOLUME_GROUP_NONE;
+}
+
+volume_group_t ProductStrategy::getVolumeGroupForStreamType(audio_stream_type_t stream) const
+{
+    for (const auto &supportedAttr : mAttributesVector) {
+        if (supportedAttr.mStream == stream) {
+            return supportedAttr.mVolumeGroup;
+        }
+    }
+    return VOLUME_GROUP_NONE;
+}
+
+volume_group_t ProductStrategy::getDefaultVolumeGroup() const
+{
+    const auto &iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
+                                    [](const auto &attr) {return attr.mAttributes == defaultAttr;});
+    return iter != end(mAttributesVector) ? iter->mVolumeGroup : VOLUME_GROUP_NONE;
+}
+
 void ProductStrategy::dump(String8 *dst, int spaces) const
 {
     dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId);
@@ -121,7 +149,7 @@
                        deviceLiteral.c_str(), mDeviceAddress.c_str());
 
     for (const auto &attr : mAttributesVector) {
-        dst->appendFormat("%*sGroup: %d stream: %s\n", spaces + 3, "", attr.mGroupId,
+        dst->appendFormat("%*sGroup: %d stream: %s\n", spaces + 3, "", attr.mVolumeGroup,
                           android::toString(attr.mStream).c_str());
         dst->appendFormat("%*s Attributes: ", spaces + 3, "");
         std::string attStr =
@@ -172,6 +200,9 @@
 
 product_strategy_t ProductStrategyMap::getDefault() const
 {
+    if (mDefaultStrategy != PRODUCT_STRATEGY_NONE) {
+        return mDefaultStrategy;
+    }
     for (const auto &iter : *this) {
         if (iter.second->isDefault()) {
             ALOGV("%s: using default %s", __FUNCTION__, iter.second->getName().c_str());
@@ -231,6 +262,42 @@
     return at(psId)->getDeviceAddress();
 }
 
+volume_group_t ProductStrategyMap::getVolumeGroupForAttributes(const audio_attributes_t &attr) const
+{
+    for (const auto &iter : *this) {
+        volume_group_t group = iter.second->getVolumeGroupForAttributes(attr);
+        if (group != VOLUME_GROUP_NONE) {
+            return group;
+        }
+    }
+    product_strategy_t defaultStrategy = getDefault();
+    if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
+        return VOLUME_GROUP_NONE;
+    }
+    return at(defaultStrategy)->getDefaultVolumeGroup();
+}
+
+volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(audio_stream_type_t stream) const
+{
+    for (const auto &iter : *this) {
+        volume_group_t group = iter.second->getVolumeGroupForStreamType(stream);
+        if (group != VOLUME_GROUP_NONE) {
+            return group;
+        }
+    }
+    product_strategy_t defaultStrategy = getDefault();
+    if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
+        return VOLUME_GROUP_NONE;
+    }
+    return at(defaultStrategy)->getDefaultVolumeGroup();
+}
+
+void ProductStrategyMap::initialize()
+{
+    mDefaultStrategy = getDefault();
+    ALOG_ASSERT(mDefaultStrategy != PRODUCT_STRATEGY_NONE, "No default product strategy found");
+}
+
 void ProductStrategyMap::dump(String8 *dst, int spaces) const
 {
     dst->appendFormat("%*sProduct Strategies dump:", spaces, "");
diff --git a/services/audiopolicy/engine/common/src/StreamVolumeCurves.cpp b/services/audiopolicy/engine/common/src/StreamVolumeCurves.cpp
deleted file mode 100644
index fe3b000..0000000
--- a/services/audiopolicy/engine/common/src/StreamVolumeCurves.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "APM::Engine::StreamVolumeCurves"
-//#define LOG_NDEBUG 0
-
-#include "StreamVolumeCurves.h"
-#include <TypeConverter.h>
-
-namespace android {
-
-void StreamVolumeCurves::dump(String8 *dst, int spaces) const
-{
-    if (mCurves.empty()) {
-        return;
-    }
-    dst->appendFormat("\n%*sStreams dump:\n", spaces, "");
-    dst->appendFormat(
-                "%*sStream  Can be muted  Index Min  Index Max  Index Cur [device : index]...\n", spaces + 2, "");
-    for (const auto &streamCurve : mCurves) {
-        streamCurve.second.dump(dst, spaces + 2, false);
-    }
-    dst->appendFormat("\n%*sVolume Curves for Use Cases (aka Stream types) dump:\n", spaces, "");
-    for (const auto &streamCurve : mCurves) {
-        std::string streamTypeLiteral;
-        StreamTypeConverter::toString(streamCurve.first, streamTypeLiteral);
-        dst->appendFormat(
-                    " %s (%02d): Curve points for device category (index, attenuation in millibel)\n",
-                    streamTypeLiteral.c_str(), streamCurve.first);
-        streamCurve.second.dump(dst, spaces + 2, true);
-    }
-}
-
-} // namespace android
diff --git a/services/audiopolicy/engine/common/src/VolumeCurve.cpp b/services/audiopolicy/engine/common/src/VolumeCurve.cpp
index be2ca73..c352578 100644
--- a/services/audiopolicy/engine/common/src/VolumeCurve.cpp
+++ b/services/audiopolicy/engine/common/src/VolumeCurve.cpp
@@ -19,13 +19,17 @@
 
 #include "VolumeCurve.h"
 #include "TypeConverter.h"
+#include <media/TypeConverter.h>
 
 namespace android {
 
 float VolumeCurve::volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const
 {
     ALOG_ASSERT(!mCurvePoints.isEmpty(), "Invalid volume curve");
-
+    if (volIndexMin < 0 || volIndexMax < 0) {
+        // In order to let AudioService initialize the min and max, convention is to use -1
+        return NAN;
+    }
     if (indexInUi < volIndexMin) {
         // an index of 0 means mute request when volIndexMin > 0
         if (indexInUi == 0) {
@@ -80,8 +84,8 @@
     }
     dst->append(" {");
     for (size_t i = 0; i < mCurvePoints.size(); i++) {
-        dst->appendFormat("%*s (%3d, %5d)", spaces, "",
-                 mCurvePoints[i].mIndex, mCurvePoints[i].mAttenuationInMb);
+        dst->appendFormat("%*s(%3d, %5d)", spaces, "", mCurvePoints[i].mIndex,
+                          mCurvePoints[i].mAttenuationInMb);
         dst->appendFormat(i == (mCurvePoints.size() - 1) ? " }\n" : ", ");
     }
 }
@@ -89,19 +93,36 @@
 void VolumeCurves::dump(String8 *dst, int spaces, bool curvePoints) const
 {
     if (!curvePoints) {
-        dst->appendFormat("%*s%02d      %s         %03d        %03d        ", spaces, "",
-                          mStream, mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
+//        dst->appendFormat("%*s%02d      %s         %03d        %03d        ", spaces, "",
+//                          mStream, mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
+        dst->appendFormat("%*s Can be muted  Index Min  Index Max  Index Cur [device : index]...\n",
+                          spaces + 1, "");
+        dst->appendFormat("%*s %s         %02d         %02d         ", spaces + 1, "",
+                          mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
         for (const auto &pair : mIndexCur) {
-            dst->appendFormat("%*s %04x : %02d, ", spaces, "", pair.first, pair.second);
+            dst->appendFormat("%04x : %02d, ", pair.first, pair.second);
         }
         dst->appendFormat("\n");
         return;
     }
+    std::string streamNames;
+    for (const auto &stream : mStreams) {
+        streamNames += android::toString(stream) + "("+std::to_string(stream)+") ";
+    }
+    dst->appendFormat("%*sVolume Curves Streams/Attributes, Curve points Streams for device"
+                      " category (index, attenuation in millibel)\n", spaces, "");
+    dst->appendFormat("%*s Streams: %s \n", spaces, "", streamNames.c_str());
+    if (!mAttributes.empty()) dst->appendFormat("%*s Attributes:", spaces, "");
+    for (const auto &attributes : mAttributes) {
+        std::string attStr = attributes == defaultAttr ? "{ Any }" : android::toString(attributes);
+        dst->appendFormat("%*s %s\n", attributes == mAttributes.front() ? 0 : spaces + 13, "",
+                          attStr.c_str());
+    }
     for (size_t i = 0; i < size(); i++) {
         std::string deviceCatLiteral;
         DeviceCategoryConverter::toString(keyAt(i), deviceCatLiteral);
         dst->appendFormat("%*s %s :", spaces, "", deviceCatLiteral.c_str());
-        valueAt(i)->dump(dst, 2, true);
+        valueAt(i)->dump(dst, 1, true);
     }
 }
 
diff --git a/services/audiopolicy/engine/common/src/VolumeGroup.cpp b/services/audiopolicy/engine/common/src/VolumeGroup.cpp
new file mode 100644
index 0000000..e189807
--- /dev/null
+++ b/services/audiopolicy/engine/common/src/VolumeGroup.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::AudioPolicyEngine/VolumeGroup"
+//#define LOG_NDEBUG 0
+
+#include "VolumeGroup.h"
+#include <media/TypeConverter.h>
+#include <utils/String8.h>
+#include <cstdint>
+#include <string>
+
+#include <log/log.h>
+
+
+namespace android {
+
+//
+// VolumeGroup implementation
+//
+VolumeGroup::VolumeGroup(const std::string &name, int indexMin, int indexMax) :
+    mName(name), mId(static_cast<volume_group_t>(HandleGenerator<uint32_t>::getNextHandle())),
+    mGroupVolumeCurves(VolumeCurves(indexMin, indexMax))
+{
+}
+
+void VolumeGroup::dump(String8 *dst, int spaces) const
+{
+    dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId);
+    mGroupVolumeCurves.dump(dst, spaces + 2, true);
+    mGroupVolumeCurves.dump(dst, spaces + 2, false);
+    dst->appendFormat("\n");
+}
+
+void VolumeGroup::add(const sp<VolumeCurve> &curve)
+{
+    mGroupVolumeCurves.add(curve);
+}
+
+void VolumeGroup::addSupportedAttributes(const audio_attributes_t &attr)
+{
+    mGroupVolumeCurves.addAttributes(attr);
+}
+
+void VolumeGroup::addSupportedStream(audio_stream_type_t stream)
+{
+    mGroupVolumeCurves.addStreamType(stream);
+}
+
+//
+// VolumeGroupMap implementation
+//
+void VolumeGroupMap::dump(String8 *dst, int spaces) const
+{
+    dst->appendFormat("\n%*sVolume Groups dump:", spaces, "");
+    for (const auto &iter : *this) {
+        iter.second->dump(dst, spaces + 2);
+    }
+}
+
+} // namespace android
+
diff --git a/services/audiopolicy/engine/config/Android.bp b/services/audiopolicy/engine/config/Android.bp
new file mode 100644
index 0000000..6e72f2a
--- /dev/null
+++ b/services/audiopolicy/engine/config/Android.bp
@@ -0,0 +1,31 @@
+cc_library_static {
+    name: "libaudiopolicyengine_config",
+    export_include_dirs: ["include"],
+    include_dirs: [
+        "external/libxml2/include",
+        "external/icu/icu4c/source/common",
+    ],
+    srcs: [
+        "src/EngineConfig.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    shared_libs: [
+        "libmedia_helper",
+        "libandroidicu",
+        "libxml2",
+        "libutils",
+        "liblog",
+        "libcutils",
+    ],
+    static_libs: [
+        "libaudiopolicycomponents",
+    ],
+    header_libs: [
+        "libaudio_system_headers",
+        "libaudiopolicycommon",
+    ],
+}
diff --git a/services/audiopolicy/engine/config/Android.mk b/services/audiopolicy/engine/config/Android.mk
deleted file mode 100644
index 0b292a5..0000000
--- a/services/audiopolicy/engine/config/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-##################################################################
-# Component build
-##################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_EXPORT_C_INCLUDE_DIRS :=  $(LOCAL_PATH)/include
-
-LOCAL_C_INCLUDES := \
-    $(LOCAL_EXPORT_C_INCLUDE_DIRS) \
-    external/libxml2/include \
-    external/icu/icu4c/source/common
-
-LOCAL_SRC_FILES := \
-    src/EngineConfig.cpp
-
-LOCAL_CFLAGS += -Wall -Werror -Wextra
-
-LOCAL_SHARED_LIBRARIES := \
-    libmedia_helper \
-    libandroidicu \
-    libxml2 \
-    libutils \
-    liblog \
-    libcutils
-
-LOCAL_STATIC_LIBRARIES := \
-    libaudiopolicycomponents
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_MODULE := libaudiopolicyengineconfig
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_HEADER_LIBRARIES := \
-    libaudio_system_headers \
-    libaudiopolicycommon
-
-include $(BUILD_SHARED_LIBRARY)
-
diff --git a/services/audiopolicy/engine/config/include/EngineConfig.h b/services/audiopolicy/engine/config/include/EngineConfig.h
index a188115..7f5ed5e 100644
--- a/services/audiopolicy/engine/config/include/EngineConfig.h
+++ b/services/audiopolicy/engine/config/include/EngineConfig.h
@@ -40,6 +40,7 @@
 struct AttributesGroup {
     std::string name;
     audio_stream_type_t stream;
+    std::string volumeGroup;
     AttributesVector attributesVect;
 };
 
@@ -59,7 +60,6 @@
 
 struct VolumeGroup {
     std::string name;
-    std::string stream;
     int indexMin;
     int indexMax;
     VolumeCurves volumeCurves;
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
index 00fbac4..1ad7739 100644
--- a/services/audiopolicy/engine/config/src/EngineConfig.cpp
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -59,6 +59,7 @@
     struct Attributes {
         static constexpr const char *name = "name";
         static constexpr const char *streamType = "streamType";
+        static constexpr const char *volumeGroup = "volumeGroup";
     };
     static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root, Collection &ps);
 };
@@ -116,6 +117,7 @@
 
     struct Attributes {
         static constexpr const char *deviceCategory = "deviceCategory";
+        static constexpr const char *stream = "stream"; // For legacy volume curves
         static constexpr const char *reference = "ref"; /**< For volume curves factorization. */
     };
 
@@ -139,8 +141,6 @@
 
 using xmlCharUnique = std::unique_ptr<xmlChar, decltype(xmlFree)>;
 
-using xmlCharUnique = std::unique_ptr<xmlChar, decltype(xmlFree)>;
-
 std::string getXmlAttribute(const xmlNode *cur, const char *attribute)
 {
     xmlCharUnique charPtr(xmlGetProp(cur, reinterpret_cast<const xmlChar *>(attribute)), xmlFree);
@@ -304,6 +304,12 @@
     }
     ALOGV("%s: %s = %s", __FUNCTION__, Attributes::name, name.c_str());
 
+    std::string volumeGroup = getXmlAttribute(child, Attributes::volumeGroup);
+    if (volumeGroup.empty()) {
+        ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::volumeGroup);
+    }
+    ALOGV("%s: %s = %s", __FUNCTION__, Attributes::volumeGroup, volumeGroup.c_str());
+
     audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT;
     std::string streamTypeXml = getXmlAttribute(child, Attributes::streamType);
     if (streamTypeXml.empty()) {
@@ -318,7 +324,7 @@
     AttributesVector attributesVect;
     deserializeAttributesCollection(doc, child, attributesVect);
 
-    attributesGroup.push_back({name, streamType, attributesVect});
+    attributesGroup.push_back({name, streamType, volumeGroup, attributesVect});
     return NO_ERROR;
 }
 
@@ -420,7 +426,6 @@
     if (deviceCategory.empty()) {
         ALOGW("%s: No %s found", __FUNCTION__, Attributes::deviceCategory);
     }
-
     std::string referenceName = getXmlAttribute(root, Attributes::reference);
     const _xmlNode *ref = NULL;
     if (!referenceName.empty()) {
@@ -458,9 +463,10 @@
 status_t VolumeGroupTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, Collection &volumes)
 {
     std::string name;
-    std::string stream = {};
     int indexMin = 0;
     int indexMax = 0;
+    StreamVector streams = {};
+    AttributesVector attributesVect = {};
 
     for (const xmlNode *child = root->xmlChildrenNode; child != NULL; child = child->next) {
         if (not xmlStrcmp(child->name, (const xmlChar *)Attributes::name)) {
@@ -470,13 +476,6 @@
             }
             name = reinterpret_cast<const char*>(nameXml.get());
         }
-        if (not xmlStrcmp(child->name, (const xmlChar *)Attributes::stream)) {
-            xmlCharUnique streamXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree);
-            if (streamXml == nullptr) {
-                return BAD_VALUE;
-            }
-            stream = reinterpret_cast<const char*>(streamXml.get());
-        }
         if (not xmlStrcmp(child->name, (const xmlChar *)Attributes::indexMin)) {
             xmlCharUnique indexMinXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree);
             if (indexMinXml == nullptr) {
@@ -498,13 +497,23 @@
             }
         }
     }
-    ALOGV("%s: group=%s stream=%s indexMin=%d, indexMax=%d",
-          __func__, name.c_str(), stream.c_str(), indexMin, indexMax);
+    deserializeAttributesCollection(doc, root, attributesVect);
+
+    std::string streamNames;
+    for (const auto &stream : streams) {
+        streamNames += android::toString(stream) + " ";
+    }
+    std::string attrmNames;
+    for (const auto &attr : attributesVect) {
+        attrmNames += android::toString(attr) + "\n";
+    }
+    ALOGV("%s: group=%s indexMin=%d, indexMax=%d streams=%s attributes=%s",
+          __func__, name.c_str(), indexMin, indexMax, streamNames.c_str(), attrmNames.c_str( ));
 
     VolumeCurves groupVolumeCurves;
     size_t skipped = 0;
     deserializeCollection<VolumeTraits>(doc, root, groupVolumeCurves, skipped);
-    volumes.push_back({ name, stream, indexMin, indexMax, groupVolumeCurves });
+    volumes.push_back({ name, indexMin, indexMax, groupVolumeCurves });
     return NO_ERROR;
 }
 
@@ -580,8 +589,16 @@
         }
     }
     for (const auto &volumeMapIter : legacyVolumeMap) {
-        volumeGroups.push_back({ volumeMapIter.first, volumeMapIter.first, 0, 100,
-                                 volumeMapIter.second });
+        // In order to let AudioService setting the min and max (compatibility), set Min and Max
+        // to -1 except for private streams
+        audio_stream_type_t streamType;
+        if (!StreamTypeConverter::fromString(volumeMapIter.first, streamType)) {
+            ALOGE("%s: Invalid stream %s", __func__, volumeMapIter.first.c_str());
+            return BAD_VALUE;
+        }
+        int indexMin = streamType >= AUDIO_STREAM_PUBLIC_CNT ? 0 : -1;
+        int indexMax = streamType >= AUDIO_STREAM_PUBLIC_CNT ? 100 : -1;
+        volumeGroups.push_back({ volumeMapIter.first, indexMin, indexMax, volumeMapIter.second });
     }
     return NO_ERROR;
 }
diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
index c9e9507..38f3401 100644
--- a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
+++ b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
@@ -18,6 +18,7 @@
 
 #include <AudioPolicyManagerObserver.h>
 #include <media/AudioProductStrategy.h>
+#include <media/AudioVolumeGroup.h>
 #include <IVolumeCurves.h>
 #include <policy.h>
 #include <Volume.h>
@@ -32,7 +33,7 @@
 
 using DeviceStrategyMap = std::map<product_strategy_t, DeviceVector>;
 using StrategyVector = std::vector<product_strategy_t>;
-
+using VolumeGroupVector = std::vector<volume_group_t>;
 
 /**
  * This interface is dedicated to the policy manager that a Policy Engine shall implement.
@@ -182,6 +183,7 @@
 
     /**
      * @brief getAttributesForStream get the audio attributes from legacy stream type
+     * Attributes returned might only be used to check upon routing decision, not volume decisions.
      * @param stream to consider
      * @return audio attributes matching the legacy stream type
      */
@@ -241,14 +243,58 @@
      * @param attr to be considered
      * @return IVolumeCurves interface pointer if found, nullptr otherwise
      */
-    virtual IVolumeCurves *getVolumeCurvesForAttributes(const audio_attributes_t &attr) = 0;
+    virtual IVolumeCurves *getVolumeCurvesForAttributes(const audio_attributes_t &attr) const = 0;
 
     /**
      * @brief getVolumeCurvesForStreamType retrieves the Volume Curves interface for the stream
      * @param stream to be considered
      * @return IVolumeCurves interface pointer if found, nullptr otherwise
      */
-    virtual IVolumeCurves *getVolumeCurvesForStreamType(audio_stream_type_t stream) = 0;
+    virtual IVolumeCurves *getVolumeCurvesForStreamType(audio_stream_type_t stream) const = 0;
+
+    /**
+     * @brief getVolumeCurvesForVolumeGroup retrieves the Volume Curves interface for volume group
+     * @param group to be considered
+     * @return IVolumeCurves interface pointer if found, nullptr otherwise
+     */
+    virtual IVolumeCurves *getVolumeCurvesForVolumeGroup(volume_group_t group) const = 0;
+
+    /**
+     * @brief getVolumeGroups retrieves the collection of volume groups.
+     * @return vector of volume groups
+     */
+    virtual VolumeGroupVector getVolumeGroups() const = 0;
+
+    /**
+     * @brief getVolumeGroupForAttributes gets the appropriate volume group to be used for a given
+     * Audio Attributes.
+     * @param attr to be considered
+     * @return volume group associated to the given audio attributes, default group if none
+     * applicable, VOLUME_GROUP_NONE if no default group defined.
+     */
+    virtual volume_group_t getVolumeGroupForAttributes(const audio_attributes_t &attr) const = 0;
+
+    /**
+     * @brief getVolumeGroupForStreamType gets the appropriate volume group to be used for a given
+     * legacy stream type
+     * @param stream type to be considered
+     * @return volume group associated to the given stream type, default group if none applicable,
+     * VOLUME_GROUP_NONE if no default group defined.
+     */
+    virtual volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const = 0;
+
+    virtual StreamTypeVector getStreamTypesForVolumeGroup(volume_group_t volumeGroup) const = 0;
+
+    virtual AttributesVector getAllAttributesForVolumeGroup(volume_group_t volumeGroup) const = 0;
+
+    /**
+     * @brief listAudioVolumeGroups introspection API to get the Audio Volume Groups, aka
+     * former stream aliases in Audio Service, defining volume curves attached to one or more
+     * Audio Attributes.
+     * @param groups
+     * @return NO_ERROR if the volume groups were retrieved successfully, error code otherwise
+     */
+    virtual status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const = 0;
 
     virtual void dump(String8 *dst) const = 0;
 
diff --git a/services/audiopolicy/engineconfigurable/Android.mk b/services/audiopolicy/engineconfigurable/Android.mk
index 2b7e4c8..84a4422 100644
--- a/services/audiopolicy/engineconfigurable/Android.mk
+++ b/services/audiopolicy/engineconfigurable/Android.mk
@@ -12,10 +12,6 @@
     src/EngineInstance.cpp \
     src/Stream.cpp \
     src/InputSource.cpp \
-    ../engine/common/src/VolumeCurve.cpp \
-    ../engine/common/src/StreamVolumeCurves.cpp \
-    ../engine/common/src/ProductStrategy.cpp \
-    ../engine/common/src/EngineBase.cpp
 
 audio_policy_engine_includes_common := \
     frameworks/av/services/audiopolicy/engineconfigurable/include \
@@ -37,7 +33,6 @@
 
 LOCAL_HEADER_LIBRARIES := \
     libaudiopolicycommon \
-    libaudiopolicyengine_common_headers \
     libaudiopolicyengine_interface_headers
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
@@ -47,13 +42,15 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libaudiopolicypfwwrapper \
-    libaudiopolicycomponents
+    libaudiopolicycomponents \
+    libaudiopolicyengine_common \
+    libaudiopolicyengine_config \
 
 LOCAL_SHARED_LIBRARIES := \
-    libaudiopolicyengineconfig \
     liblog \
     libutils \
     liblog \
+    libcutils \
     libaudioutils \
     libparameter \
     libmedia_helper \
diff --git a/services/audiopolicy/engineconfigurable/config/example/Android.mk b/services/audiopolicy/engineconfigurable/config/example/Android.mk
index ef476f7..45419f0 100644
--- a/services/audiopolicy/engineconfigurable/config/example/Android.mk
+++ b/services/audiopolicy/engineconfigurable/config/example/Android.mk
@@ -72,7 +72,8 @@
 LOCAL_REQUIRED_MODULES := \
     audio_policy_engine_product_strategies_automotive.xml \
     audio_policy_engine_criteria.xml \
-    audio_policy_engine_criterion_types.xml
+    audio_policy_engine_criterion_types.xml \
+    audio_policy_engine_volumes.xml
 
 include $(BUILD_PREBUILT)
 
@@ -89,6 +90,14 @@
 LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE_STEM)
 include $(BUILD_PREBUILT)
 
+include $(CLEAR_VARS)
+LOCAL_MODULE := audio_policy_engine_volumes.xml
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
+LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
 endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
 
 ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable))
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_configuration.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_configuration.xml
index e2fb02b..28a140a 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_configuration.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_configuration.xml
@@ -19,6 +19,7 @@
     <xi:include href="audio_policy_engine_product_strategies.xml"/>
     <xi:include href="audio_policy_engine_criterion_types.xml"/>
     <xi:include href="audio_policy_engine_criteria.xml"/>
+    <xi:include href="audio_policy_engine_volumes.xml"/>
 
 </configuration>
 
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
index 543a2f0..c487da9 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
@@ -31,7 +31,7 @@
     -->
 
     <ProductStrategy name="oem_traffic_anouncement">
-        <AttributesGroup>
+        <AttributesGroup volumeGroup="oem_traffic_anouncement">
             <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
             <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
             <!--  traffic_annoucement = 1 -->
@@ -39,14 +39,14 @@
         </AttributesGroup>
     </ProductStrategy>
     <ProductStrategy name="oem_strategy_1">
-        <AttributesGroup>
+        <AttributesGroup volumeGroup="oem_adas_2">
             <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
             <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
             <Bundle key="oem" value="2"/>
         </AttributesGroup>
     </ProductStrategy>
     <ProductStrategy name="oem_strategy_2">
-        <AttributesGroup>
+        <AttributesGroup volumeGroup="oem_adas_3">
             <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
             <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
             <Bundle key="oem" value="3"/>
@@ -70,21 +70,21 @@
         ( type == CAR_AUDIO_TYPE_RADIO ) )
         -->
     <ProductStrategy name="radio">
-        <AttributesGroup>
+        <AttributesGroup volumeGroup="media_car_audio_type_3">
             <ContentType value="AUDIO_CONTENT_TYPE_MUSIC"/>
             <Usage value="AUDIO_USAGE_MEDIA"/>
             <Bundle key="car_audio_type" value="3"/>
         </AttributesGroup>
     </ProductStrategy>
     <ProductStrategy name="ext_audio_source">
-        <AttributesGroup>
+        <AttributesGroup volumeGroup="media_car_audio_type_7">
             <ContentType value="AUDIO_CONTENT_TYPE_MUSIC"/>
             <Usage value="AUDIO_USAGE_MEDIA"/>
             <Bundle key="car_audio_type" value="7"/>
         </AttributesGroup>
     </ProductStrategy>
     <ProductStrategy name="voice_command">
-        <AttributesGroup>
+        <AttributesGroup volumeGroup="speech">
             <Attributes>
                 <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
                 <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
@@ -96,7 +96,7 @@
         </AttributesGroup>
     </ProductStrategy>
     <ProductStrategy name="safety_alert">
-        <AttributesGroup>
+        <AttributesGroup volumeGroup="system">
             <ContentType value="AUDIO_CONTENT_TYPE_SONIFICATION"/>
             <Usage value="AUDIO_USAGE_NOTIFICATION"/>
             <!--  CAR_AUDIO_TYPE_SAFETY_ALERT = 2 -->
@@ -112,7 +112,7 @@
 
     <!-- Generic Usages -->
     <ProductStrategy name="music">
-        <AttributesGroup streamType="AUDIO_STREAM_MUSIC">
+        <AttributesGroup streamType="AUDIO_STREAM_MUSIC" volumeGroup="media">
             <Attributes> <Usage value="AUDIO_USAGE_MEDIA"/> </Attributes>
             <Attributes> <Usage value="AUDIO_USAGE_GAME"/> </Attributes>
             <!-- Default product strategy has empty attributes -->
@@ -121,29 +121,31 @@
     </ProductStrategy>
 
     <ProductStrategy name="nav_guidance">
-        <AttributesGroup>
+        <AttributesGroup volumeGroup="speech">
             <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
         </AttributesGroup>
     </ProductStrategy>
     <ProductStrategy name="voice_call">
-        <AttributesGroup streamType="AUDIO_STREAM_VOICE_CALL">
+        <AttributesGroup streamType="AUDIO_STREAM_VOICE_CALL" volumeGroup="phone">
             <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION"/> </Attributes>
             <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING"/> </Attributes>
+        </AttributesGroup>
+        <AttributesGroup streamType="AUDIO_STREAM_BLUETOOTH_SCO" volumeGroup="phone">
             <Attributes> <Flags value="AUDIO_FLAG_SCO"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
     <ProductStrategy name="alarm">
-        <AttributesGroup streamType="AUDIO_STREAM_ALARM">
+        <AttributesGroup streamType="AUDIO_STREAM_ALARM" volumeGroup="ring">
             <Usage value="AUDIO_USAGE_ALARM"/>
         </AttributesGroup>
     </ProductStrategy>
     <ProductStrategy name="ring">
-        <AttributesGroup streamType="AUDIO_STREAM_RING">
+        <AttributesGroup streamType="AUDIO_STREAM_RING" volumeGroup="ring">
             <Usage value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE"/>
         </AttributesGroup>
     </ProductStrategy>
     <ProductStrategy name="notification">
-        <AttributesGroup streamType="AUDIO_STREAM_NOTIFICATION">
+        <AttributesGroup streamType="AUDIO_STREAM_NOTIFICATION" volumeGroup="ring">
             <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION"/> </Attributes>
             <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/> </Attributes>
             <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED"/> </Attributes>
@@ -152,10 +154,17 @@
         </AttributesGroup>
     </ProductStrategy>
     <ProductStrategy name="system">
-        <AttributesGroup streamType="AUDIO_STREAM_SYSTEM">
+        <AttributesGroup streamType="AUDIO_STREAM_SYSTEM" volumeGroup="system">
             <Usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/>
         </AttributesGroup>
     </ProductStrategy>
-
+    <ProductStrategy name="tts">
+        <!-- TTS stream MUST BE MANAGED OUTSIDE default product strategy if NO DEDICATED OUTPUT
+             for TTS, otherwise when beacon happens, default strategy is ... muted.
+             If it is media, it is annoying... -->
+        <AttributesGroup streamType="AUDIO_STREAM_TTS" volumeGroup="tts">
+            <Attributes> <Flags value="AUDIO_FLAG_BEACON"/> </Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
 </ProductStrategies>
 
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
new file mode 100644
index 0000000..b326b50
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
@@ -0,0 +1,192 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+     -->
+
+<!-- Volume Groups Tables included by Audio Policy Configuration file -->
+<!-- Note:
+        It is VALID to have a group without attributes if a product strategy is following
+        this group for all attributes.
+        Otherwise, attributes must be specified
+-->
+
+<volumeGroups>
+    <volumeGroup>
+        <name>oem_traffic_anouncement</name>
+        <indexMin>0</indexMin>
+        <indexMax>40</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>0,-4200</point>
+            <point>33,-2800</point>
+            <point>66,-1400</point>
+            <point>100,0</point>
+        </volume>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+            <point>0,-4200</point>
+            <point>33,-2800</point>
+            <point>66,-1400</point>
+            <point>100,0</point>
+        </volume>
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
+            <point>0,-4200</point>
+            <point>33,-2800</point>
+            <point>66,-1400</point>
+            <point>100,0</point>
+        </volume>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA">
+            <point>0,-4200</point>
+            <point>33,-2800</point>
+            <point>66,-1400</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+
+<!-- OEM ADAS is a volume group that has a single port gain (this is the reason why it is a group
+     but may host different streams.
+     A priority must be given among them (either they are multualy excluisve, so the volume
+     will be the one of the currently acitve stream, otherwise a priority must be given by
+     any mean. -->
+    <volumeGroup>
+        <name>oem_adas_2</name>
+        <indexMin>0</indexMin>
+        <indexMax>40</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>0,-4200</point>
+            <point>33,-2800</point>
+            <point>66,-1400</point>
+            <point>100,0</point>
+        </volume>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+            <point>0,-4200</point>
+            <point>33,-2800</point>
+            <point>66,-1400</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+    <volumeGroup>
+        <name>oem_adas_3</name>
+        <indexMin>0</indexMin>
+        <indexMax>40</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>0,-2400</point>
+            <point>33,-1600</point>
+            <point>66,-800</point>
+            <point>100,0</point>
+        </volume>
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
+            <point>0,-2400</point>
+            <point>33,-1600</point>
+            <point>66,-800</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+
+<!-- MEDIA is a volume group that has a single port gain (this is the reason why it is a group
+     but may host different streams.
+     A priority must be given among them (either they are multualy exclusive, so the volume
+     will be the one of the active stream with highest priority (ORDER MATTERS) unless the curves
+     followed will the the curves for the requested attributes.-->
+    <volumeGroup>
+        <name>media_car_audio_type_3</name>
+        <indexMin>0</indexMin>
+        <indexMax>40</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>0,-4200</point>
+            <point>33,-2800</point>
+            <point>66,-1400</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+    <volumeGroup>
+        <name>media_car_audio_type_7</name>
+        <indexMin>0</indexMin>
+        <indexMax>40</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>0,-2400</point>
+            <point>33,-1600</point>
+            <point>66,-800</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+    <volumeGroup>
+        <name>media</name>
+        <indexMin>0</indexMin>
+        <indexMax>40</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>0,-2400</point>
+            <point>33,-1600</point>
+            <point>66,-800</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>speech</name>
+        <indexMin>1</indexMin>
+        <indexMax>40</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>0,-4200</point>
+            <point>33,-2800</point>
+            <point>66,-1400</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>system</name>
+        <indexMin>0</indexMin>
+        <indexMax>40</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>0,-4200</point>
+            <point>33,-2800</point>
+            <point>66,-1400</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>phone</name>
+        <indexMin>1</indexMin>
+        <indexMax>40</indexMax>
+        <volume  deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>0,-4200</point>
+            <point>33,-2800</point>
+            <point>66,-1400</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>ring</name>
+        <indexMin>0</indexMin>
+        <indexMax>40</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>0,-4200</point>
+            <point>33,-2800</point>
+            <point>66,-1400</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>tts</name>
+        <indexMin>0</indexMin>
+        <indexMax>15</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>0,-0</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+</volumeGroups>
+
diff --git a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml
index f72e379..9398743 100644
--- a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml
@@ -25,37 +25,37 @@
          enforced. -->
 
     <ProductStrategy name="STRATEGY_PHONE">
-        <AttributesGroup streamType="AUDIO_STREAM_VOICE_CALL">
+        <AttributesGroup streamType="AUDIO_STREAM_VOICE_CALL" volumeGroup="voice_call">
             <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION"/> </Attributes>
         </AttributesGroup>
-        <AttributesGroup streamType="AUDIO_STREAM_BLUETOOTH_SCO">
+        <AttributesGroup streamType="AUDIO_STREAM_BLUETOOTH_SCO" volumeGroup="bluetooth_sco">
             <Attributes> <Flags value="AUDIO_FLAG_SCO"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
 
     <ProductStrategy name="STRATEGY_SONIFICATION">
-        <AttributesGroup streamType="AUDIO_STREAM_RING">
+        <AttributesGroup streamType="AUDIO_STREAM_RING" volumeGroup="ring">
             <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE"/> </Attributes>
         </AttributesGroup>
-        <AttributesGroup streamType="AUDIO_STREAM_ALARM">
+        <AttributesGroup streamType="AUDIO_STREAM_ALARM" volumeGroup="alarm">
             <Attributes> <Usage value="AUDIO_USAGE_ALARM"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
 
     <ProductStrategy name="STRATEGY_ENFORCED_AUDIBLE">
-        <AttributesGroup streamType="AUDIO_STREAM_ENFORCED_AUDIBLE">
+        <AttributesGroup streamType="AUDIO_STREAM_ENFORCED_AUDIBLE" volumeGroup="enforced_audible">
             <Attributes> <Flags value="AUDIO_FLAG_AUDIBILITY_ENFORCED"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
 
     <ProductStrategy name="STRATEGY_ACCESSIBILITY">
-        <AttributesGroup streamType="AUDIO_STREAM_ACCESSIBILITY">
+        <AttributesGroup streamType="AUDIO_STREAM_ACCESSIBILITY" volumeGroup="accessibility">
             <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
 
     <ProductStrategy name="STRATEGY_SONIFICATION_RESPECTFUL">
-        <AttributesGroup streamType="AUDIO_STREAM_NOTIFICATION">
+        <AttributesGroup streamType="AUDIO_STREAM_NOTIFICATION" volumeGroup="notification">
             <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION"/> </Attributes>
             <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/> </Attributes>
             <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/> </Attributes>
@@ -65,20 +65,20 @@
     </ProductStrategy>
 
     <ProductStrategy name="STRATEGY_MEDIA">
-         <AttributesGroup streamType="AUDIO_STREAM_MUSIC">
+         <AttributesGroup streamType="AUDIO_STREAM_MUSIC" volumeGroup="music">
             <Attributes> <Usage value="AUDIO_USAGE_MEDIA"/> </Attributes>
             <Attributes> <Usage value="AUDIO_USAGE_GAME"/> </Attributes>
             <Attributes> <Usage value="AUDIO_USAGE_ASSISTANT"/> </Attributes>
             <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/> </Attributes>
             <Attributes></Attributes>
         </AttributesGroup>
-        <AttributesGroup streamType="AUDIO_STREAM_SYSTEM">
+        <AttributesGroup streamType="AUDIO_STREAM_SYSTEM" volumeGroup="system">
             <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
 
     <ProductStrategy name="STRATEGY_DTMF">
-        <AttributesGroup streamType="AUDIO_STREAM_DTMF">
+        <AttributesGroup streamType="AUDIO_STREAM_DTMF" volumeGroup="dtmf">
             <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
@@ -86,21 +86,21 @@
     <!-- Used to identify the volume of audio streams exclusively transmitted through the  speaker
          (TTS) of the device -->
     <ProductStrategy name="STRATEGY_TRANSMITTED_THROUGH_SPEAKER">
-        <AttributesGroup streamType="AUDIO_STREAM_TTS">
+        <AttributesGroup streamType="AUDIO_STREAM_TTS" volumeGroup="tts">
             <Attributes> <Flags value="AUDIO_FLAG_BEACON"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
 
     <!-- Routing Strategy rerouting may be removed as following media??? -->
     <ProductStrategy name="STRATEGY_REROUTING">
-        <AttributesGroup streamType="AUDIO_STREAM_REROUTING">
+        <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
             <Attributes></Attributes>
         </AttributesGroup>
     </ProductStrategy>
 
     <!-- Default product strategy has empty attributes -->
     <ProductStrategy name="STRATEGY_PATCH">
-        <AttributesGroup streamType="AUDIO_STREAM_PATCH">
+        <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
             <Attributes></Attributes>
         </AttributesGroup>
     </ProductStrategy>
diff --git a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml
index 73bde1f..707a184 100644
--- a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml
@@ -16,7 +16,7 @@
 <!-- Volume section defines a volume curve for a given use case and device category.
 It contains a list of points of this curve expressing the attenuation in Millibels for a given
 volume index from 0 to 100.
-<volume stream=”AUDIO_STREAM_MUSIC” deviceCategory=””>
+<volume deviceCategory=””>
 <point>0,-9600</point>
 <point>100,0</point>
 </volume>
@@ -24,7 +24,7 @@
 
 <volumeGroups>
     <volumeGroup>
-        <stream>AUDIO_STREAM_VOICE_CALL</stream>
+        <name>voice_call</name>
         <indexMin>1</indexMin>
         <indexMax>7</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
@@ -50,7 +50,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_SYSTEM</stream>
+        <name>system</name>
         <indexMin>0</indexMin>
         <indexMax>7</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
@@ -73,7 +73,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_RING</stream>
+        <name>ring</name>
         <indexMin>0</indexMin>
         <indexMax>7</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
@@ -84,7 +84,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_MUSIC</stream>
+        <name>music</name>
         <indexMin>0</indexMin>
         <indexMax>25</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
@@ -95,7 +95,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_ALARM</stream>
+        <name>alarm</name>
         <indexMin>1</indexMin>
         <indexMax>7</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_NON_MUTABLE_HEADSET_VOLUME_CURVE"/>
@@ -106,7 +106,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_NOTIFICATION</stream>
+        <name>notification</name>
         <indexMin>0</indexMin>
         <indexMax>7</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
@@ -117,7 +117,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_BLUETOOTH_SCO</stream>
+        <name>bluetooth_sco</name>
         <indexMin>0</indexMin>
         <indexMax>15</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
@@ -143,7 +143,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_ENFORCED_AUDIBLE</stream>
+        <name>enforced_audible</name>
         <indexMin>0</indexMin>
         <indexMax>7</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
@@ -164,7 +164,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_DTMF</stream>
+        <name>dtmf</name>
         <indexMin>0</indexMin>
         <indexMax>15</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
@@ -185,7 +185,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_TTS</stream>
+        <name>tts</name>
         <indexMin>0</indexMin>
         <indexMax>15</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="SILENT_VOLUME_CURVE"/>
@@ -196,7 +196,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_ACCESSIBILITY</stream>
+        <name>accessibility</name>
         <indexMin>1</indexMin>
         <indexMax>15</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
@@ -207,7 +207,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_REROUTING</stream>
+        <name>rerouting</name>
         <indexMin>0</indexMin>
         <indexMax>1</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
@@ -218,7 +218,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_PATCH</stream>
+        <name>patch</name>
         <indexMin>0</indexMin>
         <indexMax>1</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
diff --git a/services/audiopolicy/enginedefault/Android.bp b/services/audiopolicy/enginedefault/Android.bp
new file mode 100644
index 0000000..7b42c6a
--- /dev/null
+++ b/services/audiopolicy/enginedefault/Android.bp
@@ -0,0 +1,32 @@
+cc_library_shared {
+    name: "libaudiopolicyenginedefault",
+    export_include_dirs: ["include"],
+    srcs: [
+        "src/Engine.cpp",
+        "src/EngineInstance.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    local_include_dirs: ["include"],
+    header_libs: [
+        "libbase_headers",
+        "libaudiopolicycommon",
+        "libaudiopolicyengine_interface_headers",
+    ],
+    static_libs: [
+        "libaudiopolicycomponents",
+        "libaudiopolicyengine_common",
+        "libaudiopolicyengine_config",
+    ],
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libutils",
+        "libmedia_helper",
+        "libaudiopolicy",
+        "libxml2",
+    ],
+}
diff --git a/services/audiopolicy/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk
deleted file mode 100644
index 94fa788..0000000
--- a/services/audiopolicy/enginedefault/Android.mk
+++ /dev/null
@@ -1,57 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# Component build
-#######################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    src/Engine.cpp \
-    src/EngineInstance.cpp \
-    ../engine/common/src/VolumeCurve.cpp \
-    ../engine/common/src/StreamVolumeCurves.cpp \
-    ../engine/common/src/ProductStrategy.cpp \
-    ../engine/common/src/EngineBase.cpp
-
-audio_policy_engine_includes_common := \
-    $(LOCAL_PATH)/include
-
-LOCAL_CFLAGS += \
-    -Wall \
-    -Werror \
-    -Wextra \
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
-    $(audio_policy_engine_includes_common)
-
-LOCAL_C_INCLUDES := \
-    $(audio_policy_engine_includes_common) \
-    $(TARGET_OUT_HEADERS)/hw \
-    $(call include-path-for, frameworks-av) \
-    $(call include-path-for, audio-utils) \
-    $(call include-path-for, bionic)
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_MODULE := libaudiopolicyenginedefault
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_HEADER_LIBRARIES := libbase_headers
-
-LOCAL_STATIC_LIBRARIES := \
-    libaudiopolicycomponents
-
-LOCAL_SHARED_LIBRARIES := \
-    liblog \
-    libcutils \
-    libutils \
-    libmedia_helper \
-    libaudiopolicyengineconfig \
-    libaudiopolicy
-
-LOCAL_HEADER_LIBRARIES := \
-    libaudiopolicycommon \
-    libaudiopolicyengine_common_headers \
-    libaudiopolicyengine_interface_headers
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_product_strategies.xml b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_product_strategies.xml
index f72e379..9398743 100644
--- a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_product_strategies.xml
@@ -25,37 +25,37 @@
          enforced. -->
 
     <ProductStrategy name="STRATEGY_PHONE">
-        <AttributesGroup streamType="AUDIO_STREAM_VOICE_CALL">
+        <AttributesGroup streamType="AUDIO_STREAM_VOICE_CALL" volumeGroup="voice_call">
             <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION"/> </Attributes>
         </AttributesGroup>
-        <AttributesGroup streamType="AUDIO_STREAM_BLUETOOTH_SCO">
+        <AttributesGroup streamType="AUDIO_STREAM_BLUETOOTH_SCO" volumeGroup="bluetooth_sco">
             <Attributes> <Flags value="AUDIO_FLAG_SCO"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
 
     <ProductStrategy name="STRATEGY_SONIFICATION">
-        <AttributesGroup streamType="AUDIO_STREAM_RING">
+        <AttributesGroup streamType="AUDIO_STREAM_RING" volumeGroup="ring">
             <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE"/> </Attributes>
         </AttributesGroup>
-        <AttributesGroup streamType="AUDIO_STREAM_ALARM">
+        <AttributesGroup streamType="AUDIO_STREAM_ALARM" volumeGroup="alarm">
             <Attributes> <Usage value="AUDIO_USAGE_ALARM"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
 
     <ProductStrategy name="STRATEGY_ENFORCED_AUDIBLE">
-        <AttributesGroup streamType="AUDIO_STREAM_ENFORCED_AUDIBLE">
+        <AttributesGroup streamType="AUDIO_STREAM_ENFORCED_AUDIBLE" volumeGroup="enforced_audible">
             <Attributes> <Flags value="AUDIO_FLAG_AUDIBILITY_ENFORCED"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
 
     <ProductStrategy name="STRATEGY_ACCESSIBILITY">
-        <AttributesGroup streamType="AUDIO_STREAM_ACCESSIBILITY">
+        <AttributesGroup streamType="AUDIO_STREAM_ACCESSIBILITY" volumeGroup="accessibility">
             <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
 
     <ProductStrategy name="STRATEGY_SONIFICATION_RESPECTFUL">
-        <AttributesGroup streamType="AUDIO_STREAM_NOTIFICATION">
+        <AttributesGroup streamType="AUDIO_STREAM_NOTIFICATION" volumeGroup="notification">
             <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION"/> </Attributes>
             <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/> </Attributes>
             <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/> </Attributes>
@@ -65,20 +65,20 @@
     </ProductStrategy>
 
     <ProductStrategy name="STRATEGY_MEDIA">
-         <AttributesGroup streamType="AUDIO_STREAM_MUSIC">
+         <AttributesGroup streamType="AUDIO_STREAM_MUSIC" volumeGroup="music">
             <Attributes> <Usage value="AUDIO_USAGE_MEDIA"/> </Attributes>
             <Attributes> <Usage value="AUDIO_USAGE_GAME"/> </Attributes>
             <Attributes> <Usage value="AUDIO_USAGE_ASSISTANT"/> </Attributes>
             <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/> </Attributes>
             <Attributes></Attributes>
         </AttributesGroup>
-        <AttributesGroup streamType="AUDIO_STREAM_SYSTEM">
+        <AttributesGroup streamType="AUDIO_STREAM_SYSTEM" volumeGroup="system">
             <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
 
     <ProductStrategy name="STRATEGY_DTMF">
-        <AttributesGroup streamType="AUDIO_STREAM_DTMF">
+        <AttributesGroup streamType="AUDIO_STREAM_DTMF" volumeGroup="dtmf">
             <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
@@ -86,21 +86,21 @@
     <!-- Used to identify the volume of audio streams exclusively transmitted through the  speaker
          (TTS) of the device -->
     <ProductStrategy name="STRATEGY_TRANSMITTED_THROUGH_SPEAKER">
-        <AttributesGroup streamType="AUDIO_STREAM_TTS">
+        <AttributesGroup streamType="AUDIO_STREAM_TTS" volumeGroup="tts">
             <Attributes> <Flags value="AUDIO_FLAG_BEACON"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
 
     <!-- Routing Strategy rerouting may be removed as following media??? -->
     <ProductStrategy name="STRATEGY_REROUTING">
-        <AttributesGroup streamType="AUDIO_STREAM_REROUTING">
+        <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
             <Attributes></Attributes>
         </AttributesGroup>
     </ProductStrategy>
 
     <!-- Default product strategy has empty attributes -->
     <ProductStrategy name="STRATEGY_PATCH">
-        <AttributesGroup streamType="AUDIO_STREAM_PATCH">
+        <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
             <Attributes></Attributes>
         </AttributesGroup>
     </ProductStrategy>
diff --git a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml
index 73bde1f..707a184 100644
--- a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml
+++ b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml
@@ -16,7 +16,7 @@
 <!-- Volume section defines a volume curve for a given use case and device category.
 It contains a list of points of this curve expressing the attenuation in Millibels for a given
 volume index from 0 to 100.
-<volume stream=”AUDIO_STREAM_MUSIC” deviceCategory=””>
+<volume deviceCategory=””>
 <point>0,-9600</point>
 <point>100,0</point>
 </volume>
@@ -24,7 +24,7 @@
 
 <volumeGroups>
     <volumeGroup>
-        <stream>AUDIO_STREAM_VOICE_CALL</stream>
+        <name>voice_call</name>
         <indexMin>1</indexMin>
         <indexMax>7</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
@@ -50,7 +50,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_SYSTEM</stream>
+        <name>system</name>
         <indexMin>0</indexMin>
         <indexMax>7</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
@@ -73,7 +73,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_RING</stream>
+        <name>ring</name>
         <indexMin>0</indexMin>
         <indexMax>7</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
@@ -84,7 +84,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_MUSIC</stream>
+        <name>music</name>
         <indexMin>0</indexMin>
         <indexMax>25</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
@@ -95,7 +95,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_ALARM</stream>
+        <name>alarm</name>
         <indexMin>1</indexMin>
         <indexMax>7</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_NON_MUTABLE_HEADSET_VOLUME_CURVE"/>
@@ -106,7 +106,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_NOTIFICATION</stream>
+        <name>notification</name>
         <indexMin>0</indexMin>
         <indexMax>7</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
@@ -117,7 +117,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_BLUETOOTH_SCO</stream>
+        <name>bluetooth_sco</name>
         <indexMin>0</indexMin>
         <indexMax>15</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
@@ -143,7 +143,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_ENFORCED_AUDIBLE</stream>
+        <name>enforced_audible</name>
         <indexMin>0</indexMin>
         <indexMax>7</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
@@ -164,7 +164,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_DTMF</stream>
+        <name>dtmf</name>
         <indexMin>0</indexMin>
         <indexMax>15</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
@@ -185,7 +185,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_TTS</stream>
+        <name>tts</name>
         <indexMin>0</indexMin>
         <indexMax>15</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="SILENT_VOLUME_CURVE"/>
@@ -196,7 +196,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_ACCESSIBILITY</stream>
+        <name>accessibility</name>
         <indexMin>1</indexMin>
         <indexMax>15</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
@@ -207,7 +207,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_REROUTING</stream>
+        <name>rerouting</name>
         <indexMin>0</indexMin>
         <indexMax>1</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
@@ -218,7 +218,7 @@
     </volumeGroup>
 
     <volumeGroup>
-        <stream>AUDIO_STREAM_PATCH</stream>
+        <name>patch</name>
         <indexMin>0</indexMin>
         <indexMax>1</indexMax>
         <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index fd6a013..f191738 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -402,7 +402,9 @@
                     outputDeviceTypesToIgnore);
             break;
         }
-        if (device2 == AUDIO_DEVICE_NONE) {
+        // FIXME: Find a better solution to prevent routing to BT hearing aid(b/122931261).
+        if ((device2 == AUDIO_DEVICE_NONE) &&
+                (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
             device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HEARING_AID;
         }
         if ((device2 == AUDIO_DEVICE_NONE) &&
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index b563a04..ea98253 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -33,8 +33,8 @@
 #define AUDIO_POLICY_XML_CONFIG_FILE_NAME "audio_policy_configuration.xml"
 #define AUDIO_POLICY_A2DP_OFFLOAD_DISABLED_XML_CONFIG_FILE_NAME \
         "audio_policy_configuration_a2dp_offload_disabled.xml"
-#define AUDIO_POLICY_BLUETOOTH_HAL_ENABLED_XML_CONFIG_FILE_NAME \
-        "audio_policy_configuration_bluetooth_hal_enabled.xml"
+#define AUDIO_POLICY_BLUETOOTH_LEGACY_HAL_XML_CONFIG_FILE_NAME \
+        "audio_policy_configuration_bluetooth_legacy_hal.xml"
 
 #include <inttypes.h>
 #include <math.h>
@@ -377,7 +377,7 @@
                                            (strlen(device_address) != 0)/*matchAddress*/);
 
     if (devDesc == 0) {
-        ALOGW("getDeviceConnectionState() undeclared device, type %08x, address: %s",
+        ALOGV("getDeviceConnectionState() undeclared device, type %08x, address: %s",
               device, device_address);
         return AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
     }
@@ -479,36 +479,16 @@
                                     std::vector<audio_format_t> *formats)
 {
     ALOGV("getHwOffloadEncodingFormatsSupportedForA2DP()");
-    char *tok = NULL, *saveptr;
     status_t status = NO_ERROR;
-    char encoding_formats_list[PROPERTY_VALUE_MAX];
-    audio_format_t format = AUDIO_FORMAT_DEFAULT;
-    // FIXME This list should not come from a property but the supported encoded
-    // formats of declared A2DP devices in primary module
-    property_get("persist.bluetooth.a2dp_offload.cap", encoding_formats_list, "");
-    tok = strtok_r(encoding_formats_list, "-", &saveptr);
-    for (;tok != NULL; tok = strtok_r(NULL, "-", &saveptr)) {
-        if (strcmp(tok, "sbc") == 0) {
-            ALOGV("%s: SBC offload supported\n",__func__);
-            format = AUDIO_FORMAT_SBC;
-        } else if (strcmp(tok, "aptx") == 0) {
-            ALOGV("%s: APTX offload supported\n",__func__);
-            format = AUDIO_FORMAT_APTX;
-        } else if (strcmp(tok, "aptxhd") == 0) {
-            ALOGV("%s: APTX HD offload supported\n",__func__);
-            format = AUDIO_FORMAT_APTX_HD;
-        } else if (strcmp(tok, "ldac") == 0) {
-            ALOGV("%s: LDAC offload supported\n",__func__);
-            format = AUDIO_FORMAT_LDAC;
-        } else if (strcmp(tok, "aac") == 0) {
-            ALOGV("%s: AAC offload supported\n",__func__);
-            format = AUDIO_FORMAT_AAC;
-        } else {
-            ALOGE("%s: undefined token - %s\n",__func__, tok);
-            continue;
-        }
-        formats->push_back(format);
+    std::unordered_set<audio_format_t> formatSet;
+    sp<HwModule> primaryModule =
+            mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY);
+    DeviceVector declaredDevices = primaryModule->getDeclaredDevices().getDevicesFromTypeMask(
+            AUDIO_DEVICE_OUT_ALL_A2DP);
+    for (const auto& device : declaredDevices) {
+        formatSet.insert(device->encodedFormats().begin(), device->encodedFormats().end());
     }
+    formats->assign(formatSet.begin(), formatSet.end());
     return status;
 }
 
@@ -1042,7 +1022,8 @@
         }
     }
     if (*output == AUDIO_IO_HANDLE_NONE) {
-        *output = getOutputForDevices(outputDevices, session, *stream, config, flags);
+        *output = getOutputForDevices(outputDevices, session, *stream, config,
+                flags, attr->flags & AUDIO_FLAG_MUTE_HAPTIC);
     }
     if (*output == AUDIO_IO_HANDLE_NONE) {
         return INVALID_OPERATION;
@@ -1120,11 +1101,16 @@
         audio_session_t session,
         audio_stream_type_t stream,
         const audio_config_t *config,
-        audio_output_flags_t *flags)
+        audio_output_flags_t *flags,
+        bool forceMutingHaptic)
 {
     audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
     status_t status;
 
+    // Discard haptic channel mask when forcing muting haptic channels.
+    audio_channel_mask_t channelMask = forceMutingHaptic
+            ? (config->channel_mask & ~AUDIO_CHANNEL_HAPTIC_ALL) : config->channel_mask;
+
     // open a direct output if required by specified parameters
     //force direct flag if offload flag is set: offloading implies a direct output stream
     // and all common behaviors are driven by checking only the direct flag
@@ -1161,7 +1147,7 @@
     // and not explicitly requested
     if (((*flags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) &&
             audio_is_linear_pcm(config->format) && config->sample_rate <= SAMPLE_RATE_HZ_MAX &&
-            audio_channel_count_from_out_mask(config->channel_mask) <= 2) {
+            audio_channel_count_from_out_mask(channelMask) <= 2) {
         goto non_direct_output;
     }
 
@@ -1177,7 +1163,7 @@
         profile = getProfileForOutput(devices,
                                    config->sample_rate,
                                    config->format,
-                                   config->channel_mask,
+                                   channelMask,
                                    (audio_output_flags_t)*flags,
                                    true /* directOnly */);
     }
@@ -1191,7 +1177,7 @@
                 // and configured with same parameters
                 if ((config->sample_rate == desc->mSamplingRate) &&
                     (config->format == desc->mFormat) &&
-                    (config->channel_mask == desc->mChannelMask) &&
+                    (channelMask == desc->mChannelMask) &&
                     (session == desc->mDirectClientSession)) {
                     desc->mDirectOpenCount++;
                     ALOGI("%s reusing direct output %d for session %d", __func__, 
@@ -1233,11 +1219,11 @@
         if (status != NO_ERROR ||
             (config->sample_rate != 0 && config->sample_rate != outputDesc->mSamplingRate) ||
             (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->mFormat) ||
-            (config->channel_mask != 0 && config->channel_mask != outputDesc->mChannelMask)) {
+            (channelMask != 0 && channelMask != outputDesc->mChannelMask)) {
             ALOGV("%s failed opening direct output: output %d sample rate %d %d," 
                     "format %d %d, channel mask %04x %04x", __func__, output, config->sample_rate,
                     outputDesc->mSamplingRate, config->format, outputDesc->mFormat,
-                    config->channel_mask, outputDesc->mChannelMask);
+                    channelMask, outputDesc->mChannelMask);
             if (output != AUDIO_IO_HANDLE_NONE) {
                 outputDesc->close();
             }
@@ -1278,12 +1264,11 @@
 
         // at this stage we should ignore the DIRECT flag as no direct output could be found earlier
         *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
-        output = selectOutput(outputs, *flags, config->format,
-                config->channel_mask, config->sample_rate);
+        output = selectOutput(outputs, *flags, config->format, channelMask, config->sample_rate);
     }
     ALOGW_IF((output == 0), "getOutputForDevices() could not find output for stream %d, "
             "sampling rate %d, format %#x, channels %#x, flags %#x",
-            stream, config->sample_rate, config->format, config->channel_mask, *flags);
+            stream, config->sample_rate, config->format, channelMask, *flags);
 
     return output;
 }
@@ -1986,7 +1971,11 @@
         if (status != NO_ERROR) {
             goto error;
         }
-        *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
+        if (is_mix_loopback_render(policyMix->mRouteFlags)) {
+            *inputType = API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK;
+        } else {
+            *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
+        }
         device = mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
                                                   String8(attr->tags + strlen("addr=")),
                                                   AUDIO_FORMAT_DEFAULT);
@@ -2373,16 +2362,13 @@
     }
 }
 
-void AudioPolicyManager::initStreamVolume(audio_stream_type_t stream,
-                                            int indexMin,
-                                            int indexMax)
+void AudioPolicyManager::initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax)
 {
     ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
     if (indexMin < 0 || indexMax < 0) {
         ALOGE("%s for stream %d: invalid min %d or max %d", __func__, stream , indexMin, indexMax);
         return;
     }
-    // @todo: our proposal now use XML to store Indexes Min & Max
     getVolumeCurves(stream).initVolume(indexMin, indexMax);
 
     // initialize other private stream volumes which follow this one
@@ -2501,6 +2487,107 @@
     return NO_ERROR;
 }
 
+status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                         int index,
+                                                         audio_devices_t device)
+{
+    // Get Volume group matching the Audio Attributes
+    auto volumeGroup = mEngine->getVolumeGroupForAttributes(attr);
+    if (volumeGroup == VOLUME_GROUP_NONE) {
+        ALOGD("%s: could not find group matching with %s", __FUNCTION__, toString(attr).c_str());
+        return BAD_VALUE;
+    }
+    ALOGD("%s: FOUND group %d matching with %s", __FUNCTION__, volumeGroup, toString(attr).c_str());
+    return setVolumeGroupIndex(getVolumeCurves(attr), volumeGroup, index, device, attr);
+}
+
+status_t AudioPolicyManager::setVolumeGroupIndex(IVolumeCurves &curves, volume_group_t group,
+                                                 int index,
+                                                 audio_devices_t device,
+                                                 const audio_attributes_t /*attributes*/)
+{
+    ALOGVV("%s: group=%d", __func__, group);
+    status_t status = NO_ERROR;
+    setVolumeCurveIndex(group, index, device, curves);
+    // update volume on all outputs and streams matching the following:
+    // - The requested stream (or a stream matching for volume control) is active on the output
+    // - The device (or devices) selected by the engine for this stream includes
+    // the requested device
+    // - For non default requested device, currently selected device on the output is either the
+    // requested device or one of the devices selected by the engine for this stream
+    // - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if
+    // no specific device volume value exists for currently selected device.
+    // @TODO
+    mpClientInterface->onAudioVolumeGroupChanged(group, 0 /*flags*/);
+    return status;
+}
+
+status_t AudioPolicyManager::setVolumeCurveIndex(volume_group_t volumeGroup,
+                                                 int index,
+                                                 audio_devices_t device,
+                                                 IVolumeCurves &volumeCurves)
+{
+    // VOICE_CALL stream has minVolumeIndex > 0  but can be muted directly by an
+    // app that has MODIFY_PHONE_STATE permission.
+    // If voice is member of the volume group, it will contaminate all the member of this group
+    auto streams = mEngine->getStreamTypesForVolumeGroup(volumeGroup);
+    if (((index < volumeCurves.getVolumeIndexMin()) && !(hasVoiceStream(streams) && index == 0)) ||
+            (index > volumeCurves.getVolumeIndexMax())) {
+        ALOGD("%s: wrong index %d min=%d max=%d", __FUNCTION__, index,
+              volumeCurves.getVolumeIndexMin(), volumeCurves.getVolumeIndexMax());
+        return BAD_VALUE;
+    }
+    if (!audio_is_output_device(device)) {
+        return BAD_VALUE;
+    }
+
+    // Force max volume if stream cannot be muted
+    if (!volumeCurves.canBeMuted()) index = volumeCurves.getVolumeIndexMax();
+
+    ALOGD("%s device %08x, index %d", __FUNCTION__ , device, index);
+    volumeCurves.addCurrentVolumeIndex(device, index);
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                         int &index,
+                                                         audio_devices_t device)
+{
+    // if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device selected for this
+    // stream by the engine.
+    if (device == AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
+        device = mEngine->getOutputDevicesForAttributes(attr, nullptr, true /*fromCache*/).types();
+    }
+    return getVolumeIndex(getVolumeCurves(attr), index, device);
+}
+
+status_t AudioPolicyManager::getVolumeIndex(const IVolumeCurves &curves,
+                                            int &index,
+                                            audio_devices_t device) const
+{
+    if (!audio_is_output_device(device)) {
+        return BAD_VALUE;
+    }
+    device = Volume::getDeviceForVolume(device);
+    index = curves.getVolumeIndex(device);
+    ALOGV("%s: device %08x index %d", __FUNCTION__, device, index);
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getMinVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                            int &index)
+{
+    index = getVolumeCurves(attr).getVolumeIndexMin();
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getMaxVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                            int &index)
+{
+    index = getVolumeCurves(attr).getVolumeIndexMax();
+    return NO_ERROR;
+}
+
 audio_io_handle_t AudioPolicyManager::selectOutputForMusicEffects()
 {
     // select one output among several suitable for global effects.
@@ -4080,17 +4167,17 @@
     status_t ret;
 
     if (property_get_bool("ro.bluetooth.a2dp_offload.supported", false)) {
-        if (property_get_bool("persist.bluetooth.a2dp_offload.disabled", false)) {
+        if (property_get_bool("persist.bluetooth.bluetooth_audio_hal.disabled", false) &&
+            property_get_bool("persist.bluetooth.a2dp_offload.disabled", false)) {
+            // Both BluetoothAudio@2.0 and BluetoothA2dp@1.0 (Offlaod) are disabled, and uses
+            // the legacy hardware module for A2DP and hearing aid.
+            fileNames.push_back(AUDIO_POLICY_BLUETOOTH_LEGACY_HAL_XML_CONFIG_FILE_NAME);
+        } else if (property_get_bool("persist.bluetooth.a2dp_offload.disabled", false)) {
+            // A2DP offload supported but disabled: try to use special XML file
             fileNames.push_back(AUDIO_POLICY_A2DP_OFFLOAD_DISABLED_XML_CONFIG_FILE_NAME);
-        } else if (property_get_bool("persist.bluetooth.bluetooth_audio_hal.enabled", false)) {
-            // This property persist.bluetooth.bluetooth_audio_hal.enabled is temporary only.
-            // xml files AUDIO_POLICY_BLUETOOTH_HAL_ENABLED_XML_CONFIG_FILE_NAME, although having
-            // the same name, must be different in offload and non offload cases in device
-            // specific configuration file.
-            fileNames.push_back(AUDIO_POLICY_BLUETOOTH_HAL_ENABLED_XML_CONFIG_FILE_NAME);
         }
-    } else if (property_get_bool("persist.bluetooth.bluetooth_audio_hal.enabled", false)) {
-        fileNames.push_back(AUDIO_POLICY_BLUETOOTH_HAL_ENABLED_XML_CONFIG_FILE_NAME);
+    } else if (property_get_bool("persist.bluetooth.bluetooth_audio_hal.disabled", false)) {
+        fileNames.push_back(AUDIO_POLICY_BLUETOOTH_LEGACY_HAL_XML_CONFIG_FILE_NAME);
     }
     fileNames.push_back(AUDIO_POLICY_XML_CONFIG_FILE_NAME);
 
@@ -5057,7 +5144,7 @@
 
         if ((hasVoiceStream(streams) &&
              (isInCall() || mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc))) ||
-             (hasStream(streams, AUDIO_STREAM_ALARM) &&
+             ((hasStream(streams, AUDIO_STREAM_ALARM) || hasStream(streams, AUDIO_STREAM_ENFORCED_AUDIBLE)) &&
                 mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc)) ||
                 outputDesc->isStrategyActive(productStrategy)) {
             // Retrieval of devices for voice DL is done on primary output profile, cannot
@@ -5530,7 +5617,7 @@
                                         audio_devices_t device)
 {
     auto &curves = getVolumeCurves(stream);
-    float volumeDB = curves.volIndexToDb(Volume::getDeviceCategory(device), index);
+    float volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(device), index);
 
     // handle the case of accessibility active while a ringtone is playing: if the ringtone is much
     // louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch
@@ -5540,7 +5627,7 @@
             && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState())
             && isStreamActive(AUDIO_STREAM_RING, 0)) {
         const float ringVolumeDB = computeVolume(AUDIO_STREAM_RING, index, device);
-        return ringVolumeDB - 4 > volumeDB ? ringVolumeDB - 4 : volumeDB;
+        return ringVolumeDB - 4 > volumeDb ? ringVolumeDB - 4 : volumeDb;
     }
 
     // in-call: always cap volume by voice volume + some low headroom
@@ -5559,10 +5646,10 @@
             const float maxVoiceVolDb =
                 computeVolume(AUDIO_STREAM_VOICE_CALL, voiceVolumeIndex, device)
                 + IN_CALL_EARPIECE_HEADROOM_DB;
-            if (volumeDB > maxVoiceVolDb) {
+            if (volumeDb > maxVoiceVolDb) {
                 ALOGV("computeVolume() stream %d at vol=%f overriden by stream %d at vol=%f",
-                        stream, volumeDB, AUDIO_STREAM_VOICE_CALL, maxVoiceVolDb);
-                volumeDB = maxVoiceVolDb;
+                        stream, volumeDb, AUDIO_STREAM_VOICE_CALL, maxVoiceVolDb);
+                volumeDb = maxVoiceVolDb;
             }
             } break;
         default:
@@ -5595,7 +5682,7 @@
         // just stopped
         if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) ||
                 mLimitRingtoneVolume) {
-            volumeDB += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
+            volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
             audio_devices_t musicDevice =
                     mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA),
                                                            nullptr, true /*fromCache*/).types();
@@ -5604,29 +5691,29 @@
                                    musicDevice);
             float minVolDB = (musicVolDB > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
                     musicVolDB : SONIFICATION_HEADSET_VOLUME_MIN_DB;
-            if (volumeDB > minVolDB) {
-                volumeDB = minVolDB;
+            if (volumeDb > minVolDB) {
+                volumeDb = minVolDB;
                 ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDB, musicVolDB);
             }
             if (device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
                     AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES)) {
                 // on A2DP, also ensure notification volume is not too low compared to media when
                 // intended to be played
-                if ((volumeDB > -96.0f) &&
-                        (musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDB)) {
+                if ((volumeDb > -96.0f) &&
+                        (musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDb)) {
                     ALOGV("computeVolume increasing volume for stream=%d device=0x%X from %f to %f",
                             stream, device,
-                            volumeDB, musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB);
-                    volumeDB = musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB;
+                            volumeDb, musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB);
+                    volumeDb = musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB;
                 }
             }
         } else if ((Volume::getDeviceForVolume(device) != AUDIO_DEVICE_OUT_SPEAKER) ||
                 (stream != AUDIO_STREAM_ALARM && stream != AUDIO_STREAM_RING)) {
-            volumeDB += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
+            volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
         }
     }
 
-    return volumeDB;
+    return volumeDb;
 }
 
 int AudioPolicyManager::rescaleVolumeIndex(int srcIndex,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 06a1f3e..3a31e1e 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -143,9 +143,17 @@
         virtual status_t stopInput(audio_port_handle_t portId);
         virtual void releaseInput(audio_port_handle_t portId);
         virtual void closeAllInputs();
-        virtual void initStreamVolume(audio_stream_type_t stream,
-                                                    int indexMin,
-                                                    int indexMax);
+        /**
+         * @brief initStreamVolume: even if the engine volume files provides min and max, keep this
+         * api for compatibility reason.
+         * AudioServer will get the min and max and may overwrite them if:
+         *      -using property (highest priority)
+         *      -not defined (-1 by convention), case when still using apm volume tables XML files
+         * @param stream to be considered
+         * @param indexMin to set
+         * @param indexMax to set
+         */
+        virtual void initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
         virtual status_t setStreamVolumeIndex(audio_stream_type_t stream,
                                               int index,
                                               audio_devices_t device);
@@ -153,6 +161,27 @@
                                               int *index,
                                               audio_devices_t device);
 
+        virtual status_t setVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                     int index,
+                                                     audio_devices_t device);
+        virtual status_t getVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                     int &index,
+                                                     audio_devices_t device);
+        virtual status_t getMaxVolumeIndexForAttributes(const audio_attributes_t &attr, int &index);
+
+        virtual status_t getMinVolumeIndexForAttributes(const audio_attributes_t &attr, int &index);
+
+        status_t setVolumeGroupIndex(IVolumeCurves &volumeCurves, volume_group_t group, int index,
+                                     audio_devices_t device, const audio_attributes_t attributes);
+
+        status_t setVolumeCurveIndex(volume_group_t volumeGroup,
+                                     int index,
+                                     audio_devices_t device,
+                                     IVolumeCurves &volumeCurves);
+
+        status_t getVolumeIndex(const IVolumeCurves &curves, int &index,
+                                audio_devices_t device) const;
+
         // return the strategy corresponding to a given stream type
         virtual uint32_t getStrategyForStream(audio_stream_type_t stream)
         {
@@ -260,9 +289,23 @@
             return mEngine->listAudioProductStrategies(strategies);
         }
 
-        virtual product_strategy_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa)
+        virtual status_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa,
+                                                               product_strategy_t &productStrategy)
         {
-            return mEngine->getProductStrategyForAttributes(aa.getAttributes());
+            productStrategy = mEngine->getProductStrategyForAttributes(aa.getAttributes());
+            return productStrategy != PRODUCT_STRATEGY_NONE ? NO_ERROR : BAD_VALUE;
+        }
+
+        virtual status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups)
+        {
+            return mEngine->listAudioVolumeGroups(groups);
+        }
+
+        virtual status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
+                                                           volume_group_t &volumeGroup)
+        {
+            volumeGroup = mEngine->getVolumeGroupForAttributes(aa.getAttributes());
+            return volumeGroup != VOLUME_GROUP_NONE ? NO_ERROR : BAD_VALUE;
         }
 
 protected:
@@ -736,7 +779,8 @@
                 audio_session_t session,
                 audio_stream_type_t stream,
                 const audio_config_t *config,
-                audio_output_flags_t *flags);
+                audio_output_flags_t *flags,
+                bool forceMutingHaptic = false);
 
         /**
          * @brief getInputForDevice selects an input handle for a given input device and
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index d826192..5748334 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -222,6 +222,12 @@
             clientConfig, clientEffects, deviceConfig, effects, patchHandle, source);
 }
 
+void AudioPolicyService::AudioPolicyClient::onAudioVolumeGroupChanged(volume_group_t group,
+                                                                      int flags)
+{
+    mAudioPolicyService->onAudioVolumeGroupChanged(group, flags);
+}
+
 audio_unique_id_t AudioPolicyService::AudioPolicyClient::newAudioUniqueId(audio_unique_id_use_t use)
 {
     return AudioSystem::newAudioUniqueId(use);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 8ddf824..a672521 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -20,7 +20,7 @@
 #include "AudioPolicyService.h"
 #include "TypeConverter.h"
 #include <media/MediaAnalyticsItem.h>
-#include <mediautils/ServiceUtilities.h>
+#include <media/AudioPolicy.h>
 #include <utils/Log.h>
 
 namespace android {
@@ -166,7 +166,7 @@
     return mAudioPolicyManager->getOutput(stream);
 }
 
-status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
+status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *originalAttr,
                                               audio_io_handle_t *output,
                                               audio_session_t session,
                                               audio_stream_type_t *stream,
@@ -190,9 +190,13 @@
                 "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
         uid = callingUid;
     }
+    audio_attributes_t attr = *originalAttr;
+    if (!mPackageManager.allowPlaybackCapture(uid)) {
+        attr.flags |= AUDIO_FLAG_NO_CAPTURE;
+    }
     audio_output_flags_t originalFlags = flags;
     AutoCallerClear acc;
-    status_t result = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid,
+    status_t result = mAudioPolicyManager->getOutputForAttr(&attr, output, session, stream, uid,
                                                  config,
                                                  &flags, selectedDeviceId, portId,
                                                  secondaryOutputs);
@@ -208,14 +212,14 @@
         *selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
         *portId = AUDIO_PORT_HANDLE_NONE;
         secondaryOutputs->clear();
-        result = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, config,
+        result = mAudioPolicyManager->getOutputForAttr(&attr, output, session, stream, uid, config,
                                                        &flags, selectedDeviceId, portId,
                                                        secondaryOutputs);
     }
 
     if (result == NO_ERROR) {
         sp <AudioPlaybackClient> client =
-            new AudioPlaybackClient(*attr, *output, uid, pid, session, *selectedDeviceId, *stream);
+            new AudioPlaybackClient(attr, *output, uid, pid, session, *selectedDeviceId, *stream);
         mAudioPlaybackClients.add(*portId, client);
     }
     return result;
@@ -403,6 +407,9 @@
         if (status == NO_ERROR) {
             // enforce permission (if any) required for each type of input
             switch (inputType) {
+            case AudioPolicyInterface::API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK:
+                // this use case has been validated in audio service with a MediaProjection token,
+                // and doesn't rely on regular permissions
             case AudioPolicyInterface::API_INPUT_LEGACY:
                 break;
             case AudioPolicyInterface::API_INPUT_TELEPHONY_RX:
@@ -449,28 +456,14 @@
     return NO_ERROR;
 }
 
-// this is replicated from frameworks/av/media/libaudioclient/AudioRecord.cpp
-// XXX -- figure out how to put it into a common, shared location
-
-static std::string audioSourceString(audio_source_t value) {
-    std::string source;
-    if (SourceTypeConverter::toString(value, source)) {
-        return source;
-    }
-    char rawbuffer[16];  // room for "%d"
-    snprintf(rawbuffer, sizeof(rawbuffer), "%d", value);
-    return rawbuffer;
-}
-
 std::string AudioPolicyService::getDeviceTypeStrForPortId(audio_port_handle_t portId) {
-    std::string typeStr;
     struct audio_port port = {};
     port.id = portId;
     status_t status = mAudioPolicyManager->getAudioPort(&port);
     if (status == NO_ERROR && port.type == AUDIO_PORT_TYPE_DEVICE) {
-        deviceToString(port.ext.device.type, typeStr);
+        return toString(port.ext.device.type);
     }
-    return typeStr;
+    return {};
 }
 
 status_t AudioPolicyService::startInput(audio_port_handle_t portId)
@@ -533,7 +526,7 @@
             item->setInt32(kAudioPolicyStatus, status);
 
             item->setCString(kAudioPolicyRqstSrc,
-                             audioSourceString(client->attributes.source).c_str());
+                             toString(client->attributes.source).c_str());
             item->setInt32(kAudioPolicyRqstSession, client->session);
             if (client->opPackageName.size() != 0) {
                 item->setCString(kAudioPolicyRqstPkg,
@@ -553,7 +546,7 @@
                 if (other->active) {
                     // keeps the last of the clients marked active
                     item->setCString(kAudioPolicyActiveSrc,
-                                     audioSourceString(other->attributes.source).c_str());
+                                     toString(other->attributes.source).c_str());
                     item->setInt32(kAudioPolicyActiveSession, other->session);
                     if (other->opPackageName.size() != 0) {
                         item->setCString(kAudioPolicyActivePkg,
@@ -702,6 +695,53 @@
                                                     device);
 }
 
+status_t AudioPolicyService::setVolumeIndexForAttributes(const audio_attributes_t &attributes,
+                                                         int index, audio_devices_t device)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    return mAudioPolicyManager->setVolumeIndexForAttributes(attributes, index, device);
+}
+
+status_t AudioPolicyService::getVolumeIndexForAttributes(const audio_attributes_t &attributes,
+                                                         int &index, audio_devices_t device)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    return mAudioPolicyManager->getVolumeIndexForAttributes(attributes, index, device);
+}
+
+status_t AudioPolicyService::getMinVolumeIndexForAttributes(const audio_attributes_t &attributes,
+                                                            int &index)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    return mAudioPolicyManager->getMinVolumeIndexForAttributes(attributes, index);
+}
+
+status_t AudioPolicyService::getMaxVolumeIndexForAttributes(const audio_attributes_t &attributes,
+                                                            int &index)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    return mAudioPolicyManager->getMaxVolumeIndexForAttributes(attributes, index);
+}
+
 uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream)
 {
     if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
@@ -1032,9 +1072,14 @@
 status_t AudioPolicyService::registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration)
 {
     Mutex::Autolock _l(mLock);
-    if(!modifyAudioRoutingAllowed()) {
+
+    // loopback|render only need a MediaProjection (checked in caller AudioService.java)
+    bool needModifyAudioRouting = std::any_of(mixes.begin(), mixes.end(), [](auto& mix) {
+            return !is_mix_loopback_render(mix.mRouteFlags); });
+    if (needModifyAudioRouting && !modifyAudioRoutingAllowed()) {
         return PERMISSION_DENIED;
     }
+
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
@@ -1198,13 +1243,32 @@
     return mAudioPolicyManager->listAudioProductStrategies(strategies);
 }
 
-product_strategy_t AudioPolicyService::getProductStrategyFromAudioAttributes(
-        const AudioAttributes &aa)
+status_t AudioPolicyService::getProductStrategyFromAudioAttributes(
+        const AudioAttributes &aa, product_strategy_t &productStrategy)
 {
     if (mAudioPolicyManager == NULL) {
-        return PRODUCT_STRATEGY_NONE;
+        return NO_INIT;
     }
     Mutex::Autolock _l(mLock);
-    return mAudioPolicyManager->getProductStrategyFromAudioAttributes(aa);
+    return mAudioPolicyManager->getProductStrategyFromAudioAttributes(aa, productStrategy);
+}
+
+status_t AudioPolicyService::listAudioVolumeGroups(AudioVolumeGroupVector &groups)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    return mAudioPolicyManager->listAudioVolumeGroups(groups);
+}
+
+status_t AudioPolicyService::getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
+                                                               volume_group_t &volumeGroup)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    return mAudioPolicyManager->getVolumeGroupFromAudioAttributes(aa, volumeGroup);
 }
 } // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 76ac191..8cbf3af 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -150,6 +150,20 @@
     mNotificationClients.valueFor(token)->setAudioPortCallbacksEnabled(enabled);
 }
 
+void AudioPolicyService::setAudioVolumeGroupCallbacksEnabled(bool enabled)
+{
+    Mutex::Autolock _l(mNotificationClientsLock);
+
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    int64_t token = ((int64_t)uid<<32) | pid;
+
+    if (mNotificationClients.indexOfKey(token) < 0) {
+        return;
+    }
+    mNotificationClients.valueFor(token)->setAudioVolumeGroupCallbacksEnabled(enabled);
+}
+
 // removeNotificationClient() is called when the client process dies.
 void AudioPolicyService::removeNotificationClient(uid_t uid, pid_t pid)
 {
@@ -200,6 +214,19 @@
     }
 }
 
+void AudioPolicyService::onAudioVolumeGroupChanged(volume_group_t group, int flags)
+{
+    mOutputCommandThread->changeAudioVolumeGroupCommand(group, flags);
+}
+
+void AudioPolicyService::doOnAudioVolumeGroupChanged(volume_group_t group, int flags)
+{
+    Mutex::Autolock _l(mNotificationClientsLock);
+    for (size_t i = 0; i < mNotificationClients.size(); i++) {
+        mNotificationClients.valueAt(i)->onAudioVolumeGroupChanged(group, flags);
+    }
+}
+
 void AudioPolicyService::onDynamicPolicyMixStateUpdate(const String8& regId, int32_t state)
 {
     ALOGV("AudioPolicyService::onDynamicPolicyMixStateUpdate(%s, %d)",
@@ -270,7 +297,7 @@
                                                      uid_t uid,
                                                      pid_t pid)
     : mService(service), mUid(uid), mPid(pid), mAudioPolicyServiceClient(client),
-      mAudioPortCallbacksEnabled(false)
+      mAudioPortCallbacksEnabled(false), mAudioVolumeGroupCallbacksEnabled(false)
 {
 }
 
@@ -301,6 +328,15 @@
     }
 }
 
+void AudioPolicyService::NotificationClient::onAudioVolumeGroupChanged(volume_group_t group, 
+                                                                      int flags)
+{
+    if (mAudioPolicyServiceClient != 0 && mAudioVolumeGroupCallbacksEnabled) {
+        mAudioPolicyServiceClient->onAudioVolumeGroupChanged(group, flags);
+    }
+}
+
+
 void AudioPolicyService::NotificationClient::onDynamicPolicyMixStateUpdate(
         const String8& regId, int32_t state)
 {
@@ -330,6 +366,10 @@
     mAudioPortCallbacksEnabled = enabled;
 }
 
+void AudioPolicyService::NotificationClient::setAudioVolumeGroupCallbacksEnabled(bool enabled)
+{
+    mAudioVolumeGroupCallbacksEnabled = enabled;
+}
 
 void AudioPolicyService::binderDied(const wp<IBinder>& who) {
     ALOGW("binderDied() %p, calling pid %d", who.unsafe_get(),
@@ -410,7 +450,7 @@
     for (size_t i =0; i < mAudioRecordClients.size(); i++) {
         sp<AudioRecordClient> current = mAudioRecordClients[i];
         if (!current->active) continue;
-        if (isPrivacySensitive(current->attributes.source)) {
+        if (isPrivacySensitiveSource(current->attributes.source)) {
             if (current->startTimeNs > latestSensitiveStartNs) {
                 latestSensitiveActive = current;
                 latestSensitiveStartNs = current->startTimeNs;
@@ -449,7 +489,10 @@
         bool isLatest = current == latestActive;
         bool isLatestSensitive = current == latestSensitiveActive;
         bool forceIdle = true;
-        if (mUidPolicy->isAssistantUid(current->uid)) {
+
+        if (isVirtualSource(source)) {
+            forceIdle = false;
+        } else if (mUidPolicy->isAssistantUid(current->uid)) {
             if (isA11yOnTop) {
                 if (source == AUDIO_SOURCE_HOTWORD || source == AUDIO_SOURCE_VOICE_RECOGNITION) {
                     forceIdle = false;
@@ -465,10 +508,6 @@
                 (source == AUDIO_SOURCE_VOICE_RECOGNITION || source == AUDIO_SOURCE_HOTWORD)) {
                 forceIdle = false;
             }
-        } else if (source == AUDIO_SOURCE_VOICE_DOWNLINK ||
-                   source == AUDIO_SOURCE_VOICE_CALL ||
-                   (source == AUDIO_SOURCE_VOICE_UPLINK)) {
-            forceIdle = false;
         } else {
             if (!isAssistantOnTop && (isOnTop || isLatest) &&
                 (!isSensitiveActive || isLatestSensitive)) {
@@ -502,14 +541,27 @@
 }
 
 /* static */
-bool AudioPolicyService::isPrivacySensitive(audio_source_t source)
+bool AudioPolicyService::isPrivacySensitiveSource(audio_source_t source)
+{
+    switch (source) {
+        case AUDIO_SOURCE_CAMCORDER:
+        case AUDIO_SOURCE_VOICE_COMMUNICATION:
+            return true;
+        default:
+            break;
+    }
+    return false;
+}
+
+/* static */
+bool AudioPolicyService::isVirtualSource(audio_source_t source)
 {
     switch (source) {
         case AUDIO_SOURCE_VOICE_UPLINK:
         case AUDIO_SOURCE_VOICE_DOWNLINK:
         case AUDIO_SOURCE_VOICE_CALL:
-        case AUDIO_SOURCE_CAMCORDER:
-        case AUDIO_SOURCE_VOICE_COMMUNICATION:
+        case AUDIO_SOURCE_REMOTE_SUBMIX:
+        case AUDIO_SOURCE_FM_TUNER:
             return true;
         default:
             break;
@@ -551,6 +603,8 @@
             mAudioPolicyManager->dump(fd);
         }
 
+        mPackageManager.dump(fd);
+
         if (locked) mLock.unlock();
     }
     return NO_ERROR;
@@ -1058,6 +1112,18 @@
                     svc->doOnAudioPatchListUpdate();
                     mLock.lock();
                     }break;
+                case CHANGED_AUDIOVOLUMEGROUP: {
+                    AudioVolumeGroupData *data =
+                            static_cast<AudioVolumeGroupData *>(command->mParam.get());
+                    ALOGV("AudioCommandThread() processing update audio volume group");
+                    svc = mService.promote();
+                    if (svc == 0) {
+                        break;
+                    }
+                    mLock.unlock();
+                    svc->doOnAudioVolumeGroupChanged(data->mGroup, data->mFlags);
+                    mLock.lock();
+                    }break;
                 case SET_AUDIOPORT_CONFIG: {
                     SetAudioPortConfigData *data = (SetAudioPortConfigData *)command->mParam.get();
                     ALOGV("AudioCommandThread() processing set port config");
@@ -1302,6 +1368,19 @@
     sendCommand(command);
 }
 
+void AudioPolicyService::AudioCommandThread::changeAudioVolumeGroupCommand(volume_group_t group,
+                                                                           int flags)
+{
+    sp<AudioCommand>command = new AudioCommand();
+    command->mCommand = CHANGED_AUDIOVOLUMEGROUP;
+    AudioVolumeGroupData *data= new AudioVolumeGroupData();
+    data->mGroup = group;
+    data->mFlags = flags;
+    command->mParam = data;
+    ALOGV("AudioCommandThread() adding audio volume group changed");
+    sendCommand(command);
+}
+
 status_t AudioPolicyService::AudioCommandThread::setAudioPortConfigCommand(
                                             const struct audio_port_config *config, int delayMs)
 {
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 8cd6e81..a2e75cd 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -31,6 +31,7 @@
 #include <media/ToneGenerator.h>
 #include <media/AudioEffect.h>
 #include <media/AudioPolicy.h>
+#include <mediautils/ServiceUtilities.h>
 #include "AudioPolicyEffects.h"
 #include "managerdefault/AudioPolicyManager.h"
 #include <android/hardware/BnSensorPrivacyListener.h>
@@ -111,6 +112,17 @@
                                           int *index,
                                           audio_devices_t device);
 
+    virtual status_t setVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                 int index,
+                                                 audio_devices_t device);
+    virtual status_t getVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                 int &index,
+                                                 audio_devices_t device);
+    virtual status_t getMinVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                    int &index);
+    virtual status_t getMaxVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                    int &index);
+
     virtual uint32_t getStrategyForStream(audio_stream_type_t stream);
     virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream);
 
@@ -192,6 +204,8 @@
 
     virtual void setAudioPortCallbacksEnabled(bool enabled);
 
+    virtual void setAudioVolumeGroupCallbacksEnabled(bool enabled);
+
     virtual status_t acquireSoundTriggerSession(audio_session_t *session,
                                            audio_io_handle_t *ioHandle,
                                            audio_devices_t *device);
@@ -231,7 +245,13 @@
     virtual bool     isHapticPlaybackSupported();
 
     virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies);
-    virtual product_strategy_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa);
+    virtual status_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa,
+                                                           product_strategy_t &productStrategy);
+
+    virtual status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups);
+
+    virtual status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
+                                                       volume_group_t &volumeGroup);
 
             status_t doStopOutput(audio_port_handle_t portId);
             void doReleaseOutput(audio_port_handle_t portId);
@@ -269,6 +289,9 @@
                                                   audio_patch_handle_t patchHandle,
                                                   audio_source_t source);
 
+            void onAudioVolumeGroupChanged(volume_group_t group, int flags);
+            void doOnAudioVolumeGroupChanged(volume_group_t group, int flags);
+
 private:
                         AudioPolicyService() ANDROID_API;
     virtual             ~AudioPolicyService();
@@ -304,7 +327,8 @@
 
     void silenceAllRecordings_l();
 
-    static bool isPrivacySensitive(audio_source_t source);
+    static bool isPrivacySensitiveSource(audio_source_t source);
+    static bool isVirtualSource(audio_source_t source);
 
     // If recording we need to make sure the UID is allowed to do that. If the UID is idle
     // then it cannot record and gets buffers with zeros - silence. As soon as the UID
@@ -398,6 +422,7 @@
             RELEASE_AUDIO_PATCH,
             UPDATE_AUDIOPORT_LIST,
             UPDATE_AUDIOPATCH_LIST,
+            CHANGED_AUDIOVOLUMEGROUP,
             SET_AUDIOPORT_CONFIG,
             DYN_POLICY_MIX_STATE_UPDATE,
             RECORDING_CONFIGURATION_UPDATE
@@ -429,6 +454,7 @@
                                                          int delayMs);
                     void        updateAudioPortListCommand();
                     void        updateAudioPatchListCommand();
+                    void        changeAudioVolumeGroupCommand(volume_group_t group, int flags);
                     status_t    setAudioPortConfigCommand(const struct audio_port_config *config,
                                                           int delayMs);
                     void        dynamicPolicyMixStateUpdateCommand(const String8& regId,
@@ -510,6 +536,12 @@
             audio_patch_handle_t mHandle;
         };
 
+        class AudioVolumeGroupData : public AudioCommandData {
+        public:
+            volume_group_t mGroup;
+            int mFlags;
+        };
+
         class SetAudioPortConfigData : public AudioCommandData {
         public:
             struct audio_port_config mConfig;
@@ -642,6 +674,8 @@
                                                     audio_patch_handle_t patchHandle,
                                                     audio_source_t source);
 
+        virtual void onAudioVolumeGroupChanged(volume_group_t group, int flags);
+
         virtual audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t use);
 
      private:
@@ -660,6 +694,7 @@
                             void      onAudioPatchListUpdate();
                             void      onDynamicPolicyMixStateUpdate(const String8& regId,
                                                                     int32_t state);
+                            void      onAudioVolumeGroupChanged(volume_group_t group, int flags);
                             void      onRecordingConfigurationUpdate(
                                                     int event,
                                                     const record_client_info_t *clientInfo,
@@ -670,6 +705,7 @@
                                                     audio_patch_handle_t patchHandle,
                                                     audio_source_t source);
                             void      setAudioPortCallbacksEnabled(bool enabled);
+                            void setAudioVolumeGroupCallbacksEnabled(bool enabled);
 
                             uid_t uid() {
                                 return mUid;
@@ -687,6 +723,7 @@
         const pid_t                         mPid;
         const sp<IAudioPolicyServiceClient> mAudioPolicyServiceClient;
               bool                          mAudioPortCallbacksEnabled;
+              bool                          mAudioVolumeGroupCallbacksEnabled;
     };
 
     class AudioClient : public virtual RefBase {
@@ -784,6 +821,8 @@
 
     DefaultKeyedVector< audio_port_handle_t, sp<AudioRecordClient> >   mAudioRecordClients;
     DefaultKeyedVector< audio_port_handle_t, sp<AudioPlaybackClient> >   mAudioPlaybackClients;
+
+    MediaPackageManager mPackageManager; // To check allowPlaybackCapture
 };
 
 } // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 6ae354b..8854eb2 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -73,6 +73,7 @@
                                 int /*delayMs*/) override { return NO_INIT; }
     void onAudioPortListUpdate() override { }
     void onAudioPatchListUpdate() override { }
+    void onAudioVolumeGroupChanged(volume_group_t /*group*/, int /*flags*/) override { }
     audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t /*use*/) override { return 0; }
     void onDynamicPolicyMixStateUpdate(String8 /*regId*/, int32_t /*state*/) override { }
     void onRecordingConfigurationUpdate(int event __unused,
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index e06897f..62ec955 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -227,7 +227,7 @@
     Mutex::Autolock lock(mStatusListenerLock);
 
     for (auto& i : mListenerList) {
-        i.second->onTorchStatusChanged(mapToInterface(status), String16{cameraId});
+        i.second->getListener()->onTorchStatusChanged(mapToInterface(status), String16{cameraId});
     }
 }
 
@@ -1654,6 +1654,18 @@
     return Status::ok();
 }
 
+void CameraService::notifyMonitoredUids() {
+    Mutex::Autolock lock(mStatusListenerLock);
+
+    for (const auto& it : mListenerList) {
+        auto ret = it.second->getListener()->onCameraAccessPrioritiesChanged();
+        if (!ret.isOk()) {
+            ALOGE("%s: Failed to trigger permission callback: %d", __FUNCTION__,
+                    ret.exceptionCode());
+        }
+    }
+}
+
 Status CameraService::notifyDeviceStateChange(int64_t newState) {
     const int pid = CameraThreadState::getCallingPid();
     const int selfPid = getpid();
@@ -1721,15 +1733,25 @@
 
     {
         Mutex::Autolock lock(mStatusListenerLock);
-        for (auto& it : mListenerList) {
-            if (IInterface::asBinder(it.second) == IInterface::asBinder(listener)) {
+        for (const auto &it : mListenerList) {
+            if (IInterface::asBinder(it.second->getListener()) == IInterface::asBinder(listener)) {
                 ALOGW("%s: Tried to add listener %p which was already subscribed",
                       __FUNCTION__, listener.get());
                 return STATUS_ERROR(ERROR_ALREADY_EXISTS, "Listener already registered");
             }
         }
 
-        mListenerList.emplace_back(isVendorListener, listener);
+        auto clientUid = CameraThreadState::getCallingUid();
+        sp<ServiceListener> serviceListener = new ServiceListener(this, listener, clientUid);
+        auto ret = serviceListener->initialize();
+        if (ret != NO_ERROR) {
+            String8 msg = String8::format("Failed to initialize service listener: %s (%d)",
+                    strerror(-ret), ret);
+            ALOGE("%s: %s", __FUNCTION__, msg.string());
+            return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
+        }
+        mListenerList.emplace_back(isVendorListener, serviceListener);
+        mUidPolicy->registerMonitorUid(clientUid);
     }
 
     /* Collect current devices and status */
@@ -1776,7 +1798,9 @@
     {
         Mutex::Autolock lock(mStatusListenerLock);
         for (auto it = mListenerList.begin(); it != mListenerList.end(); it++) {
-            if (IInterface::asBinder(it->second) == IInterface::asBinder(listener)) {
+            if (IInterface::asBinder(it->second->getListener()) == IInterface::asBinder(listener)) {
+                mUidPolicy->unregisterMonitorUid(it->second->getListenerUid());
+                IInterface::asBinder(listener)->unlinkToDeath(it->second);
                 mListenerList.erase(it);
                 return Status::ok();
             }
@@ -2396,6 +2420,8 @@
     sCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_OPEN,
             mCameraIdStr, mCameraFacing, mClientPackageName, apiLevel);
 
+    sCameraService->mUidPolicy->registerMonitorUid(mClientUid);
+
     return OK;
 }
 
@@ -2433,6 +2459,8 @@
     }
     mOpsCallback.clear();
 
+    sCameraService->mUidPolicy->unregisterMonitorUid(mClientUid);
+
     return OK;
 }
 
@@ -2523,7 +2551,7 @@
     if (mRegistered) return;
     am.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE
             | ActivityManager::UID_OBSERVER_IDLE
-            | ActivityManager::UID_OBSERVER_ACTIVE,
+            | ActivityManager::UID_OBSERVER_ACTIVE | ActivityManager::UID_OBSERVER_PROCSTATE,
             ActivityManager::PROCESS_STATE_UNKNOWN,
             String16("cameraserver"));
     status_t res = am.linkToDeath(this);
@@ -2569,6 +2597,51 @@
     }
 }
 
+void CameraService::UidPolicy::onUidStateChanged(uid_t uid, int32_t procState,
+        int64_t /*procStateSeq*/) {
+    bool procStateChange = false;
+    {
+        Mutex::Autolock _l(mUidLock);
+        if ((mMonitoredUids.find(uid) != mMonitoredUids.end()) &&
+                (mMonitoredUids[uid].first != procState)) {
+            mMonitoredUids[uid].first = procState;
+            procStateChange = true;
+        }
+    }
+
+    if (procStateChange) {
+        sp<CameraService> service = mService.promote();
+        if (service != nullptr) {
+            service->notifyMonitoredUids();
+        }
+    }
+}
+
+void CameraService::UidPolicy::registerMonitorUid(uid_t uid) {
+    Mutex::Autolock _l(mUidLock);
+    auto it = mMonitoredUids.find(uid);
+    if (it != mMonitoredUids.end()) {
+        it->second.second++;
+    } else {
+        mMonitoredUids.emplace(
+                std::pair<uid_t, std::pair<int32_t, size_t>> (uid,
+                    std::pair<int32_t, size_t> (ActivityManager::PROCESS_STATE_NONEXISTENT, 1)));
+    }
+}
+
+void CameraService::UidPolicy::unregisterMonitorUid(uid_t uid) {
+    Mutex::Autolock _l(mUidLock);
+    auto it = mMonitoredUids.find(uid);
+    if (it != mMonitoredUids.end()) {
+        it->second.second--;
+        if (it->second.second == 0) {
+            mMonitoredUids.erase(it);
+        }
+    } else {
+        ALOGE("%s: Trying to unregister uid: %d which is not monitored!", __FUNCTION__, uid);
+    }
+}
+
 bool CameraService::UidPolicy::isUidActive(uid_t uid, String16 callingPackage) {
     Mutex::Autolock _l(mUidLock);
     return isUidActiveLocked(uid, callingPackage);
@@ -3118,7 +3191,8 @@
                           cameraId.c_str());
                     continue;
                 }
-                listener.second->onStatusChanged(mapToInterface(status), String16(cameraId));
+                listener.second->getListener()->onStatusChanged(mapToInterface(status),
+                        String16(cameraId));
             }
         });
 }
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index cf0cef8..65727ec 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -179,6 +179,9 @@
             /*out*/
             std::vector<hardware::CameraStatus>* cameraStatuses, bool isVendor = false);
 
+    // Monitored UIDs availability notification
+    void                notifyMonitoredUids();
+
     /////////////////////////////////////////////////////////////////////
     // Client functionality
 
@@ -543,11 +546,14 @@
         void onUidGone(uid_t uid, bool disabled);
         void onUidActive(uid_t uid);
         void onUidIdle(uid_t uid, bool disabled);
-        void onUidStateChanged(uid_t uid __unused, int32_t procState __unused, int64_t procStateSeq __unused) {}
+        void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq);
 
         void addOverrideUid(uid_t uid, String16 callingPackage, bool active);
         void removeOverrideUid(uid_t uid, String16 callingPackage);
 
+        void registerMonitorUid(uid_t uid);
+        void unregisterMonitorUid(uid_t uid);
+
         // IBinder::DeathRecipient implementation
         virtual void binderDied(const wp<IBinder> &who);
     private:
@@ -558,6 +564,8 @@
         bool mRegistered;
         wp<CameraService> mService;
         std::unordered_set<uid_t> mActiveUids;
+        // Monitored uid map to cached procState and refCount pair
+        std::unordered_map<uid_t, std::pair<int32_t, size_t>> mMonitoredUids;
         std::unordered_map<uid_t, bool> mOverrideUids;
     }; // class UidPolicy
 
@@ -790,8 +798,33 @@
 
     sp<CameraProviderManager> mCameraProviderManager;
 
+    class ServiceListener : public virtual IBinder::DeathRecipient {
+        public:
+            ServiceListener(sp<CameraService> parent, sp<hardware::ICameraServiceListener> listener,
+                    int uid) : mParent(parent), mListener(listener), mListenerUid(uid) {}
+
+            status_t initialize() {
+                return IInterface::asBinder(mListener)->linkToDeath(this);
+            }
+
+            virtual void binderDied(const wp<IBinder> &/*who*/) {
+                auto parent = mParent.promote();
+                if (parent.get() != nullptr) {
+                    parent->removeListener(mListener);
+                }
+            }
+
+            int getListenerUid() { return mListenerUid; }
+            sp<hardware::ICameraServiceListener> getListener() { return mListener; }
+
+        private:
+            wp<CameraService> mParent;
+            sp<hardware::ICameraServiceListener> mListener;
+            int mListenerUid;
+    };
+
     // Guarded by mStatusListenerMutex
-    std::vector<std::pair<bool, sp<hardware::ICameraServiceListener>>> mListenerList;
+    std::vector<std::pair<bool, sp<ServiceListener>>> mListenerList;
 
     Mutex       mStatusListenerLock;
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 7223b8d..22e09e4 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2849,12 +2849,19 @@
         }
         streams.add(outputStream);
 
-        if (outputStream->format == HAL_PIXEL_FORMAT_BLOB &&
-                outputStream->data_space == HAL_DATASPACE_V0_JFIF) {
+        if (outputStream->format == HAL_PIXEL_FORMAT_BLOB) {
             size_t k = i + ((mInputStream != nullptr) ? 1 : 0); // Input stream if present should
                                                                 // always occupy the initial entry.
-            bufferSizes[k] = static_cast<uint32_t>(
-                    getJpegBufferSize(outputStream->width, outputStream->height));
+            if (outputStream->data_space == HAL_DATASPACE_V0_JFIF) {
+                bufferSizes[k] = static_cast<uint32_t>(
+                        getJpegBufferSize(outputStream->width, outputStream->height));
+            } else if (outputStream->data_space ==
+                    static_cast<android_dataspace>(HAL_DATASPACE_JPEG_APP_SEGMENTS)) {
+                bufferSizes[k] = outputStream->width * outputStream->height;
+            } else {
+                ALOGW("%s: Blob dataSpace %d not supported",
+                        __FUNCTION__, outputStream->data_space);
+            }
         }
     }
 
diff --git a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
index ca9143d..0f6be79 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
+++ b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
@@ -50,6 +50,10 @@
 
     virtual ::android::binder::Status onTorchStatusChanged(
         int32_t status, const ::android::String16& cameraId) override;
+    virtual binder::Status onCameraAccessPrioritiesChanged() {
+        // TODO: no implementation yet.
+        return binder::Status::ok();
+    }
 };
 
 } // implementation
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index 7654982..661a475 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -6,26 +6,8 @@
 LOCAL_SRC_FILES := \
     MediaExtractorService.cpp
 
-LOCAL_SHARED_LIBRARIES := libmedia libstagefright libbinder libutils liblog
+LOCAL_SHARED_LIBRARIES := libmedia libstagefright libbinder libutils
 LOCAL_MODULE:= libmediaextractorservice
-
-sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
-  $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
-  $(UBSAN_RUNTIME_LIBRARY) \
-  $(TSAN_RUNTIME_LIBRARY)))
-
-# $(info Sanitizer:  $(sanitizer_runtime_libraries))
-
-ndk_libraries := $(call normalize-path-list,$(addprefix lib,$(addsuffix .so,\
-  $(NDK_PREBUILT_SHARED_LIBRARIES))))
-
-# $(info NDK:  $(ndk_libraries))
-
-LOCAL_CFLAGS += -DLINKED_LIBRARIES='"$(sanitizer_runtime_libraries):$(ndk_libraries)"'
-
-sanitizer_runtime_libraries :=
-ndk_libraries :=
-
 include $(BUILD_SHARED_LIBRARY)
 
 
@@ -39,7 +21,7 @@
 
 LOCAL_SRC_FILES := main_extractorservice.cpp
 LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils \
-    liblog libbase libandroidicu libavservices_minijail
+    liblog libandroidicu libavservices_minijail
 LOCAL_STATIC_LIBRARIES := libicuandroid_utils
 LOCAL_MODULE:= mediaextractor
 LOCAL_INIT_RC := mediaextractor.rc
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index 0665930..de5c3e4 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -30,9 +30,7 @@
 namespace android {
 
 MediaExtractorService::MediaExtractorService()
-        : BnMediaExtractorService() {
-    MediaExtractorFactory::SetLinkedLibraries(std::string(LINKED_LIBRARIES));
-}
+        : BnMediaExtractorService() { }
 
 sp<IMediaExtractor> MediaExtractorService::makeExtractor(
         const sp<IDataSource> &remoteSource, const char *mime) {
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index 1c63f64..f3339a0 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -16,8 +16,6 @@
         "liblog",
     ],
 
-    compile_multilib: "32",
-
     include_dirs: ["frameworks/av/include"],
 
     cflags: [