Merge "CCodec: don't update pipeline watcher if using input surface"
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/apex/Android.bp b/apex/Android.bp
index 9455290..0a9551d 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -42,6 +42,9 @@
     },
     key: "com.android.media.key",
     certificate: ":com.android.media.certificate",
+
+    // Use a custom AndroidManifest.xml used for API targeting.
+    androidManifest: ":com.android.media-androidManifest",
 }
 
 apex {
@@ -50,14 +53,46 @@
     defaults: ["com.android.media-defaults"],
 }
 
+filegroup {
+    name: "com.android.media-androidManifest",
+    srcs: ["AndroidManifest-media.xml"],
+}
+
+filegroup {
+    name: "com.android.media.swcodec-androidManifest",
+    srcs: ["AndroidManifest-swcodec.xml"],
+}
+
 apex_defaults {
     name: "com.android.media.swcodec-defaults",
-    native_shared_libs: [
-        "libmedia_codecserviceregistrant",
+    binaries: [
+        "mediaswcodec",
+    ],
+    prebuilts: [
+        "com.android.media.swcodec-mediaswcodec.rc",
+        "com.android.media.swcodec-ld.config.txt",
+        "mediaswcodec.policy",
     ],
     use_vendor: true,
     key: "com.android.media.swcodec.key",
     certificate: ":com.android.media.swcodec.certificate",
+
+    // Use a custom AndroidManifest.xml used for API targeting.
+    androidManifest: ":com.android.media.swcodec-androidManifest",
+}
+
+prebuilt_etc {
+    name: "com.android.media.swcodec-mediaswcodec.rc",
+    src: "mediaswcodec.rc",
+    filename: "init.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "com.android.media.swcodec-ld.config.txt",
+    src: "ld.config.txt",
+    filename: "ld.config.txt",
+    installable: false,
 }
 
 apex {
diff --git a/apex/AndroidManifest-media.xml b/apex/AndroidManifest-media.xml
new file mode 100644
index 0000000..17d3f3a
--- /dev/null
+++ b/apex/AndroidManifest-media.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="com.android.media">
+  <!-- APEX does not have classes.dex -->
+  <application android:hasCode="false" />
+  <uses-sdk
+      android:minSdkVersion="28"
+      android:targetSdkVersion="28"
+  />
+</manifest>
diff --git a/apex/AndroidManifest-swcodec.xml b/apex/AndroidManifest-swcodec.xml
new file mode 100644
index 0000000..bd20dc0
--- /dev/null
+++ b/apex/AndroidManifest-swcodec.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="com.android.media.swcodec">
+  <!-- APEX does not have classes.dex -->
+  <application android:hasCode="false" />
+  <uses-sdk
+      android:minSdkVersion="28"
+      android:targetSdkVersion="28"
+  />
+</manifest>
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
new file mode 100644
index 0000000..b342206
--- /dev/null
+++ b/apex/ld.config.txt
@@ -0,0 +1,74 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Bionic loader config file for the media swcodec APEX.
+#
+# There are no versioned APEX paths here - this APEX module does not support
+# having several versions mounted.
+
+dir.swcodec = /apex/com.android.media.swcodec/bin/
+
+[swcodec]
+additional.namespaces = platform
+
+###############################################################################
+# "default" namespace
+#
+# This namespace is for the binaries and libraries on the swcodec APEX.
+###############################################################################
+
+namespace.default.isolated = true
+namespace.default.visible = true
+
+namespace.default.search.paths      = /apex/com.android.media.swcodec/${LIB}
+namespace.default.asan.search.paths = /apex/com.android.media.swcodec/${LIB}
+
+# Keep the below in sync with "sphal" namespace in system's /etc/ld.config.txt
+# Codec2 has dependencies on some SP-hals (eg. android.hardware.graphics.mapper@2.0)
+# These are dlopen'ed by libvndksupport.so.
+namespace.default.search.paths += /odm/${LIB}
+namespace.default.search.paths += /vendor/${LIB}
+
+namespace.default.permitted.paths  = /odm/${LIB}
+namespace.default.permitted.paths += /vendor/${LIB}
+namespace.default.permitted.paths += /vendor/${LIB}/hw
+namespace.default.permitted.paths += /system/vendor/${LIB}
+
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}
+namespace.default.asan.search.paths +=           /odm/${LIB}
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.default.asan.search.paths +=           /vendor/${LIB}
+
+namespace.default.asan.permitted.paths  = /data/asan/odm/${LIB}
+namespace.default.asan.permitted.paths +=           /odm/${LIB}
+namespace.default.asan.permitted.paths += /data/asan/vendor/${LIB}
+namespace.default.asan.permitted.paths +=           /vendor/${LIB}
+
+namespace.default.links = platform
+
+# TODO: replace the following when apex has a way to auto-generate this list
+# namespace.default.link.platform.shared_libs  = %LLNDK_LIBRARIES%
+# namespace.default.link.platform.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+namespace.default.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libvulkan.so
+
+###############################################################################
+# "platform" namespace
+#
+# This namespace is for linking to LLNDK and ASAN libraries on the system.
+###############################################################################
+
+namespace.platform.isolated = true
+
+namespace.platform.search.paths = /system/${LIB}
+namespace.platform.asan.search.paths = /data/asan/system/${LIB}
+
+# /system/lib/libc.so, etc are symlinks to /apex/com.android.lib/lib/bionic/libc.so, etc.
+# Add /apex/... pat to the permitted paths because linker uses realpath(3)
+# to check the accessibility of the lib. We could add this to search.paths
+# instead but that makes the resolution of bionic libs be dependent on
+# the order of /system/lib and /apex/... in search.paths. If /apex/...
+# is after /system/lib, then /apex/... is never tried because libc.so
+# is always found in /system/lib but fails to pass the accessibility test
+# because of its realpath.  It's better to not depend on the ordering if
+# possible.
+namespace.platform.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
+namespace.platform.asan.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
diff --git a/apex/mediaswcodec.rc b/apex/mediaswcodec.rc
new file mode 100644
index 0000000..d17481b
--- /dev/null
+++ b/apex/mediaswcodec.rc
@@ -0,0 +1,7 @@
+service media.swcodec /apex/com.android.media.swcodec/bin/mediaswcodec
+    class main
+    user mediacodec
+    group camera drmrpc mediadrm
+    override
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
diff --git a/camera/OWNERS b/camera/OWNERS
index 18acfee..d6b95da 100644
--- a/camera/OWNERS
+++ b/camera/OWNERS
@@ -1,6 +1,8 @@
-cychen@google.com
 epeev@google.com
 etalvala@google.com
+jchowdhary@google.com
 shuzhenwang@google.com
 yinchiayeh@google.com
+# backup owner
+cychen@google.com
 zhijunhe@google.com
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
index ab796fb..1ac8482 100644
--- a/camera/ndk/NdkCameraCaptureSession.cpp
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -105,7 +105,9 @@
 
     if (session->isClosed()) {
         ALOGE("%s: session %p is already closed", __FUNCTION__, session);
-        *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+        if (captureSequenceId) {
+            *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+        }
         return ACAMERA_ERROR_SESSION_CLOSED;
     }
 
@@ -127,7 +129,9 @@
 
     if (session->isClosed()) {
         ALOGE("%s: session %p is already closed", __FUNCTION__, session);
-        *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+        if (captureSequenceId) {
+            *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+        }
         return ACAMERA_ERROR_SESSION_CLOSED;
     }
 
@@ -149,7 +153,9 @@
 
     if (session->isClosed()) {
         ALOGE("%s: session %p is already closed", __FUNCTION__, session);
-        *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+        if (captureSequenceId) {
+            *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+        }
         return ACAMERA_ERROR_SESSION_CLOSED;
     }
 
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
index 98608da..09b85d5 100644
--- a/camera/ndk/NdkCameraDevice.cpp
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -78,7 +78,34 @@
             ALOGE("%s: unknown template ID %d", __FUNCTION__, templateId);
             return ACAMERA_ERROR_INVALID_PARAMETER;
     }
-    return device->createCaptureRequest(templateId, request);
+    return device->createCaptureRequest(templateId, nullptr /*physicalIdList*/, request);
+}
+
+EXPORT
+camera_status_t ACameraDevice_createCaptureRequest_withPhysicalIds(
+        const ACameraDevice* device,
+        ACameraDevice_request_template templateId,
+        const ACameraIdList* physicalCameraIdList,
+        ACaptureRequest** request) {
+    ATRACE_CALL();
+    if (device == nullptr || request == nullptr || physicalCameraIdList == nullptr) {
+        ALOGE("%s: invalid argument! device %p request %p, physicalCameraIdList %p",
+                __FUNCTION__, device, request, physicalCameraIdList);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    switch (templateId) {
+        case TEMPLATE_PREVIEW:
+        case TEMPLATE_STILL_CAPTURE:
+        case TEMPLATE_RECORD:
+        case TEMPLATE_VIDEO_SNAPSHOT:
+        case TEMPLATE_ZERO_SHUTTER_LAG:
+        case TEMPLATE_MANUAL:
+            break;
+        default:
+            ALOGE("%s: unknown template ID %d", __FUNCTION__, templateId);
+            return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    return device->createCaptureRequest(templateId, physicalCameraIdList, request);
 }
 
 EXPORT
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
index 8742d9c..23d01ef 100644
--- a/camera/ndk/NdkCameraManager.cpp
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -105,6 +105,60 @@
 }
 
 EXPORT
+camera_status_t ACameraManager_registerExtendedAvailabilityCallback(
+        ACameraManager* /*manager*/, const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+    ATRACE_CALL();
+    if (callback == nullptr) {
+        ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    if ((callback->availabilityCallbacks.onCameraAvailable == nullptr) ||
+            (callback->availabilityCallbacks.onCameraUnavailable == nullptr) ||
+            (callback->onCameraAccessPrioritiesChanged == nullptr)) {
+        ALOGE("%s: invalid argument! callback %p, "
+                "onCameraAvailable %p, onCameraUnavailable %p onCameraAccessPrioritiesChanged %p",
+               __FUNCTION__, callback,
+               callback->availabilityCallbacks.onCameraAvailable,
+               callback->availabilityCallbacks.onCameraUnavailable,
+               callback->onCameraAccessPrioritiesChanged);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    auto reservedEntriesCount = sizeof(callback->reserved) / sizeof(callback->reserved[0]);
+    for (size_t i = 0; i < reservedEntriesCount; i++) {
+        if (callback->reserved[i] != nullptr) {
+            ALOGE("%s: invalid argument! callback reserved entries must be set to NULL",
+                    __FUNCTION__);
+            return ACAMERA_ERROR_INVALID_PARAMETER;
+        }
+    }
+    CameraManagerGlobal::getInstance().registerExtendedAvailabilityCallback(callback);
+    return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraManager_unregisterExtendedAvailabilityCallback(
+        ACameraManager* /*manager*/, const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+    ATRACE_CALL();
+    if (callback == nullptr) {
+        ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    if ((callback->availabilityCallbacks.onCameraAvailable == nullptr) ||
+            (callback->availabilityCallbacks.onCameraUnavailable == nullptr) ||
+            (callback->onCameraAccessPrioritiesChanged == nullptr)) {
+        ALOGE("%s: invalid argument! callback %p, "
+                "onCameraAvailable %p, onCameraUnavailable %p onCameraAccessPrioritiesChanged %p",
+               __FUNCTION__, callback,
+               callback->availabilityCallbacks.onCameraAvailable,
+               callback->availabilityCallbacks.onCameraUnavailable,
+               callback->onCameraAccessPrioritiesChanged);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    CameraManagerGlobal::getInstance().unregisterExtendedAvailabilityCallback(callback);
+    return ACAMERA_OK;
+}
+
+EXPORT
 camera_status_t ACameraManager_getCameraCharacteristics(
         ACameraManager* mgr, const char* cameraId, ACameraMetadata** chars){
     ATRACE_CALL();
diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
index c64de3e..87de4a9 100644
--- a/camera/ndk/NdkCaptureRequest.cpp
+++ b/camera/ndk/NdkCaptureRequest.cpp
@@ -98,6 +98,27 @@
 }
 
 EXPORT
+camera_status_t ACaptureRequest_getConstEntry_physicalCamera(
+        const ACaptureRequest* req, const char* physicalId,
+        uint32_t tag, ACameraMetadata_const_entry* entry) {
+    ATRACE_CALL();
+    if (req == nullptr || entry == nullptr || physicalId == nullptr) {
+        ALOGE("%s: invalid argument! req %p, tag 0x%x, entry %p, physicalId %p",
+               __FUNCTION__, req, tag, entry, physicalId);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+
+    const auto& physicalSettings = req->physicalSettings.find(physicalId);
+    if (physicalSettings == req->physicalSettings.end()) {
+        ALOGE("%s: Failed to find metadata for physical camera id  %s",
+                __FUNCTION__, physicalId);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+
+    return physicalSettings->second->getConstEntry(tag, entry);
+}
+
+EXPORT
 camera_status_t ACaptureRequest_getAllTags(
         const ACaptureRequest* req, /*out*/int32_t* numTags, /*out*/const uint32_t** tags) {
     ATRACE_CALL();
@@ -131,6 +152,34 @@
 
 #undef SET_ENTRY
 
+#define SET_PHYSICAL_ENTRY(NAME,NDK_TYPE)                                               \
+EXPORT                                                                                  \
+camera_status_t ACaptureRequest_setEntry_physicalCamera_##NAME(                         \
+        ACaptureRequest* req, const char* physicalId, uint32_t tag,                     \
+        uint32_t count, const NDK_TYPE* data) {                                         \
+    ATRACE_CALL();                                                                      \
+    if (req == nullptr || (count > 0 && data == nullptr) || physicalId == nullptr) {    \
+        ALOGE("%s: invalid argument! req %p, tag 0x%x, count %d, data 0x%p, physicalId %p", \
+               __FUNCTION__, req, tag, count, data, physicalId);                        \
+        return ACAMERA_ERROR_INVALID_PARAMETER;                                         \
+    }                                                                                   \
+    if (req->physicalSettings.find(physicalId) == req->physicalSettings.end()) {        \
+        ALOGE("%s: Failed to find metadata for physical camera id %s",                  \
+            __FUNCTION__, physicalId);                                                  \
+      return ACAMERA_ERROR_INVALID_PARAMETER;                                           \
+    }                                                                                   \
+    return req->physicalSettings[physicalId]->update(tag, count, data);                 \
+}
+
+SET_PHYSICAL_ENTRY(u8,uint8_t)
+SET_PHYSICAL_ENTRY(i32,int32_t)
+SET_PHYSICAL_ENTRY(float,float)
+SET_PHYSICAL_ENTRY(double,double)
+SET_PHYSICAL_ENTRY(i64,int64_t)
+SET_PHYSICAL_ENTRY(rational,ACameraMetadata_rational)
+
+#undef SET_PHYSICAL_ENTRY
+
 EXPORT
 void ACaptureRequest_free(ACaptureRequest* request) {
     ATRACE_CALL();
@@ -138,6 +187,7 @@
         return;
     }
     request->settings.clear();
+    request->physicalSettings.clear();
     delete request->targets;
     delete request;
     return;
@@ -174,6 +224,9 @@
 
     ACaptureRequest* pRequest = new ACaptureRequest();
     pRequest->settings = new ACameraMetadata(*(src->settings));
+    for (const auto& entry : src->physicalSettings) {
+        pRequest->physicalSettings[entry.first] = new ACameraMetadata(*(entry.second));
+    }
     pRequest->targets  = new ACameraOutputTargets();
     *(pRequest->targets)  = *(src->targets);
     pRequest->context = src->context;
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index d8a5765..5e4fcd0 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -76,7 +76,7 @@
                 __FUNCTION__, strerror(-err), err);
         setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
     }
-    mHandler = new CallbackHandler();
+    mHandler = new CallbackHandler(id);
     mCbLooper->registerHandler(mHandler);
 
     const CameraMetadata& metadata = mChars->getInternalData();
@@ -97,6 +97,14 @@
         mShadingMapSize[0] = entry.data.i32[0];
         mShadingMapSize[1] = entry.data.i32[1];
     }
+
+    size_t physicalIdCnt = 0;
+    const char*const* physicalCameraIds;
+    if (mChars->isLogicalMultiCamera(&physicalIdCnt, &physicalCameraIds)) {
+        for (size_t i = 0; i < physicalIdCnt; i++) {
+            mPhysicalIds.push_back(physicalCameraIds[i]);
+        }
+    }
 }
 
 // Device close implementaiton
@@ -129,8 +137,29 @@
 camera_status_t
 CameraDevice::createCaptureRequest(
         ACameraDevice_request_template templateId,
+        const ACameraIdList* physicalIdList,
         ACaptureRequest** request) const {
     Mutex::Autolock _l(mDeviceLock);
+
+    if (physicalIdList != nullptr) {
+        if (physicalIdList->numCameras > static_cast<int>(mPhysicalIds.size())) {
+            ALOGE("%s: physicalIdList size %d exceeds number of available physical cameras %zu",
+                    __FUNCTION__, physicalIdList->numCameras, mPhysicalIds.size());
+            return ACAMERA_ERROR_INVALID_PARAMETER;
+        }
+        for (auto i = 0; i < physicalIdList->numCameras; i++) {
+            if (physicalIdList->cameraIds[i] == nullptr) {
+                ALOGE("%s: physicalId is null!", __FUNCTION__);
+                return ACAMERA_ERROR_INVALID_PARAMETER;
+            }
+            if (mPhysicalIds.end() == std::find(
+                    mPhysicalIds.begin(), mPhysicalIds.end(), physicalIdList->cameraIds[i])) {
+                ALOGE("%s: Invalid physicalId %s!", __FUNCTION__, physicalIdList->cameraIds[i]);
+                return ACAMERA_ERROR_INVALID_PARAMETER;
+            }
+        }
+    }
+
     camera_status_t ret = checkCameraClosedOrErrorLocked();
     if (ret != ACAMERA_OK) {
         return ret;
@@ -151,6 +180,12 @@
     }
     ACaptureRequest* outReq = new ACaptureRequest();
     outReq->settings = new ACameraMetadata(rawRequest.release(), ACameraMetadata::ACM_REQUEST);
+    if (physicalIdList != nullptr) {
+        for (auto i = 0; i < physicalIdList->numCameras; i++) {
+            outReq->physicalSettings.emplace(physicalIdList->cameraIds[i],
+                    new ACameraMetadata(*(outReq->settings)));
+        }
+    }
     outReq->targets  = new ACameraOutputTargets();
     *request = outReq;
     return ACAMERA_OK;
@@ -275,8 +310,12 @@
         const ACaptureRequest* request, /*out*/sp<CaptureRequest>& outReq) {
     camera_status_t ret;
     sp<CaptureRequest> req(new CaptureRequest());
-    req->mPhysicalCameraSettings.push_back({std::string(mCameraId.string()),
+    req->mPhysicalCameraSettings.push_back({getId(),
             request->settings->getInternalData()});
+    for (auto& entry : request->physicalSettings) {
+        req->mPhysicalCameraSettings.push_back({entry.first,
+                entry.second->getInternalData()});
+    }
     req->mIsReprocess = false; // NDK does not support reprocessing yet
     req->mContext = request->context;
     req->mSurfaceConverted = true; // set to true, and fill in stream/surface idx to speed up IPC
@@ -320,10 +359,17 @@
 }
 
 ACaptureRequest*
-CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req) {
+CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req, const std::string& deviceId) {
     ACaptureRequest* pRequest = new ACaptureRequest();
-    CameraMetadata clone = req->mPhysicalCameraSettings.begin()->settings;
-    pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
+    for (auto& entry : req->mPhysicalCameraSettings) {
+        CameraMetadata clone = entry.settings;
+        if (entry.id == deviceId) {
+            pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
+        } else {
+            pRequest->physicalSettings.emplace(entry.id,
+                    new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST));
+        }
+    }
     pRequest->targets  = new ACameraOutputTargets();
     for (size_t i = 0; i < req->mSurfaceList.size(); i++) {
         ANativeWindow* anw = static_cast<ANativeWindow*>(req->mSurfaceList[i].get());
@@ -340,6 +386,7 @@
         return;
     }
     req->settings.clear();
+    req->physicalSettings.clear();
     delete req->targets;
     delete req;
 }
@@ -786,6 +833,9 @@
     return;
 }
 
+CameraDevice::CallbackHandler::CallbackHandler(const char* id) : mId(id) {
+}
+
 void CameraDevice::CallbackHandler::onMessageReceived(
         const sp<AMessage> &msg) {
     switch (msg->what()) {
@@ -927,7 +977,7 @@
                         ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
                         return;
                     }
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp);
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
                     (*onStart)(context, session.get(), request, timestamp);
                     freeACaptureRequest(request);
                     break;
@@ -950,7 +1000,7 @@
                         return;
                     }
                     sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp);
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
                     (*onResult)(context, session.get(), request, result.get());
                     freeACaptureRequest(request);
                     break;
@@ -1006,7 +1056,7 @@
                         physicalMetadataCopyPtrs.push_back(physicalMetadataCopy[i].get());
                     }
 
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp);
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
                     (*onResult)(context, session.get(), request, result.get(),
                             physicalResultInfo.size(), physicalCameraIdPtrs.data(),
                             physicalMetadataCopyPtrs.data());
@@ -1034,7 +1084,7 @@
                             static_cast<CameraCaptureFailure*>(obj.get()));
                     ACameraCaptureFailure* failure =
                             static_cast<ACameraCaptureFailure*>(failureSp.get());
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp);
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
                     (*onFail)(context, session.get(), request, failure);
                     freeACaptureRequest(request);
                     break;
@@ -1111,7 +1161,7 @@
                         return;
                     }
 
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp);
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
                     (*onBufferLost)(context, session.get(), request, anw, frameNumber);
                     freeACaptureRequest(request);
                     break;
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index d0f363b..103efd5 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -68,6 +68,7 @@
 
     camera_status_t createCaptureRequest(
             ACameraDevice_request_template templateId,
+            const ACameraIdList* physicalIdList,
             ACaptureRequest** request) const;
 
     camera_status_t createCaptureSession(
@@ -145,7 +146,8 @@
     camera_status_t allocateCaptureRequest(
             const ACaptureRequest* request, sp<CaptureRequest>& outReq);
 
-    static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req);
+    static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req,
+            const std::string& deviceId);
     static void freeACaptureRequest(ACaptureRequest*);
 
     // only For session to hold device lock
@@ -230,9 +232,11 @@
 
     class CallbackHandler : public AHandler {
       public:
+        explicit CallbackHandler(const char* id);
         void onMessageReceived(const sp<AMessage> &msg) override;
 
       private:
+        std::string mId;
         // This handler will cache all capture session sp until kWhatCleanUpSessions
         // is processed. This is used to guarantee the last session reference is always
         // being removed in callback thread without holding camera device lock
@@ -327,6 +331,7 @@
     // Misc variables
     int32_t mShadingMapSize[2];   // const after constructor
     int32_t mPartialResultCount;  // const after constructor
+    std::vector<std::string> mPhysicalIds; // const after constructor
 
 };
 
@@ -351,8 +356,9 @@
 
     camera_status_t createCaptureRequest(
             ACameraDevice_request_template templateId,
+            const ACameraIdList* physicalCameraIdList,
             ACaptureRequest** request) const {
-        return mDevice->createCaptureRequest(templateId, request);
+        return mDevice->createCaptureRequest(templateId, physicalCameraIdList, request);
     }
 
     camera_status_t createCaptureSession(
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 7d6ecac..9d40fd7 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -193,6 +193,20 @@
     }
 }
 
+void CameraManagerGlobal::registerExtendedAvailabilityCallback(
+        const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+    Mutex::Autolock _l(mLock);
+    Callback cb(callback);
+    mCallbacks.insert(cb);
+}
+
+void CameraManagerGlobal::unregisterExtendedAvailabilityCallback(
+        const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+    Mutex::Autolock _l(mLock);
+    Callback cb(callback);
+    mCallbacks.erase(cb);
+}
+
 void CameraManagerGlobal::registerAvailabilityCallback(
         const ACameraManager_AvailabilityCallbacks *callback) {
     Mutex::Autolock _l(mLock);
@@ -289,12 +303,40 @@
             (*cb)(context, cameraId.c_str());
             break;
         }
+        case kWhatSendSingleAccessCallback:
+        {
+            ACameraManager_AccessPrioritiesChangedCallback cb;
+            void* context;
+            AString cameraId;
+            bool found = msg->findPointer(kCallbackFpKey, (void**) &cb);
+            if (!found) {
+                ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__);
+                return;
+            }
+            found = msg->findPointer(kContextKey, &context);
+            if (!found) {
+                ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+                return;
+            }
+            (*cb)(context);
+            break;
+        }
         default:
             ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
             break;
     }
 }
 
+binder::Status CameraManagerGlobal::CameraServiceListener::onCameraAccessPrioritiesChanged() {
+    sp<CameraManagerGlobal> cm = mCameraManager.promote();
+    if (cm != nullptr) {
+        cm->onCameraAccessPrioritiesChanged();
+    } else {
+        ALOGE("Cannot deliver camera access priority callback. Global camera manager died");
+    }
+    return binder::Status::ok();
+}
+
 binder::Status CameraManagerGlobal::CameraServiceListener::onStatusChanged(
         int32_t status, const String16& cameraId) {
     sp<CameraManagerGlobal> cm = mCameraManager.promote();
@@ -306,6 +348,19 @@
     return binder::Status::ok();
 }
 
+void CameraManagerGlobal::onCameraAccessPrioritiesChanged() {
+    Mutex::Autolock _l(mLock);
+    for (auto cb : mCallbacks) {
+        sp<AMessage> msg = new AMessage(kWhatSendSingleAccessCallback, mHandler);
+        ACameraManager_AccessPrioritiesChangedCallback cbFp = cb.mAccessPriorityChanged;
+        if (cbFp != nullptr) {
+            msg->setPointer(kCallbackFpKey, (void *) cbFp);
+            msg->setPointer(kContextKey, cb.mContext);
+            msg->post();
+        }
+    }
+}
+
 void CameraManagerGlobal::onStatusChanged(
         int32_t status, const String8& cameraId) {
     Mutex::Autolock _l(mLock);
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index c3407f0..8c1da36 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -54,6 +54,11 @@
     void unregisterAvailabilityCallback(
             const ACameraManager_AvailabilityCallbacks *callback);
 
+    void registerExtendedAvailabilityCallback(
+            const ACameraManager_ExtendedAvailabilityCallbacks* callback);
+    void unregisterExtendedAvailabilityCallback(
+            const ACameraManager_ExtendedAvailabilityCallbacks* callback);
+
     /**
      * Return camera IDs that support camera2
      */
@@ -86,10 +91,7 @@
             return binder::Status::ok();
         }
 
-        // Access priority API not implemented yet
-        virtual binder::Status onCameraAccessPrioritiesChanged() {
-            return binder::Status::ok();
-        }
+        virtual binder::Status onCameraAccessPrioritiesChanged();
 
       private:
         const wp<CameraManagerGlobal> mCameraManager;
@@ -101,11 +103,19 @@
         explicit Callback(const ACameraManager_AvailabilityCallbacks *callback) :
             mAvailable(callback->onCameraAvailable),
             mUnavailable(callback->onCameraUnavailable),
+            mAccessPriorityChanged(nullptr),
             mContext(callback->context) {}
 
+        explicit Callback(const ACameraManager_ExtendedAvailabilityCallbacks *callback) :
+            mAvailable(callback->availabilityCallbacks.onCameraAvailable),
+            mUnavailable(callback->availabilityCallbacks.onCameraUnavailable),
+            mAccessPriorityChanged(callback->onCameraAccessPrioritiesChanged),
+            mContext(callback->availabilityCallbacks.context) {}
+
         bool operator == (const Callback& other) const {
             return (mAvailable == other.mAvailable &&
                     mUnavailable == other.mUnavailable &&
+                    mAccessPriorityChanged == other.mAccessPriorityChanged &&
                     mContext == other.mContext);
         }
         bool operator != (const Callback& other) const {
@@ -114,6 +124,9 @@
         bool operator < (const Callback& other) const {
             if (*this == other) return false;
             if (mContext != other.mContext) return mContext < other.mContext;
+            if (mAccessPriorityChanged != other.mAccessPriorityChanged) {
+                return mAccessPriorityChanged < other.mAccessPriorityChanged;
+            }
             if (mAvailable != other.mAvailable) return mAvailable < other.mAvailable;
             return mUnavailable < other.mUnavailable;
         }
@@ -122,13 +135,15 @@
         }
         ACameraManager_AvailabilityCallback mAvailable;
         ACameraManager_AvailabilityCallback mUnavailable;
+        ACameraManager_AccessPrioritiesChangedCallback mAccessPriorityChanged;
         void*                               mContext;
     };
     std::set<Callback> mCallbacks;
 
     // definition of handler and message
     enum {
-        kWhatSendSingleCallback
+        kWhatSendSingleCallback,
+        kWhatSendSingleAccessCallback,
     };
     static const char* kCameraIdKey;
     static const char* kCallbackFpKey;
@@ -141,6 +156,7 @@
     sp<CallbackHandler> mHandler;
     sp<ALooper>         mCbLooper; // Looper thread where callbacks actually happen on
 
+    void onCameraAccessPrioritiesChanged();
     void onStatusChanged(int32_t status, const String8& cameraId);
     void onStatusChangedLocked(int32_t status, const String8& cameraId);
     // Utils for status
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index 359eaed..d832deb 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -215,7 +215,7 @@
     const int STREAM_HEIGHT_OFFSET = 2;
     const int STREAM_IS_INPUT_OFFSET = 3;
     camera_metadata_entry entry = mData.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
-    if (entry.count == 0 || entry.count % 4 || entry.type != TYPE_INT32) {
+    if (entry.count > 0 && (entry.count % 4 || entry.type != TYPE_INT32)) {
         ALOGE("%s: malformed available stream configuration key! count %zu, type %d",
                 __FUNCTION__, entry.count, entry.type);
         return;
@@ -243,9 +243,17 @@
         filteredStreamConfigs.push_back(isInput);
     }
 
-    mData.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, filteredStreamConfigs);
+    if (filteredStreamConfigs.size() > 0) {
+        mData.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, filteredStreamConfigs);
+    }
 
     entry = mData.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS);
+    if (entry.count > 0 && (entry.count % 4 || entry.type != TYPE_INT32)) {
+        ALOGE("%s: malformed available depth stream configuration key! count %zu, type %d",
+                __FUNCTION__, entry.count, entry.type);
+        return;
+    }
+
     Vector<int32_t> filteredDepthStreamConfigs;
     filteredDepthStreamConfigs.setCapacity(entry.count);
 
@@ -270,7 +278,11 @@
         filteredDepthStreamConfigs.push_back(height);
         filteredDepthStreamConfigs.push_back(isInput);
     }
-    mData.update(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, filteredDepthStreamConfigs);
+
+    if (filteredDepthStreamConfigs.size() > 0) {
+        mData.update(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,
+                filteredDepthStreamConfigs);
+    }
 
     entry = mData.find(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS);
     Vector<int32_t> filteredHeicStreamConfigs;
diff --git a/camera/ndk/impl/ACaptureRequest.h b/camera/ndk/impl/ACaptureRequest.h
index 5c82ab7..2ffcafe 100644
--- a/camera/ndk/impl/ACaptureRequest.h
+++ b/camera/ndk/impl/ACaptureRequest.h
@@ -18,6 +18,7 @@
 
 #include <camera/NdkCaptureRequest.h>
 #include <set>
+#include <unordered_map>
 
 using namespace android;
 
@@ -59,7 +60,8 @@
         return ACAMERA_OK;
     }
 
-    sp<ACameraMetadata>   settings;
+    sp<ACameraMetadata> settings;
+    std::unordered_map<std::string, sp<ACameraMetadata>> physicalSettings;
     ACameraOutputTargets* targets;
     void*                 context;
 };
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
index 26af4f8..cedf83a 100644
--- a/camera/ndk/include/camera/NdkCameraDevice.h
+++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -53,6 +53,17 @@
  */
 typedef struct ACameraDevice ACameraDevice;
 
+/**
+ * Struct to hold list of camera device Ids. This can refer to either the Ids
+ * of connected camera devices returned from {@link ACameraManager_getCameraIdList},
+ * or the physical camera Ids passed into
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ */
+typedef struct ACameraIdList {
+    int numCameras;          ///< Number of camera device Ids
+    const char** cameraIds;  ///< list of camera device Ids
+} ACameraIdList;
+
 /// Enum for ACameraDevice_ErrorStateCallback error code
 enum {
     /**
@@ -793,6 +804,47 @@
         ACameraWindowType* anw, const char* physicalId,
         /*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(29);
 
+/**
+ * Create a logical multi-camera ACaptureRequest for capturing images, initialized with template
+ * for a target use case, with the ability to specify physical camera settings.
+ *
+ * <p>The settings are chosen to be the best options for this camera device,
+ * so it is not recommended to reuse the same request for a different camera device.</p>
+ *
+ * <p>Note that for all keys in physical camera settings, only the keys
+ * advertised in ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS are
+ * applicable. All other keys are ignored by the camera device.</p>
+ *
+ * @param device the camera device of interest
+ * @param templateId the type of capture request to be created.
+ *        See {@link ACameraDevice_request_template}.
+ * @param physicalIdList The list of physical camera Ids that can be used to
+ *        customize the request for a specific physical camera.
+ * @param request the output request will be stored here if the method call succeeds.
+ *
+ * @return <ul>
+ *         <li>{@link ACAMERA_OK} if the method call succeeds. The created capture request will be
+ *                                filled in request argument.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if device, physicalIdList, or request is
+ *                                NULL, templateId is undefined or camera device does not support
+ *                                requested template, or if some Ids in physicalIdList isn't a
+ *                                valid physical camera backing the current camera device.</li>
+ *         <li>{@link ACAMERA_ERROR_CAMERA_DISCONNECTED} if the camera device is closed.</li>
+ *         <li>{@link ACAMERA_ERROR_CAMERA_DEVICE} if the camera device encounters fatal error.</li>
+ *         <li>{@link ACAMERA_ERROR_CAMERA_SERVICE} if the camera service encounters fatal error.</li>
+ *         <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons.</li></ul>
+ *
+ * @see TEMPLATE_PREVIEW
+ * @see TEMPLATE_RECORD
+ * @see TEMPLATE_STILL_CAPTURE
+ * @see TEMPLATE_VIDEO_SNAPSHOT
+ * @see TEMPLATE_MANUAL
+ */
+camera_status_t ACameraDevice_createCaptureRequest_withPhysicalIds(
+        const ACameraDevice* device, ACameraDevice_request_template templateId,
+        const ACameraIdList* physicalIdList,
+        /*out*/ACaptureRequest** request) __INTRODUCED_IN(29);
+
 #endif /* __ANDROID_API__ >= 29 */
 
 __END_DECLS
diff --git a/camera/ndk/include/camera/NdkCameraManager.h b/camera/ndk/include/camera/NdkCameraManager.h
index ea76738..136a497 100644
--- a/camera/ndk/include/camera/NdkCameraManager.h
+++ b/camera/ndk/include/camera/NdkCameraManager.h
@@ -74,12 +74,6 @@
  */
 void ACameraManager_delete(ACameraManager* manager) __INTRODUCED_IN(24);
 
-/// Struct to hold list of camera devices
-typedef struct ACameraIdList {
-    int numCameras;          ///< Number of connected camera devices
-    const char** cameraIds;  ///< list of identifier of connected camera devices
-} ACameraIdList;
-
 /**
  * Create a list of currently connected camera devices, including
  * cameras that may be in use by other camera API clients.
@@ -278,6 +272,105 @@
 
 #endif /* __ANDROID_API__ >= 24 */
 
+#if __ANDROID_API__ >= 29
+
+/**
+ * Definition of camera access permission change callback.
+ *
+ * <p>Notification that camera access priorities have changed and the camera may
+ * now be openable. An application that was previously denied camera access due to
+ * a higher-priority user already using the camera, or that was disconnected from an
+ * active camera session due to a higher-priority user trying to open the camera,
+ * should try to open the camera again if it still wants to use it.  Note that
+ * multiple applications may receive this callback at the same time, and only one of
+ * them will succeed in opening the camera in practice, depending on exact access
+ * priority levels and timing. This method is useful in cases where multiple
+ * applications may be in the resumed state at the same time, and the user switches
+ * focus between them, or if the current camera-using application moves between
+ * full-screen and Picture-in-Picture (PiP) states. In such cases, the camera
+ * available/unavailable callbacks will not be invoked, but another application may
+ * now have higher priority for camera access than the current camera-using
+ * application.</p>
+
+ * @param context The optional application context provided by user in
+ *                {@link ACameraManager_AvailabilityListener}.
+ */
+typedef void (*ACameraManager_AccessPrioritiesChangedCallback)(void* context);
+
+/**
+ * A listener for camera devices becoming available/unavailable to open or when
+ * the camera access permissions change.
+ *
+ * <p>Cameras become available when they are no longer in use, or when a new
+ * removable camera is connected. They become unavailable when some
+ * application or service starts using a camera, or when a removable camera
+ * is disconnected.</p>
+ *
+ * @see ACameraManager_registerExtendedAvailabilityCallback
+ */
+typedef struct ACameraManager_ExtendedAvailabilityListener {
+    ///
+    ACameraManager_AvailabilityCallbacks availabilityCallbacks;
+
+    /// Called when there is camera access permission change
+    ACameraManager_AccessPrioritiesChangedCallback onCameraAccessPrioritiesChanged;
+
+    /// Reserved for future use, please ensure that all entries are set to NULL
+    void *reserved[6];
+} ACameraManager_ExtendedAvailabilityCallbacks;
+
+/**
+ * Register camera extended availability callbacks.
+ *
+ * <p>onCameraUnavailable will be called whenever a camera device is opened by any camera API
+ * client. Other camera API clients may still be able to open such a camera device, evicting the
+ * existing client if they have higher priority than the existing client of a camera device.
+ * See {@link ACameraManager_openCamera} for more details.</p>
+ *
+ * <p>The callbacks will be called on a dedicated thread shared among all ACameraManager
+ * instances.</p>
+ *
+ * <p>Since this callback will be registered with the camera service, remember to unregister it
+ * once it is no longer needed; otherwise the callback will continue to receive events
+ * indefinitely and it may prevent other resources from being released. Specifically, the
+ * callbacks will be invoked independently of the general activity lifecycle and independently
+ * of the state of individual ACameraManager instances.</p>
+ *
+ * @param manager the {@link ACameraManager} of interest.
+ * @param callback the {@link ACameraManager_ExtendedAvailabilityCallbacks} to be registered.
+ *
+ * @return <ul>
+ *         <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if manager or callback is NULL, or
+ *                  {ACameraManager_ExtendedAvailabilityCallbacks#onCameraAccessPrioritiesChanged}
+ *                  or {ACameraManager_AvailabilityCallbacks#onCameraAvailable} or
+ *                  {ACameraManager_AvailabilityCallbacks#onCameraUnavailable} is NULL.</li></ul>
+ */
+camera_status_t ACameraManager_registerExtendedAvailabilityCallback(
+        ACameraManager* manager,
+        const ACameraManager_ExtendedAvailabilityCallbacks* callback) __INTRODUCED_IN(29);
+
+/**
+ * Unregister camera extended availability callbacks.
+ *
+ * <p>Removing a callback that isn't registered has no effect.</p>
+ *
+ * @param manager the {@link ACameraManager} of interest.
+ * @param callback the {@link ACameraManager_ExtendedAvailabilityCallbacks} to be unregistered.
+ *
+ * @return <ul>
+ *         <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if callback,
+ *                  {ACameraManager_ExtendedAvailabilityCallbacks#onCameraAccessPrioritiesChanged}
+ *                  or {ACameraManager_AvailabilityCallbacks#onCameraAvailable} or
+ *                  {ACameraManager_AvailabilityCallbacks#onCameraUnavailable} is NULL.</li></ul>
+ */
+camera_status_t ACameraManager_unregisterExtendedAvailabilityCallback(
+        ACameraManager* manager,
+        const ACameraManager_ExtendedAvailabilityCallbacks* callback) __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
+
 __END_DECLS
 
 #endif /* _NDK_CAMERA_MANAGER_H */
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index b200abf..acf6999 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -3046,6 +3046,28 @@
      */
     ACAMERA_REQUEST_AVAILABLE_SESSION_KEYS =                    // int32[n]
             ACAMERA_REQUEST_START + 16,
+    /**
+     * <p>A subset of the available request keys that can be overridden for
+     * physical devices backing a logical multi-camera.</p>
+     *
+     * <p>Type: int32[n]</p>
+     *
+     * <p>This tag may appear in:
+     * <ul>
+     *   <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+     * </ul></p>
+     *
+     * <p>This is a subset of ACAMERA_REQUEST_AVAILABLE_REQUEST_KEYS which contains a list
+     * of keys that can be overridden using <a href="https://developer.android.com/reference/CaptureRequest/Builder.html#setPhysicalCameraKey">Builder#setPhysicalCameraKey</a>.
+     * The respective value of such request key can be obtained by calling
+     * <a href="https://developer.android.com/reference/CaptureRequest/Builder.html#getPhysicalCameraKey">Builder#getPhysicalCameraKey</a>. Capture requests that contain
+     * individual physical device requests must be built via
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureRequest(int,">Set)</a>.</p>
+     *
+     * @see ACAMERA_REQUEST_AVAILABLE_REQUEST_KEYS
+     */
+    ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS =    // int32[n]
+            ACAMERA_REQUEST_START + 17,
     ACAMERA_REQUEST_END,
 
     /**
@@ -7740,7 +7762,9 @@
 typedef enum acamera_metadata_enum_acamera_scaler_available_recommended_stream_configurations {
     /**
      * <p>Preview must only include non-stalling processed stream configurations with
-     * output formats like YUV_420_888, IMPLEMENTATION_DEFINED, etc.</p>
+     * output formats like
+     * {@link AIMAGE_FORMAT_YUV_420_888 },
+     * {@link AIMAGE_FORMAT_PRIVATE }, etc.</p>
      */
     ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PREVIEW
                                                                       = 0x0,
@@ -7755,19 +7779,20 @@
 
     /**
      * <p>Video snapshot must include stream configurations at least as big as
-     * the maximum RECORD resolutions and only with format BLOB + DATASPACE_JFIF
-     * format/dataspace combination (JPEG). Additionally the configurations shouldn't cause
-     * preview glitches and also be able to run at 30 fps.</p>
+     * the maximum RECORD resolutions and only with
+     * {@link AIMAGE_FORMAT_JPEG JPEG output format}.
+     * Additionally the configurations shouldn't cause preview glitches and also be able to
+     * run at 30 fps.</p>
      */
     ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VIDEO_SNAPSHOT
                                                                       = 0x2,
 
     /**
      * <p>Recommended snapshot stream configurations must include at least one with
-     * size close to ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE with BLOB + DATASPACE_JFIF
-     * format/dataspace combination (JPEG). Taking into account restrictions on aspect
-     * ratio, alignment etc. the area of the maximum suggested size shouldn’t be less than
-     * 97% of the sensor array size area.</p>
+     * size close to ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE and
+     * {@link AIMAGE_FORMAT_JPEG JPEG output format}.
+     * Taking into account restrictions on aspect ratio, alignment etc. the area of the
+     * maximum suggested size shouldn’t be less than 97% of the sensor array size area.</p>
      *
      * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
@@ -7786,9 +7811,20 @@
      */
     ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_RAW   = 0x5,
 
-    ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END
+    /**
+     * <p>If supported, the recommended low latency stream configurations must have
+     * end-to-end latency that does not exceed 200 ms. under standard operating conditions
+     * (reasonable light levels, not loaded system) and using template
+     * TEMPLATE_STILL_CAPTURE. This is primarily for listing configurations for the
+     * {@link AIMAGE_FORMAT_JPEG JPEG output format}
+     * however other supported output formats can be added as well.</p>
+     */
+    ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_LOW_LATENCY_SNAPSHOT
                                                                       = 0x6,
 
+    ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END
+                                                                      = 0x7,
+
     /**
      * <p>Vendor defined use cases. These depend on the vendor implementation.</p>
      */
diff --git a/camera/ndk/include/camera/NdkCaptureRequest.h b/camera/ndk/include/camera/NdkCaptureRequest.h
index 136989a..d3f8826 100644
--- a/camera/ndk/include/camera/NdkCaptureRequest.h
+++ b/camera/ndk/include/camera/NdkCaptureRequest.h
@@ -358,6 +358,219 @@
 
 #endif /* __ANDROID_API__ >= 28 */
 
+#if __ANDROID_API__ >= 29
+
+/**
+ * Get a metadata entry from input {@link ACaptureRequest} for
+ * a physical camera backing a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_getConstEntry, except that if the key is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * returns the entry set by ACaptureRequest_setEntry_physicalCamera_* class of
+ * functions on the particular physical camera.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ *                {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ *                   {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag the capture request metadata tag in
+ *            {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}
+ *            that is set by ACaptureRequest_setEntry_physicalCamera_* class of functions.
+ *
+ * @return <ul>
+ *         <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if metadata, physicalId, or entry is NULL,
+ *         physicalId is not one of the Ids used in creating the request, or if the capture
+ *         request is a regular request with no physical Ids at all.</li>
+ *         <li>{@link ACAMERA_ERROR_METADATA_NOT_FOUND} if the capture request does not contain an
+ *             entry of input tag value.</li></ul>
+ */
+camera_status_t ACaptureRequest_getConstEntry_physicalCamera(
+        const ACaptureRequest* request, const char* physicalId, uint32_t tag,
+        ACameraMetadata_const_entry* entry) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with unsigned 8 bits data type for
+ * a physical camera backing a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_u8, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ *                {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ *                   {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ *            {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ *         <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ *             larger than zero while data is NULL, the data type of the tag is not unsigned 8 bits,
+ *             the tag is not controllable by application, physicalId is not one of the Ids used
+ *             in creating the request, or if the capture request is a regular request with no
+ *             physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_u8(
+        ACaptureRequest* request, const char* physicalId, uint32_t tag,
+        uint32_t count, const uint8_t* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with signed 32 bits data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_i32, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ *                {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ *                   {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ *            {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ *         <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ *             larger than zero while data is NULL, the data type of the tag is not signed 32 bits,
+ *             the tag is not controllable by application, physicalId is not one of the Ids used
+ *             in creating the request, or if the capture request is a regular request with no
+ *             physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_i32(
+        ACaptureRequest* request, const char* physicalId, uint32_t tag,
+        uint32_t count, const int32_t* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with float data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_float, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ *                {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ *                   {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ *            {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ *         <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ *             larger than zero while data is NULL, the data type of the tag is not float,
+ *             the tag is not controllable by application, physicalId is not one of the Ids used
+ *             in creating the request, or if the capture request is a regular request with no
+ *             physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_float(
+        ACaptureRequest* request, const char* physicalId, uint32_t tag,
+        uint32_t count, const float* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with signed 64 bits data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_i64, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ *                {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ *                   {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ *            {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ *         <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ *             larger than zero while data is NULL, the data type of the tag is not signed 64 bits,
+ *             the tag is not controllable by application, physicalId is not one of the Ids used
+ *             in creating the request, or if the capture request is a regular request with no
+ *             physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_i64(
+        ACaptureRequest* request, const char* physicalId, uint32_t tag,
+        uint32_t count, const int64_t* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with double data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_double, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ *                {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ *                   {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ *            {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ *         <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ *             larger than zero while data is NULL, the data type of the tag is not double,
+ *             the tag is not controllable by application, physicalId is not one of the Ids used
+ *             in creating the request, or if the capture request is a regular request with no
+ *             physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_double(
+        ACaptureRequest* request, const char* physicalId, uint32_t tag,
+        uint32_t count, const double* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with rational data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_rational, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ *                {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ *                   {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ *            {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ *         <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ *             larger than zero while data is NULL, the data type of the tag is not rational,
+ *             the tag is not controllable by application, physicalId is not one of the Ids used
+ *             in creating the request, or if the capture request is a regular request with no
+ *             physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_rational(
+        ACaptureRequest* request, const char* physicalId, uint32_t tag,
+        uint32_t count, const ACameraMetadata_rational* data) __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
+
 __END_DECLS
 
 #endif /* _NDK_CAPTURE_REQUEST_H */
diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt
index 5a00022..946a98e 100644
--- a/camera/ndk/libcamera2ndk.map.txt
+++ b/camera/ndk/libcamera2ndk.map.txt
@@ -11,6 +11,7 @@
     ACameraCaptureSession_updateSharedOutput; # introduced=28
     ACameraDevice_close;
     ACameraDevice_createCaptureRequest;
+    ACameraDevice_createCaptureRequest_withPhysicalIds; # introduced=29
     ACameraDevice_createCaptureSession;
     ACameraDevice_createCaptureSessionWithSessionParameters; # introduced=28
     ACameraDevice_getId;
@@ -22,6 +23,8 @@
     ACameraManager_openCamera;
     ACameraManager_registerAvailabilityCallback;
     ACameraManager_unregisterAvailabilityCallback;
+    ACameraManager_registerExtendedAvailabilityCallback; # introduced=29
+    ACameraManager_unregisterExtendedAvailabilityCallback; # introduced=29
     ACameraMetadata_copy;
     ACameraMetadata_free;
     ACameraMetadata_getAllTags;
@@ -34,14 +37,21 @@
     ACaptureRequest_free;
     ACaptureRequest_getAllTags;
     ACaptureRequest_getConstEntry;
+    ACaptureRequest_getConstEntry_physicalCamera; # introduced=29
     ACaptureRequest_getUserContext; # introduced=28
     ACaptureRequest_removeTarget;
     ACaptureRequest_setEntry_double;
+    ACaptureRequest_setEntry_physicalCamera_double; # introduced=29
     ACaptureRequest_setEntry_float;
+    ACaptureRequest_setEntry_physicalCamera_float; # introduced=29
     ACaptureRequest_setEntry_i32;
+    ACaptureRequest_setEntry_physicalCamera_i32; # introduced=29
     ACaptureRequest_setEntry_i64;
+    ACaptureRequest_setEntry_physicalCamera_i64; # introduced=29
     ACaptureRequest_setEntry_rational;
+    ACaptureRequest_setEntry_physicalCamera_rational; # introduced=29
     ACaptureRequest_setEntry_u8;
+    ACaptureRequest_setEntry_physicalCamera_u8; # introduced=29
     ACaptureRequest_setUserContext; # introduced=28
     ACaptureSessionOutputContainer_add;
     ACaptureSessionOutputContainer_create;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index 9aafcd3..a38a31e 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -138,6 +138,7 @@
 camera_status_t
 CameraDevice::createCaptureRequest(
         ACameraDevice_request_template templateId,
+        const ACameraIdList* physicalCameraIdList,
         ACaptureRequest** request) const {
     Mutex::Autolock _l(mDeviceLock);
     camera_status_t ret = checkCameraClosedOrErrorLocked();
@@ -168,6 +169,12 @@
     }
     ACaptureRequest* outReq = new ACaptureRequest();
     outReq->settings = new ACameraMetadata(rawRequest.release(), ACameraMetadata::ACM_REQUEST);
+    if (physicalCameraIdList != nullptr) {
+        for (auto i = 0; i < physicalCameraIdList->numCameras; i++) {
+            outReq->physicalSettings.emplace(physicalCameraIdList->cameraIds[i],
+                    new ACameraMetadata(*(outReq->settings)));
+        }
+    }
     outReq->targets  = new ACameraOutputTargets();
     *request = outReq;
     return ACAMERA_OK;
@@ -292,29 +299,16 @@
 CameraDevice::allocateCaptureRequestLocked(
         const ACaptureRequest* request, /*out*/sp<CaptureRequest> &outReq) {
     sp<CaptureRequest> req(new CaptureRequest());
-    req->mCaptureRequest.physicalCameraSettings.resize(1);
-    req->mCaptureRequest.physicalCameraSettings[0].id = mCameraId;
-    // TODO: Do we really need to copy the metadata here ?
-    CameraMetadata metadataCopy = request->settings->getInternalData();
-    const camera_metadata_t *cameraMetadata = metadataCopy.getAndLock();
-    HCameraMetadata hCameraMetadata;
-    utils::convertToHidl(cameraMetadata, &hCameraMetadata);
-    metadataCopy.unlock(cameraMetadata);
-    if (request->settings != nullptr) {
-        if (hCameraMetadata.data() != nullptr &&
-            mCaptureRequestMetadataQueue != nullptr &&
-            mCaptureRequestMetadataQueue->write(
-                reinterpret_cast<const uint8_t *>(hCameraMetadata.data()),
-                hCameraMetadata.size())) {
-            // The metadata field of the union would've been destructued, so no need
-            // to re-size it.
-            req->mCaptureRequest.physicalCameraSettings[0].settings.fmqMetadataSize(
-                hCameraMetadata.size());
-        } else {
-            ALOGE("Fmq write capture result failed, falling back to hwbinder");
-            req->mCaptureRequest.physicalCameraSettings[0].settings.metadata(
-                std::move(hCameraMetadata));
-        }
+    req->mCaptureRequest.physicalCameraSettings.resize(1 + request->physicalSettings.size());
+
+    size_t index = 0;
+    allocateOneCaptureRequestMetadata(
+            req->mCaptureRequest.physicalCameraSettings[index++], mCameraId, request->settings);
+
+    for (auto& physicalEntry : request->physicalSettings) {
+        allocateOneCaptureRequestMetadata(
+                req->mCaptureRequest.physicalCameraSettings[index++],
+                physicalEntry.first, physicalEntry.second);
     }
 
     std::vector<int32_t> requestStreamIdxList;
@@ -356,13 +350,48 @@
     return ACAMERA_OK;
 }
 
+void CameraDevice::allocateOneCaptureRequestMetadata(
+        PhysicalCameraSettings& cameraSettings,
+        const std::string& id, const sp<ACameraMetadata>& metadata) {
+    cameraSettings.id = id;
+    // TODO: Do we really need to copy the metadata here ?
+    CameraMetadata metadataCopy = metadata->getInternalData();
+    const camera_metadata_t *cameraMetadata = metadataCopy.getAndLock();
+    HCameraMetadata hCameraMetadata;
+    utils::convertToHidl(cameraMetadata, &hCameraMetadata);
+    metadataCopy.unlock(cameraMetadata);
+    if (metadata != nullptr) {
+        if (hCameraMetadata.data() != nullptr &&
+            mCaptureRequestMetadataQueue != nullptr &&
+            mCaptureRequestMetadataQueue->write(
+                reinterpret_cast<const uint8_t *>(hCameraMetadata.data()),
+                hCameraMetadata.size())) {
+            // The metadata field of the union would've been destructued, so no need
+            // to re-size it.
+            cameraSettings.settings.fmqMetadataSize(hCameraMetadata.size());
+        } else {
+            ALOGE("Fmq write capture result failed, falling back to hwbinder");
+            cameraSettings.settings.metadata(std::move(hCameraMetadata));
+        }
+    }
+}
+
+
 ACaptureRequest*
-CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req) {
+CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req, const char* deviceId) {
     ACaptureRequest* pRequest = new ACaptureRequest();
-    CameraMetadata clone;
-    utils::convertFromHidlCloned(req->mPhysicalCameraSettings[0].settings.metadata(), &clone);
-    pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
-    pRequest->targets  = new ACameraOutputTargets();
+    for (size_t i = 0; i < req->mPhysicalCameraSettings.size(); i++) {
+        const std::string& id = req->mPhysicalCameraSettings[i].id;
+        CameraMetadata clone;
+        utils::convertFromHidlCloned(req->mPhysicalCameraSettings[i].settings.metadata(), &clone);
+        if (id == deviceId) {
+            pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
+        } else {
+            pRequest->physicalSettings[req->mPhysicalCameraSettings[i].id] =
+                    new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
+        }
+    }
+    pRequest->targets = new ACameraOutputTargets();
     for (size_t i = 0; i < req->mSurfaceList.size(); i++) {
         native_handle_t* anw = req->mSurfaceList[i];
         ACameraOutputTarget outputTarget(anw);
@@ -930,6 +959,7 @@
                 return;
             }
             sp<ACameraCaptureSession> session(static_cast<ACameraCaptureSession*>(obj.get()));
+            ACameraDevice* device = session->getDevice();
             mCachedSessions.push(session);
             sp<CaptureRequest> requestSp = nullptr;
             switch (msg->what()) {
@@ -979,7 +1009,7 @@
                         ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
                         return;
                     }
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp);
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
                     (*onStart)(context, session.get(), request, timestamp);
                     freeACaptureRequest(request);
                     break;
@@ -1002,7 +1032,7 @@
                         return;
                     }
                     sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp);
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
                     (*onResult)(context, session.get(), request, result.get());
                     freeACaptureRequest(request);
                     break;
@@ -1055,7 +1085,7 @@
                         physicalMetadataCopyPtrs.push_back(physicalMetadataCopy[i].get());
                     }
 
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp);
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
                     (*onResult)(context, session.get(), request, result.get(),
                             physicalResultInfo.size(), physicalCameraIdPtrs.data(),
                             physicalMetadataCopyPtrs.data());
@@ -1084,7 +1114,7 @@
                             static_cast<CameraCaptureFailure*>(obj.get()));
                     ACameraCaptureFailure* failure =
                             static_cast<ACameraCaptureFailure*>(failureSp.get());
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp);
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
                     (*onFail)(context, session.get(), request, failure);
                     freeACaptureRequest(request);
                     break;
@@ -1161,7 +1191,7 @@
                         return;
                     }
 
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp);
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
                     (*onBufferLost)(context, session.get(), request, anw, frameNumber);
                     freeACaptureRequest(request);
                     break;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index d571585..28092fd 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -92,6 +92,7 @@
 
     camera_status_t createCaptureRequest(
             ACameraDevice_request_template templateId,
+            const ACameraIdList* physicalCameraIdList,
             ACaptureRequest** request) const;
 
     camera_status_t createCaptureSession(
@@ -176,8 +177,11 @@
     //      metadata associated with it.
     camera_status_t allocateCaptureRequestLocked(
             const ACaptureRequest* request, sp<CaptureRequest>& outReq);
+    void allocateOneCaptureRequestMetadata(
+            PhysicalCameraSettings& cameraSettings,
+            const std::string& id, const sp<ACameraMetadata>& metadata);
 
-    static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req);
+    static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req, const char* deviceId);
     static void freeACaptureRequest(ACaptureRequest*);
 
     // only For session to hold device lock
@@ -380,8 +384,9 @@
 
     camera_status_t createCaptureRequest(
             ACameraDevice_request_template templateId,
+            const ACameraIdList* physicalCameraIdList,
             ACaptureRequest** request) const {
-        return mDevice->createCaptureRequest(templateId, request);
+        return mDevice->createCaptureRequest(templateId, physicalCameraIdList, request);
     }
 
     camera_status_t createCaptureSession(
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
index 6b1365a..df69353 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -64,6 +64,11 @@
     void unregisterAvailabilityCallback(
             const ACameraManager_AvailabilityCallbacks *callback);
 
+    void registerExtendedAvailabilityCallback(
+            const ACameraManager_ExtendedAvailabilityCallbacks* /*callback*/) {}
+    void unregisterExtendedAvailabilityCallback(
+            const ACameraManager_ExtendedAvailabilityCallbacks* /*callback*/) {}
+
     /**
      * Return camera IDs that support camera2
      */
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
index 93108b0..2398922 100644
--- a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -61,7 +61,8 @@
         native_handle_t* anw;
     };
     int initCamera(native_handle_t* imgReaderAnw,
-            const std::vector<PhysicalImgReaderInfo>& physicalImgReaders) {
+            const std::vector<PhysicalImgReaderInfo>& physicalImgReaders,
+            bool usePhysicalSettings) {
         if (imgReaderAnw == nullptr) {
             ALOGE("Cannot initialize camera before image reader get initialized.");
             return -1;
@@ -97,6 +98,7 @@
             return ret;
         }
 
+        std::vector<const char*> idPointerList;
         for (auto& physicalStream : physicalImgReaders) {
             ACaptureSessionOutput* sessionOutput = nullptr;
             ret = ACaptureSessionPhysicalOutput_create(physicalStream.anw,
@@ -113,7 +115,11 @@
             mExtraOutputs.push_back(sessionOutput);
             // Assume that at most one physical stream per physical camera.
             mPhysicalCameraIds.push_back(physicalStream.physicalCameraId);
+            idPointerList.push_back(physicalStream.physicalCameraId);
         }
+        ACameraIdList cameraIdList;
+        cameraIdList.numCameras = idPointerList.size();
+        cameraIdList.cameraIds = idPointerList.data();
 
         ret = ACameraDevice_createCaptureSession(mDevice, mOutputs, &mSessionCb, &mSession);
         if (ret != AMEDIA_OK) {
@@ -122,7 +128,13 @@
         }
 
         // Create capture request
-        ret = ACameraDevice_createCaptureRequest(mDevice, TEMPLATE_STILL_CAPTURE, &mStillRequest);
+        if (usePhysicalSettings) {
+            ret = ACameraDevice_createCaptureRequest_withPhysicalIds(mDevice,
+                    TEMPLATE_STILL_CAPTURE, &cameraIdList, &mStillRequest);
+        } else {
+            ret = ACameraDevice_createCaptureRequest(mDevice,
+                    TEMPLATE_STILL_CAPTURE, &mStillRequest);
+        }
         if (ret != AMEDIA_OK) {
             ALOGE("ACameraDevice_createCaptureRequest failed, ret=%d", ret);
             return ret;
@@ -557,7 +569,8 @@
         }
 
         CameraHelper cameraHelper(id, mCameraManager);
-        ret = cameraHelper.initCamera(testCase.getNativeWindow(), {});
+        ret = cameraHelper.initCamera(testCase.getNativeWindow(),
+                {}/*physicalImageReaders*/, false/*usePhysicalSettings*/);
         if (ret < 0) {
             ALOGE("Unable to initialize camera helper");
             return false;
@@ -695,6 +708,69 @@
         *cameraId = nullptr;
         return;
     }
+
+    void testLogicalCameraPhysicalStream(bool usePhysicalSettings) {
+        const char* cameraId = nullptr;
+        ACameraMetadata* staticMetadata = nullptr;
+        std::vector<const char*> physicalCameraIds;
+
+        findCandidateLogicalCamera(&cameraId, &staticMetadata, &physicalCameraIds);
+        if (cameraId == nullptr) {
+            // Couldn't find logical camera to test
+            return;
+        }
+
+        // Test streaming the logical multi-camera
+        uint64_t readerUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
+        int32_t readerMaxImages = 8;
+        bool readerAsync = false;
+        const int pictureCount = 6;
+        std::vector<ImageReaderTestCase*> testCases;
+        for (size_t i = 0; i < 3; i++) {
+            ImageReaderTestCase* testCase = new ImageReaderTestCase(
+                    kTestImageWidth, kTestImageHeight, kTestImageFormat, readerUsage,
+                    readerMaxImages, readerAsync);
+            ASSERT_EQ(testCase->initImageReader(), 0);
+            testCases.push_back(testCase);
+        }
+
+        CameraHelper cameraHelper(cameraId, mCameraManager);
+        std::vector<CameraHelper::PhysicalImgReaderInfo> physicalImgReaderInfo;
+        physicalImgReaderInfo.push_back({physicalCameraIds[0], testCases[1]->getNativeWindow()});
+        physicalImgReaderInfo.push_back({physicalCameraIds[1], testCases[2]->getNativeWindow()});
+
+        int ret = cameraHelper.initCamera(testCases[0]->getNativeWindow(),
+                physicalImgReaderInfo, usePhysicalSettings);
+        ASSERT_EQ(ret, 0);
+
+        if (!cameraHelper.isCameraReady()) {
+            ALOGW("Camera is not ready after successful initialization. It's either due to camera "
+                  "on board lacks BACKWARDS_COMPATIBLE capability or the device does not have "
+                  "camera on board.");
+            return;
+        }
+
+        for (int i = 0; i < pictureCount; i++) {
+            ret = cameraHelper.takeLogicalCameraPicture();
+            ASSERT_EQ(ret, 0);
+        }
+
+        // Sleep until all capture finished
+        for (int i = 0; i < kCaptureWaitRetry * pictureCount; i++) {
+            usleep(kCaptureWaitUs);
+            if (testCases[0]->getAcquiredImageCount() == pictureCount) {
+                ALOGI("Session take ~%d ms to capture %d images", i * kCaptureWaitUs / 1000,
+                      pictureCount);
+                break;
+            }
+        }
+        ASSERT_EQ(testCases[0]->getAcquiredImageCount(), pictureCount);
+        ASSERT_EQ(testCases[1]->getAcquiredImageCount(), pictureCount);
+        ASSERT_EQ(testCases[2]->getAcquiredImageCount(), pictureCount);
+        ASSERT_TRUE(cameraHelper.checkCallbacks(pictureCount));
+
+        ACameraMetadata_free(staticMetadata);
+    }
 };
 
 TEST_F(AImageReaderVendorTest, CreateWindowNativeHandle) {
@@ -722,65 +798,8 @@
 }
 
 TEST_F(AImageReaderVendorTest, LogicalCameraPhysicalStream) {
-    const char* cameraId = nullptr;
-    ACameraMetadata* staticMetadata = nullptr;
-    std::vector<const char*> physicalCameraIds;
-
-    findCandidateLogicalCamera(&cameraId, &staticMetadata, &physicalCameraIds);
-    if (cameraId == nullptr) {
-        // Couldn't find logical camera to test
-        return;
-    }
-
-    // Test streaming the logical multi-camera
-    uint64_t readerUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
-    int32_t readerMaxImages = 8;
-    bool readerAsync = false;
-    const int pictureCount = 6;
-    std::vector<ImageReaderTestCase*> testCases;
-    for (size_t i = 0; i < 3; i++) {
-        ImageReaderTestCase* testCase = new ImageReaderTestCase(
-                kTestImageWidth, kTestImageHeight, kTestImageFormat, readerUsage, readerMaxImages,
-                readerAsync);
-        ASSERT_EQ(testCase->initImageReader(), 0);
-        testCases.push_back(testCase);
-    }
-
-    CameraHelper cameraHelper(cameraId, mCameraManager);
-    std::vector<CameraHelper::PhysicalImgReaderInfo> physicalImgReaderInfo;
-    physicalImgReaderInfo.push_back({physicalCameraIds[0], testCases[1]->getNativeWindow()});
-    physicalImgReaderInfo.push_back({physicalCameraIds[1], testCases[2]->getNativeWindow()});
-
-    int ret = cameraHelper.initCamera(testCases[0]->getNativeWindow(), physicalImgReaderInfo);
-    ASSERT_EQ(ret, 0);
-
-    if (!cameraHelper.isCameraReady()) {
-        ALOGW("Camera is not ready after successful initialization. It's either due to camera on "
-              "board lacks BACKWARDS_COMPATIBLE capability or the device does not have camera on "
-              "board.");
-        return;
-    }
-
-    for (int i = 0; i < pictureCount; i++) {
-        ret = cameraHelper.takeLogicalCameraPicture();
-        ASSERT_EQ(ret, 0);
-    }
-
-    // Sleep until all capture finished
-    for (int i = 0; i < kCaptureWaitRetry * pictureCount; i++) {
-        usleep(kCaptureWaitUs);
-        if (testCases[0]->getAcquiredImageCount() == pictureCount) {
-            ALOGI("Session take ~%d ms to capture %d images", i * kCaptureWaitUs / 1000,
-                  pictureCount);
-            break;
-        }
-    }
-    ASSERT_EQ(testCases[0]->getAcquiredImageCount(), pictureCount);
-    ASSERT_EQ(testCases[1]->getAcquiredImageCount(), pictureCount);
-    ASSERT_EQ(testCases[2]->getAcquiredImageCount(), pictureCount);
-    ASSERT_TRUE(cameraHelper.checkCallbacks(pictureCount));
-
-    ACameraMetadata_free(staticMetadata);
+    testLogicalCameraPhysicalStream(false/*usePhysicalSettings*/);
+    testLogicalCameraPhysicalStream(true/*usePhysicalSettings*/);
 }
 
 }  // namespace
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
index fc0cceb..23a35e5 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
@@ -135,7 +135,7 @@
         }
 
         if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
-            _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
+            _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "invalid buffer size");
             return Void();
         }
         destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index badb99e..d7dacb8 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -527,6 +527,10 @@
             mMockError = Status_V1_2::ERROR_DRM_SESSION_LOST_STATE;
         } else if (value == kFrameTooLargeValue) {
             mMockError = Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE;
+        } else if (value == kInvalidStateValue)  {
+            mMockError = Status_V1_2::ERROR_DRM_INVALID_STATE;
+        } else {
+            mMockError = Status_V1_2::ERROR_DRM_UNKNOWN;
         }
     }
 
@@ -683,6 +687,10 @@
 Return<void> DrmPlugin::getOfflineLicenseKeySetIds(getOfflineLicenseKeySetIds_cb _hidl_cb) {
     std::vector<std::string> licenseNames = mFileHandle.ListLicenses();
     std::vector<KeySetId> keySetIds;
+    if (mMockError != Status_V1_2::OK) {
+        _hidl_cb(toStatus_1_0(mMockError), keySetIds);
+        return Void();
+    }
     for (const auto& name : licenseNames) {
         std::vector<uint8_t> keySetId(name.begin(), name.end());
         keySetIds.push_back(keySetId);
@@ -693,6 +701,9 @@
 
 
 Return<Status> DrmPlugin::removeOfflineLicense(const KeySetId& keySetId) {
+    if (mMockError != Status_V1_2::OK) {
+        return toStatus_1_0(mMockError);
+    }
     std::string licenseName(keySetId.begin(), keySetId.end());
     if (mFileHandle.DeleteLicense(licenseName)) {
         return Status::OK;
@@ -706,7 +717,9 @@
     DeviceFiles::LicenseState state;
     std::string license;
     OfflineLicenseState hLicenseState;
-    if (mFileHandle.RetrieveLicense(licenseName, &state, &license)) {
+    if (mMockError != Status_V1_2::OK) {
+        _hidl_cb(toStatus_1_0(mMockError), OfflineLicenseState::UNKNOWN);
+    } else if (mFileHandle.RetrieveLicense(licenseName, &state, &license)) {
         switch (state) {
         case DeviceFiles::kLicenseStateActive:
             hLicenseState = OfflineLicenseState::USABLE;
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
index 1bbc822..b83ce69 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
@@ -40,6 +40,7 @@
 static const std::string kResourceContentionValue("resourceContention");
 static const std::string kLostStateValue("lostState");
 static const std::string kFrameTooLargeValue("frameTooLarge");
+static const std::string kInvalidStateValue("invalidState");
 
 static const std::string kDeviceIdKey("deviceId");
 static const uint8_t kTestDeviceIdData[] =
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/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
index d3b37d7..89947d4 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
@@ -506,16 +506,17 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-class Codec2AudioDecDecodeTest : public Codec2AudioDecHidlTest,
-                                 public ::testing::WithParamInterface<int32_t> {
+class Codec2AudioDecDecodeTest
+    : public Codec2AudioDecHidlTest,
+      public ::testing::WithParamInterface<std::pair<int32_t, bool>> {
 };
 
 TEST_P(Codec2AudioDecDecodeTest, DecodeTest) {
     description("Decodes input file");
     if (mDisableTest) return;
 
-    uint32_t streamIndex = GetParam();
-    ASSERT_EQ(mComponent->start(), C2_OK);
+    uint32_t streamIndex = GetParam().first;
+    bool signalEOS = GetParam().second;
     mTimestampDevTest = true;
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
@@ -567,16 +568,27 @@
     ASSERT_EQ(eleStream.is_open(), true);
     ASSERT_NO_FATAL_FAILURE(decodeNFrames(
         mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
-        mLinearPool, eleStream, &Info, 0, (int)Info.size()));
+        mLinearPool, eleStream, &Info, 0, (int)Info.size(), signalEOS));
+
+    // If EOS is not sent, sending empty input with EOS flag
+    size_t infoSize = Info.size();
+    if (!signalEOS) {
+        ASSERT_NO_FATAL_FAILURE(
+            waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
+        ASSERT_NO_FATAL_FAILURE(
+            testInputBuffer(mComponent, mQueueLock, mWorkQueue,
+                            C2FrameData::FLAG_END_OF_STREAM, false));
+        infoSize += 1;
+    }
     // blocking call to ensures application to Wait till all the inputs are
     // consumed
     ASSERT_NO_FATAL_FAILURE(
         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
     eleStream.close();
-    if (mFramesReceived != Info.size()) {
+    if (mFramesReceived != infoSize) {
         ALOGE("Input buffer count and Output buffer count mismatch");
         ALOGE("framesReceived : %d inputFrames : %zu", mFramesReceived,
-              Info.size());
+              infoSize);
         ASSERT_TRUE(false);
     }
     ASSERT_EQ(mEos, true);
@@ -608,9 +620,12 @@
     }
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
-
-INSTANTIATE_TEST_CASE_P(StreamIndexes, Codec2AudioDecDecodeTest,
-                        ::testing::Values(0, 1));
+// DecodeTest with StreamIndex and EOS / No EOS
+INSTANTIATE_TEST_CASE_P(StreamIndexAndEOS, Codec2AudioDecDecodeTest,
+                        ::testing::Values(std::make_pair(0, false),
+                                          std::make_pair(0, true),
+                                          std::make_pair(1, false),
+                                          std::make_pair(1, true)));
 
 // thumbnail test
 TEST_F(Codec2AudioDecHidlTest, ThumbnailTest) {
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
index a74d43e..0946fa6 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
@@ -123,6 +123,7 @@
         mFramesReceived = 0;
         if (mCompName == unknown_comp) mDisableTest = true;
         if (mDisableTest) std::cout << "[   WARN   ] Test Disabled \n";
+        getInputMaxBufSize();
     }
 
     virtual void TearDown() override {
@@ -157,6 +158,7 @@
     bool mDisableTest;
     standardComp mCompName;
     uint32_t mFramesReceived;
+    int32_t mInputMaxBufSize;
     std::list<uint64_t> mFlushedIndices;
 
     C2BlockPool::local_id_t mBlockPoolId;
@@ -175,6 +177,27 @@
     static void description(const std::string& description) {
         RecordProperty("description", description);
     }
+
+    // In encoder components, fetch the size of input buffer allocated
+    void getInputMaxBufSize() {
+        int32_t bitStreamInfo[1] = {0};
+        std::vector<std::unique_ptr<C2Param>> inParams;
+        c2_status_t status = mComponent->query(
+            {}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE}, C2_DONT_BLOCK,
+            &inParams);
+        if (status != C2_OK && inParams.size() == 0) {
+            ALOGE("Query MaxBufferSizeInfo failed => %d", status);
+            ASSERT_TRUE(false);
+        } else {
+            size_t offset = sizeof(C2Param);
+            for (size_t i = 0; i < inParams.size(); ++i) {
+                C2Param* param = inParams[i].get();
+                bitStreamInfo[i] = *(int32_t*)((uint8_t*)param + offset);
+            }
+        }
+        mInputMaxBufSize = bitStreamInfo[0];
+    }
+
 };
 
 void validateComponent(
@@ -355,60 +378,79 @@
     ASSERT_EQ(mDisableTest, false);
 }
 
-TEST_F(Codec2AudioEncHidlTest, EncodeTest) {
+class Codec2AudioEncEncodeTest
+    : public Codec2AudioEncHidlTest,
+      public ::testing::WithParamInterface<std::pair<bool, int32_t>> {
+};
+
+TEST_P(Codec2AudioEncEncodeTest, EncodeTest) {
     ALOGV("EncodeTest");
     if (mDisableTest) return;
     char mURL[512];
     strcpy(mURL, gEnv->getRes().c_str());
     GetURLForComponent(mCompName, mURL);
+    bool signalEOS = GetParam().first;
+    // Ratio w.r.t to mInputMaxBufSize
+    int32_t inputMaxBufRatio = GetParam().second;
 
-    // Setting default configuration
+    // Setting default sampleRate
     int32_t nChannels = 2;
     int32_t nSampleRate = 44100;
-    int32_t samplesPerFrame = 1024;
     switch (mCompName) {
         case aac:
             nChannels = 2;
             nSampleRate = 48000;
-            samplesPerFrame = 1024;
             break;
         case flac:
             nChannels = 2;
             nSampleRate = 48000;
-            samplesPerFrame = 1152;
             break;
         case opus:
             nChannels = 2;
             nSampleRate = 48000;
-            samplesPerFrame = 960;
             break;
         case amrnb:
             nChannels = 1;
             nSampleRate = 8000;
-            samplesPerFrame = 160;
             break;
         case amrwb:
             nChannels = 1;
             nSampleRate = 16000;
-            samplesPerFrame = 160;
             break;
         default:
             ASSERT_TRUE(false);
     }
+    int32_t samplesPerFrame =
+        ((mInputMaxBufSize / inputMaxBufRatio) / (nChannels * 2));
+    ALOGV("signalEOS %d mInputMaxBufSize %d samplesPerFrame %d", signalEOS,
+          mInputMaxBufSize, samplesPerFrame);
+
     if (!setupConfigParam(mComponent, nChannels, nSampleRate)) {
         std::cout << "[   WARN   ] Test Skipped \n";
         return;
     }
     ASSERT_EQ(mComponent->start(), C2_OK);
     std::ifstream eleStream;
-    uint32_t numFrames = 128;
+    uint32_t numFrames = 16;
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
     ALOGV("mURL : %s", mURL);
     ASSERT_NO_FATAL_FAILURE(
         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
                       mFlushedIndices, mLinearPool, eleStream, numFrames,
-                      samplesPerFrame, nChannels, nSampleRate));
+                      samplesPerFrame, nChannels, nSampleRate, false,
+                      signalEOS));
+
+    // If EOS is not sent, sending empty input with EOS flag
+    if (!signalEOS) {
+        ASSERT_NO_FATAL_FAILURE(
+            waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
+        ASSERT_NO_FATAL_FAILURE(
+            testInputBuffer(mComponent, mQueueLock, mWorkQueue,
+                            C2FrameData::FLAG_END_OF_STREAM, false));
+        numFrames += 1;
+    }
+
     // blocking call to ensures application to Wait till all the inputs are
     // consumed
     ASSERT_NO_FATAL_FAILURE(
@@ -429,6 +471,15 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
+// EncodeTest with EOS / No EOS and inputMaxBufRatio
+// inputMaxBufRatio is ratio w.r.t. to mInputMaxBufSize
+INSTANTIATE_TEST_CASE_P(EncodeTest, Codec2AudioEncEncodeTest,
+                        ::testing::Values(std::make_pair(false, 1),
+                                          std::make_pair(false, 2),
+                                          std::make_pair(true, 1),
+                                          std::make_pair(true, 2)));
+
+
 TEST_F(Codec2AudioEncHidlTest, EOSTest) {
     description("Test empty input buffer with EOS flag");
     if (mDisableTest) return;
diff --git a/media/codec2/hidl/1.0/vts/functional/master/VtsHidlC2V1_0TargetMasterTest.cpp b/media/codec2/hidl/1.0/vts/functional/master/VtsHidlC2V1_0TargetMasterTest.cpp
index 01e64cb..e88fbc7 100644
--- a/media/codec2/hidl/1.0/vts/functional/master/VtsHidlC2V1_0TargetMasterTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/master/VtsHidlC2V1_0TargetMasterTest.cpp
@@ -64,7 +64,7 @@
     C2String name = mClient->getName();
     EXPECT_NE(name.empty(), true) << "Invalid Codec2Client Name";
 
-    // Get List of components from HIDL Codec2Client instance
+    // Get List of components from all known services
     const std::vector<C2Component::Traits> listTraits =
         mClient->ListComponents();
 
@@ -78,8 +78,9 @@
             listener.reset(new CodecListener());
             ASSERT_NE(listener, nullptr);
 
-            mClient->createComponent(listTraits[i].name.c_str(), listener,
-                                     &component);
+            // Create component from all known services
+            component = mClient->CreateComponentByName(
+                listTraits[i].name.c_str(), listener, &mClient);
             ASSERT_NE(component, nullptr) << "Create component failed for "
                                           << listTraits[i].name.c_str();
         }
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
index 8cbb7a7..dffcb6e 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
@@ -421,8 +421,9 @@
     ASSERT_EQ(mDisableTest, false);
 }
 
-class Codec2VideoDecDecodeTest : public Codec2VideoDecHidlTest,
-                                 public ::testing::WithParamInterface<int32_t> {
+class Codec2VideoDecDecodeTest
+    : public Codec2VideoDecHidlTest,
+      public ::testing::WithParamInterface<std::pair<int32_t, bool>> {
 };
 
 // Bitstream Test
@@ -430,7 +431,8 @@
     description("Decodes input file");
     if (mDisableTest) return;
 
-    uint32_t streamIndex = GetParam();
+    uint32_t streamIndex = GetParam().first;
+    bool signalEOS = GetParam().second;
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
     strcpy(mURL, gEnv->getRes().c_str());
@@ -464,8 +466,18 @@
     ASSERT_EQ(eleStream.is_open(), true);
     ASSERT_NO_FATAL_FAILURE(decodeNFrames(
         mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
-        mLinearPool, eleStream, &Info, 0, (int)Info.size()));
+        mLinearPool, eleStream, &Info, 0, (int)Info.size(), signalEOS));
 
+    // If EOS is not sent, sending empty input with EOS flag
+    size_t infoSize = Info.size();
+    if (!signalEOS) {
+        ASSERT_NO_FATAL_FAILURE(
+            waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
+        ASSERT_NO_FATAL_FAILURE(
+            testInputBuffer(mComponent, mQueueLock, mWorkQueue,
+                            C2FrameData::FLAG_END_OF_STREAM, false));
+        infoSize += 1;
+    }
     // blocking call to ensures application to Wait till all the inputs are
     // consumed
     if (!mEos) {
@@ -475,19 +487,22 @@
     }
 
     eleStream.close();
-    if (mFramesReceived != Info.size()) {
+    if (mFramesReceived != infoSize) {
         ALOGE("Input buffer count and Output buffer count mismatch");
         ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived,
-              Info.size());
+              infoSize);
         ASSERT_TRUE(false);
     }
 
     if (mTimestampDevTest) EXPECT_EQ(mTimestampUslist.empty(), true);
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
-
-INSTANTIATE_TEST_CASE_P(StreamIndexes, Codec2VideoDecDecodeTest,
-                        ::testing::Values(0, 1));
+// DecodeTest with StreamIndex and EOS / No EOS
+INSTANTIATE_TEST_CASE_P(StreamIndexAndEOS, Codec2VideoDecDecodeTest,
+                        ::testing::Values(std::make_pair(0, false),
+                                          std::make_pair(0, true),
+                                          std::make_pair(1, false),
+                                          std::make_pair(1, true)));
 
 // Adaptive Test
 TEST_F(Codec2VideoDecHidlTest, AdaptiveDecodeTest) {
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
index 7db41c0..673dc85 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
@@ -343,13 +343,18 @@
     ASSERT_EQ(mDisableTest, false);
 }
 
-TEST_F(Codec2VideoEncHidlTest, EncodeTest) {
+class Codec2VideoEncEncodeTest : public Codec2VideoEncHidlTest,
+                                 public ::testing::WithParamInterface<bool> {
+};
+
+TEST_P(Codec2VideoEncEncodeTest, EncodeTest) {
     description("Encodes input file");
     if (mDisableTest) return;
 
     char mURL[512];
     int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH;
     int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT;
+    bool signalEOS = GetParam();
 
     strcpy(mURL, gEnv->getRes().c_str());
     GetURLForComponent(mURL);
@@ -367,7 +372,18 @@
     ASSERT_NO_FATAL_FAILURE(
         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
                       mFlushedIndices, mGraphicPool, eleStream,
-                      0, ENC_NUM_FRAMES, nWidth, nHeight));
+                      0, ENC_NUM_FRAMES, nWidth, nHeight, false, signalEOS));
+
+    // If EOS is not sent, sending empty input with EOS flag
+    uint32_t inputFrames = ENC_NUM_FRAMES;
+    if (!signalEOS) {
+        ASSERT_NO_FATAL_FAILURE(
+            waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
+        ASSERT_NO_FATAL_FAILURE(
+            testInputBuffer(mComponent, mQueueLock, mWorkQueue,
+                            C2FrameData::FLAG_END_OF_STREAM, false));
+        inputFrames += 1;
+    }
 
     // blocking call to ensures application to Wait till all the inputs are
     // consumed
@@ -376,10 +392,10 @@
         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
 
     eleStream.close();
-    if (mFramesReceived != ENC_NUM_FRAMES) {
+    if (mFramesReceived != inputFrames) {
         ALOGE("Input buffer count and Output buffer count mismatch");
         ALOGE("framesReceived : %d inputFrames : %d", mFramesReceived,
-              ENC_NUM_FRAMES);
+              inputFrames);
         ASSERT_TRUE(false);
     }
 
@@ -394,6 +410,10 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
+// EncodeTest with EOS / No EOS
+INSTANTIATE_TEST_CASE_P(EncodeTestwithEOS, Codec2VideoEncEncodeTest,
+                        ::testing::Values(true, false));
+
 TEST_F(Codec2VideoEncHidlTest, EOSTest) {
     description("Test empty input buffer with EOS flag");
     if (mDisableTest) return;
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 7239302..20cc643 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -32,6 +32,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaDataUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <utils/String8.h>
 
 #include <arpa/inet.h>
@@ -119,6 +120,9 @@
     const mkvparser::BlockEntry *mBlockEntry;
     long mBlockEntryIndex;
 
+    unsigned long mTrackType;
+    void seekwithoutcue_l(int64_t seekTimeUs, int64_t *actualFrameTimeUs);
+
     void advance_l();
 
     BlockIterator(const BlockIterator &);
@@ -144,6 +148,7 @@
         AVC,
         AAC,
         HEVC,
+        MP3,
         OTHER
     };
 
@@ -156,6 +161,15 @@
 
     List<MediaBufferHelper *> mPendingFrames;
 
+    int64_t mCurrentTS; // add for mp3
+    uint32_t mMP3Header;
+
+    media_status_t findMP3Header(uint32_t * header,
+        const uint8_t *dataSource, int length, int *outStartPos);
+    media_status_t mp3FrameRead(
+            MediaBufferHelper **out, const ReadOptions *options,
+            int64_t targetSampleTimeUs);
+
     status_t advance();
 
     status_t setWebmBlockCryptoInfo(MediaBufferHelper *mbuf);
@@ -222,7 +236,9 @@
       mBlockIter(mExtractor,
                  mExtractor->mTracks.itemAt(index).mTrackNum,
                  index),
-      mNALSizeLen(-1) {
+      mNALSizeLen(-1),
+      mCurrentTS(0),
+      mMP3Header(0) {
     MatroskaExtractor::TrackInfo &trackInfo = mExtractor->mTracks.editItemAt(index);
     AMediaFormat *meta = trackInfo.mMeta;
 
@@ -251,6 +267,8 @@
         }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
         mType = AAC;
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+        mType = MP3;
     }
 }
 
@@ -267,6 +285,16 @@
     mBufferGroup->init(1 /* number of buffers */, 1024 /* buffer size */, 64 /* growth limit */);
     mBlockIter.reset();
 
+    if (mType == MP3 && mMP3Header == 0) {
+        int start = -1;
+        media_status_t err = findMP3Header(&mMP3Header, NULL, 0, &start);
+        if (err != OK) {
+            ALOGE("No mp3 header found");
+            clearPendingFrames();
+            return err;
+        }
+    }
+
     return AMEDIA_OK;
 }
 
@@ -290,6 +318,7 @@
       mCluster(NULL),
       mBlockEntry(NULL),
       mBlockEntryIndex(0) {
+    mTrackType = mExtractor->mSegment->GetTracks()->GetTrackByNumber(trackNum)->GetType();
     reset();
 }
 
@@ -442,12 +471,14 @@
         }
 
         if (!pCues) {
-            ALOGE("No Cues in file");
+            ALOGV("No Cues in file,seek without cue data");
+            seekwithoutcue_l(seekTimeUs, actualFrameTimeUs);
             return;
         }
     }
     else if (!pSH) {
-        ALOGE("No SeekHead");
+        ALOGV("No SeekHead, seek without cue data");
+        seekwithoutcue_l(seekTimeUs, actualFrameTimeUs);
         return;
     }
 
@@ -456,7 +487,9 @@
     while (!pCues->DoneParsing()) {
         pCues->LoadCuePoint();
         pCP = pCues->GetLast();
-        CHECK(pCP);
+        ALOGV("pCP = %s", pCP == NULL ? "NULL" : "not NULL");
+        if (pCP == NULL)
+            continue;
 
         size_t trackCount = mExtractor->mTracks.size();
         for (size_t index = 0; index < trackCount; ++index) {
@@ -494,6 +527,7 @@
     // Always *search* based on the video track, but finalize based on mTrackNum
     if (!pTP) {
         ALOGE("Did not locate the video track for seeking");
+        seekwithoutcue_l(seekTimeUs, actualFrameTimeUs);
         return;
     }
 
@@ -537,6 +571,31 @@
     return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll;
 }
 
+void BlockIterator::seekwithoutcue_l(int64_t seekTimeUs, int64_t *actualFrameTimeUs) {
+    mCluster = mExtractor->mSegment->FindCluster(seekTimeUs * 1000ll);
+    const long status = mCluster->GetFirst(mBlockEntry);
+    if (status < 0) {  // error
+        ALOGE("get last blockenry failed!");
+        mCluster = NULL;
+        return;
+    }
+    mBlockEntryIndex = 0;
+    while (!eos() && ((block()->GetTrackNumber() != mTrackNum) || (blockTimeUs() < seekTimeUs))) {
+        advance_l();
+    }
+
+    // video track will seek to the next key frame.
+    if (mTrackType == 1) {
+        while (!eos() && ((block()->GetTrackNumber() != mTrackNum) ||
+                      !mBlockEntry->GetBlock()->IsKey())) {
+            advance_l();
+        }
+    }
+    *actualFrameTimeUs = blockTimeUs();
+     ALOGV("seekTimeUs:%lld, actualFrameTimeUs:%lld, tracknum:%lld",
+              (long long)seekTimeUs, (long long)*actualFrameTimeUs, (long long)mTrackNum);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 static unsigned U24_AT(const uint8_t *ptr) {
@@ -762,6 +821,188 @@
     return AMEDIA_OK;
 }
 
+//the value of kMP3HeaderMask is from MP3Extractor
+static const uint32_t kMP3HeaderMask = 0xfffe0c00;
+
+media_status_t MatroskaSource::findMP3Header(uint32_t * header,
+        const uint8_t *dataSource, int length, int *outStartPos) {
+    if (NULL == header) {
+        ALOGE("header is null!");
+        return AMEDIA_ERROR_END_OF_STREAM;
+    }
+
+    //to find header start position
+    if (0 != *header) {
+        if (NULL == dataSource) {
+            *outStartPos = -1;
+            return AMEDIA_OK;
+        }
+        uint32_t tmpCode = 0;
+        for (int i = 0; i < length; i++) {
+            tmpCode = (tmpCode << 8) + dataSource[i];
+            if ((tmpCode & kMP3HeaderMask) == (*header & kMP3HeaderMask)) {
+                *outStartPos = i - 3;
+                return AMEDIA_OK;
+            }
+        }
+        *outStartPos = -1;
+        return AMEDIA_OK;
+    }
+
+    //to find mp3 header
+    uint32_t code = 0;
+    while (0 == *header) {
+        while (mPendingFrames.empty()) {
+            media_status_t err = readBlock();
+            if (err != OK) {
+                clearPendingFrames();
+                return err;
+            }
+        }
+        MediaBufferHelper *frame = *mPendingFrames.begin();
+        size_t size = frame->range_length();
+        size_t offset = frame->range_offset();
+        size_t i;
+        size_t frame_size;
+        for (i = 0; i < size; i++) {
+            ALOGV("data[%zu]=%x", i, *((uint8_t*)frame->data() + offset + i));
+            code = (code << 8) + *((uint8_t*)frame->data() + offset + i);
+            if (GetMPEGAudioFrameSize(code, &frame_size, NULL, NULL, NULL)) {
+                *header = code;
+                mBlockIter.reset();
+                clearPendingFrames();
+                return AMEDIA_OK;
+            }
+        }
+    }
+
+    return AMEDIA_ERROR_END_OF_STREAM;
+}
+
+media_status_t MatroskaSource::mp3FrameRead(
+        MediaBufferHelper **out, const ReadOptions *options,
+        int64_t targetSampleTimeUs) {
+    MediaBufferHelper *frame = *mPendingFrames.begin();
+    int64_t seekTimeUs;
+    ReadOptions::SeekMode mode;
+    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+        CHECK(AMediaFormat_getInt64(frame->meta_data(),
+                    AMEDIAFORMAT_KEY_TIME_US, &mCurrentTS));
+        if (mCurrentTS < 0) {
+            mCurrentTS = 0;
+            AMediaFormat_setInt64(frame->meta_data(),
+                    AMEDIAFORMAT_KEY_TIME_US, mCurrentTS);
+        }
+    }
+
+    int32_t start = -1;
+    while (start < 0) {
+        //find header start position
+        findMP3Header(&mMP3Header,
+            (const uint8_t*)frame->data() + frame->range_offset(),
+            frame->range_length(), &start);
+        ALOGV("start=%d, frame->range_length() = %zu, frame->range_offset() =%zu",
+                      start, frame->range_length(), frame->range_offset());
+        if (start >= 0)
+            break;
+        frame->release();
+        mPendingFrames.erase(mPendingFrames.begin());
+        while (mPendingFrames.empty()) {
+            media_status_t err = readBlock();
+            if (err != OK) {
+                clearPendingFrames();
+                return err;
+            }
+        }
+        frame = *mPendingFrames.begin();
+    }
+
+    frame->set_range(frame->range_offset() + start, frame->range_length() - start);
+
+    uint32_t header = *(uint32_t*)((uint8_t*)frame->data() + frame->range_offset());
+    header = ((header >> 24) & 0xff) | ((header >> 8) & 0xff00) |
+                    ((header << 8) & 0xff0000) | ((header << 24) & 0xff000000);
+    size_t frame_size;
+    int out_sampling_rate;
+    int out_channels;
+    int out_bitrate;
+    if (!GetMPEGAudioFrameSize(header, &frame_size,
+                               &out_sampling_rate, &out_channels, &out_bitrate)) {
+        ALOGE("MP3 Header read fail!!");
+        return AMEDIA_ERROR_UNSUPPORTED;
+    }
+
+    MediaBufferHelper *buffer;
+    mBufferGroup->acquire_buffer(&buffer, false /* nonblocking */, frame_size /* requested size */);
+    buffer->set_range(0, frame_size);
+
+    uint8_t *data = static_cast<uint8_t *>(buffer->data());
+    ALOGV("MP3 frame %zu frame->range_length() %zu", frame_size, frame->range_length());
+
+    if (frame_size > frame->range_length()) {
+        memcpy(data, (uint8_t*)(frame->data()) + frame->range_offset(), frame->range_length());
+        size_t sumSize = 0;
+        sumSize += frame->range_length();
+        size_t needSize = frame_size - frame->range_length();
+        frame->release();
+        mPendingFrames.erase(mPendingFrames.begin());
+        while (mPendingFrames.empty()) {
+            media_status_t err = readBlock();
+            if (err != OK) {
+                clearPendingFrames();
+                return err;
+            }
+        }
+        frame = *mPendingFrames.begin();
+        size_t offset = frame->range_offset();
+        size_t size = frame->range_length();
+
+        // the next buffer frame is not enough to fullfill mp3 frame,
+        // we have to read until mp3 frame is completed.
+        while (size < needSize) {
+            memcpy(data + sumSize, (uint8_t*)(frame->data()) + offset, size);
+            needSize -= size;
+            sumSize += size;
+            frame->release();
+            mPendingFrames.erase(mPendingFrames.begin());
+            while (mPendingFrames.empty()) {
+                media_status_t err = readBlock();
+                if (err != OK) {
+                    clearPendingFrames();
+                    return err;
+                }
+            }
+            frame = *mPendingFrames.begin();
+            offset = frame->range_offset();
+            size = frame->range_length();
+        }
+        memcpy(data + sumSize, (uint8_t*)(frame->data()) + offset, needSize);
+        frame->set_range(offset + needSize, size - needSize);
+     } else {
+        size_t offset = frame->range_offset();
+        size_t size = frame->range_length();
+        memcpy(data, (uint8_t*)(frame->data()) + offset, frame_size);
+        frame->set_range(offset + frame_size, size - frame_size);
+    }
+    if (frame->range_length() < 4) {
+        frame->release();
+        frame = NULL;
+        mPendingFrames.erase(mPendingFrames.begin());
+    }
+    ALOGV("MatroskaSource::read MP3 frame kKeyTime=%lld,kKeyTargetTime=%lld",
+                    (long long)mCurrentTS, (long long)targetSampleTimeUs);
+    AMediaFormat_setInt64(buffer->meta_data(),
+            AMEDIAFORMAT_KEY_TIME_US, mCurrentTS);
+    mCurrentTS += (int64_t)frame_size * 8000ll / out_bitrate;
+
+    if (targetSampleTimeUs >= 0ll)
+        AMediaFormat_setInt64(buffer->meta_data(),
+                AMEDIAFORMAT_KEY_TARGET_TIME, targetSampleTimeUs);
+    *out = buffer;
+    ALOGV("MatroskaSource::read MP3, keyTime=%lld for next frame", (long long)mCurrentTS);
+    return AMEDIA_OK;
+}
+
 media_status_t MatroskaSource::read(
         MediaBufferHelper **out, const ReadOptions *options) {
     *out = NULL;
@@ -799,6 +1040,10 @@
         }
     }
 
+    if (mType == MP3) {
+        return mp3FrameRead(out, options, targetSampleTimeUs);
+    }
+
     MediaBufferHelper *frame = *mPendingFrames.begin();
     mPendingFrames.erase(mPendingFrames.begin());
 
@@ -924,6 +1169,59 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+// trans all FOURCC  to lower char
+static uint32_t FourCCtoLower(uint32_t fourcc) {
+    uint8_t ch_1 = tolower((fourcc >> 24) & 0xff);
+    uint8_t ch_2 = tolower((fourcc >> 16) & 0xff);
+    uint8_t ch_3 = tolower((fourcc >> 8) & 0xff);
+    uint8_t ch_4 = tolower((fourcc) & 0xff);
+    uint32_t fourcc_out = ch_1 << 24 | ch_2 << 16 | ch_3 << 8 | ch_4;
+
+    return fourcc_out;
+}
+
+static const char *MKVFourCC2MIME(uint32_t fourcc) {
+    ALOGV("MKVFourCC2MIME fourcc 0x%8.8x", fourcc);
+    uint32_t lowerFourcc = FourCCtoLower(fourcc);
+    switch (lowerFourcc) {
+        case FOURCC("mp4v"):
+            return MEDIA_MIMETYPE_VIDEO_MPEG4;
+
+        case FOURCC("s263"):
+        case FOURCC("h263"):
+            return MEDIA_MIMETYPE_VIDEO_H263;
+
+        case FOURCC("avc1"):
+        case FOURCC("h264"):
+            return MEDIA_MIMETYPE_VIDEO_AVC;
+
+        case FOURCC("mpg2"):
+            return MEDIA_MIMETYPE_VIDEO_MPEG2;
+
+        case FOURCC("xvid"):
+            return MEDIA_MIMETYPE_VIDEO_XVID;
+
+        case FOURCC("divx"):
+        case FOURCC("dx50"):
+            return MEDIA_MIMETYPE_VIDEO_DIVX;
+
+        case FOURCC("div3"):
+        case FOURCC("div4"):
+            return MEDIA_MIMETYPE_VIDEO_DIVX3;
+
+        case FOURCC("mjpg"):
+        case FOURCC("mppg"):
+            return MEDIA_MIMETYPE_VIDEO_MJPEG;
+
+        default:
+            char fourccString[5];
+            MakeFourCCString(fourcc, fourccString);
+            ALOGW("mkv unsupport fourcc %s", fourccString);
+            return "";
+    }
+}
+
+
 MatroskaExtractor::MatroskaExtractor(DataSourceHelper *source)
     : mDataSource(source),
       mReader(new DataSourceBaseReader(mDataSource)),
@@ -956,17 +1254,56 @@
         return;
     }
 
-    // from mkvparser::Segment::Load(), but stop at first cluster
-    ret = mSegment->ParseHeaders();
-    if (ret == 0) {
-        long len;
-        ret = mSegment->LoadCluster(pos, len);
-        if (ret >= 1) {
-            // no more clusters
-            ret = 0;
+    if (mIsLiveStreaming) {
+        // from mkvparser::Segment::Load(), but stop at first cluster
+        ret = mSegment->ParseHeaders();
+        if (ret == 0) {
+            long len;
+            ret = mSegment->LoadCluster(pos, len);
+            if (ret >= 1) {
+                // no more clusters
+                ret = 0;
+            }
+        } else if (ret > 0) {
+            ret = mkvparser::E_BUFFER_NOT_FULL;
         }
-    } else if (ret > 0) {
-        ret = mkvparser::E_BUFFER_NOT_FULL;
+    } else {
+        ret = mSegment->ParseHeaders();
+        if (ret < 0) {
+            ALOGE("Segment parse header return fail %lld", ret);
+            delete mSegment;
+            mSegment = NULL;
+            return;
+        } else if (ret == 0) {
+            const mkvparser::Cues* mCues = mSegment->GetCues();
+            const mkvparser::SeekHead* mSH = mSegment->GetSeekHead();
+            if ((mCues == NULL) && (mSH != NULL)) {
+                size_t count = mSH->GetCount();
+                const mkvparser::SeekHead::Entry* mEntry;
+                for (size_t index = 0; index < count; index++) {
+                    mEntry = mSH->GetEntry(index);
+                    if (mEntry->id == 0x0C53BB6B) {  // Cues ID
+                        long len;
+                        long long pos;
+                        mSegment->ParseCues(mEntry->pos, pos, len);
+                        mCues = mSegment->GetCues();
+                        ALOGV("find cue data by seekhead");
+                        break;
+                    }
+                }
+            }
+
+            if (mCues) {
+                long len;
+                ret = mSegment->LoadCluster(pos, len);
+                ALOGV("has Cue data, Cluster num=%ld", mSegment->GetCount());
+            } else  {
+                long status_Load = mSegment->Load();
+                ALOGW("no Cue data,Segment Load status:%ld",status_Load);
+            }
+        } else if (ret > 0) {
+            ret = mkvparser::E_BUFFER_NOT_FULL;
+        }
     }
 
     if (ret < 0) {
@@ -1235,6 +1572,89 @@
     return OK;
 }
 
+status_t MatroskaExtractor::synthesizeMPEG2(TrackInfo *trackInfo, size_t index) {
+    ALOGV("synthesizeMPEG2");
+    BlockIterator iter(this, trackInfo->mTrackNum, index);
+    if (iter.eos()) {
+        return ERROR_MALFORMED;
+    }
+
+    const mkvparser::Block *block = iter.block();
+    if (block->GetFrameCount() <= 0) {
+        return ERROR_MALFORMED;
+    }
+
+    const mkvparser::Block::Frame &frame = block->GetFrame(0);
+    auto tmpData = heapbuffer<unsigned char>(frame.len);
+    long n = frame.Read(mReader, tmpData.get());
+    if (n != 0) {
+        return ERROR_MALFORMED;
+    }
+
+    size_t header_start = 0;
+    size_t header_lenth = 0;
+    for (header_start = 0; header_start < frame.len - 4; header_start++) {
+        if (ntohl(0x000001b3) == *(uint32_t*)((uint8_t*)tmpData.get() + header_start)) {
+            break;
+        }
+    }
+    bool isComplete_csd = false;
+    for (header_lenth = 0; header_lenth < frame.len - 4 - header_start; header_lenth++) {
+        if (ntohl(0x000001b8) == *(uint32_t*)((uint8_t*)tmpData.get()
+                                + header_start + header_lenth)) {
+            isComplete_csd = true;
+            break;
+        }
+    }
+    if (!isComplete_csd) {
+        ALOGE("can't parse complete csd for MPEG2!");
+        return ERROR_MALFORMED;
+    }
+    addESDSFromCodecPrivate(trackInfo->mMeta, false,
+                              (uint8_t*)(tmpData.get()) + header_start, header_lenth);
+
+    return OK;
+
+}
+
+status_t MatroskaExtractor::synthesizeMPEG4(TrackInfo *trackInfo, size_t index) {
+    ALOGV("synthesizeMPEG4");
+    BlockIterator iter(this, trackInfo->mTrackNum, index);
+    if (iter.eos()) {
+        return ERROR_MALFORMED;
+    }
+
+    const mkvparser::Block *block = iter.block();
+    if (block->GetFrameCount() <= 0) {
+        return ERROR_MALFORMED;
+    }
+
+    const mkvparser::Block::Frame &frame = block->GetFrame(0);
+    auto tmpData = heapbuffer<unsigned char>(frame.len);
+    long n = frame.Read(mReader, tmpData.get());
+    if (n != 0) {
+        return ERROR_MALFORMED;
+    }
+
+     size_t vosend;
+     bool isComplete_csd = false;
+     for (vosend = 0; (long)vosend < frame.len - 4; vosend++) {
+         if (ntohl(0x000001b6) == *(uint32_t*)((uint8_t*)tmpData.get() + vosend)) {
+             isComplete_csd = true;
+             break;  // Send VOS until VOP
+         }
+     }
+     if (!isComplete_csd) {
+         ALOGE("can't parse complete csd for MPEG4!");
+         return ERROR_MALFORMED;
+     }
+     addESDSFromCodecPrivate(trackInfo->mMeta, false, tmpData.get(), vosend);
+
+    return OK;
+
+}
+
+
 static inline bool isValidInt32ColourValue(long long value) {
     return value != mkvparser::Colour::kValueNotPresent
             && value >= INT32_MIN
@@ -1417,6 +1837,8 @@
         status_t err = OK;
         int32_t nalSize = -1;
 
+        bool isSetCsdFrom1stFrame = false;
+
         switch (track->GetType()) {
             case VIDEO_TRACK:
             {
@@ -1443,15 +1865,15 @@
                         continue;
                     }
                 } else if (!strcmp("V_MPEG4/ISO/ASP", codecID)) {
+                    AMediaFormat_setString(meta,
+                            AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_MPEG4);
                     if (codecPrivateSize > 0) {
-                        AMediaFormat_setString(meta,
-                                AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_MPEG4);
                         addESDSFromCodecPrivate(
                                 meta, false, codecPrivate, codecPrivateSize);
                     } else {
                         ALOGW("%s is detected, but does not have configuration.",
                                 codecID);
-                        continue;
+                        isSetCsdFrom1stFrame = true;
                     }
                 } else if (!strcmp("V_VP8", codecID)) {
                     AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_VP8);
@@ -1465,6 +1887,49 @@
                     }
                 } else if (!strcmp("V_AV1", codecID)) {
                     AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AV1);
+                } else if (!strcmp("V_MPEG2", codecID) || !strcmp("V_MPEG1", codecID)) {
+                        AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME,
+                                MEDIA_MIMETYPE_VIDEO_MPEG2);
+                        if (codecPrivate != NULL) {
+                            addESDSFromCodecPrivate(meta, false, codecPrivate, codecPrivateSize);
+                        } else {
+                            ALOGW("No specific codec private data, find it from the first frame");
+                            isSetCsdFrom1stFrame = true;
+                        }
+                } else if (!strcmp("V_MJPEG", codecID)) {
+                        AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME,
+                                MEDIA_MIMETYPE_VIDEO_MJPEG);
+                } else if (!strcmp("V_MS/VFW/FOURCC", codecID)) {
+                    if (NULL == codecPrivate ||codecPrivateSize < 20) {
+                        ALOGE("V_MS/VFW/FOURCC has no valid private data(%p),codecPrivateSize:%zu",
+                                 codecPrivate, codecPrivateSize);
+                        continue;
+                    } else {
+                        uint32_t fourcc = *(uint32_t *)(codecPrivate + 16);
+                        fourcc = ntohl(fourcc);
+                        const char* mime = MKVFourCC2MIME(fourcc);
+                        ALOGV("V_MS/VFW/FOURCC type is %s", mime);
+                        if (!strncasecmp("video/", mime, 6)) {
+                            AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, mime);
+                        } else {
+                            ALOGE("V_MS/VFW/FOURCC continue,unsupport video type=%s,fourcc=0x%08x.",
+                                 mime, fourcc);
+                            continue;
+                        }
+                        if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) ||
+                            !strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
+                            !strcmp(mime, MEDIA_MIMETYPE_VIDEO_XVID) ||
+                            !strcmp(mime, MEDIA_MIMETYPE_VIDEO_DIVX) ||
+                            !strcmp(mime, MEDIA_MIMETYPE_VIDEO_DIVX3) ||
+                            !strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG2) ||
+                            !strcmp(mime, MEDIA_MIMETYPE_VIDEO_H263)) {
+                            isSetCsdFrom1stFrame = true;
+                        } else {
+                            ALOGW("FourCC have unsupport codec, type=%s,fourcc=0x%08x.",
+                                  mime, fourcc);
+                            continue;
+                        }
+                    }
                 } else {
                     ALOGW("%s is not supported.", codecID);
                     continue;
@@ -1608,13 +2073,35 @@
         initTrackInfo(track, meta, trackInfo);
         trackInfo->mNalLengthSize = nalSize;
 
-        if (!strcmp("V_MPEG4/ISO/AVC", codecID) && codecPrivateSize == 0) {
+        const char *mimetype = "";
+        AMediaFormat_getString(meta, AMEDIAFORMAT_KEY_MIME, &mimetype);
+
+        if ((!strcmp("V_MPEG4/ISO/AVC", codecID) && codecPrivateSize == 0) ||
+            (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_AVC) && isSetCsdFrom1stFrame)) {
             // Attempt to recover from AVC track without codec private data
             err = synthesizeAVCC(trackInfo, n);
             if (err != OK) {
                 mTracks.pop();
             }
+        } else if ((!strcmp("V_MPEG2", codecID) && codecPrivateSize == 0) ||
+            (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_MPEG2) && isSetCsdFrom1stFrame)) {
+            // Attempt to recover from MPEG2 track without codec private data
+            err = synthesizeMPEG2(trackInfo, n);
+            if (err != OK) {
+                mTracks.pop();
+            }
+        } else if ((!strcmp("V_MPEG4/ISO/ASP", codecID) && codecPrivateSize == 0) ||
+            (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_MPEG4) && isSetCsdFrom1stFrame) ||
+            (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_XVID) && isSetCsdFrom1stFrame) ||
+            (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_DIVX) && isSetCsdFrom1stFrame) ||
+            (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_DIVX3) && isSetCsdFrom1stFrame)) {
+            // Attempt to recover from MPEG4 track without codec private data
+            err = synthesizeMPEG4(trackInfo, n);
+            if (err != OK) {
+                mTracks.pop();
+            }
         }
+
     }
 }
 
diff --git a/media/extractors/mkv/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
index 3871bdf..d53d9e3 100644
--- a/media/extractors/mkv/MatroskaExtractor.h
+++ b/media/extractors/mkv/MatroskaExtractor.h
@@ -95,6 +95,8 @@
     int64_t mSeekPreRollNs;
 
     status_t synthesizeAVCC(TrackInfo *trackInfo, size_t index);
+    status_t synthesizeMPEG2(TrackInfo *trackInfo, size_t index);
+    status_t synthesizeMPEG4(TrackInfo *trackInfo, size_t index);
     status_t initTrackInfo(
             const mkvparser::Track *track,
             AMediaFormat *meta,
diff --git a/media/extractors/mp4/AC4Parser.cpp b/media/extractors/mp4/AC4Parser.cpp
index 59a2e9b..13d60c8 100644
--- a/media/extractors/mp4/AC4Parser.cpp
+++ b/media/extractors/mp4/AC4Parser.cpp
@@ -260,7 +260,7 @@
 
     int32_t short_program_id = -1;
     if (bitstream_version > 1) {
-        if (ac4_dsi_version == 0){
+        if (ac4_dsi_version == 0) {
             ALOGE("invalid ac4 dsi");
             return false;
         }
@@ -295,6 +295,7 @@
         bool b_single_substream_group = false;
         uint32_t presentation_config = 0, presentation_version = 0;
         uint32_t pres_bytes = 0;
+        uint64_t start = 0;
 
         if (ac4_dsi_version == 0) {
             CHECK_BITS_LEFT(1 + 5 + 5);
@@ -315,6 +316,8 @@
                 mBitReader.skipBits(pres_bytes * 8);
                 continue;
             }
+            /* record a marker, less the size of the presentation_config */
+            start = (mDSISize - mBitReader.numBitsLeft()) / 8;
             // ac4_presentation_v0_dsi(), ac4_presentation_v1_dsi() and ac4_presentation_v2_dsi()
             // all start with a presentation_config of 5 bits
             CHECK_BITS_LEFT(5);
@@ -338,9 +341,6 @@
             (presentation_config >= NELEM(PresentationConfig) ?
             "reserved" : PresentationConfig[presentation_config]));
 
-        /* record a marker, less the size of the presentation_config */
-        uint64_t start = (mDSISize - mBitReader.numBitsLeft()) / 8;
-
         bool b_add_emdf_substreams = false;
         if (!b_single_substream_group && presentation_config == 6) {
             b_add_emdf_substreams = true;
@@ -535,14 +535,14 @@
                     }
                     break;
                 }
-                CHECK_BITS_LEFT(1 + 1);
-                bool b_pre_virtualized = (mBitReader.getBits(1) == 1);
-                mPresentations[presentation].mPreVirtualized = b_pre_virtualized;
-                b_add_emdf_substreams = (mBitReader.getBits(1) == 1);
-                ALOGV("%u: b_pre_virtualized = %s\n", presentation, BOOLSTR(b_pre_virtualized));
-                ALOGV("%u: b_add_emdf_substreams = %s\n", presentation,
-                    BOOLSTR(b_add_emdf_substreams));
             }
+            CHECK_BITS_LEFT(1 + 1);
+            bool b_pre_virtualized = (mBitReader.getBits(1) == 1);
+            mPresentations[presentation].mPreVirtualized = b_pre_virtualized;
+            b_add_emdf_substreams = (mBitReader.getBits(1) == 1);
+            ALOGV("%u: b_pre_virtualized = %s\n", presentation, BOOLSTR(b_pre_virtualized));
+            ALOGV("%u: b_add_emdf_substreams = %s\n", presentation,
+                BOOLSTR(b_add_emdf_substreams));
         }
         if (b_add_emdf_substreams) {
             CHECK_BITS_LEFT(7);
@@ -599,10 +599,6 @@
 
         if (ac4_dsi_version == 1) {
             uint64_t end = (mDSISize - mBitReader.numBitsLeft()) / 8;
-            if (mBitReader.numBitsLeft() % 8 != 0) {
-                end += 1;
-            }
-
             uint64_t presentation_bytes = end - start;
             uint64_t skip_bytes = pres_bytes - presentation_bytes;
             ALOGV("skipping = %" PRIu64 " bytes", skip_bytes);
@@ -612,7 +608,7 @@
 
         // we should know this or something is probably wrong
         // with the bitstream (or we don't support it)
-        if (mPresentations[presentation].mChannelMode == -1){
+        if (mPresentations[presentation].mChannelMode == -1) {
             ALOGE("could not determing channel mode of presentation %d", presentation);
             return false;
         }
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index a72e589..d56abaa 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -1540,7 +1540,8 @@
                 AMediaFormat_setInt32(meta,
                         AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT, thumbnail.height);
                 AMediaFormat_setBuffer(meta,
-                        AMEDIAFORMAT_KEY_CSD_HEVC, thumbnail.hvcc->data(), thumbnail.hvcc->size());
+                        AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC,
+                        thumbnail.hvcc->data(), thumbnail.hvcc->size());
                 ALOGV("image[%u]: thumbnail: size %dx%d, item index %zd",
                         imageIndex, thumbnail.width, thumbnail.height, thumbItemIndex);
             } else {
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 4298b57..22819cb 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -90,7 +90,7 @@
     virtual media_status_t getFormat(AMediaFormat *);
 
     virtual media_status_t read(MediaBufferHelper **buffer, const ReadOptions *options = NULL);
-    virtual bool supportNonblockingRead() { return true; }
+    bool supportsNonBlockingRead() override { return true; }
     virtual media_status_t fragmentedRead(
             MediaBufferHelper **buffer, const ReadOptions *options = NULL);
 
@@ -1487,8 +1487,13 @@
                 }
             }
             if (duration != 0 && mLastTrack->timescale != 0) {
-                AMediaFormat_setInt64(mLastTrack->meta, AMEDIAFORMAT_KEY_DURATION,
-                        (duration * 1000000) / mLastTrack->timescale);
+                long double durationUs = ((long double)duration * 1000000) / mLastTrack->timescale;
+                if (durationUs < 0 || durationUs > INT64_MAX) {
+                    ALOGE("cannot represent %lld * 1000000 / %lld in 64 bits",
+                          (long long) duration, (long long) mLastTrack->timescale);
+                    return ERROR_MALFORMED;
+                }
+                AMediaFormat_setInt64(mLastTrack->meta, AMEDIAFORMAT_KEY_DURATION, durationUs);
             }
 
             uint8_t lang[2];
@@ -5402,7 +5407,7 @@
                     break;
             }
             if( mode != ReadOptions::SEEK_FRAME_INDEX) {
-                seekTimeUs += ((int64_t)mElstShiftStartTicks * 1000000) / mTimescale;
+                seekTimeUs += ((long double)mElstShiftStartTicks * 1000000) / mTimescale;
             }
 
             uint32_t sampleIndex;
@@ -5550,7 +5555,7 @@
                 AMediaFormat *meta = mBuffer->meta_data();
                 AMediaFormat_clear(meta);
                 AMediaFormat_setInt64(
-                      meta, AMEDIAFORMAT_KEY_TIME_US, ((int64_t)cts * 1000000) / mTimescale);
+                      meta, AMEDIAFORMAT_KEY_TIME_US, ((long double)cts * 1000000) / mTimescale);
                 AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_IS_SYNC_FRAME, 1);
 
                 int32_t byteOrder;
@@ -5585,9 +5590,9 @@
                 AMediaFormat *meta = mBuffer->meta_data();
                 AMediaFormat_clear(meta);
                 AMediaFormat_setInt64(
-                        meta, AMEDIAFORMAT_KEY_TIME_US, ((int64_t)cts * 1000000) / mTimescale);
+                        meta, AMEDIAFORMAT_KEY_TIME_US, ((long double)cts * 1000000) / mTimescale);
                 AMediaFormat_setInt64(
-                        meta, AMEDIAFORMAT_KEY_DURATION, ((int64_t)stts * 1000000) / mTimescale);
+                        meta, AMEDIAFORMAT_KEY_DURATION, ((long double)stts * 1000000) / mTimescale);
 
                 if (targetSampleTimeUs >= 0) {
                     AMediaFormat_setInt64(
@@ -5641,9 +5646,9 @@
         AMediaFormat *meta = mBuffer->meta_data();
         AMediaFormat_clear(meta);
         AMediaFormat_setInt64(
-                meta, AMEDIAFORMAT_KEY_TIME_US, ((int64_t)cts * 1000000) / mTimescale);
+                meta, AMEDIAFORMAT_KEY_TIME_US, ((long double)cts * 1000000) / mTimescale);
         AMediaFormat_setInt64(
-                meta, AMEDIAFORMAT_KEY_DURATION, ((int64_t)stts * 1000000) / mTimescale);
+                meta, AMEDIAFORMAT_KEY_DURATION, ((long double)stts * 1000000) / mTimescale);
 
         if (targetSampleTimeUs >= 0) {
             AMediaFormat_setInt64(
@@ -5722,9 +5727,9 @@
         AMediaFormat *meta = mBuffer->meta_data();
         AMediaFormat_clear(meta);
         AMediaFormat_setInt64(
-                meta, AMEDIAFORMAT_KEY_TIME_US, ((int64_t)cts * 1000000) / mTimescale);
+                meta, AMEDIAFORMAT_KEY_TIME_US, ((long double)cts * 1000000) / mTimescale);
         AMediaFormat_setInt64(
-                meta, AMEDIAFORMAT_KEY_DURATION, ((int64_t)stts * 1000000) / mTimescale);
+                meta, AMEDIAFORMAT_KEY_DURATION, ((long double)stts * 1000000) / mTimescale);
 
         if (targetSampleTimeUs >= 0) {
             AMediaFormat_setInt64(
@@ -5771,7 +5776,7 @@
     ReadOptions::SeekMode mode;
     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
 
-        seekTimeUs += ((int64_t)mElstShiftStartTicks * 1000000) / mTimescale;
+        seekTimeUs += ((long double)mElstShiftStartTicks * 1000000) / mTimescale;
         ALOGV("shifted seekTimeUs :%" PRId64 ", mElstShiftStartTicks:%" PRId32, seekTimeUs,
                 mElstShiftStartTicks);
 
@@ -5932,9 +5937,9 @@
             CHECK(mBuffer != NULL);
             mBuffer->set_range(0, size);
             AMediaFormat_setInt64(bufmeta,
-                    AMEDIAFORMAT_KEY_TIME_US, ((int64_t)cts * 1000000) / mTimescale);
+                    AMEDIAFORMAT_KEY_TIME_US, ((long double)cts * 1000000) / mTimescale);
             AMediaFormat_setInt64(bufmeta,
-                    AMEDIAFORMAT_KEY_DURATION, ((int64_t)smpl->duration * 1000000) / mTimescale);
+                    AMEDIAFORMAT_KEY_DURATION, ((long double)smpl->duration * 1000000) / mTimescale);
 
             if (targetSampleTimeUs >= 0) {
                 AMediaFormat_setInt64(bufmeta, AMEDIAFORMAT_KEY_TARGET_TIME, targetSampleTimeUs);
@@ -6047,9 +6052,9 @@
 
         AMediaFormat *bufmeta = mBuffer->meta_data();
         AMediaFormat_setInt64(bufmeta,
-                AMEDIAFORMAT_KEY_TIME_US, ((int64_t)cts * 1000000) / mTimescale);
+                AMEDIAFORMAT_KEY_TIME_US, ((long double)cts * 1000000) / mTimescale);
         AMediaFormat_setInt64(bufmeta,
-                AMEDIAFORMAT_KEY_DURATION, ((int64_t)smpl->duration * 1000000) / mTimescale);
+                AMEDIAFORMAT_KEY_DURATION, ((long double)smpl->duration * 1000000) / mTimescale);
 
         if (targetSampleTimeUs >= 0) {
             AMediaFormat_setInt64(bufmeta, AMEDIAFORMAT_KEY_TARGET_TIME, targetSampleTimeUs);
@@ -6119,6 +6124,7 @@
         FOURCC("mp41"),
         FOURCC("mp42"),
         FOURCC("dash"),
+        FOURCC("nvr1"),
 
         // Won't promise that the following file types can be played.
         // Just give these file types a chance.
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index e58bd1f..020951b 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -81,7 +81,7 @@
     virtual media_status_t read(
             MediaBufferHelper **buffer, const ReadOptions *options = NULL);
 
-    virtual bool supportNonblockingRead() { return true; }
+    bool supportsNonBlockingRead() override { return false; }
 
 protected:
     virtual ~WAVSource();
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 6578156..c7c42eb 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -295,6 +295,7 @@
     AAudioArgsParser::usage();
     printf("      -B{frames}        input capacity in frames\n");
     printf("      -C{channels}      number of input channels\n");
+    printf("      -D{deviceId}      input device ID\n");
     printf("      -F{0,1,2}         input format, 1=I16, 2=FLOAT\n");
     printf("      -g{gain}          recirculating loopback gain\n");
     printf("      -h{hangMillis}    occasionally hang in the callback\n");
@@ -393,6 +394,7 @@
     AAudioStream         *outputStream               = nullptr;
 
     aaudio_result_t       result = AAUDIO_OK;
+    int32_t               requestedInputDeviceId     = AAUDIO_UNSPECIFIED;
     aaudio_sharing_mode_t requestedInputSharingMode  = AAUDIO_SHARING_MODE_SHARED;
     int                   requestedInputChannelCount = kNumInputChannels;
     aaudio_format_t       requestedInputFormat       = AAUDIO_FORMAT_UNSPECIFIED;
@@ -431,6 +433,9 @@
                     case 'C':
                         requestedInputChannelCount = atoi(&arg[2]);
                         break;
+                    case 'D':
+                        requestedInputDeviceId = atoi(&arg[2]);
+                        break;
                     case 'F':
                         requestedInputFormat = atoi(&arg[2]);
                         break;
@@ -529,6 +534,7 @@
 
     printf("INPUT  stream ----------------------------------------\n");
     // Use different parameters for the input.
+    argParser.setDeviceId(requestedInputDeviceId);
     argParser.setNumberOfBursts(AAUDIO_UNSPECIFIED);
     argParser.setFormat(requestedInputFormat);
     argParser.setPerformanceMode(inputPerformanceLevel);
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index baa1469..5851533 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -70,70 +70,34 @@
 
 // ---------------------------------------------------------------------------
 
-static std::string audioFormatTypeString(audio_format_t value) {
-    std::string formatType;
-    if (FormatConverter::toString(value, formatType)) {
-        return formatType;
-    }
-    char rawbuffer[16];  // room for "%d"
-    snprintf(rawbuffer, sizeof(rawbuffer), "%d", value);
-    return rawbuffer;
-}
-
-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;
-}
-
 void AudioRecord::MediaMetrics::gather(const AudioRecord *record)
 {
-    // key for media statistics is defined in the header
-    // attrs for media statistics
-    // NB: these are matched with public Java API constants defined
-    // in frameworks/base/media/java/android/media/AudioRecord.java
-    // These must be kept synchronized with the constants there.
-    static constexpr char kAudioRecordEncoding[] = "android.media.audiorecord.encoding";
-    static constexpr char kAudioRecordSource[] = "android.media.audiorecord.source";
-    static constexpr char kAudioRecordLatency[] = "android.media.audiorecord.latency";
-    static constexpr char kAudioRecordSampleRate[] = "android.media.audiorecord.samplerate";
-    static constexpr char kAudioRecordChannelCount[] = "android.media.audiorecord.channels";
-    static constexpr char kAudioRecordCreated[] = "android.media.audiorecord.createdMs";
-    static constexpr char kAudioRecordDuration[] = "android.media.audiorecord.durationMs";
-    static constexpr char kAudioRecordCount[] = "android.media.audiorecord.n";
-    static constexpr char kAudioRecordError[] = "android.media.audiorecord.errcode";
-    static constexpr char kAudioRecordErrorFunction[] = "android.media.audiorecord.errfunc";
+#define MM_PREFIX "android.media.audiorecord." // avoid cut-n-paste errors.
 
-    // constructor guarantees mAnalyticsItem is valid
+    // Java API 28 entries, do not change.
+    mAnalyticsItem->setCString(MM_PREFIX "encoding", toString(record->mFormat).c_str());
+    mAnalyticsItem->setCString(MM_PREFIX "source", toString(record->mAttributes.source).c_str());
+    mAnalyticsItem->setInt32(MM_PREFIX "latency", (int32_t)record->mLatency); // bad estimate.
+    mAnalyticsItem->setInt32(MM_PREFIX "samplerate", (int32_t)record->mSampleRate);
+    mAnalyticsItem->setInt32(MM_PREFIX "channels", (int32_t)record->mChannelCount);
 
-    mAnalyticsItem->setInt32(kAudioRecordLatency, record->mLatency);
-    mAnalyticsItem->setInt32(kAudioRecordSampleRate, record->mSampleRate);
-    mAnalyticsItem->setInt32(kAudioRecordChannelCount, record->mChannelCount);
-    mAnalyticsItem->setCString(kAudioRecordEncoding,
-                               audioFormatTypeString(record->mFormat).c_str());
-    mAnalyticsItem->setCString(kAudioRecordSource,
-                               audioSourceString(record->mAttributes.source).c_str());
+    // Non-API entries, these can change.
+    mAnalyticsItem->setInt32(MM_PREFIX "portId", (int32_t)record->mPortId);
+    mAnalyticsItem->setInt32(MM_PREFIX "frameCount", (int32_t)record->mFrameCount);
+    mAnalyticsItem->setCString(MM_PREFIX "attributes", toString(record->mAttributes).c_str());
+    mAnalyticsItem->setInt64(MM_PREFIX "channelMask", (int64_t)record->mChannelMask);
 
-    // log total duration recording, including anything currently running [and count].
-    nsecs_t active = 0;
+    // log total duration recording, including anything currently running.
+    int64_t activeNs = 0;
     if (mStartedNs != 0) {
-        active = systemTime() - mStartedNs;
+        activeNs = systemTime() - mStartedNs;
     }
-    mAnalyticsItem->setInt64(kAudioRecordDuration, (mDurationNs + active) / (1000 * 1000));
-    mAnalyticsItem->setInt32(kAudioRecordCount, mCount);
-
-    // XXX I don't know that this adds a lot of value, long term
-    if (mCreatedNs != 0) {
-        mAnalyticsItem->setInt64(kAudioRecordCreated, mCreatedNs / (1000 * 1000));
-    }
+    mAnalyticsItem->setDouble(MM_PREFIX "durationMs", (mDurationNs + activeNs) * 1e-6);
+    mAnalyticsItem->setInt64(MM_PREFIX "startCount", (int64_t)mCount);
 
     if (mLastError != NO_ERROR) {
-        mAnalyticsItem->setInt32(kAudioRecordError, mLastError);
-        mAnalyticsItem->setCString(kAudioRecordErrorFunction, mLastErrorFunc.c_str());
+        mAnalyticsItem->setInt32(MM_PREFIX "lastError.code", (int32_t)mLastError);
+        mAnalyticsItem->setCString(MM_PREFIX "lastError.at", mLastErrorFunc.c_str());
     }
 }
 
@@ -153,7 +117,9 @@
     : mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName),
       mSessionId(AUDIO_SESSION_ALLOCATE),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE)
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mSelectedMicDirection(MIC_DIRECTION_UNSPECIFIED),
+      mSelectedMicFieldDimension(MIC_FIELD_DIMENSION_DEFAULT)
 {
 }
 
@@ -173,7 +139,9 @@
         uid_t uid,
         pid_t pid,
         const audio_attributes_t* pAttributes,
-        audio_port_handle_t selectedDeviceId)
+        audio_port_handle_t selectedDeviceId,
+        audio_microphone_direction_t selectedMicDirection,
+        float microphoneFieldDimension)
     : mActive(false),
       mStatus(NO_INIT),
       mOpPackageName(opPackageName),
@@ -184,7 +152,8 @@
 {
     (void)set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
             notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,
-            uid, pid, pAttributes, selectedDeviceId);
+            uid, pid, pAttributes, selectedDeviceId,
+            selectedMicDirection, microphoneFieldDimension);
 }
 
 AudioRecord::~AudioRecord()
@@ -233,7 +202,9 @@
         uid_t uid,
         pid_t pid,
         const audio_attributes_t* pAttributes,
-        audio_port_handle_t selectedDeviceId)
+        audio_port_handle_t selectedDeviceId,
+        audio_microphone_direction_t selectedMicDirection,
+        float microphoneFieldDimension)
 {
     status_t status = NO_ERROR;
     uint32_t channelCount;
@@ -249,6 +220,8 @@
           sessionId, transferType, flags, String8(mOpPackageName).string(), uid, pid);
 
     mSelectedDeviceId = selectedDeviceId;
+    mSelectedMicDirection = selectedMicDirection;
+    mSelectedMicFieldDimension = microphoneFieldDimension;
 
     switch (transferType) {
     case TRANSFER_DEFAULT:
@@ -349,7 +322,7 @@
     mCbf = cbf;
 
     if (cbf != NULL) {
-        mAudioRecordThread = new AudioRecordThread(*this, threadCanCallJava);
+        mAudioRecordThread = new AudioRecordThread(*this);
         mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO);
         // thread begins in paused state, and will not reference us until start()
     }
@@ -436,6 +409,10 @@
         status = restoreRecord_l("start");
     }
 
+    // Call these directly because we are already holding the lock.
+    mAudioRecord->setMicrophoneDirection(mSelectedMicDirection);
+    mAudioRecord->setMicrophoneFieldDimension(mSelectedMicFieldDimension);
+
     if (status != NO_ERROR) {
         mActive = false;
         ALOGE("%s(%d): status %d", __func__, mPortId, status);
@@ -653,6 +630,8 @@
              mNotificationFramesAct, mNotificationFramesReq);
     result.appendFormat("  input(%d), latency(%u), selected device Id(%d), routed device Id(%d)\n",
                         mInput, mLatency, mSelectedDeviceId, mRoutedDeviceId);
+    result.appendFormat("  mic direction(%d) mic field dimension(%f)",
+                        mSelectedMicDirection, mSelectedMicFieldDimension);
     ::write(fd, result.string(), result.size());
     return NO_ERROR;
 }
@@ -1405,12 +1384,34 @@
 status_t AudioRecord::setMicrophoneDirection(audio_microphone_direction_t direction)
 {
     AutoMutex lock(mLock);
-    return mAudioRecord->setMicrophoneDirection(direction).transactionError();
+    if (mSelectedMicDirection == direction) {
+        // NOP
+        return OK;
+    }
+
+    mSelectedMicDirection = direction;
+    if (mAudioRecord == 0) {
+        // the internal AudioRecord hasn't be created yet, so just stash the attribute.
+        return OK;
+    } else {
+        return mAudioRecord->setMicrophoneDirection(direction).transactionError();
+    }
 }
 
 status_t AudioRecord::setMicrophoneFieldDimension(float zoom) {
     AutoMutex lock(mLock);
-    return mAudioRecord->setMicrophoneFieldDimension(zoom).transactionError();
+    if (mSelectedMicFieldDimension == zoom) {
+        // NOP
+        return OK;
+    }
+
+    mSelectedMicFieldDimension = zoom;
+    if (mAudioRecord == 0) {
+        // the internal AudioRecord hasn't be created yet, so just stash the attribute.
+        return OK;
+    } else {
+        return mAudioRecord->setMicrophoneFieldDimension(zoom).transactionError();
+    }
 }
 
 // =========================================================================
@@ -1426,8 +1427,9 @@
 
 // =========================================================================
 
-AudioRecord::AudioRecordThread::AudioRecordThread(AudioRecord& receiver, bool bCanCallJava)
-    : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
+AudioRecord::AudioRecordThread::AudioRecordThread(AudioRecord& receiver)
+    : 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/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 7881bb8..e59f7e0 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -170,44 +170,8 @@
 
 // ---------------------------------------------------------------------------
 
-static std::string audioContentTypeString(audio_content_type_t value) {
-    std::string contentType;
-    if (AudioContentTypeConverter::toString(value, contentType)) {
-        return contentType;
-    }
-    char rawbuffer[16];  // room for "%d"
-    snprintf(rawbuffer, sizeof(rawbuffer), "%d", value);
-    return rawbuffer;
-}
-
-static std::string audioUsageString(audio_usage_t value) {
-    std::string usage;
-    if (UsageTypeConverter::toString(value, usage)) {
-        return usage;
-    }
-    char rawbuffer[16];  // room for "%d"
-    snprintf(rawbuffer, sizeof(rawbuffer), "%d", value);
-    return rawbuffer;
-}
-
 void AudioTrack::MediaMetrics::gather(const AudioTrack *track)
 {
-
-    // key for media statistics is defined in the header
-    // attrs for media statistics
-    // NB: these are matched with public Java API constants defined
-    // in frameworks/base/media/java/android/media/AudioTrack.java
-    // These must be kept synchronized with the constants there.
-    static constexpr char kAudioTrackStreamType[] = "android.media.audiotrack.streamtype";
-    static constexpr char kAudioTrackContentType[] = "android.media.audiotrack.type";
-    static constexpr char kAudioTrackUsage[] = "android.media.audiotrack.usage";
-    static constexpr char kAudioTrackSampleRate[] = "android.media.audiotrack.samplerate";
-    static constexpr char kAudioTrackChannelMask[] = "android.media.audiotrack.channelmask";
-
-    // NB: These are not yet exposed as public Java API constants.
-    static constexpr char kAudioTrackUnderrunFrames[] = "android.media.audiotrack.underrunframes";
-    static constexpr char kAudioTrackStartupGlitch[] = "android.media.audiotrack.glitch.startup";
-
     // only if we're in a good state...
     // XXX: shall we gather alternative info if failing?
     const status_t lstatus = track->initCheck();
@@ -216,28 +180,22 @@
         return;
     }
 
-    // constructor guarantees mAnalyticsItem is valid
+#define MM_PREFIX "android.media.audiotrack." // avoid cut-n-paste errors.
 
-    const int32_t underrunFrames = track->getUnderrunFrames();
-    if (underrunFrames != 0) {
-        mAnalyticsItem->setInt32(kAudioTrackUnderrunFrames, underrunFrames);
-    }
+    // Java API 28 entries, do not change.
+    mAnalyticsItem->setCString(MM_PREFIX "streamtype", toString(track->streamType()).c_str());
+    mAnalyticsItem->setCString(MM_PREFIX "type",
+            toString(track->mAttributes.content_type).c_str());
+    mAnalyticsItem->setCString(MM_PREFIX "usage", toString(track->mAttributes.usage).c_str());
 
-    if (track->mTimestampStartupGlitchReported) {
-        mAnalyticsItem->setInt32(kAudioTrackStartupGlitch, 1);
-    }
-
-    if (track->mStreamType != -1) {
-        // deprecated, but this will tell us who still uses it.
-        mAnalyticsItem->setInt32(kAudioTrackStreamType, track->mStreamType);
-    }
-    // XXX: consider including from mAttributes: source type
-    mAnalyticsItem->setCString(kAudioTrackContentType,
-                               audioContentTypeString(track->mAttributes.content_type).c_str());
-    mAnalyticsItem->setCString(kAudioTrackUsage,
-                               audioUsageString(track->mAttributes.usage).c_str());
-    mAnalyticsItem->setInt32(kAudioTrackSampleRate, track->mSampleRate);
-    mAnalyticsItem->setInt64(kAudioTrackChannelMask, track->mChannelMask);
+    // Non-API entries, these can change due to a Java string mistake.
+    mAnalyticsItem->setInt32(MM_PREFIX "sampleRate", (int32_t)track->mSampleRate);
+    mAnalyticsItem->setInt64(MM_PREFIX "channelMask", (int64_t)track->mChannelMask);
+    // Non-API entries, these can change.
+    mAnalyticsItem->setInt32(MM_PREFIX "portId", (int32_t)track->mPortId);
+    mAnalyticsItem->setCString(MM_PREFIX "encoding", toString(track->mFormat).c_str());
+    mAnalyticsItem->setInt32(MM_PREFIX "frameCount", (int32_t)track->mFrameCount);
+    mAnalyticsItem->setCString(MM_PREFIX "attributes", toString(track->mAttributes).c_str());
 }
 
 // hand the user a snapshot of the metrics.
@@ -615,7 +573,7 @@
     mCbf = cbf;
 
     if (cbf != NULL) {
-        mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
+        mAudioTrackThread = new AudioTrackThread(*this);
         mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
         // thread begins in paused state, and will not reference us until start()
     }
@@ -3127,8 +3085,9 @@
 
 // =========================================================================
 
-AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
-    : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
+AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver)
+    : 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/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h
index 41b425f..783eef3 100644
--- a/media/libaudioclient/include/media/AudioMixer.h
+++ b/media/libaudioclient/include/media/AudioMixer.h
@@ -273,7 +273,7 @@
             mPostDownmixReformatBufferProvider.reset(nullptr);
             mDownmixerBufferProvider.reset(nullptr);
             mReformatBufferProvider.reset(nullptr);
-            mAdjustChannelsNonDestructiveBufferProvider.reset(nullptr);
+            mContractChannelsNonDestructiveBufferProvider.reset(nullptr);
             mAdjustChannelsBufferProvider.reset(nullptr);
         }
 
@@ -347,8 +347,12 @@
          * all pre-mixer track buffer conversions outside the AudioMixer class.
          *
          * 1) mInputBufferProvider: The AudioTrack buffer provider.
-         * 2) mAdjustChannelsBufferProvider: Expend or contracts data
-         * 3) mAdjustChannelsNonDestructiveBufferProvider: Non-destructively adjust sample data
+         * 2) mAdjustChannelsBufferProvider: Expands or contracts sample data from one interleaved
+         *    channel format to another. Expanded channels are filled with zeros and put at the end
+         *    of each audio frame. Contracted channels are copied to the end of the buffer.
+         * 3) mContractChannelsNonDestructiveBufferProvider: Non-destructively contract sample data.
+         *    This is currently using at audio-haptic coupled playback to separate audio and haptic
+         *    data. Contracted channels could be written to given buffer.
          * 4) mReformatBufferProvider: If not NULL, performs the audio reformat to
          *    match either mMixerInFormat or mDownmixRequiresFormat, if the downmixer
          *    requires reformat. For example, it may convert floating point input to
@@ -360,9 +364,10 @@
          * 7) mTimestretchBufferProvider: Adds timestretching for playback rate
          */
         AudioBufferProvider*     mInputBufferProvider;    // externally provided buffer provider.
-        // TODO: combine AdjustChannelsBufferProvider and AdjustChannelsNonDestructiveBufferProvider
+        // TODO: combine mAdjustChannelsBufferProvider and
+        // mContractChannelsNonDestructiveBufferProvider
         std::unique_ptr<PassthruBufferProvider> mAdjustChannelsBufferProvider;
-        std::unique_ptr<PassthruBufferProvider> mAdjustChannelsNonDestructiveBufferProvider;
+        std::unique_ptr<PassthruBufferProvider> mContractChannelsNonDestructiveBufferProvider;
         std::unique_ptr<PassthruBufferProvider> mReformatBufferProvider;
         std::unique_ptr<PassthruBufferProvider> mDownmixerBufferProvider;
         std::unique_ptr<PassthruBufferProvider> mPostDownmixReformatBufferProvider;
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index 4707c4a..b4ddb69 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -189,7 +189,10 @@
                                     uid_t uid = AUDIO_UID_INVALID,
                                     pid_t pid = -1,
                                     const audio_attributes_t* pAttributes = NULL,
-                                    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
+                                    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
+                                    audio_microphone_direction_t
+                                        selectedMicDirection = MIC_DIRECTION_UNSPECIFIED,
+                                    float selectedMicFieldDimension = MIC_FIELD_DIMENSION_DEFAULT);
 
     /* Terminates the AudioRecord and unregisters it from AudioFlinger.
      * Also destroys all resources associated with the AudioRecord.
@@ -228,7 +231,10 @@
                             uid_t uid = AUDIO_UID_INVALID,
                             pid_t pid = -1,
                             const audio_attributes_t* pAttributes = NULL,
-                            audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
+                            audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
+                            audio_microphone_direction_t
+                                selectedMicDirection = MIC_DIRECTION_UNSPECIFIED,
+                            float selectedMicFieldDimension = MIC_FIELD_DIMENSION_DEFAULT);
 
     /* Result of constructing the AudioRecord. This must be checked for successful initialization
      * before using any AudioRecord API (except for set()), because using
@@ -562,7 +568,7 @@
     class AudioRecordThread : public Thread
     {
     public:
-        AudioRecordThread(AudioRecord& receiver, bool bCanCallJava = false);
+        AudioRecordThread(AudioRecord& receiver);
 
         // Do not call Thread::requestExitAndWait() without first calling requestExit().
         // Thread::requestExitAndWait() is not virtual, and the implementation doesn't do enough.
@@ -716,6 +722,9 @@
                                               // activity and connected devices
     wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
 
+    audio_microphone_direction_t mSelectedMicDirection;
+    float mSelectedMicFieldDimension;
+
 private:
     class MediaMetrics {
       public:
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 12f5d71..3926ead 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -934,7 +934,7 @@
     class AudioTrackThread : public Thread
     {
     public:
-        AudioTrackThread(AudioTrack& receiver, bool bCanCallJava = false);
+        AudioTrackThread(AudioTrack& receiver);
 
         // Do not call Thread::requestExitAndWait() without first calling requestExit().
         // Thread::requestExitAndWait() is not virtual, and the implementation doesn't do enough.
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index 2c57db7..f7cc096 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -408,8 +408,8 @@
 void AudioMixer::Track::unprepareForAdjustChannelsNonDestructive()
 {
     ALOGV("AUDIOMIXER::unprepareForAdjustChannelsNonDestructive");
-    if (mAdjustChannelsNonDestructiveBufferProvider.get() != nullptr) {
-        mAdjustChannelsNonDestructiveBufferProvider.reset(nullptr);
+    if (mContractChannelsNonDestructiveBufferProvider.get() != nullptr) {
+        mContractChannelsNonDestructiveBufferProvider.reset(nullptr);
         reconfigureBufferProviders();
     }
 }
@@ -426,13 +426,13 @@
                 ? (uint8_t*)mainBuffer + frames * audio_bytes_per_frame(
                         mMixerChannelCount, mMixerFormat)
                 : NULL;
-        mAdjustChannelsNonDestructiveBufferProvider.reset(
-                new AdjustChannelsNonDestructiveBufferProvider(
+        mContractChannelsNonDestructiveBufferProvider.reset(
+                new AdjustChannelsBufferProvider(
                         mFormat,
                         mAdjustNonDestructiveInChannelCount,
                         mAdjustNonDestructiveOutChannelCount,
-                        mKeepContractedChannels ? mMixerFormat : AUDIO_FORMAT_INVALID,
                         frames,
+                        mKeepContractedChannels ? mMixerFormat : AUDIO_FORMAT_INVALID,
                         buffer));
         reconfigureBufferProviders();
     }
@@ -441,9 +441,9 @@
 
 void AudioMixer::Track::clearContractedBuffer()
 {
-    if (mAdjustChannelsNonDestructiveBufferProvider.get() != nullptr) {
-        static_cast<AdjustChannelsNonDestructiveBufferProvider*>(
-                mAdjustChannelsNonDestructiveBufferProvider.get())->clearContractedFrames();
+    if (mContractChannelsNonDestructiveBufferProvider.get() != nullptr) {
+        static_cast<AdjustChannelsBufferProvider*>(
+                mContractChannelsNonDestructiveBufferProvider.get())->clearContractedFrames();
     }
 }
 
@@ -455,9 +455,9 @@
         mAdjustChannelsBufferProvider->setBufferProvider(bufferProvider);
         bufferProvider = mAdjustChannelsBufferProvider.get();
     }
-    if (mAdjustChannelsNonDestructiveBufferProvider.get() != nullptr) {
-        mAdjustChannelsNonDestructiveBufferProvider->setBufferProvider(bufferProvider);
-        bufferProvider = mAdjustChannelsNonDestructiveBufferProvider.get();
+    if (mContractChannelsNonDestructiveBufferProvider.get() != nullptr) {
+        mContractChannelsNonDestructiveBufferProvider->setBufferProvider(bufferProvider);
+        bufferProvider = mContractChannelsNonDestructiveBufferProvider.get();
     }
     if (mReformatBufferProvider.get() != nullptr) {
         mReformatBufferProvider->setBufferProvider(bufferProvider);
@@ -966,8 +966,8 @@
         track->mDownmixerBufferProvider->reset();
     } else if (track->mReformatBufferProvider.get() != nullptr) {
         track->mReformatBufferProvider->reset();
-    } else if (track->mAdjustChannelsNonDestructiveBufferProvider.get() != nullptr) {
-        track->mAdjustChannelsNonDestructiveBufferProvider->reset();
+    } else if (track->mContractChannelsNonDestructiveBufferProvider.get() != nullptr) {
+        track->mContractChannelsNonDestructiveBufferProvider->reset();
     } else if (track->mAdjustChannelsBufferProvider.get() != nullptr) {
         track->mAdjustChannelsBufferProvider->reset();
     }
diff --git a/media/libaudioprocessing/BufferProviders.cpp b/media/libaudioprocessing/BufferProviders.cpp
index b764ccb..21d25e1 100644
--- a/media/libaudioprocessing/BufferProviders.cpp
+++ b/media/libaudioprocessing/BufferProviders.cpp
@@ -627,79 +627,68 @@
     }
 }
 
-AdjustChannelsBufferProvider::AdjustChannelsBufferProvider(audio_format_t format,
-        size_t inChannelCount, size_t outChannelCount, size_t frameCount) :
+AdjustChannelsBufferProvider::AdjustChannelsBufferProvider(
+        audio_format_t format, size_t inChannelCount, size_t outChannelCount,
+        size_t frameCount, audio_format_t contractedFormat, void* contractedBuffer) :
         CopyBufferProvider(
                 audio_bytes_per_frame(inChannelCount, format),
-                audio_bytes_per_frame(outChannelCount, format),
+                audio_bytes_per_frame(std::max(inChannelCount, outChannelCount), format),
                 frameCount),
         mFormat(format),
         mInChannelCount(inChannelCount),
         mOutChannelCount(outChannelCount),
-        mSampleSizeInBytes(audio_bytes_per_sample(format))
-{
-    ALOGV("AdjustBufferProvider(%p)(%#x, %zu, %zu, %zu)",
-            this, format, inChannelCount, outChannelCount, frameCount);
-}
-
-void AdjustChannelsBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
-{
-    adjust_channels(src, mInChannelCount, dst, mOutChannelCount, mSampleSizeInBytes,
-            frames * mInChannelCount * mSampleSizeInBytes);
-}
-
-AdjustChannelsNonDestructiveBufferProvider::AdjustChannelsNonDestructiveBufferProvider(
-        audio_format_t format, size_t inChannelCount, size_t outChannelCount,
-        audio_format_t contractedFormat, size_t contractedFrameCount, void* contractedBuffer) :
-        CopyBufferProvider(
-                audio_bytes_per_frame(std::max(inChannelCount, outChannelCount), format),
-                audio_bytes_per_frame(std::max(inChannelCount, outChannelCount), format),
-                contractedFrameCount),
-        mFormat(format),
-        mInChannelCount(inChannelCount),
-        mOutChannelCount(outChannelCount),
         mSampleSizeInBytes(audio_bytes_per_sample(format)),
+        mFrameCount(frameCount),
         mContractedChannelCount(inChannelCount - outChannelCount),
         mContractedFormat(contractedFormat),
-        mContractedFrameCount(contractedFrameCount),
         mContractedBuffer(contractedBuffer),
         mContractedWrittenFrames(0)
 {
-    ALOGV("AdjustChannelsNonDestructiveBufferProvider(%p)(%#x, %zu, %zu, %#x, %p)",
-            this, format, inChannelCount, outChannelCount, contractedFormat, contractedBuffer);
+    ALOGV("AdjustChannelsBufferProvider(%p)(%#x, %zu, %zu, %zu, %#x, %p)", this, format,
+            inChannelCount, outChannelCount, frameCount, contractedFormat, contractedBuffer);
     if (mContractedFormat != AUDIO_FORMAT_INVALID && mInChannelCount > mOutChannelCount) {
         mContractedFrameSize = audio_bytes_per_frame(mContractedChannelCount, mContractedFormat);
     }
 }
 
-status_t AdjustChannelsNonDestructiveBufferProvider::getNextBuffer(
-        AudioBufferProvider::Buffer* pBuffer)
+status_t AdjustChannelsBufferProvider::getNextBuffer(AudioBufferProvider::Buffer* pBuffer)
 {
-    const size_t outFramesLeft = mContractedFrameCount - mContractedWrittenFrames;
-    if (outFramesLeft < pBuffer->frameCount) {
-        // Restrict the frame count so that we don't write over the size of the output buffer.
-        pBuffer->frameCount = outFramesLeft;
+    if (mContractedBuffer != nullptr) {
+        // Restrict frame count only when it is needed to save contracted frames.
+        const size_t outFramesLeft = mFrameCount - mContractedWrittenFrames;
+        if (outFramesLeft < pBuffer->frameCount) {
+            // Restrict the frame count so that we don't write over the size of the output buffer.
+            pBuffer->frameCount = outFramesLeft;
+        }
     }
     return CopyBufferProvider::getNextBuffer(pBuffer);
 }
 
-void AdjustChannelsNonDestructiveBufferProvider::copyFrames(
-        void *dst, const void *src, size_t frames)
+void AdjustChannelsBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
 {
-    adjust_channels_non_destructive(src, mInChannelCount, dst, mOutChannelCount, mSampleSizeInBytes,
-            frames * mInChannelCount * mSampleSizeInBytes);
-    if (mContractedFormat != AUDIO_FORMAT_INVALID && mContractedBuffer != NULL
-            && mInChannelCount > mOutChannelCount) {
-        const size_t contractedIdx = frames * mOutChannelCount * mSampleSizeInBytes;
-        memcpy_by_audio_format(
-                (uint8_t*)mContractedBuffer + mContractedWrittenFrames * mContractedFrameSize,
-                mContractedFormat, (uint8_t*)dst + contractedIdx, mFormat,
-                mContractedChannelCount * frames);
-        mContractedWrittenFrames += frames;
+    if (mInChannelCount > mOutChannelCount) {
+        // For case multi to mono, adjust_channels has special logic that will mix first two input
+        // channels into a single output channel. In that case, use adjust_channels_non_destructive
+        // to keep only one channel data even when contracting to mono.
+        adjust_channels_non_destructive(src, mInChannelCount, dst, mOutChannelCount,
+                mSampleSizeInBytes, frames * mInChannelCount * mSampleSizeInBytes);
+        if (mContractedFormat != AUDIO_FORMAT_INVALID
+            && mContractedBuffer != nullptr) {
+            const size_t contractedIdx = frames * mOutChannelCount * mSampleSizeInBytes;
+            memcpy_by_audio_format(
+                    (uint8_t*) mContractedBuffer + mContractedWrittenFrames * mContractedFrameSize,
+                    mContractedFormat, (uint8_t*) dst + contractedIdx, mFormat,
+                    mContractedChannelCount * frames);
+            mContractedWrittenFrames += frames;
+        }
+    } else {
+        // Prefer expanding data from the end of each audio frame.
+        adjust_channels(src, mInChannelCount, dst, mOutChannelCount,
+                mSampleSizeInBytes, frames * mInChannelCount * mSampleSizeInBytes);
     }
 }
 
-void AdjustChannelsNonDestructiveBufferProvider::reset()
+void AdjustChannelsBufferProvider::reset()
 {
     mContractedWrittenFrames = 0;
     CopyBufferProvider::reset();
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/libmedia/Android.bp b/media/libmedia/Android.bp
index 9799cad..a529628 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -1,3 +1,10 @@
+cc_defaults {
+    name: "libmedia_defaults",
+    include_dirs: [
+        "bionic/libc/private",
+    ],
+}
+
 cc_library_headers {
     name: "libmedia_headers",
     vendor_available: true,
@@ -86,6 +93,7 @@
     export_shared_lib_headers: [
         "android.hidl.token@1.0-utils",
         "android.hardware.media.omx@1.0",
+        "libgui",
         "libstagefright_foundation",
         "libui",
     ],
@@ -148,6 +156,8 @@
 cc_library {
     name: "libmedia",
 
+    defaults: [ "libmedia_defaults" ],
+
     srcs: [
         "IDataSource.cpp",
         "BufferingSettings.cpp",
@@ -258,6 +268,8 @@
 cc_library_static {
     name: "libmedia_player2_util",
 
+    defaults: [ "libmedia_defaults" ],
+
     srcs: [
         "AudioParameter.cpp",
         "BufferingSettings.cpp",
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 56ee18e..f283569 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -66,6 +66,8 @@
     ENABLE_AUDIO_DEVICE_CALLBACK,
     GET_ACTIVE_MICROPHONES,
     GET_PORT_ID,
+    SET_MICROPHONE_DIRECTION,
+    SET_MICROPHONE_FIELD_DIMENSION
 };
 
 class BpMediaRecorder: public BpInterface<IMediaRecorder>
@@ -407,6 +409,24 @@
         return status;
     }
 
+    status_t setMicrophoneDirection(audio_microphone_direction_t direction) {
+        ALOGV("setMicrophoneDirection(%d)", direction);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(direction);
+        status_t status = remote()->transact(SET_MICROPHONE_DIRECTION, data, &reply);
+        return status == NO_ERROR ? (status_t)reply.readInt32() : status;
+    }
+
+    status_t setMicrophoneFieldDimension(float zoom) {
+        ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeFloat(zoom);
+        status_t status = remote()->transact(SET_MICROPHONE_FIELD_DIMENSION, data, &reply);
+        return status == NO_ERROR ? (status_t)reply.readInt32() : status;
+    }
+
     status_t getPortId(audio_port_handle_t *portId)
     {
         ALOGV("getPortId");
@@ -689,6 +709,23 @@
             }
             return NO_ERROR;
         }
+        case SET_MICROPHONE_DIRECTION: {
+            ALOGV("SET_MICROPHONE_DIRECTION");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int direction = data.readInt32();
+            status_t status =
+                setMicrophoneDirection(static_cast<audio_microphone_direction_t>(direction));
+            reply->writeInt32(status);
+            return NO_ERROR;
+        }
+        case SET_MICROPHONE_FIELD_DIMENSION: {
+            ALOGV("SET_MICROPHONE_FIELD_DIMENSION");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            float zoom = data.readFloat();
+            status_t status = setMicrophoneFieldDimension(zoom);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/MediaUtils.cpp b/media/libmedia/MediaUtils.cpp
index bcc7ebf..31972fa 100644
--- a/media/libmedia/MediaUtils.cpp
+++ b/media/libmedia/MediaUtils.cpp
@@ -22,23 +22,16 @@
 #include <sys/resource.h>
 #include <unistd.h>
 
+#include <bionic_malloc.h>
+
 #include "MediaUtils.h"
 
-extern "C" size_t __cfi_shadow_size();
 extern "C" void __scudo_set_rss_limit(size_t, int) __attribute__((weak));
 
 namespace android {
 
-void limitProcessMemory(
-    const char *property,
-    size_t numberOfBytes,
-    size_t percentageOfTotalMem) {
-
-    if (running_with_asan()) {
-        ALOGW("Running with (HW)ASan, skip enforcing memory limitations.");
-        return;
-    }
-
+void limitProcessMemory(const char *property, size_t numberOfBytes,
+                        size_t percentageOfTotalMem) {
     long pageSize = sysconf(_SC_PAGESIZE);
     long numPages = sysconf(_SC_PHYS_PAGES);
     size_t maxMem = SIZE_MAX;
@@ -66,38 +59,17 @@
         maxMem = propVal;
     }
 
-    // If 64-bit Scudo is in use, enforce the hard RSS limit (in MB).
-    if (maxMem != SIZE_MAX && sizeof(void *) == 8 &&
-        &__scudo_set_rss_limit != 0) {
+    // If Scudo is in use, enforce the hard RSS limit (in MB).
+    if (maxMem != SIZE_MAX && &__scudo_set_rss_limit != 0) {
       __scudo_set_rss_limit(maxMem >> 20, 1);
       ALOGV("Scudo hard RSS limit set to %zu MB", maxMem >> 20);
       return;
     }
 
-    // Increase by the size of the CFI shadow mapping. Most of the shadow is not
-    // backed with physical pages, and it is possible for the result to be
-    // higher than total physical memory. This is fine for RLIMIT_AS.
-    size_t cfi_size = __cfi_shadow_size();
-    if (cfi_size) {
-      ALOGV("cfi shadow size: %zu", cfi_size);
-      if (maxMem <= SIZE_MAX - cfi_size) {
-        maxMem += cfi_size;
-      } else {
-        maxMem = SIZE_MAX;
-      }
+    if (!android_mallopt(M_SET_ALLOCATION_LIMIT_BYTES, &maxMem,
+                         sizeof(maxMem))) {
+      ALOGW("couldn't set allocation limit");
     }
-    ALOGV("actual limit: %zu", maxMem);
-
-    struct rlimit limit;
-    getrlimit(RLIMIT_AS, &limit);
-    ALOGV("original limits: %lld/%lld", (long long)limit.rlim_cur, (long long)limit.rlim_max);
-    limit.rlim_cur = maxMem;
-    setrlimit(RLIMIT_AS, &limit);
-    limit.rlim_cur = -1;
-    limit.rlim_max = -1;
-    getrlimit(RLIMIT_AS, &limit);
-    ALOGV("new limits: %lld/%lld", (long long)limit.rlim_cur, (long long)limit.rlim_max);
-
 }
 
 } // namespace android
diff --git a/media/libmedia/MediaUtils.h b/media/libmedia/MediaUtils.h
index 26075c4..f80dd30 100644
--- a/media/libmedia/MediaUtils.h
+++ b/media/libmedia/MediaUtils.h
@@ -19,13 +19,6 @@
 
 namespace android {
 
-extern "C" void __asan_init(void) __attribute__((weak));
-extern "C" void __hwasan_init(void) __attribute__((weak));
-
-static inline int running_with_asan() {
-    return &__asan_init != 0 || &__hwasan_init != 0;
-}
-
 /**
    Limit the amount of memory a process can allocate using setrlimit(RLIMIT_AS).
    The value to use will be read from the specified system property, or if the
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmedia/TypeConverter.cpp
index 0301b21..469c5b6 100644
--- a/media/libmedia/TypeConverter.cpp
+++ b/media/libmedia/TypeConverter.cpp
@@ -217,6 +217,7 @@
     MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX_ADAPTIVE),
     MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_LHDC),
     MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_LHDC_LL),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX_TWSP),
     TERMINATOR
 };
 
diff --git a/media/libmedia/include/media/BufferProviders.h b/media/libmedia/include/media/BufferProviders.h
index ea41527..b038854 100644
--- a/media/libmedia/include/media/BufferProviders.h
+++ b/media/libmedia/include/media/BufferProviders.h
@@ -218,33 +218,21 @@
     bool                 mAudioPlaybackRateValid; // flag for current parameters validity
 };
 
-// AdjustBufferProvider derives from CopyBufferProvider to adjust sample data.
+// AdjustChannelsBufferProvider derives from CopyBufferProvider to adjust sample data.
 // Expands or contracts sample data from one interleaved channel format to another.
-// Expanded channels are filled with zeros and put at the end of each audio frame.
-// Contracted channels are omitted from the end of each audio frame.
+// Extra expanded channels are filled with zeros and put at the end of each audio frame.
+// Contracted channels are copied to the end of the output buffer(storage should be
+// allocated appropriately).
+// Contracted channels could be written to output buffer.
 class AdjustChannelsBufferProvider : public CopyBufferProvider {
 public:
     AdjustChannelsBufferProvider(audio_format_t format, size_t inChannelCount,
-            size_t outChannelCount, size_t frameCount);
-    //Overrides
-    void copyFrames(void *dst, const void *src, size_t frames) override;
-
-protected:
-    const audio_format_t mFormat;
-    const size_t         mInChannelCount;
-    const size_t         mOutChannelCount;
-    const size_t         mSampleSizeInBytes;
-};
-
-// AdjustChannelsNonDestructiveBufferProvider derives from CopyBufferProvider to adjust sample data.
-// Expands or contracts sample data from one interleaved channel format to another.
-// Extra expanded channels are interleaved in from the end of the input buffer.
-// Contracted channels are copied to the end of the output buffer.
-// Contracted channels could be written to output buffer.
-class AdjustChannelsNonDestructiveBufferProvider : public CopyBufferProvider {
-public:
-    AdjustChannelsNonDestructiveBufferProvider(audio_format_t format, size_t inChannelCount,
-            size_t outChannelCount, audio_format_t contractedFormat, size_t contractedFrameCount,
+            size_t outChannelCount, size_t frameCount) : AdjustChannelsBufferProvider(
+                    format, inChannelCount, outChannelCount,
+                    frameCount, AUDIO_FORMAT_INVALID, nullptr) { }
+    // Contracted data is converted to contractedFormat and put into contractedBuffer.
+    AdjustChannelsBufferProvider(audio_format_t format, size_t inChannelCount,
+            size_t outChannelCount, size_t frameCount, audio_format_t contractedFormat,
             void* contractedBuffer);
     //Overrides
     status_t getNextBuffer(Buffer* pBuffer) override;
@@ -258,9 +246,9 @@
     const size_t         mInChannelCount;
     const size_t         mOutChannelCount;
     const size_t         mSampleSizeInBytes;
+    const size_t         mFrameCount;
     const size_t         mContractedChannelCount;
     const audio_format_t mContractedFormat;
-    const size_t         mContractedFrameCount;
     void                *mContractedBuffer;
     size_t               mContractedWrittenFrames;
     size_t               mContractedFrameSize;
diff --git a/media/libmedia/include/media/IMediaRecorder.h b/media/libmedia/include/media/IMediaRecorder.h
index e7c466d..0b09420 100644
--- a/media/libmedia/include/media/IMediaRecorder.h
+++ b/media/libmedia/include/media/IMediaRecorder.h
@@ -73,6 +73,8 @@
     virtual status_t enableAudioDeviceCallback(bool enabled) = 0;
     virtual status_t getActiveMicrophones(
                         std::vector<media::MicrophoneInfo>* activeMicrophones) = 0;
+    virtual status_t setMicrophoneDirection(audio_microphone_direction_t direction) = 0;
+    virtual status_t setMicrophoneFieldDimension(float zoom) = 0;
     virtual status_t getPortId(audio_port_handle_t *portId) = 0;
 };
 
diff --git a/media/libmedia/include/media/IMediaSource.h b/media/libmedia/include/media/IMediaSource.h
index 7a4b1b9..5ab6e37 100644
--- a/media/libmedia/include/media/IMediaSource.h
+++ b/media/libmedia/include/media/IMediaSource.h
@@ -126,8 +126,8 @@
 
     static const size_t kBinderMediaBuffers = 4; // buffers managed by BnMediaSource
     static const size_t kTransferSharedAsSharedThreshold = 4 * 1024;  // if >= shared, else inline
-    static const size_t kTransferInlineAsSharedThreshold = 64 * 1024; // if >= shared, else inline
-    static const size_t kInlineMaxTransfer = 256 * 1024; // Binder size limited to BINDER_VM_SIZE.
+    static const size_t kTransferInlineAsSharedThreshold = 8 * 1024; // if >= shared, else inline
+    static const size_t kInlineMaxTransfer = 64 * 1024; // Binder size limited to BINDER_VM_SIZE.
 
 protected:
     virtual ~BnMediaSource();
diff --git a/media/libmedia/include/media/MediaRecorderBase.h b/media/libmedia/include/media/MediaRecorderBase.h
index e1c5d47..88282ac 100644
--- a/media/libmedia/include/media/MediaRecorderBase.h
+++ b/media/libmedia/include/media/MediaRecorderBase.h
@@ -72,6 +72,8 @@
     virtual status_t enableAudioDeviceCallback(bool enabled) = 0;
     virtual status_t getActiveMicrophones(
                         std::vector<media::MicrophoneInfo>* activeMicrophones) = 0;
+    virtual status_t setMicrophoneDirection(audio_microphone_direction_t direction) = 0;
+    virtual status_t setMicrophoneFieldDimension(float zoom) = 0;
     virtual status_t getPortId(audio_port_handle_t *portId) const = 0;
 
 
diff --git a/media/libmedia/include/media/mediarecorder.h b/media/libmedia/include/media/mediarecorder.h
index 33be559..8580437 100644
--- a/media/libmedia/include/media/mediarecorder.h
+++ b/media/libmedia/include/media/mediarecorder.h
@@ -264,6 +264,9 @@
     status_t    getRoutedDeviceId(audio_port_handle_t *deviceId);
     status_t    enableAudioDeviceCallback(bool enabled);
     status_t    getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
+    status_t    setMicrophoneDirection(audio_microphone_direction_t direction);
+    status_t    setMicrophoneFieldDimension(float zoom);
+
     status_t    getPortId(audio_port_handle_t *portId) const;
 
 private:
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index d07e703..6c59a29 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -842,6 +842,16 @@
     return mMediaRecorder->getActiveMicrophones(activeMicrophones);
 }
 
+status_t MediaRecorder::setMicrophoneDirection(audio_microphone_direction_t direction) {
+    ALOGV("setMicrophoneDirection(%d)", direction);
+    return mMediaRecorder->setMicrophoneDirection(direction);
+}
+
+status_t MediaRecorder::setMicrophoneFieldDimension(float zoom) {
+    ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+    return mMediaRecorder->setMicrophoneFieldDimension(zoom);
+}
+
 status_t MediaRecorder::getPortId(audio_port_handle_t *portId) const
 {
     ALOGV("getPortId");
diff --git a/media/libmedia/xsd/Android.bp b/media/libmedia/xsd/Android.bp
new file mode 100644
index 0000000..1635f70
--- /dev/null
+++ b/media/libmedia/xsd/Android.bp
@@ -0,0 +1,21 @@
+//
+// 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.
+// 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.
+//
+
+xsd_config {
+    name: "media_profiles",
+    srcs: ["media_profiles.xsd"],
+    package_name: "media.profiles",
+}
diff --git a/media/libmedia/xsd/api/current.txt b/media/libmedia/xsd/api/current.txt
new file mode 100644
index 0000000..0924dd9
--- /dev/null
+++ b/media/libmedia/xsd/api/current.txt
@@ -0,0 +1,140 @@
+// Signature format: 2.0
+package media.profiles {
+
+  public class Audio {
+    ctor public Audio();
+    method public int getBitRate();
+    method public int getChannels();
+    method public String getCodec();
+    method public int getSampleRate();
+    method public void setBitRate(int);
+    method public void setChannels(int);
+    method public void setCodec(String);
+    method public void setSampleRate(int);
+  }
+
+  public class AudioDecoderCap {
+    ctor public AudioDecoderCap();
+    method public boolean getEnabled();
+    method public String getName();
+    method public void setEnabled(boolean);
+    method public void setName(String);
+  }
+
+  public class AudioEncoderCap {
+    ctor public AudioEncoderCap();
+    method public boolean getEnabled();
+    method public int getMaxBitRate();
+    method public int getMaxChannels();
+    method public int getMaxSampleRate();
+    method public int getMinBitRate();
+    method public int getMinChannels();
+    method public int getMinSampleRate();
+    method public String getName();
+    method public void setEnabled(boolean);
+    method public void setMaxBitRate(int);
+    method public void setMaxChannels(int);
+    method public void setMaxSampleRate(int);
+    method public void setMinBitRate(int);
+    method public void setMinChannels(int);
+    method public void setMinSampleRate(int);
+    method public void setName(String);
+  }
+
+  public class CamcorderProfiles {
+    ctor public CamcorderProfiles();
+    method public int getCameraId();
+    method public java.util.List<media.profiles.EncoderProfile> getEncoderProfile();
+    method public java.util.List<media.profiles.CamcorderProfiles.ImageEncoding> getImageEncoding();
+    method public void setCameraId(int);
+  }
+
+  public static class CamcorderProfiles.ImageEncoding {
+    ctor public CamcorderProfiles.ImageEncoding();
+    method public int getQuality();
+    method public void setQuality(int);
+  }
+
+  public class EncoderProfile {
+    ctor public EncoderProfile();
+    method public java.util.List<media.profiles.Audio> getAudio();
+    method public int getDuration();
+    method public String getFileFormat();
+    method public String getQuality();
+    method public java.util.List<media.profiles.Video> getVideo();
+    method public void setDuration(int);
+    method public void setFileFormat(String);
+    method public void setQuality(String);
+  }
+
+  public class MediaSettings {
+    ctor public MediaSettings();
+    method public java.util.List<media.profiles.AudioDecoderCap> getAudioDecoderCap();
+    method public java.util.List<media.profiles.AudioEncoderCap> getAudioEncoderCap();
+    method public java.util.List<media.profiles.CamcorderProfiles> getCamcorderProfiles();
+    method public java.util.List<media.profiles.MediaSettings.EncoderOutputFileFormat> getEncoderOutputFileFormat();
+    method public java.util.List<media.profiles.VideoDecoderCap> getVideoDecoderCap();
+    method public java.util.List<media.profiles.VideoEncoderCap> getVideoEncoderCap();
+  }
+
+  public static class MediaSettings.EncoderOutputFileFormat {
+    ctor public MediaSettings.EncoderOutputFileFormat();
+    method public String getName();
+    method public void setName(String);
+  }
+
+  public class Video {
+    ctor public Video();
+    method public int getBitRate();
+    method public String getCodec();
+    method public int getFrameRate();
+    method public int getHeight();
+    method public int getWidth();
+    method public void setBitRate(int);
+    method public void setCodec(String);
+    method public void setFrameRate(int);
+    method public void setHeight(int);
+    method public void setWidth(int);
+  }
+
+  public class VideoDecoderCap {
+    ctor public VideoDecoderCap();
+    method public boolean getEnabled();
+    method public String getName();
+    method public void setEnabled(boolean);
+    method public void setName(String);
+  }
+
+  public class VideoEncoderCap {
+    ctor public VideoEncoderCap();
+    method public boolean getEnabled();
+    method public int getMaxBitRate();
+    method public int getMaxFrameHeight();
+    method public int getMaxFrameRate();
+    method public int getMaxFrameWidth();
+    method public int getMinBitRate();
+    method public int getMinFrameHeight();
+    method public int getMinFrameRate();
+    method public int getMinFrameWidth();
+    method public String getName();
+    method public void setEnabled(boolean);
+    method public void setMaxBitRate(int);
+    method public void setMaxFrameHeight(int);
+    method public void setMaxFrameRate(int);
+    method public void setMaxFrameWidth(int);
+    method public void setMinBitRate(int);
+    method public void setMinFrameHeight(int);
+    method public void setMinFrameRate(int);
+    method public void setMinFrameWidth(int);
+    method public void setName(String);
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method public static media.profiles.MediaSettings read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/media/libmedia/xsd/api/last_current.txt b/media/libmedia/xsd/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libmedia/xsd/api/last_current.txt
diff --git a/media/libmedia/xsd/api/last_removed.txt b/media/libmedia/xsd/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libmedia/xsd/api/last_removed.txt
diff --git a/media/libmedia/xsd/api/removed.txt b/media/libmedia/xsd/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/media/libmedia/xsd/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/libmedia/xsd/media_profiles.xsd b/media/libmedia/xsd/media_profiles.xsd
new file mode 100644
index 0000000..a9687b0
--- /dev/null
+++ b/media/libmedia/xsd/media_profiles.xsd
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+         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.
+-->
+<!-- TODO: define a targetNamespace. Note that it will break retrocompatibility -->
+<xs:schema version="2.0"
+           elementFormDefault="qualified"
+           attributeFormDefault="unqualified"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <xs:element name="MediaSettings">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="CamcorderProfiles" type="CamcorderProfiles" minOccurs="0" maxOccurs="unbounded"/>
+                <xs:element name="EncoderOutputFileFormat" minOccurs="0" maxOccurs="unbounded">
+                    <xs:complexType>
+                        <xs:attribute name="name" type="xs:string"/>
+                    </xs:complexType>
+                </xs:element>
+                <xs:element name="VideoEncoderCap" type="VideoEncoderCap" minOccurs="0" maxOccurs="unbounded"/>
+                <xs:element name="AudioEncoderCap" type="AudioEncoderCap" minOccurs="0" maxOccurs="unbounded"/>
+                <xs:element name="VideoDecoderCap" type="VideoDecoderCap" minOccurs="0" maxOccurs="unbounded"/>
+                <xs:element name="AudioDecoderCap" type="AudioDecoderCap" minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+    <xs:complexType name="CamcorderProfiles">
+        <xs:sequence>
+            <xs:element name="EncoderProfile" type="EncoderProfile" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="ImageEncoding" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="quality" type="xs:int"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+        <xs:attribute name="cameraId" type="xs:int"/>
+    </xs:complexType>
+    <xs:complexType name="EncoderProfile">
+        <xs:sequence>
+            <xs:element name="Video" type="Video" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="Audio" type="Audio" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="quality" type="xs:string"/>
+        <xs:attribute name="fileFormat" type="xs:string"/>
+        <xs:attribute name="duration" type="xs:int"/>
+    </xs:complexType>
+    <xs:complexType name="Video">
+        <xs:attribute name="codec" type="xs:string"/>
+        <xs:attribute name="bitRate" type="xs:int"/>
+        <xs:attribute name="width" type="xs:int"/>
+        <xs:attribute name="height" type="xs:int"/>
+        <xs:attribute name="frameRate" type="xs:int"/>
+    </xs:complexType>
+    <xs:complexType name="Audio">
+        <xs:attribute name="codec" type="xs:string"/>
+        <xs:attribute name="bitRate" type="xs:int"/>
+        <xs:attribute name="sampleRate" type="xs:int"/>
+        <xs:attribute name="channels" type="xs:int"/>
+    </xs:complexType>
+    <xs:complexType name="VideoEncoderCap">
+        <xs:attribute name="name" type="xs:string"/>
+        <xs:attribute name="enabled" type="xs:boolean"/>
+        <xs:attribute name="minBitRate" type="xs:int"/>
+        <xs:attribute name="maxBitRate" type="xs:int"/>
+        <xs:attribute name="minFrameWidth" type="xs:int"/>
+        <xs:attribute name="maxFrameWidth" type="xs:int"/>
+        <xs:attribute name="minFrameHeight" type="xs:int"/>
+        <xs:attribute name="maxFrameHeight" type="xs:int"/>
+        <xs:attribute name="minFrameRate" type="xs:int"/>
+        <xs:attribute name="maxFrameRate" type="xs:int"/>
+    </xs:complexType>
+    <xs:complexType name="AudioEncoderCap">
+        <xs:attribute name="name" type="xs:string"/>
+        <xs:attribute name="enabled" type="xs:boolean"/>
+        <xs:attribute name="minBitRate" type="xs:int"/>
+        <xs:attribute name="maxBitRate" type="xs:int"/>
+        <xs:attribute name="minSampleRate" type="xs:int"/>
+        <xs:attribute name="maxSampleRate" type="xs:int"/>
+        <xs:attribute name="minChannels" type="xs:int"/>
+        <xs:attribute name="maxChannels" type="xs:int"/>
+    </xs:complexType>
+    <xs:complexType name="VideoDecoderCap">
+        <xs:attribute name="name" type="xs:string"/>
+        <xs:attribute name="enabled" type="xs:boolean"/>
+    </xs:complexType>
+    <xs:complexType name="AudioDecoderCap">
+        <xs:attribute name="name" type="xs:string"/>
+        <xs:attribute name="enabled" type="xs:boolean"/>
+    </xs:complexType>
+</xs:schema>
diff --git a/media/libmediaplayer2/JAudioTrack.cpp b/media/libmediaplayer2/JAudioTrack.cpp
index a01afa3..fab6c64 100644
--- a/media/libmediaplayer2/JAudioTrack.cpp
+++ b/media/libmediaplayer2/JAudioTrack.cpp
@@ -571,10 +571,9 @@
 }
 
 void JAudioTrack::registerRoutingDelegates(
-        std::vector<std::pair<jobject, jobject>>& routingDelegates) {
-    for (std::vector<std::pair<jobject, jobject>>::iterator it = routingDelegates.begin();
-            it != routingDelegates.end(); it++) {
-        addAudioDeviceCallback(it->second, getHandler(it->second));
+        Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& routingDelegates) {
+    for (auto it = routingDelegates.begin(); it != routingDelegates.end(); it++) {
+        addAudioDeviceCallback(it->second->getJObject(), getHandler(it->second->getJObject()));
     }
 }
 
@@ -597,34 +596,22 @@
     return env->CallObjectMethod(routingDelegateObj, jGetHandler);
 }
 
-jobject JAudioTrack::addGlobalRef(const jobject obj) {
+jobject JAudioTrack::findByKey(
+        Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key) {
     JNIEnv *env = JavaVMHelper::getJNIEnv();
-    return reinterpret_cast<jobject>(env->NewGlobalRef(obj));
-}
-
-status_t JAudioTrack::removeGlobalRef(const jobject obj) {
-    if (obj == NULL) {
-        return BAD_VALUE;
-    }
-    JNIEnv *env = JavaVMHelper::getJNIEnv();
-    env->DeleteGlobalRef(obj);
-    return NO_ERROR;
-}
-
-jobject JAudioTrack::findByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
-    JNIEnv *env = JavaVMHelper::getJNIEnv();
-    for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
-        if (env->IsSameObject(it->first, key)) {
-            return it->second;
+    for (auto it = mp.begin(); it != mp.end(); it++) {
+        if (env->IsSameObject(it->first->getJObject(), key)) {
+            return it->second->getJObject();
         }
     }
     return nullptr;
 }
 
-void JAudioTrack::eraseByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
+void JAudioTrack::eraseByKey(
+        Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key) {
     JNIEnv *env = JavaVMHelper::getJNIEnv();
-    for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
-        if (env->IsSameObject(it->first, key)) {
+    for (auto it = mp.begin(); it != mp.end(); it++) {
+        if (env->IsSameObject(it->first->getJObject(), key)) {
             mp.erase(it);
             return;
         }
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
index 4de92ad..b4fa0c1 100644
--- a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
+++ b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
@@ -85,9 +85,6 @@
 }
 
 MediaPlayer2AudioOutput::~MediaPlayer2AudioOutput() {
-    for (auto routingDelegate : mRoutingDelegates) {
-        JAudioTrack::removeGlobalRef(routingDelegate.second);
-    }
     close();
     delete mCallbackData;
 }
@@ -525,12 +522,18 @@
     ALOGV("addAudioDeviceCallback");
     Mutex::Autolock lock(mLock);
     jobject listener = JAudioTrack::getListener(jRoutingDelegate);
-    if (mJAudioTrack != nullptr &&
-        JAudioTrack::findByKey(mRoutingDelegates, listener) == nullptr) {
+    if (JAudioTrack::findByKey(mRoutingDelegates, listener) == nullptr) {
+        sp<JObjectHolder> listenerHolder = new JObjectHolder(listener);
         jobject handler = JAudioTrack::getHandler(jRoutingDelegate);
-        jobject routingDelegate = JAudioTrack::addGlobalRef(jRoutingDelegate);
-        mRoutingDelegates.push_back(std::pair<jobject, jobject>(listener, routingDelegate));
-        return mJAudioTrack->addAudioDeviceCallback(routingDelegate, handler);
+        sp<JObjectHolder> routingDelegateHolder = new JObjectHolder(jRoutingDelegate);
+
+        mRoutingDelegates.push_back(std::pair<sp<JObjectHolder>, sp<JObjectHolder>>(
+                listenerHolder, routingDelegateHolder));
+
+        if (mJAudioTrack != nullptr) {
+            return mJAudioTrack->addAudioDeviceCallback(
+                    routingDelegateHolder->getJObject(), handler);
+        }
     }
     return NO_ERROR;
 }
@@ -539,13 +542,11 @@
     ALOGV("removeAudioDeviceCallback");
     Mutex::Autolock lock(mLock);
     jobject routingDelegate = nullptr;
-    if (mJAudioTrack != nullptr &&
-        (routingDelegate = JAudioTrack::findByKey(mRoutingDelegates, listener)) != nullptr) {
-        mJAudioTrack->removeAudioDeviceCallback(routingDelegate);
-        JAudioTrack::eraseByKey(mRoutingDelegates, listener);
-        if (JAudioTrack::removeGlobalRef(routingDelegate) != NO_ERROR) {
-            return BAD_VALUE;
+    if ((routingDelegate = JAudioTrack::findByKey(mRoutingDelegates, listener)) != nullptr) {
+        if (mJAudioTrack != nullptr) {
+            mJAudioTrack->removeAudioDeviceCallback(routingDelegate);
         }
+        JAudioTrack::eraseByKey(mRoutingDelegates, listener);
     }
     return NO_ERROR;
 }
diff --git a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
index 87dc889..2ed4632 100644
--- a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
+++ b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
@@ -17,7 +17,6 @@
 #ifndef ANDROID_JAUDIOTRACK_H
 #define ANDROID_JAUDIOTRACK_H
 
-#include <vector>
 #include <utility>
 #include <jni.h>
 #include <media/AudioResamplerPublic.h>
@@ -25,6 +24,7 @@
 #include <media/VolumeShaper.h>
 #include <system/audio.h>
 #include <utils/Errors.h>
+#include <utils/Vector.h>
 #include <mediaplayer2/JObjectHolder.h>
 #include <media/AudioTimestamp.h>   // It has dependency on audio.h/Errors.h, but doesn't
                                     // include them in it. Therefore it is included here at last.
@@ -405,7 +405,8 @@
      * routingDelegates: backed-up routing delegates
      *
      */
-    void registerRoutingDelegates(std::vector<std::pair<jobject, jobject>>& routingDelegates);
+    void registerRoutingDelegates(
+            Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& routingDelegates);
 
     /* get listener from RoutingDelegate object
      */
@@ -415,17 +416,6 @@
      */
     static jobject getHandler(const jobject routingDelegateObj);
 
-    /* convert local reference to global reference.
-     */
-    static jobject addGlobalRef(const jobject obj);
-
-    /* erase global reference.
-     *
-     * Returns NO_ERROR if succeeds
-     *         BAD_VALUE if obj is NULL
-     */
-    static status_t removeGlobalRef(const jobject obj);
-
     /*
      * Parameters:
      * map and key
@@ -433,13 +423,15 @@
      * Returns value if key is in the map
      *         nullptr if key is not in the map
      */
-    static jobject findByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key);
+    static jobject findByKey(
+            Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key);
 
     /*
      * Parameters:
      * map and key
      */
-    static void eraseByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key);
+    static void eraseByKey(
+            Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key);
 
 private:
     audio_output_flags_t mFlags;
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
index bda4f61..f38b7cc 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
@@ -22,7 +22,6 @@
 #include <mediaplayer2/JAudioTrack.h>
 #include <mediaplayer2/JObjectHolder.h>
 
-#include <vector>
 #include <utility>
 #include <utils/String16.h>
 #include <utils/Vector.h>
@@ -125,7 +124,9 @@
     audio_output_flags_t    mFlags;
     sp<JObjectHolder>       mPreferredDevice;
     mutable Mutex           mLock;
-    std::vector<std::pair<jobject, jobject>> mRoutingDelegates; // <listener, routingDelegate>
+
+    // <listener, routingDelegate>
+    Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>> mRoutingDelegates;
 
     // static variables below not protected by mutex
     static bool             mIsOnEmulator;
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 3fa8e3f..d6628d9 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -538,6 +538,22 @@
     return NO_INIT;
 }
 
+status_t MediaRecorderClient::setMicrophoneDirection(audio_microphone_direction_t direction) {
+    ALOGV("setMicrophoneDirection(%d)", direction);
+    if (mRecorder != NULL) {
+        return mRecorder->setMicrophoneDirection(direction);
+    }
+    return NO_INIT;
+}
+
+status_t MediaRecorderClient::setMicrophoneFieldDimension(float zoom) {
+    ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+    if (mRecorder != NULL) {
+        return mRecorder->setMicrophoneFieldDimension(zoom);
+    }
+    return NO_INIT;
+}
+
 status_t MediaRecorderClient::getPortId(audio_port_handle_t *portId) {
     ALOGV("getPortId");
     Mutex::Autolock lock(mLock);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 303cefc..8da718f 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -109,6 +109,8 @@
     virtual     status_t   enableAudioDeviceCallback(bool enabled);
     virtual     status_t   getActiveMicrophones(
                               std::vector<media::MicrophoneInfo>* activeMicrophones);
+    virtual     status_t   setMicrophoneDirection(audio_microphone_direction_t direction);
+    virtual     status_t   setMicrophoneFieldDimension(float zoom);
                 status_t   getPortId(audio_port_handle_t *portId) override;
 
 private:
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index d111313..77777b8 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -118,7 +118,9 @@
       mVideoSource(VIDEO_SOURCE_LIST_END),
       mStarted(false),
       mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
-      mDeviceCallbackEnabled(false) {
+      mDeviceCallbackEnabled(false),
+      mSelectedMicDirection(MIC_DIRECTION_UNSPECIFIED),
+      mSelectedMicFieldDimension(MIC_FIELD_DIMENSION_NORMAL) {
 
     ALOGV("Constructor");
 
@@ -398,14 +400,15 @@
         return -EBADF;
     }
 
-    // start with a clean, empty file
-    ftruncate(fd, 0);
-    int nextFd = dup(fd);
-    if (mWriter == NULL) {
+    if (mWriter == nullptr) {
         ALOGE("setNextOutputFile failed. Writer has been freed");
         return INVALID_OPERATION;
     }
-    return mWriter->setNextFd(nextFd);
+
+    // start with a clean, empty file
+    ftruncate(fd, 0);
+
+    return mWriter->setNextFd(fd);
 }
 
 // Attempt to parse an float literal optionally surrounded by whitespace,
@@ -1090,7 +1093,9 @@
                 mSampleRate,
                 mClientUid,
                 mClientPid,
-                mSelectedDeviceId);
+                mSelectedDeviceId,
+                mSelectedMicDirection,
+                mSelectedMicFieldDimension);
 
     status_t err = audioSource->initCheck();
 
@@ -2269,6 +2274,24 @@
     return NO_INIT;
 }
 
+status_t StagefrightRecorder::setMicrophoneDirection(audio_microphone_direction_t direction) {
+    ALOGV("setMicrophoneDirection(%d)", direction);
+    mSelectedMicDirection = direction;
+    if (mAudioSourceNode != 0) {
+        return mAudioSourceNode->setMicrophoneDirection(direction);
+    }
+    return NO_INIT;
+}
+
+status_t StagefrightRecorder::setMicrophoneFieldDimension(float zoom) {
+    ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+    mSelectedMicFieldDimension = zoom;
+    if (mAudioSourceNode != 0) {
+        return mAudioSourceNode->setMicrophoneFieldDimension(zoom);
+    }
+    return NO_INIT;
+}
+
 status_t StagefrightRecorder::getPortId(audio_port_handle_t *portId) const {
     if (mAudioSourceNode != 0) {
         return mAudioSourceNode->getPortId(portId);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index a292e58..236b19e 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -77,6 +77,8 @@
     virtual void setAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
     virtual status_t enableAudioDeviceCallback(bool enabled);
     virtual status_t getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
+    virtual status_t setMicrophoneDirection(audio_microphone_direction_t direction);
+    virtual status_t setMicrophoneFieldDimension(float zoom);
             status_t getPortId(audio_port_handle_t *portId) const override;
 
 private:
@@ -159,6 +161,9 @@
     bool mDeviceCallbackEnabled;
     wp<AudioSystem::AudioDeviceCallback> mAudioDeviceCallback;
 
+    audio_microphone_direction_t mSelectedMicDirection;
+    float mSelectedMicFieldDimension;
+
     static const int kMaxHighSpeedFps = 1000;
 
     status_t prepareInternal();
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 9eba7e9..e173974 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -154,11 +154,11 @@
     mDone = true;
 
     void *dummy;
+    status_t status = mSource->stop();
     pthread_join(mThread, &dummy);
 
     status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
     {
-        status_t status = mSource->stop();
         if (err == OK &&
             (status != OK && status != ERROR_END_OF_STREAM)) {
             err = status;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 1dee4f7..f00c895 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -6667,7 +6667,7 @@
         return false;
     }
 
-    mDeathNotifier = new DeathNotifier(notify);
+    mDeathNotifier = new DeathNotifier(new AMessage(kWhatOMXDied, mCodec));
     auto tOmxNode = omxNode->getHalInterface<IOmxNode>();
     if (tOmxNode && !tOmxNode->linkToDeath(mDeathNotifier, 0)) {
         mDeathNotifier.clear();
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 41106a1..24f6f0b 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -149,11 +149,11 @@
     mDone = true;
 
     void *dummy;
+    status_t status = mSource->stop();
     pthread_join(mThread, &dummy);
 
     status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
     {
-        status_t status = mSource->stop();
         if (err == OK &&
             (status != OK && status != ERROR_END_OF_STREAM)) {
             err = status;
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index d8b825d..dc51b16 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -225,6 +225,7 @@
     ],
 
     export_shared_lib_headers: [
+        "libgui",
         "libmedia",
         "android.hidl.allocator@1.0",
     ],
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 5027303..5f86bd3 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -52,7 +52,9 @@
 AudioSource::AudioSource(
         audio_source_t inputSource, const String16 &opPackageName,
         uint32_t sampleRate, uint32_t channelCount, uint32_t outSampleRate,
-        uid_t uid, pid_t pid, audio_port_handle_t selectedDeviceId)
+        uid_t uid, pid_t pid, audio_port_handle_t selectedDeviceId,
+        audio_microphone_direction_t selectedMicDirection,
+        float selectedMicFieldDimension)
     : mStarted(false),
       mSampleRate(sampleRate),
       mOutSampleRate(outSampleRate > 0 ? outSampleRate : sampleRate),
@@ -103,7 +105,9 @@
                     uid,
                     pid,
                     NULL /*pAttributes*/,
-                    selectedDeviceId);
+                    selectedDeviceId,
+                    selectedMicDirection,
+                    selectedMicFieldDimension);
         mInitCheck = mRecord->initCheck();
         if (mInitCheck != OK) {
             mRecord.clear();
@@ -506,6 +510,22 @@
     return NO_INIT;
 }
 
+status_t AudioSource::setMicrophoneDirection(audio_microphone_direction_t direction) {
+    ALOGV("setMicrophoneDirection(%d)", direction);
+    if (mRecord != 0) {
+        return mRecord->setMicrophoneDirection(direction);
+    }
+    return NO_INIT;
+}
+
+status_t AudioSource::setMicrophoneFieldDimension(float zoom) {
+    ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+    if (mRecord != 0) {
+        return mRecord->setMicrophoneFieldDimension(zoom);
+    }
+    return NO_INIT;
+}
+
 status_t AudioSource::getPortId(audio_port_handle_t *portId) const {
     if (mRecord != 0) {
         *portId = mRecord->getPortId();
diff --git a/media/libstagefright/HevcUtils.cpp b/media/libstagefright/HevcUtils.cpp
index f152a38..482a1a7 100644
--- a/media/libstagefright/HevcUtils.cpp
+++ b/media/libstagefright/HevcUtils.cpp
@@ -312,14 +312,23 @@
             for (uint32_t j = 0; j < numPics; ++j) {
                 skipUE(&reader); // delta_poc_s0|1_minus1[i]
                 reader.skipBits(1); // used_by_curr_pic_s0|1_flag[i]
+                if (reader.overRead()) {
+                    return ERROR_MALFORMED;
+                }
             }
         }
+        if (reader.overRead()) {
+            return ERROR_MALFORMED;
+        }
     }
     if (reader.getBitsWithFallback(1, 0)) { // long_term_ref_pics_present_flag
         uint32_t numLongTermRefPicSps = parseUEWithFallback(&reader, 0);
         for (uint32_t i = 0; i < numLongTermRefPicSps; ++i) {
             reader.skipBits(log2MaxPicOrderCntLsb); // lt_ref_pic_poc_lsb_sps[i]
             reader.skipBits(1); // used_by_curr_pic_lt_sps_flag[i]
+            if (reader.overRead()) {
+                return ERROR_MALFORMED;
+            }
         }
     }
     reader.skipBits(1); // sps_temporal_mvp_enabled_flag
@@ -457,8 +466,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..a52da45 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -460,7 +460,7 @@
 };
 
 MPEG4Writer::MPEG4Writer(int fd) {
-    initInternal(fd, true /*isFirstSession*/);
+    initInternal(dup(fd), true /*isFirstSession*/);
 }
 
 MPEG4Writer::~MPEG4Writer() {
@@ -481,7 +481,7 @@
 
 void MPEG4Writer::initInternal(int fd, bool isFirstSession) {
     ALOGV("initInternal");
-    mFd = dup(fd);
+    mFd = fd;
     mNextFd = -1;
     mInitCheck = mFd < 0? NO_INIT: OK;
 
@@ -1044,6 +1044,10 @@
 void MPEG4Writer::release() {
     close(mFd);
     mFd = -1;
+    if (mNextFd != -1) {
+        close(mNextFd);
+        mNextFd = -1;
+    }
     mInitCheck = NO_INIT;
     mStarted = false;
     free(mInMemoryCache);
@@ -1981,7 +1985,7 @@
         // No need to set a new FD yet.
         return INVALID_OPERATION;
     }
-    mNextFd = fd;
+    mNextFd = dup(fd);
     return OK;
 }
 
@@ -2180,11 +2184,11 @@
     switch (msg->what()) {
         case kWhatSwitch:
         {
-            finishCurrentSession();
             mLock.lock();
             int fd = mNextFd;
             mNextFd = -1;
             mLock.unlock();
+            finishCurrentSession();
             initInternal(fd, false /*isFirstSession*/);
             start(mStartMeta.get());
             mSwitchPending = false;
@@ -3128,8 +3132,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/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/Utils.cpp b/media/libstagefright/Utils.cpp
index 16b3319..2aa9ed8 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -642,6 +642,15 @@
         { "icc-profile", kKeyIccProfile },
         { "sei", kKeySEI },
         { "text-format-data", kKeyTextFormatData },
+        { "thumbnail-csd-hevc", kKeyThumbnailHVCC },
+    }
+};
+
+static std::vector<std::pair<const char *, uint32_t>> CSDMappings {
+    {
+        { "csd-0", kKeyOpaqueCSD0 },
+        { "csd-1", kKeyOpaqueCSD1 },
+        { "csd-2", kKeyOpaqueCSD2 },
     }
 };
 
@@ -681,6 +690,14 @@
                     MetaDataBase::Type::TYPE_NONE, value->data(), value->size());
         }
     }
+
+    for (auto elem : CSDMappings) {
+        sp<ABuffer> value;
+        if (msg->findBuffer(elem.first, &value)) {
+            meta->setData(elem.second,
+                    MetaDataBase::Type::TYPE_NONE, value->data(), value->size());
+        }
+    }
 }
 
 void convertMetaDataToMessageFromMappings(const MetaDataBase *meta, sp<AMessage> format) {
@@ -721,6 +738,18 @@
             format->setBuffer(elem.first, buf);
         }
     }
+
+    for (auto elem : CSDMappings) {
+        uint32_t type;
+        const void* data;
+        size_t size;
+        if (meta->findData(elem.second, &type, &data, &size)) {
+            sp<ABuffer> buf = ABuffer::CreateAsCopy(data, size);
+            buf->meta()->setInt32("csd", true);
+            buf->meta()->setInt64("timeUs", 0);
+            format->setBuffer(elem.first, buf);
+        }
+    }
 }
 
 status_t convertMetaDataToMessage(
@@ -1248,30 +1277,6 @@
     } else if (meta->findData(kKeyD263, &type, &data, &size)) {
         const uint8_t *ptr = (const uint8_t *)data;
         parseH263ProfileLevelFromD263(ptr, size, msg);
-    } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
-        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
-        if (buffer.get() == NULL || buffer->base() == NULL) {
-            return NO_MEMORY;
-        }
-        memcpy(buffer->data(), data, size);
-
-        buffer->meta()->setInt32("csd", true);
-        buffer->meta()->setInt64("timeUs", 0);
-        msg->setBuffer("csd-0", buffer);
-
-        if (!meta->findData(kKeyVorbisBooks, &type, &data, &size)) {
-            return -EINVAL;
-        }
-
-        buffer = new (std::nothrow) ABuffer(size);
-        if (buffer.get() == NULL || buffer->base() == NULL) {
-            return NO_MEMORY;
-        }
-        memcpy(buffer->data(), data, size);
-
-        buffer->meta()->setInt32("csd", true);
-        buffer->meta()->setInt64("timeUs", 0);
-        msg->setBuffer("csd-1", buffer);
     } else if (meta->findData(kKeyOpusHeader, &type, &data, &size)) {
         sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
         if (buffer.get() == NULL || buffer->base() == NULL) {
@@ -1310,16 +1315,6 @@
         buffer->meta()->setInt32("csd", true);
         buffer->meta()->setInt64("timeUs", 0);
         msg->setBuffer("csd-2", buffer);
-    } else if (meta->findData(kKeyFlacMetadata, &type, &data, &size)) {
-        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
-        if (buffer.get() == NULL || buffer->base() == NULL) {
-            return NO_MEMORY;
-        }
-        memcpy(buffer->data(), data, size);
-
-        buffer->meta()->setInt32("csd", true);
-        buffer->meta()->setInt64("timeUs", 0);
-        msg->setBuffer("csd-0", buffer);
     } else if (meta->findData(kKeyVp9CodecPrivate, &type, &data, &size)) {
         sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
         if (buffer.get() == NULL || buffer->base() == NULL) {
@@ -1796,11 +1791,6 @@
             if (seekPreRollBuf) {
                 meta->setData(kKeyOpusSeekPreRoll, 0, seekPreRollBuf, seekPreRollBufSize);
             }
-        } else if (mime == MEDIA_MIMETYPE_AUDIO_VORBIS) {
-            meta->setData(kKeyVorbisInfo, 0, csd0->data(), csd0->size());
-            if (msg->findBuffer("csd-1", &csd1)) {
-                meta->setData(kKeyVorbisBooks, 0, csd1->data(), csd1->size());
-            }
         } else if (mime == MEDIA_MIMETYPE_AUDIO_ALAC) {
             meta->setData(kKeyAlacMagicCookie, 0, csd0->data(), csd0->size());
         }
diff --git a/media/libstagefright/VideoFrameScheduler2.cpp b/media/libstagefright/VideoFrameScheduler2.cpp
index fc76904..23671f2 100644
--- a/media/libstagefright/VideoFrameScheduler2.cpp
+++ b/media/libstagefright/VideoFrameScheduler2.cpp
@@ -160,13 +160,13 @@
     mPhase = (long) (atan2(sampleAvgY, sampleAvgX) / scale);
 }
 
-static void frameCallback(long frameTimeNanos, void* data) {
+static void frameCallback(int64_t frameTimeNanos, void* data) {
     if (data == NULL) {
         return;
     }
     sp<VsyncTracker> vsyncTracker(static_cast<VsyncTracker*>(data));
     vsyncTracker->addSample(frameTimeNanos);
-    AChoreographer_postFrameCallback(AChoreographer_getInstance(),
+    AChoreographer_postFrameCallback64(AChoreographer_getInstance(),
             frameCallback, static_cast<void*>(vsyncTracker.get()));
 }
 
@@ -247,7 +247,7 @@
     if (AChoreographer_getInstance() == NULL) {
         return NO_INIT;
     }
-    AChoreographer_postFrameCallback(AChoreographer_getInstance(), frameCallback, mData);
+    AChoreographer_postFrameCallback64(AChoreographer_getInstance(), frameCallback, mData);
     return OK;
 }
 
diff --git a/media/libstagefright/codecs/m4v_h263/enc/test/m4v_h263_enc_test.cpp b/media/libstagefright/codecs/m4v_h263/enc/test/m4v_h263_enc_test.cpp
index db2c61a..5554ebd 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/test/m4v_h263_enc_test.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/test/m4v_h263_enc_test.cpp
@@ -183,6 +183,10 @@
     // Initialize the encoder.
     if (!PVInitVideoEncoder(&handle, &encParams)) {
         fprintf(stderr, "Failed to initialize the encoder\n");
+        fclose(fpInput);
+        fclose(fpOutput);
+        free(inputBuf);
+        free(outputBuf);
         return EXIT_FAILURE;
     }
 
@@ -190,6 +194,10 @@
     int32_t headerLength = kOutputBufferSize;
     if (!PVGetVolHeader(&handle, outputBuf, &headerLength, 0)) {
         fprintf(stderr, "Failed to get VOL header\n");
+        fclose(fpInput);
+        fclose(fpOutput);
+        free(inputBuf);
+        free(outputBuf);
         return EXIT_FAILURE;
     }
     fwrite(outputBuf, 1, headerLength, fpOutput);
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index 9d1ec1f..52b2765 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -32,6 +32,10 @@
 const char *MEDIA_MIMETYPE_VIDEO_RAW = "video/raw";
 const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
 const char *MEDIA_MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX = "video/divx";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX3 = "video/divx3";
+const char *MEDIA_MIMETYPE_VIDEO_XVID = "video/xvid";
+const char *MEDIA_MIMETYPE_VIDEO_MJPEG = "video/x-motion-jpeg";
 
 const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
 const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
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/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index e68852d..007a09b 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -34,6 +34,10 @@
 extern const char *MEDIA_MIMETYPE_VIDEO_RAW;
 extern const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION;
 extern const char *MEDIA_MIMETYPE_VIDEO_SCRAMBLED;
+extern const char *MEDIA_MIMETYPE_VIDEO_DIVX;
+extern const char *MEDIA_MIMETYPE_VIDEO_DIVX3;
+extern const char *MEDIA_MIMETYPE_VIDEO_XVID;
+extern const char *MEDIA_MIMETYPE_VIDEO_MJPEG;
 
 extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
 extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
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/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index b2361b8..cb97a3c 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -1397,6 +1397,18 @@
         case 'ulaw':
         case 'vdva':
         case 'ac-4':
+        case 'Opus':
+        case 'a3ds':
+        case 'dts+':
+        case 'dts-':
+        case 'dtsx':
+        case 'dtsy':
+        case 'ec+3':
+        case 'mha1':
+        case 'mha2':
+        case 'mhm1':
+        case 'mhm2':
+        case 'sevs':
             return !strcmp("audio", type);
 
         case 'avc1':
@@ -1445,6 +1457,35 @@
         case 'tga ':
         case 'tiff':
         case 'WRLE':
+        case 'a3d1':
+        case 'a3d2':
+        case 'a3d3':
+        case 'a3d4':
+        case 'avc3':
+        case 'avc4':
+        case 'dva1':
+        case 'dvav':
+        case 'dvh1':
+        case 'dvhe':
+        case 'hev1':
+        case 'hev2':
+        case 'hvc1':
+        case 'hvc2':
+        case 'hvt1':
+        case 'lhe1':
+        case 'lht1':
+        case 'lhv1':
+        case 'mjpg':
+        case 'mvc3':
+        case 'mvc4':
+        case 'mvd1':
+        case 'mvd2':
+        case 'mvd3':
+        case 'mvd4':
+        case 'rv60':
+        case 'svc2':
+        case 'vp08':
+        case 'vp09':
             return !strcmp("video", type);
 
         default:
diff --git a/media/libstagefright/include/media/stagefright/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h
index b0e32d0..18e5f10 100644
--- a/media/libstagefright/include/media/stagefright/AudioSource.h
+++ b/media/libstagefright/include/media/stagefright/AudioSource.h
@@ -44,7 +44,9 @@
             uint32_t outSampleRate = 0,
             uid_t uid = -1,
             pid_t pid = -1,
-            audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
+            audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
+            audio_microphone_direction_t selectedMicDirection = MIC_DIRECTION_UNSPECIFIED,
+            float selectedMicFieldDimension = MIC_FIELD_DIMENSION_NORMAL);
 
     status_t initCheck() const;
 
@@ -68,6 +70,8 @@
     status_t removeAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
 
     status_t getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
+    status_t setMicrophoneDirection(audio_microphone_direction_t direction);
+    status_t setMicrophoneFieldDimension(float zoom);
 
     status_t getPortId(audio_port_handle_t *portId) const;
 
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index a0407af..75fd0d9 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -67,7 +67,6 @@
     kKeyOpusHeader        = 'ohdr',  // raw data
     kKeyOpusCodecDelay    = 'ocod',  // uint64_t (codec delay in ns)
     kKeyOpusSeekPreRoll   = 'ospr',  // uint64_t (seek preroll in ns)
-    kKeyFlacMetadata      = 'flMd',  // raw data
     kKeyVp9CodecPrivate   = 'vp9p',  // raw data (vp9 csd information)
     kKeyIsSyncFrame       = 'sync',  // int32_t (bool)
     kKeyIsCodecConfig     = 'conf',  // int32_t (bool)
@@ -234,6 +233,11 @@
 
     // AC-4 AudioPresentationInfo
     kKeyAudioPresentationInfo = 'audP',  // raw data
+
+    // opaque codec specific data being passed from extractor to codec
+    kKeyOpaqueCSD0       = 'csd0',
+    kKeyOpaqueCSD1       = 'csd1',
+    kKeyOpaqueCSD2       = 'csd2',
 };
 
 enum {
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index b91edcd..5af7b23 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -1526,6 +1526,7 @@
                 header, &frameSize, &samplingRate, &numChannels,
                 &bitrate, &numSamples)) {
         ALOGE("Failed to get audio frame size");
+        mBuffer->setRange(0, 0);
         return NULL;
     }
 
@@ -1550,6 +1551,22 @@
         return NULL;
     }
 
+    if (mFormat != NULL) {
+        const char *mime;
+        if (mFormat->findCString(kKeyMIMEType, &mime)) {
+            if ((layer == 1) && strcmp (mime, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I)) {
+                ALOGE("Audio layer is not MPEG_LAYER_I");
+                return NULL;
+            } else if ((layer == 2) && strcmp (mime, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II)) {
+                ALOGE("Audio layer is not MPEG_LAYER_II");
+                return NULL;
+            } else if ((layer == 3) && strcmp (mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+                ALOGE("Audio layer is not AUDIO_MPEG");
+                return NULL;
+            }
+        }
+    }
+
     accessUnit->meta()->setInt64("timeUs", timeUs);
     accessUnit->meta()->setInt32("isSync", 1);
 
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index b964bc0..1aa8a20 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -376,8 +376,8 @@
     ALOGI("VOL dimensions = %dx%d", *width, *height);
 
     size_t len1 = config->size() + GetSizeWidth(config->size()) + 1;
-    size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13;
-    size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3;
+    size_t len2 = len1 + GetSizeWidth(len1 + 13) + 1 + 13;
+    size_t len3 = len2 + GetSizeWidth(len2 + 3) + 1 + 3;
 
     sp<ABuffer> csd = new ABuffer(len3);
     uint8_t *dst = csd->data();
diff --git a/media/libstagefright/xmlparser/Android.bp b/media/libstagefright/xmlparser/Android.bp
index 819058c..202e964 100644
--- a/media/libstagefright/xmlparser/Android.bp
+++ b/media/libstagefright/xmlparser/Android.bp
@@ -10,7 +10,6 @@
     vndk: {
         enabled: true,
     },
-    double_loadable: true,
 
     srcs: [
         "MediaCodecsXmlParser.cpp",
@@ -47,3 +46,9 @@
 
 }
 
+xsd_config {
+    name: "media_codecs",
+    srcs: ["media_codecs.xsd"],
+    package_name: "media.codecs",
+}
+
diff --git a/media/libstagefright/xmlparser/api/current.txt b/media/libstagefright/xmlparser/api/current.txt
new file mode 100644
index 0000000..f5245c1
--- /dev/null
+++ b/media/libstagefright/xmlparser/api/current.txt
@@ -0,0 +1,108 @@
+// Signature format: 2.0
+package media.codecs {
+
+  public class Decoders {
+    ctor public Decoders();
+    method public java.util.List<media.codecs.MediaCodec> getMediaCodec();
+  }
+
+  public class Encoders {
+    ctor public Encoders();
+    method public java.util.List<media.codecs.MediaCodec> getMediaCodec();
+  }
+
+  public class Feature {
+    ctor public Feature();
+    method public String getName();
+    method public String getOptional();
+    method public String getRequired();
+    method public String getValue();
+    method public void setName(String);
+    method public void setOptional(String);
+    method public void setRequired(String);
+    method public void setValue(String);
+  }
+
+  public class Limit {
+    ctor public Limit();
+    method public String getIn();
+    method public String getMax();
+    method public String getMin();
+    method public String getName();
+    method public String getRange();
+    method public String getRanges();
+    method public String getScale();
+    method public String getValue();
+    method public String get_default();
+    method public void setIn(String);
+    method public void setMax(String);
+    method public void setMin(String);
+    method public void setName(String);
+    method public void setRange(String);
+    method public void setRanges(String);
+    method public void setScale(String);
+    method public void setValue(String);
+    method public void set_default(String);
+  }
+
+  public class MediaCodec {
+    ctor public MediaCodec();
+    method public java.util.List<media.codecs.Feature> getFeature();
+    method public java.util.List<media.codecs.Limit> getLimit();
+    method public String getName();
+    method public java.util.List<media.codecs.Quirk> getQuirk();
+    method public java.util.List<media.codecs.Type> getType();
+    method public String getType();
+    method public String getUpdate();
+    method public void setName(String);
+    method public void setType(String);
+    method public void setUpdate(String);
+  }
+
+  public class MediaCodecs {
+    ctor public MediaCodecs();
+    method public java.util.List<media.codecs.Decoders> getDecoders();
+    method public java.util.List<media.codecs.Encoders> getEncoders();
+    method public java.util.List<media.codecs.Settings> getSettings();
+  }
+
+  public class Quirk {
+    ctor public Quirk();
+    method public String getName();
+    method public void setName(String);
+  }
+
+  public class Setting {
+    ctor public Setting();
+    method public String getName();
+    method public String getUpdate();
+    method public String getValue();
+    method public void setName(String);
+    method public void setUpdate(String);
+    method public void setValue(String);
+  }
+
+  public class Settings {
+    ctor public Settings();
+    method public java.util.List<media.codecs.Setting> getSetting();
+  }
+
+  public class Type {
+    ctor public Type();
+    method public java.util.List<media.codecs.Feature> getFeature();
+    method public java.util.List<media.codecs.Limit> getLimit();
+    method public String getName();
+    method public String getUpdate();
+    method public void setName(String);
+    method public void setUpdate(String);
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method public static media.codecs.MediaCodecs read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/media/libstagefright/xmlparser/api/last_current.txt b/media/libstagefright/xmlparser/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libstagefright/xmlparser/api/last_current.txt
diff --git a/media/libstagefright/xmlparser/api/last_removed.txt b/media/libstagefright/xmlparser/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libstagefright/xmlparser/api/last_removed.txt
diff --git a/media/libstagefright/xmlparser/api/removed.txt b/media/libstagefright/xmlparser/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/media/libstagefright/xmlparser/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/libstagefright/xmlparser/media_codecs.xsd b/media/libstagefright/xmlparser/media_codecs.xsd
new file mode 100644
index 0000000..4faba87
--- /dev/null
+++ b/media/libstagefright/xmlparser/media_codecs.xsd
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+         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.
+-->
+<!-- TODO: define a targetNamespace. Note that it will break retrocompatibility -->
+<xs:schema version="2.0"
+           elementFormDefault="qualified"
+           attributeFormDefault="unqualified"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <xs:element name="MediaCodecs">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="Decoders" type="Decoders" maxOccurs="unbounded"/>
+                <xs:element name="Encoders" type="Encoders" maxOccurs="unbounded"/>
+                <xs:element name="Settings" type="Settings" maxOccurs="unbounded"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+    <xs:complexType name="Decoders">
+        <xs:sequence>
+            <xs:element name="MediaCodec" type="MediaCodec" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="Encoders">
+        <xs:sequence>
+            <xs:element name="MediaCodec" type="MediaCodec" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="Settings">
+        <xs:sequence>
+            <xs:element name="Setting" type="Setting" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="MediaCodec">
+        <xs:sequence>
+            <xs:element name="Quirk" type="Quirk" maxOccurs="unbounded"/>
+            <xs:element name="Type" type="Type" maxOccurs="unbounded"/>
+            <xs:element name="Limit" type="Limit" maxOccurs="unbounded"/>
+            <xs:element name="Feature" type="Feature" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="name" type="xs:string"/>
+        <xs:attribute name="type" type="xs:string"/>
+        <xs:attribute name="update" type="xs:string"/>
+    </xs:complexType>
+    <xs:complexType name="Quirk">
+        <xs:attribute name="name" type="xs:string"/>
+    </xs:complexType>
+    <xs:complexType name="Type">
+        <xs:sequence>
+            <xs:element name="Limit" type="Limit" maxOccurs="unbounded"/>
+            <xs:element name="Feature" type="Feature" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="name" type="xs:string"/>
+        <xs:attribute name="update" type="xs:string"/>
+    </xs:complexType>
+    <xs:complexType name="Limit">
+        <xs:attribute name="name" type="xs:string"/>
+        <xs:attribute name="default" type="xs:string"/>
+        <xs:attribute name="in" type="xs:string"/>
+        <xs:attribute name="max" type="xs:string"/>
+        <xs:attribute name="min" type="xs:string"/>
+        <xs:attribute name="range" type="xs:string"/>
+        <xs:attribute name="ranges" type="xs:string"/>
+        <xs:attribute name="scale" type="xs:string"/>
+        <xs:attribute name="value" type="xs:string"/>
+    </xs:complexType>
+    <xs:complexType name="Feature">
+        <xs:attribute name="name" type="xs:string"/>
+        <xs:attribute name="optional" type="xs:string"/>
+        <xs:attribute name="required" type="xs:string"/>
+        <xs:attribute name="value" type="xs:string"/>
+    </xs:complexType>
+    <xs:complexType name="Setting">
+        <xs:attribute name="name" type="xs:string"/>
+        <xs:attribute name="value" type="xs:string"/>
+        <xs:attribute name="update" type="xs:string"/>
+    </xs:complexType>
+</xs:schema>
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
index 8377723..6a1cc71 100644
--- a/media/mediaserver/Android.bp
+++ b/media/mediaserver/Android.bp
@@ -25,7 +25,6 @@
     ],
 
     static_libs: [
-        "libicuandroid_utils",
         "libregistermsext",
     ],
 
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index ecddc48..7b22b05 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "mediaserver"
 //#define LOG_NDEBUG 0
 
+#include <aicu/AIcu.h>
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
@@ -25,7 +26,6 @@
 #include "RegisterExtensions.h"
 
 // from LOCAL_C_INCLUDES
-#include "IcuUtils.h"
 #include "MediaPlayerService.h"
 #include "ResourceManagerService.h"
 
@@ -38,7 +38,7 @@
     sp<ProcessState> proc(ProcessState::self());
     sp<IServiceManager> sm(defaultServiceManager());
     ALOGI("ServiceManager: %p", sm.get());
-    InitializeIcuOrDie();
+    AIcu_initializeIcuOrDie();
     MediaPlayerService::instantiate();
     ResourceManagerService::instantiate();
     registerExtensions();
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index f9f1acc..f4cc704 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -101,6 +101,10 @@
 
     export_include_dirs: ["include"],
 
+    export_shared_lib_headers: [
+        "libgui",
+    ],
+
     product_variables: {
         pdk: {
             enabled: false,
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index bcc7ff3..22e15d3 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -21,6 +21,7 @@
 
 #include "NdkImagePriv.h"
 #include "NdkImageReaderPriv.h"
+#include <private/media/NdkImage.h>
 
 #include <cutils/atomic.h>
 #include <utils/Log.h>
@@ -63,6 +64,7 @@
         case AIMAGE_FORMAT_YUV_420_888:
         case AIMAGE_FORMAT_JPEG:
         case AIMAGE_FORMAT_RAW16:
+        case AIMAGE_FORMAT_RAW_DEPTH:
         case AIMAGE_FORMAT_RAW_PRIVATE:
         case AIMAGE_FORMAT_RAW10:
         case AIMAGE_FORMAT_RAW12:
@@ -92,6 +94,7 @@
         case AIMAGE_FORMAT_RGBA_FP16:
         case AIMAGE_FORMAT_JPEG:
         case AIMAGE_FORMAT_RAW16:
+        case AIMAGE_FORMAT_RAW_DEPTH:
         case AIMAGE_FORMAT_RAW_PRIVATE:
         case AIMAGE_FORMAT_RAW10:
         case AIMAGE_FORMAT_RAW12:
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 768a7a9..ed88cf3 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -371,6 +371,7 @@
 EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID = "temporal-layer-id";
 EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYERING = "ts-schema";
 EXPORT const char* AMEDIAFORMAT_KEY_TEXT_FORMAT_DATA = "text-format-data";
+EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC = "thumbnail-csd-hevc";
 EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT = "thumbnail-height";
 EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_TIME = "thumbnail-time";
 EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_WIDTH = "thumbnail-width";
diff --git a/media/ndk/OWNERS b/media/ndk/OWNERS
index 11e8340..9dc441e 100644
--- a/media/ndk/OWNERS
+++ b/media/ndk/OWNERS
@@ -1,5 +1,3 @@
 marcone@google.com
 # For AImage/AImageReader
-etalvala@google.com
-yinchiayeh@google.com
-zhijunhe@google.com
+include platform/frameworks/av:/camera/OWNERS
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 56bcaab..259481d 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -226,6 +226,7 @@
 extern const char* AMEDIAFORMAT_KEY_TARGET_TIME __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_COUNT __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_TEXT_FORMAT_DATA __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_THUMBNAIL_TIME __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_THUMBNAIL_WIDTH __INTRODUCED_IN(29);
diff --git a/media/ndk/include/private/media/NdkImage.h b/media/ndk/include/private/media/NdkImage.h
new file mode 100644
index 0000000..4368a56
--- /dev/null
+++ b/media/ndk/include/private/media/NdkImage.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _PRIVATE_MEDIA_NDKIMAGE_H_
+#define _PRIVATE_MEDIA_NDKIMAGE_H_
+// Formats not listed in the public API, but still available to AImageReader
+enum AIMAGE_PRIVATE_FORMATS {
+    /**
+     * Unprocessed implementation-dependent raw
+     * depth measurements, opaque with 16 bit
+     * samples.
+     *
+     */
+
+    AIMAGE_FORMAT_RAW_DEPTH = 0x1002,
+};
+#endif // _PRIVATE_MEDIA_NDKIMAGE
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 9756926..4725e9e 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -135,6 +135,7 @@
     AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID; # var introduced=28
     AMEDIAFORMAT_KEY_TEMPORAL_LAYERING; # var introduced=28
     AMEDIAFORMAT_KEY_TEXT_FORMAT_DATA; # var introduced=29
+    AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC; # var introduced=29
     AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT; # var introduced=29
     AMEDIAFORMAT_KEY_THUMBNAIL_TIME; # var introduced=29
     AMEDIAFORMAT_KEY_THUMBNAIL_WIDTH; # var introduced=29
diff --git a/media/ndk/tests/AImageReaderWindowHandleTest.cpp b/media/ndk/tests/AImageReaderWindowHandleTest.cpp
index ef0ff67..5b65064 100644
--- a/media/ndk/tests/AImageReaderWindowHandleTest.cpp
+++ b/media/ndk/tests/AImageReaderWindowHandleTest.cpp
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 #include <media/NdkImageReader.h>
 #include <media/NdkImage.h>
+#include <private/media/NdkImage.h>
 #include <mediautils/AImageReaderUtils.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
@@ -26,6 +27,8 @@
 
 namespace android {
 
+using HGraphicBufferProducer = hardware::graphics::bufferqueue::V1_0::
+        IGraphicBufferProducer;
 using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
 using aimg::AImageReader_getHGBPFromHandle;
 
@@ -182,4 +185,25 @@
     EXPECT_TRUE(imageAvailable_) <<  "Timed out waiting for image data to be handled!\n";
 }
 
+class AImageReaderPrivateFormatTest : public ::testing::Test {
+  public:
+    void SetUp() override {
+        auto status = AImageReader_new(kImageWidth, kImageHeight, AIMAGE_FORMAT_RAW_DEPTH,
+                                       kMaxImages, &imgReader);
+        EXPECT_TRUE(status == AMEDIA_OK);
+    }
+
+    void TearDown() override {
+        if (imgReader) {
+            AImageReader_delete(imgReader);
+        }
+    }
+    AImageReader *imgReader = nullptr;
+};
+
+TEST_F(AImageReaderPrivateFormatTest, CreateTest) {
+    EXPECT_TRUE(imgReader != nullptr);
+}
+
+
 }  // namespace android
diff --git a/services/OWNERS b/services/OWNERS
index d5d00da..66a4bcb 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -1,4 +1,7 @@
+chz@google.com
 elaurent@google.com
+essick@google.com
 etalvala@google.com
 gkasten@google.com
 hunga@google.com
+marcone@google.com
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 91b7587..40980a6 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -32,6 +32,7 @@
     libbinder \
     libaudioclient \
     libmedialogservice \
+    libmediametrics \
     libmediautils \
     libnbaio \
     libnblog \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 4033247..b8f88cf 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -224,6 +224,14 @@
         // closeOutput_nonvirtual() will remove specified entry from mPlaybackThreads
         closeOutput_nonvirtual(mPlaybackThreads.keyAt(0));
     }
+    while (!mMmapThreads.isEmpty()) {
+        const audio_io_handle_t io = mMmapThreads.keyAt(0);
+        if (mMmapThreads.valueAt(0)->isOutput()) {
+            closeOutput_nonvirtual(io); // removes entry from mMmapThreads
+        } else {
+            closeInput_nonvirtual(io);  // removes entry from mMmapThreads
+        }
+    }
 
     for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
         // no mHardwareLock needed, as there are no other references to this
@@ -836,8 +844,10 @@
                 }
                 teePatches.push_back({patchRecord, patchTrack});
                 secondaryThread->addPatchTrack(patchTrack);
-                patchTrack->setPeerProxy(patchRecord.get());
-                patchRecord->setPeerProxy(patchTrack.get());
+                // In case the downstream patchTrack on the secondaryThread temporarily outlives
+                // our created track, ensure the corresponding patchRecord is still alive.
+                patchTrack->setPeerProxy(patchRecord, true /* holdReference */);
+                patchRecord->setPeerProxy(patchTrack, false /* holdReference */);
             }
             track->setTeePatches(std::move(teePatches));
         }
@@ -3206,24 +3216,44 @@
         goto Exit;
     }
 
-    // check audio settings permission for global effects
-    if (sessionId == AUDIO_SESSION_OUTPUT_MIX && !settingsAllowed()) {
-        lStatus = PERMISSION_DENIED;
-        goto Exit;
-    }
-
-    // Session AUDIO_SESSION_OUTPUT_STAGE is reserved for output stage effects
-    // that can only be created by audio policy manager
-    if (sessionId == AUDIO_SESSION_OUTPUT_STAGE && !isAudioServerUid(callingUid)) {
-        lStatus = PERMISSION_DENIED;
-        goto Exit;
-    }
-
     if (mEffectsFactoryHal == 0) {
+        ALOGE("%s: no effects factory hal", __func__);
         lStatus = NO_INIT;
         goto Exit;
     }
 
+    // check audio settings permission for global effects
+    if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
+        if (!settingsAllowed()) {
+            ALOGE("%s: no permission for AUDIO_SESSION_OUTPUT_MIX", __func__);
+            lStatus = PERMISSION_DENIED;
+            goto Exit;
+        }
+    } else if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
+        if (!isAudioServerUid(callingUid)) {
+            ALOGE("%s: only APM can create using AUDIO_SESSION_OUTPUT_STAGE", __func__);
+            lStatus = PERMISSION_DENIED;
+            goto Exit;
+        }
+
+        if (io == AUDIO_IO_HANDLE_NONE) {
+            ALOGE("%s: APM must specify output when using AUDIO_SESSION_OUTPUT_STAGE", __func__);
+            lStatus = BAD_VALUE;
+            goto Exit;
+        }
+    } else {
+        // general sessionId.
+
+        if (audio_unique_id_get_use(sessionId) != AUDIO_UNIQUE_ID_USE_SESSION) {
+            ALOGE("%s: invalid sessionId %d", __func__, sessionId);
+            lStatus = BAD_VALUE;
+            goto Exit;
+        }
+
+        // TODO: should we check if the callingUid (limited to pid) is in mAudioSessionRefs
+        // to prevent creating an effect when one doesn't actually have track with that session?
+    }
+
     {
         // Get the full effect descriptor from the uuid/type.
         // If the session is the output mix, prefer an auxiliary effect,
@@ -3269,38 +3299,13 @@
         // because of code checking output when entering the function.
         // Note: io is never 0 when creating an effect on an input
         if (io == AUDIO_IO_HANDLE_NONE) {
-            if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
-                // output must be specified by AudioPolicyManager when using session
-                // AUDIO_SESSION_OUTPUT_STAGE
-                lStatus = BAD_VALUE;
-                goto Exit;
-            }
             // look for the thread where the specified audio session is present
-            for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-                uint32_t sessionType = mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId);
-                if (sessionType != 0) {
-                    io = mPlaybackThreads.keyAt(i);
-                    // thread with same effect session is preferable
-                    if ((sessionType & ThreadBase::EFFECT_SESSION) != 0) {
-                        break;
-                    }
-                }
+            io = findIoHandleBySessionId_l(sessionId, mPlaybackThreads);
+            if (io == AUDIO_IO_HANDLE_NONE) {
+                io = findIoHandleBySessionId_l(sessionId, mRecordThreads);
             }
             if (io == AUDIO_IO_HANDLE_NONE) {
-                for (size_t i = 0; i < mRecordThreads.size(); i++) {
-                    if (mRecordThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
-                        io = mRecordThreads.keyAt(i);
-                        break;
-                    }
-                }
-            }
-            if (io == AUDIO_IO_HANDLE_NONE) {
-                for (size_t i = 0; i < mMmapThreads.size(); i++) {
-                    if (mMmapThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
-                        io = mMmapThreads.keyAt(i);
-                        break;
-                    }
-                }
+                io = findIoHandleBySessionId_l(sessionId, mMmapThreads);
             }
             // If no output thread contains the requested session ID, default to
             // first output. The effect chain will be moved to the correct output
@@ -3309,6 +3314,21 @@
                 io = mPlaybackThreads.keyAt(0);
             }
             ALOGV("createEffect() got io %d for effect %s", io, desc.name);
+        } else if (checkPlaybackThread_l(io) != nullptr) {
+            // allow only one effect chain per sessionId on mPlaybackThreads.
+            for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+                const audio_io_handle_t checkIo = mPlaybackThreads.keyAt(i);
+                if (io == checkIo) continue;
+                const uint32_t sessionType =
+                        mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId);
+                if ((sessionType & ThreadBase::EFFECT_SESSION) != 0) {
+                    ALOGE("%s: effect %s io %d denied because session %d effect exists on io %d",
+                            __func__, desc.name, (int)io, (int)sessionId, (int)checkIo);
+                    android_errorWriteLog(0x534e4554, "123237974");
+                    lStatus = BAD_VALUE;
+                    goto Exit;
+                }
+            }
         }
         ThreadBase *thread = checkRecordThread_l(io);
         if (thread == NULL) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 1441e15..ec5dfb1 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -558,6 +558,26 @@
 
 #include "PatchPanel.h"
 
+    // Find io handle by session id.
+    // Preference is given to an io handle with a matching effect chain to session id.
+    // If none found, AUDIO_IO_HANDLE_NONE is returned.
+    template <typename T>
+    static audio_io_handle_t findIoHandleBySessionId_l(
+            audio_session_t sessionId, const T& threads) {
+        audio_io_handle_t io = AUDIO_IO_HANDLE_NONE;
+
+        for (size_t i = 0; i < threads.size(); i++) {
+            const uint32_t sessionType = threads.valueAt(i)->hasAudioSession(sessionId);
+            if (sessionType != 0) {
+                io = threads.keyAt(i);
+                if ((sessionType & AudioFlinger::ThreadBase::EFFECT_SESSION) != 0) {
+                    break; // effect chain here.
+                }
+            }
+        }
+        return io;
+    }
+
     // server side of the client's IAudioTrack
     class TrackHandle : public android::BnAudioTrack {
     public:
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 676a575..a210a6d 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -527,8 +527,8 @@
     }
 
     // tie playback and record tracks together
-    mRecord.setTrackAndPeer(tempRecordTrack, tempPatchTrack.get());
-    mPlayback.setTrackAndPeer(tempPatchTrack, tempRecordTrack.get());
+    mRecord.setTrackAndPeer(tempRecordTrack, tempPatchTrack);
+    mPlayback.setTrackAndPeer(tempPatchTrack, tempRecordTrack);
 
     // start capture and playback
     mRecord.track()->start(AudioSystem::SYNC_EVENT_NONE, AUDIO_SESSION_NONE);
@@ -543,6 +543,7 @@
             __func__, mRecord.handle(), mPlayback.handle());
     mRecord.stopTrack();
     mPlayback.stopTrack();
+    mRecord.clearTrackPeer(); // mRecord stop is synchronous. Break PeerProxy sp<> cycle.
     mRecord.closeConnections(panel);
     mPlayback.closeConnections(panel);
 }
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index 612855f..181e27c 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -122,12 +122,13 @@
             mThread = thread;
             mCloseThread = closeThread;
         }
-        void setTrackAndPeer(const sp<TrackType>& track,
-                             ThreadBase::PatchProxyBufferProvider *peer) {
+        template <typename T>
+        void setTrackAndPeer(const sp<TrackType>& track, const sp<T> &peer) {
             mTrack = track;
             mThread->addPatchTrack(mTrack);
-            mTrack->setPeerProxy(peer);
+            mTrack->setPeerProxy(peer, true /* holdReference */);
         }
+        void clearTrackPeer() { if (mTrack) mTrack->clearPeerProxy(); }
         void stopTrack() { if (mTrack) mTrack->stop(); }
 
         void swap(Endpoint &other) noexcept {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 8f181a4..3ecb37d 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -488,6 +488,8 @@
         sp<IBinder> binder = IInterface::asBinder(mPowerManager);
         binder->unlinkToDeath(mDeathRecipient);
     }
+
+    sendStatistics(true /* force */);
 }
 
 status_t AudioFlinger::ThreadBase::readyToRun()
@@ -571,6 +573,15 @@
 // sendIoConfigEvent_l() must be called with ThreadBase::mLock held
 void AudioFlinger::ThreadBase::sendIoConfigEvent_l(audio_io_config_event event, pid_t pid)
 {
+    // The audio statistics history is exponentially weighted to forget events
+    // about five or more seconds in the past.  In order to have
+    // crisper statistics for mediametrics, we reset the statistics on
+    // an IoConfigEvent, to reflect different properties for a new device.
+    mIoJitterMs.reset();
+    mLatencyMs.reset();
+    mProcessTimeMs.reset();
+    mTimestampVerifier.discontinuity();
+
     sp<ConfigEvent> configEvent = (ConfigEvent *)new IoConfigEvent(event, pid);
     sendConfigEvent_l(configEvent);
 }
@@ -1651,6 +1662,65 @@
     mWaitWorkCV.broadcast();
 }
 
+// Call only from threadLoop() or when it is idle.
+// Do not call from high performance code as this may do binder rpc to the MediaMetrics service.
+void AudioFlinger::ThreadBase::sendStatistics(bool force)
+{
+    // Do not log if we have no stats.
+    // We choose the timestamp verifier because it is the most likely item to be present.
+    const int64_t nstats = mTimestampVerifier.getN() - mLastRecordedTimestampVerifierN;
+    if (nstats == 0) {
+        return;
+    }
+
+    // Don't log more frequently than once per 12 hours.
+    // We use BOOTTIME to include suspend time.
+    const int64_t timeNs = systemTime(SYSTEM_TIME_BOOTTIME);
+    const int64_t sinceNs = timeNs - mLastRecordedTimeNs; // ok if mLastRecordedTimeNs = 0
+    if (!force && sinceNs <= 12 * NANOS_PER_HOUR) {
+        return;
+    }
+
+    mLastRecordedTimestampVerifierN = mTimestampVerifier.getN();
+    mLastRecordedTimeNs = timeNs;
+
+    std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("audiothread"));
+
+#define MM_PREFIX "android.media.audiothread." // avoid cut-n-paste errors.
+
+    // thread configuration
+    item->setInt32(MM_PREFIX "id", (int32_t)mId); // IO handle
+    // item->setInt32(MM_PREFIX "portId", (int32_t)mPortId);
+    item->setCString(MM_PREFIX "type", threadTypeToString(mType));
+    item->setInt32(MM_PREFIX "sampleRate", (int32_t)mSampleRate);
+    item->setInt64(MM_PREFIX "channelMask", (int64_t)mChannelMask);
+    item->setCString(MM_PREFIX "encoding", toString(mFormat).c_str());
+    item->setInt32(MM_PREFIX "frameCount", (int32_t)mFrameCount);
+    item->setCString(MM_PREFIX "outDevice", toString(mOutDevice).c_str());
+    item->setCString(MM_PREFIX "inDevice", toString(mInDevice).c_str());
+
+    // thread statistics
+    if (mIoJitterMs.getN() > 0) {
+        item->setDouble(MM_PREFIX "ioJitterMs.mean", mIoJitterMs.getMean());
+        item->setDouble(MM_PREFIX "ioJitterMs.std", mIoJitterMs.getStdDev());
+    }
+    if (mProcessTimeMs.getN() > 0) {
+        item->setDouble(MM_PREFIX "processTimeMs.mean", mProcessTimeMs.getMean());
+        item->setDouble(MM_PREFIX "processTimeMs.std", mProcessTimeMs.getStdDev());
+    }
+    const auto tsjitter = mTimestampVerifier.getJitterMs();
+    if (tsjitter.getN() > 0) {
+        item->setDouble(MM_PREFIX "timestampJitterMs.mean", tsjitter.getMean());
+        item->setDouble(MM_PREFIX "timestampJitterMs.std", tsjitter.getStdDev());
+    }
+    if (mLatencyMs.getN() > 0) {
+        item->setDouble(MM_PREFIX "latencyMs.mean", mLatencyMs.getMean());
+        item->setDouble(MM_PREFIX "latencyMs.std", mLatencyMs.getStdDev());
+    }
+
+    item->selfrecord();
+}
+
 // ----------------------------------------------------------------------------
 //      Playback
 // ----------------------------------------------------------------------------
@@ -2718,28 +2788,6 @@
     }
 }
 
-// hasAudioSession_l() must be called with ThreadBase::mLock held
-uint32_t AudioFlinger::PlaybackThread::hasAudioSession_l(audio_session_t sessionId) const
-{
-    uint32_t result = 0;
-    if (getEffectChain_l(sessionId) != 0) {
-        result = EFFECT_SESSION;
-    }
-
-    for (size_t i = 0; i < mTracks.size(); ++i) {
-        sp<Track> track = mTracks[i];
-        if (sessionId == track->sessionId() && !track->isInvalid()) {
-            result |= TRACK_SESSION;
-            if (track->isFastTrack()) {
-                result |= FAST_SESSION;
-            }
-            break;
-        }
-    }
-
-    return result;
-}
-
 uint32_t AudioFlinger::PlaybackThread::getStrategyForSession_l(audio_session_t sessionId)
 {
     // session AUDIO_SESSION_OUTPUT_MIX is placed in same strategy as MUSIC stream so that
@@ -3447,6 +3495,7 @@
                         LOG_AUDIO_STATE();
                     }
                     mStandby = true;
+                    sendStatistics(false /* force */);
                 }
 
                 if (mActiveTracks.isEmpty() && mConfigEvents.isEmpty()) {
@@ -7612,6 +7661,8 @@
     // note that threadLoop may still be processing the track at this point [without lock]
     recordTrack->mState = TrackBase::PAUSING;
 
+    // NOTE: Waiting here is important to keep stop synchronous.
+    // This is needed for proper patchRecord peer release.
     while (recordTrack->mState == TrackBase::PAUSING && !recordTrack->isInvalid()) {
         mWaitWorkCV.broadcast(); // signal thread to stop
         mStartStopCond.wait(mLock);
@@ -7669,14 +7720,14 @@
 
 status_t AudioFlinger::RecordThread::setMicrophoneDirection(audio_microphone_direction_t direction)
 {
-    ALOGV("RecordThread::setMicrophoneDirection");
+    ALOGV("setMicrophoneDirection(%d)", direction);
     AutoMutex _l(mLock);
     return mInput->stream->setMicrophoneDirection(direction);
 }
 
 status_t AudioFlinger::RecordThread::setMicrophoneFieldDimension(float zoom)
 {
-    ALOGV("RecordThread::setMicrophoneFieldDimension");
+    ALOGV("setMicrophoneFieldDimension(%f)", zoom);
     AutoMutex _l(mLock);
     return mInput->stream->setMicrophoneFieldDimension(zoom);
 }
@@ -8146,27 +8197,6 @@
     return 0;
 }
 
-// hasAudioSession_l() must be called with ThreadBase::mLock held
-uint32_t AudioFlinger::RecordThread::hasAudioSession_l(audio_session_t sessionId) const
-{
-    uint32_t result = 0;
-    if (getEffectChain_l(sessionId) != 0) {
-        result = EFFECT_SESSION;
-    }
-
-    for (size_t i = 0; i < mTracks.size(); ++i) {
-        if (sessionId == mTracks[i]->sessionId()) {
-            result |= TRACK_SESSION;
-            if (mTracks[i]->isFastTrack()) {
-                result |= FAST_SESSION;
-            }
-            break;
-        }
-    }
-
-    return result;
-}
-
 KeyedVector<audio_session_t, bool> AudioFlinger::RecordThread::sessionIds() const
 {
     KeyedVector<audio_session_t, bool> ids;
@@ -8674,9 +8704,11 @@
 
     while (!exitPending())
     {
-        Mutex::Autolock _l(mLock);
         Vector< sp<EffectChain> > effectChains;
 
+        { // under Thread lock
+        Mutex::Autolock _l(mLock);
+
         if (mSignalPending) {
             // A signal was raised while we were unlocked
             mSignalPending = false;
@@ -8711,10 +8743,13 @@
         updateMetadata_l();
 
         lockEffectChains_l(effectChains);
+        } // release Thread lock
+
         for (size_t i = 0; i < effectChains.size(); i ++) {
-            effectChains[i]->process_l();
+            effectChains[i]->process_l(); // Thread is not locked, but effect chain is locked
         }
-        // enable changes in effect chain
+
+        // enable changes in effect chain, including moving to another thread.
         unlockEffectChains(effectChains);
         // Effect chains will be actually deleted here if they were removed from
         // mEffectChains list during mixing or effects processing
@@ -8975,28 +9010,6 @@
     return mEffectChains.size();
 }
 
-// hasAudioSession_l() must be called with ThreadBase::mLock held
-uint32_t AudioFlinger::MmapThread::hasAudioSession_l(audio_session_t sessionId) const
-{
-    uint32_t result = 0;
-    if (getEffectChain_l(sessionId) != 0) {
-        result = EFFECT_SESSION;
-    }
-
-    for (size_t i = 0; i < mActiveTracks.size(); i++) {
-        sp<MmapTrack> track = mActiveTracks[i];
-        if (sessionId == track->sessionId()) {
-            result |= TRACK_SESSION;
-            if (track->isFastTrack()) {
-                result |= FAST_SESSION;
-            }
-            break;
-        }
-    }
-
-    return result;
-}
-
 void AudioFlinger::MmapThread::threadLoop_standby()
 {
     mHalStream->standby();
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 1afea08..47e580b 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -356,6 +356,27 @@
                     return hasAudioSession_l(sessionId);
                 }
 
+                template <typename T>
+                uint32_t hasAudioSession_l(audio_session_t sessionId, const T& tracks) const {
+                    uint32_t result = 0;
+                    if (getEffectChain_l(sessionId) != 0) {
+                        result = EFFECT_SESSION;
+                    }
+                    for (size_t i = 0; i < tracks.size(); ++i) {
+                        const sp<TrackBase>& track = tracks[i];
+                        if (sessionId == track->sessionId()
+                                && !track->isInvalid()       // not yet removed from tracks.
+                                && !track->isTerminated()) {
+                            result |= TRACK_SESSION;
+                            if (track->isFastTrack()) {
+                                result |= FAST_SESSION;  // caution, only represents first track.
+                            }
+                            break;
+                        }
+                    }
+                    return result;
+                }
+
                 // the value returned by default implementation is not important as the
                 // strategy is only meaningful for PlaybackThread which implements this method
                 virtual uint32_t getStrategyForSession_l(audio_session_t sessionId __unused)
@@ -399,6 +420,9 @@
 
     virtual     void                dump(int fd, const Vector<String16>& args) = 0;
 
+                // deliver stats to mediametrics.
+                void                sendStatistics(bool force);
+
     mutable     Mutex                   mLock;
 
 protected:
@@ -522,6 +546,10 @@
                 audio_utils::Statistics<double> mProcessTimeMs{0.995 /* alpha */};
                 audio_utils::Statistics<double> mLatencyMs{0.995 /* alpha */};
 
+                // Save the last count when we delivered statistics to mediametrics.
+                int64_t                 mLastRecordedTimestampVerifierN = 0;
+                int64_t                 mLastRecordedTimeNs = 0;  // BOOTTIME to include suspend.
+
                 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
@@ -803,7 +831,9 @@
 
                 virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
                 virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
-                virtual uint32_t hasAudioSession_l(audio_session_t sessionId) const;
+                        uint32_t hasAudioSession_l(audio_session_t sessionId) const override {
+                            return ThreadBase::hasAudioSession_l(sessionId, mTracks);
+                        }
                 virtual uint32_t getStrategyForSession_l(audio_session_t sessionId);
 
 
@@ -1543,7 +1573,9 @@
 
     virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
     virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
-    virtual uint32_t hasAudioSession_l(audio_session_t sessionId) const;
+            uint32_t hasAudioSession_l(audio_session_t sessionId) const override {
+                         return ThreadBase::hasAudioSession_l(sessionId, mTracks);
+                     }
 
             // Return the set of unique session IDs across all tracks.
             // The keys are the session IDs, and the associated values are meaningless.
@@ -1718,7 +1750,10 @@
     virtual     status_t    checkEffectCompatibility_l(const effect_descriptor_t *desc,
                                                                audio_session_t sessionId);
 
-    virtual     uint32_t    hasAudioSession_l(audio_session_t sessionId) const;
+                uint32_t    hasAudioSession_l(audio_session_t sessionId) const override {
+                                // Note: using mActiveTracks as no mTracks here.
+                                return ThreadBase::hasAudioSession_l(sessionId, mActiveTracks);
+                            }
     virtual     status_t    setSyncEvent(const sp<SyncEvent>& event);
     virtual     bool        isValidSyncEvent(const sp<SyncEvent>& event) const;
 
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 0ba0ab4..4402d99 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -94,6 +94,9 @@
     virtual void        invalidate() { mIsInvalid = true; }
             bool        isInvalid() const { return mIsInvalid; }
 
+            void        terminate() { mTerminated = true; }
+            bool        isTerminated() const { return mTerminated; }
+
     audio_attributes_t  attributes() const { return mAttr; }
 
 #ifdef TEE_SINK
@@ -228,14 +231,6 @@
         return mState == STOPPING_2;
     }
 
-    bool isTerminated() const {
-        return mTerminated;
-    }
-
-    void terminate() {
-        mTerminated = true;
-    }
-
     // Upper case characters are final states.
     // Lower case characters are transitory.
     const char *getTrackStateString() const {
@@ -337,10 +332,19 @@
                         PatchTrackBase(sp<ClientProxy> proxy, const ThreadBase& thread,
                                        const Timeout& timeout);
             void        setPeerTimeout(std::chrono::nanoseconds timeout);
-            void        setPeerProxy(PatchProxyBufferProvider *proxy) { mPeerProxy = proxy; }
+            template <typename T>
+            void        setPeerProxy(const sp<T> &proxy, bool holdReference) {
+                            mPeerReferenceHold = holdReference ? proxy : nullptr;
+                            mPeerProxy = proxy.get();
+                        }
+            void        clearPeerProxy() {
+                            mPeerReferenceHold.clear();
+                            mPeerProxy = nullptr;
+                        }
 
 protected:
     const sp<ClientProxy>       mProxy;
+    sp<RefBase>                 mPeerReferenceHold;   // keeps mPeerProxy alive during access.
     PatchProxyBufferProvider*   mPeerProxy = nullptr;
     struct timespec             mPeerTimeout{};
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index ad78a45..5a43696 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1723,6 +1723,7 @@
 
 AudioFlinger::PlaybackThread::PatchTrack::~PatchTrack()
 {
+    ALOGV("%s(%d)", __func__, mId);
 }
 
 status_t AudioFlinger::PlaybackThread::PatchTrack::start(AudioSystem::sync_event_t event,
@@ -2193,6 +2194,7 @@
 
 AudioFlinger::RecordThread::PatchRecord::~PatchRecord()
 {
+    ALOGV("%s(%d)", __func__, mId);
 }
 
 // AudioBufferProvider interface
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index 9e4eebc..3badda1 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -62,10 +62,6 @@
 $(error Configurable policy does not support legacy conf file)
 endif #ifneq ($(USE_XML_AUDIO_POLICY_CONF), 1)
 
-LOCAL_REQUIRED_MODULES := \
-    parameter-framework.policy \
-    audio_policy_criteria.conf \
-
 LOCAL_C_INCLUDES += frameworks/av/services/audiopolicy/engineconfigurable/include
 LOCAL_C_INCLUDES += frameworks/av/include
 
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 48b5271..561f100 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -16,19 +16,22 @@
 
 #pragma once
 
+#include <media/AudioCommonTypes.h>
 #include <system/audio.h>
 #include <utils/Log.h>
 #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
- * we allow to have more than one curve per volume group.
+ * we allow to have more than one curve per volume group (mandatory to get rid of AudioServer
+ * stream aliases.
  */
-enum VolumeSource : std::underlying_type<audio_stream_type_t>::type;
-static const VolumeSource VOLUME_SOURCE_NONE = static_cast<VolumeSource>(AUDIO_STREAM_DEFAULT);
+enum VolumeSource : std::underlying_type<volume_group_t>::type;
+static const VolumeSource VOLUME_SOURCE_NONE = static_cast<VolumeSource>(VOLUME_GROUP_NONE);
 
 static inline VolumeSource streamToVolumeSource(audio_stream_type_t stream) {
     return static_cast<VolumeSource>(stream);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 803cfac..e071fe0 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -29,7 +29,7 @@
 
 namespace android {
 
-class AudioMix;
+class AudioPolicyMix;
 class AudioPolicyClientInterface;
 
 // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
@@ -53,7 +53,7 @@
     void dump(String8 *dst) const override;
 
     audio_io_handle_t   mIoHandle = AUDIO_IO_HANDLE_NONE; // input handle
-    AudioMix            *mPolicyMix = nullptr;        // non NULL when used by a dynamic policy
+    wp<AudioPolicyMix>  mPolicyMix;                   // non NULL when used by a dynamic policy
     const sp<IOProfile> mProfile;                     // I/O profile this output derives from
 
     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 704f404..cd54085 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -34,7 +34,7 @@
 namespace android {
 
 class IOProfile;
-class AudioMix;
+class AudioPolicyMix;
 class AudioPolicyClientInterface;
 
 class ActivityTracking
@@ -107,7 +107,7 @@
 };
 /**
  * Note: volume activities shall be indexed by CurvesId if we want to allow multiple
- * curves per volume group, inferring a mute management or volume balancing between HW and SW is
+ * curves per volume source, inferring a mute management or volume balancing between HW and SW is
  * done
  */
 using VolumeActivities = std::map<VolumeSource, VolumeActivity>;
@@ -157,7 +157,7 @@
     virtual uint32_t latency() { return 0; }
     virtual bool isFixedVolume(audio_devices_t device);
     virtual bool setVolume(float volumeDb,
-                           audio_stream_type_t stream,
+                           VolumeSource volumeSource, const StreamTypeVector &streams,
                            audio_devices_t device,
                            uint32_t delayMs,
                            bool force);
@@ -221,7 +221,7 @@
     }
     void setCurVolume(VolumeSource vs, float volumeDb)
     {
-        // Even if not activity for this group registered, need to create anyway
+        // Even if not activity for this source registered, need to create anyway
         mVolumeActivities[vs].setVolume(volumeDb);
     }
     float getCurVolume(VolumeSource vs) const
@@ -280,8 +280,13 @@
         return mActiveClients;
     }
 
+    bool useHwGain() const
+    {
+        return !devices().isEmpty() ? devices().itemAt(0)->hasGainController() : false;
+    }
+
     DeviceVector mDevices; /**< current devices this output is routed to */
-    AudioMix *mPolicyMix = nullptr;              // non NULL when used by a dynamic policy
+    wp<AudioPolicyMix> mPolicyMix;  // non NULL when used by a dynamic policy
 
 protected:
     const sp<AudioPort> mPort;
@@ -328,7 +333,7 @@
         }
     }
     virtual bool setVolume(float volumeDb,
-                           audio_stream_type_t stream,
+                           VolumeSource volumeSource, const StreamTypeVector &streams,
                            audio_devices_t device,
                            uint32_t delayMs,
                            bool force);
@@ -402,7 +407,7 @@
             void dump(String8 *dst) const override;
 
     virtual bool setVolume(float volumeDb,
-                           audio_stream_type_t stream,
+                           VolumeSource volumeSource, const StreamTypeVector &streams,
                            audio_devices_t device,
                            uint32_t delayMs,
                            bool force);
@@ -422,7 +427,7 @@
     bool isActive(VolumeSource volumeSource, uint32_t inPastMs = 0) const;
 
     /**
-     * return whether any source contributing to VolumeSource is playing remotely, override 
+     * return whether any source contributing to VolumeSource is playing remotely, override
      * to change the definition of
      * local/remote playback, used for instance by notification manager to not make
      * media players lose audio focus when not playing locally
@@ -488,8 +493,8 @@
     /**
      * @brief isAnyOutputActive checks if any output is active (aka playing) except the one(s) that
      * hold the volume source to be ignored
-     * @param volumeSourceToIgnore source not considered in the activity detection
-     * @return true if any output is active for any source except the one to be ignored
+     * @param volumeSourceToIgnore source not to be considered in the activity detection
+     * @return true if any output is active for any volume source except the one to be ignored
      */
     bool isAnyOutputActive(VolumeSource volumeSourceToIgnore) const
     {
@@ -518,8 +523,8 @@
     /**
      * @brief isAnyOutputActive checks if any output is active (aka playing) except the one(s) that
      * hold the volume source to be ignored
-     * @param volumeSourceToIgnore source not considered in the activity detection
-     * @return true if any output is active for any source except the one to be ignored
+     * @param volumeSourceToIgnore source not to be considered in the activity detection
+     * @return true if any output is active for any volume source except the one to be ignored
      */
     bool isAnyOutputActive(VolumeSource volumeSourceToIgnore) const
     {
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index d6f24b2..7a9c26e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -31,24 +31,19 @@
 /**
  * custom mix entry in mPolicyMixes
  */
-class AudioPolicyMix : public RefBase {
+class AudioPolicyMix : public AudioMix, public RefBase {
 public:
-    AudioPolicyMix() {}
+    AudioPolicyMix(const AudioMix &mix) : AudioMix(mix) {}
+    AudioPolicyMix(const AudioPolicyMix&) = delete;
+    AudioPolicyMix& operator=(const AudioPolicyMix&) = delete;
 
-    const sp<SwAudioOutputDescriptor> &getOutput() const;
-
-    void setOutput(sp<SwAudioOutputDescriptor> &output);
-
-    void clearOutput();
-
-    android::AudioMix *getMix();
-
-    void setMix(const AudioMix &mix);
+    const sp<SwAudioOutputDescriptor> &getOutput() const { return mOutput; }
+    void setOutput(const sp<SwAudioOutputDescriptor> &output) { mOutput = output; }
+    void clearOutput() { mOutput.clear(); }
 
     void dump(String8 *dst, int spaces, int index) const;
 
 private:
-    AudioMix    mMix;                     // Audio policy mix descriptor
     sp<SwAudioOutputDescriptor> mOutput;  // Corresponding output stream
 };
 
@@ -77,21 +72,19 @@
 
     sp<DeviceDescriptor> getDeviceAndMixForInputSource(audio_source_t inputSource,
                                                        const DeviceVector &availableDeviceTypes,
-                                                       AudioMix **policyMix) const;
+                                                       sp<AudioPolicyMix> *policyMix) const;
 
     /**
      * @brief try to find a matching mix for a given output descriptor and returns the associated
      * output device.
      * @param output to be considered
      * @param availableOutputDevices list of output devices currently reachable
-     * @param policyMix to be returned if any mix matching ouput descriptor
      * @return device selected from the mix attached to the output, null pointer otherwise
      */
     sp<DeviceDescriptor> getDeviceAndMixForOutput(const sp<SwAudioOutputDescriptor> &output,
-                                                  const DeviceVector &availableOutputDevices,
-                                                  AudioMix **policyMix = nullptr);
+                                                  const DeviceVector &availableOutputDevices);
 
-    status_t getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix);
+    status_t getInputMixForAttr(audio_attributes_t attr, sp<AudioPolicyMix> *policyMix);
 
     status_t setUidDeviceAffinities(uid_t uid, const Vector<AudioDeviceTypeAddr>& devices);
     status_t removeUidDeviceAffinities(uid_t uid);
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 1fa1123..635de6f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -22,6 +22,7 @@
 #include <AudioPolicyInterface.h>
 #include "AudioInputDescriptor.h"
 #include "AudioGain.h"
+#include "AudioPolicyMix.h"
 #include "HwModule.h"
 
 namespace android {
@@ -308,16 +309,17 @@
     const int delta = active ? 1 : -1;
     mGlobalActiveCount += delta;
 
+    sp<AudioPolicyMix> policyMix = mPolicyMix.promote();
     if ((oldGlobalActiveCount == 0) && (mGlobalActiveCount > 0)) {
-        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+        if ((policyMix != NULL) && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
         {
-            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
+            mClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
                                                             MIX_STATE_MIXING);
         }
     } else if ((oldGlobalActiveCount > 0) && (mGlobalActiveCount == 0)) {
-        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+        if ((policyMix != NULL) && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
         {
-            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
+            mClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
                                                             MIX_STATE_IDLE);
         }
     }
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index fd33649..97b7a01 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -19,10 +19,12 @@
 
 #include <AudioPolicyInterface.h>
 #include "AudioOutputDescriptor.h"
+#include "AudioPolicyMix.h"
 #include "IOProfile.h"
 #include "AudioGain.h"
 #include "Volume.h"
 #include "HwModule.h"
+#include "TypeConverter.h"
 #include <media/AudioParameter.h>
 #include <media/AudioPolicy.h>
 
@@ -111,9 +113,10 @@
     }
     mGlobalActiveCount += delta;
 
-    if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+    sp<AudioPolicyMix> policyMix = mPolicyMix.promote();
+    if ((policyMix != NULL) && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
         if ((oldGlobalActiveCount == 0) || (mGlobalActiveCount == 0)) {
-            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
+            mClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
                 mGlobalActiveCount > 0 ? MIX_STATE_MIXING : MIX_STATE_IDLE);
         }
     }
@@ -150,17 +153,18 @@
 }
 
 bool AudioOutputDescriptor::setVolume(float volumeDb,
-                                      audio_stream_type_t stream,
-                                      audio_devices_t device __unused,
+                                      VolumeSource volumeSource,
+                                      const StreamTypeVector &/*streams*/,
+                                      audio_devices_t /*device*/,
                                       uint32_t delayMs,
                                       bool force)
 {
     // We actually change the volume if:
     // - the float value returned by computeVolume() changed
     // - the force flag is set
-    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);
+    if (volumeDb != getCurVolume(volumeSource) || force) {
+        ALOGV("%s for volumeSrc %d, volume %f, delay %d", __func__, volumeSource, volumeDb, delayMs);
+        setCurVolume(volumeSource, volumeDb);
         return true;
     }
     return false;
@@ -389,23 +393,33 @@
 }
 
 bool SwAudioOutputDescriptor::setVolume(float volumeDb,
-                                        audio_stream_type_t stream,
+                                        VolumeSource vs, const StreamTypeVector &streamTypes,
                                         audio_devices_t device,
                                         uint32_t delayMs,
                                         bool force)
 {
-    if (!AudioOutputDescriptor::setVolume(volumeDb, stream, device, delayMs, force)) {
+    StreamTypeVector streams = streamTypes;
+    if (!AudioOutputDescriptor::setVolume(volumeDb, vs, streamTypes, 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)) {
+    if (streams.empty()) {
+        streams.push_back(AUDIO_STREAM_MUSIC);
+    }
+    for (const auto& devicePort : devices()) {
+        // APM loops on all group, so filter on active group to set the port gain,
+        // let the other groups set the stream volume as per legacy
+        // TODO: Pass in the device address and check against it.
+        if (device == devicePort->type() &&
+                devicePort->hasGainController(true) && isActive(vs)) {
+            ALOGV("%s: device %s has gain controller", __func__, devicePort->toString().c_str());
+            // @todo: here we might be in trouble if the SwOutput has several active clients with
+            // different Volume Source (or if we allow several curves within same volume group)
+            //
             // @todo: default stream volume to max (0) when using HW Port gain?
             float volumeAmpl = Volume::DbToAmpl(0);
-            mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+            for (const auto &stream : streams) {
+                mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+            }
 
             AudioGains gains = devicePort->getGains();
             int gainMinValueInMb = gains[0]->getMinValueInMb();
@@ -422,11 +436,15 @@
         }
     }
     // 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) {
+    float volumeAmpl = Volume::DbToAmpl(getCurVolume(vs));
+    if (hasStream(streams, AUDIO_STREAM_BLUETOOTH_SCO)) {
         mClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volumeAmpl, mIoHandle, delayMs);
     }
-    mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+    for (const auto &stream : streams) {
+        ALOGV("%s output %d for volumeSource %d, volume %f, delay %d stream=%s", __func__,
+              mIoHandle, vs, volumeDb, delayMs, toString(stream).c_str());
+        mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+    }
     return true;
 }
 
@@ -616,12 +634,13 @@
 
 
 bool HwAudioOutputDescriptor::setVolume(float volumeDb,
-                                        audio_stream_type_t stream,
+                                        VolumeSource volumeSource, const StreamTypeVector &streams,
                                         audio_devices_t device,
                                         uint32_t delayMs,
                                         bool force)
 {
-    bool changed = AudioOutputDescriptor::setVolume(volumeDb, stream, device, delayMs, force);
+    bool changed =
+        AudioOutputDescriptor::setVolume(volumeDb, volumeSource, streams, 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/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 23d764e..f7289ca 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -27,51 +27,26 @@
 
 namespace android {
 
-void AudioPolicyMix::setOutput(sp<SwAudioOutputDescriptor> &output)
-{
-    mOutput = output;
-}
-
-const sp<SwAudioOutputDescriptor> &AudioPolicyMix::getOutput() const
-{
-    return mOutput;
-}
-
-void AudioPolicyMix::clearOutput()
-{
-    mOutput.clear();
-}
-
-void AudioPolicyMix::setMix(const AudioMix &mix)
-{
-    mMix = mix;
-}
-
-android::AudioMix *AudioPolicyMix::getMix()
-{
-    return &mMix;
-}
-
 void AudioPolicyMix::dump(String8 *dst, int spaces, int index) const
 {
     dst->appendFormat("%*sAudio Policy Mix %d:\n", spaces, "", index + 1);
     std::string mixTypeLiteral;
-    if (!MixTypeConverter::toString(mMix.mMixType, mixTypeLiteral)) {
-        ALOGE("%s: failed to convert mix type %d", __FUNCTION__, mMix.mMixType);
+    if (!MixTypeConverter::toString(mMixType, mixTypeLiteral)) {
+        ALOGE("%s: failed to convert mix type %d", __FUNCTION__, mMixType);
         return;
     }
     dst->appendFormat("%*s- mix type: %s\n", spaces, "", mixTypeLiteral.c_str());
 
     std::string routeFlagLiteral;
-    RouteFlagTypeConverter::maskToString(mMix.mRouteFlags, routeFlagLiteral);
+    RouteFlagTypeConverter::maskToString(mRouteFlags, routeFlagLiteral);
     dst->appendFormat("%*s- Route Flags: %s\n", spaces, "", routeFlagLiteral.c_str());
 
-    dst->appendFormat("%*s- device type: %s\n", spaces, "", toString(mMix.mDeviceType).c_str());
+    dst->appendFormat("%*s- device type: %s\n", spaces, "", toString(mDeviceType).c_str());
 
-    dst->appendFormat("%*s- device address: %s\n", spaces, "", mMix.mDeviceAddress.string());
+    dst->appendFormat("%*s- device address: %s\n", spaces, "", mDeviceAddress.string());
 
     int indexCriterion = 0;
-    for (const auto &criterion : mMix.mCriteria) {
+    for (const auto &criterion : mCriteria) {
         dst->appendFormat("%*s- Criterion %d:\n", spaces + 2, "", indexCriterion++);
 
         std::string usageLiteral;
@@ -81,7 +56,7 @@
         }
         dst->appendFormat("%*s- Usage:%s\n", spaces + 4, "", usageLiteral.c_str());
 
-        if (mMix.mMixType == MIX_TYPE_RECORDERS) {
+        if (mMixType == MIX_TYPE_RECORDERS) {
             std::string sourceLiteral;
             if (!SourceTypeConverter::toString(criterion.mValue.mSource, sourceLiteral)) {
                 ALOGE("%s: failed to convert source %d", __FUNCTION__, criterion.mValue.mSource);
@@ -109,12 +84,11 @@
         ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string());
         return BAD_VALUE;
     }
-    sp<AudioPolicyMix> policyMix = new AudioPolicyMix();
-    policyMix->setMix(mix);
+    sp<AudioPolicyMix> policyMix = new AudioPolicyMix(mix);
     add(address, policyMix);
 
     if (desc != 0) {
-        desc->mPolicyMix = policyMix->getMix();
+        desc->mPolicyMix = policyMix;
         policyMix->setOutput(desc);
     }
     return NO_ERROR;
@@ -168,15 +142,14 @@
             continue;
         }
 
-        AudioMix *mix = policyMix->getMix();
-        const bool primaryOutputMix = !is_mix_loopback_render(mix->mRouteFlags);
+        const bool primaryOutputMix = !is_mix_loopback_render(policyMix->mRouteFlags);
 
         if (primaryOutputMix && primaryDesc != 0) {
             ALOGV("%s: Skiping %zu: Primary output already found", __func__, i);
             continue; // Primary output already found
         }
 
-        switch (mixMatch(mix, i, attributes, uid)) {
+        switch (mixMatch(policyMix.get(), i, attributes, uid)) {
             case MixMatchStatus::INVALID_MIX: return BAD_VALUE; // TODO: Do we really want to abort?
             case MixMatchStatus::NO_MATCH:
                 ALOGV("%s: Mix %zu: does not match", __func__, i);
@@ -184,7 +157,7 @@
             case MixMatchStatus::MATCH:;
         }
 
-        policyDesc->mPolicyMix = mix;
+        policyDesc->mPolicyMix = policyMix;
         if (primaryOutputMix) {
             primaryDesc = policyDesc;
             ALOGV("%s: Mix %zu: set primary desc", __func__, i);
@@ -327,17 +300,13 @@
 
 sp<DeviceDescriptor> AudioPolicyMixCollection::getDeviceAndMixForOutput(
         const sp<SwAudioOutputDescriptor> &output,
-        const DeviceVector &availableOutputDevices,
-        AudioMix **policyMix)
+        const DeviceVector &availableOutputDevices)
 {
     for (size_t i = 0; i < size(); i++) {
         if (valueAt(i)->getOutput() == output) {
-            AudioMix *mix = valueAt(i)->getMix();
-            if (policyMix != nullptr)
-                *policyMix = mix;
             // This Desc is involved in a Mix, which has the highest prio
-            audio_devices_t deviceType = mix->mDeviceType;
-            String8 address = mix->mDeviceAddress;
+            audio_devices_t deviceType = valueAt(i)->mDeviceType;
+            String8 address = valueAt(i)->mDeviceAddress;
             ALOGV("%s: device (0x%x, addr=%s) forced by mix",
                   __FUNCTION__, deviceType, address.c_str());
             return availableOutputDevices.getDevice(deviceType, address, AUDIO_FORMAT_DEFAULT);
@@ -347,10 +316,12 @@
 }
 
 sp<DeviceDescriptor> AudioPolicyMixCollection::getDeviceAndMixForInputSource(
-        audio_source_t inputSource, const DeviceVector &availDevices, AudioMix **policyMix) const
+        audio_source_t inputSource,
+        const DeviceVector &availDevices,
+        sp<AudioPolicyMix> *policyMix) const
 {
     for (size_t i = 0; i < size(); i++) {
-        AudioMix *mix = valueAt(i)->getMix();
+        AudioPolicyMix *mix = valueAt(i).get();
         if (mix->mMixType != MIX_TYPE_RECORDERS) {
             continue;
         }
@@ -365,7 +336,7 @@
                 auto mixDevice =
                         availDevices.getDevice(device, mix->mDeviceAddress, AUDIO_FORMAT_DEFAULT);
                 if (mixDevice != nullptr) {
-                    if (policyMix != NULL) {
+                    if (policyMix != nullptr) {
                         *policyMix = mix;
                     }
                     return mixDevice;
@@ -377,7 +348,8 @@
     return nullptr;
 }
 
-status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix)
+status_t AudioPolicyMixCollection::getInputMixForAttr(
+        audio_attributes_t attr, sp<AudioPolicyMix> *policyMix)
 {
     if (strncmp(attr.tags, "addr=", strlen("addr=")) != 0) {
         return BAD_VALUE;
@@ -387,9 +359,8 @@
 #ifdef LOG_NDEBUG
     ALOGV("getInputMixForAttr looking for address %s\n  mixes available:", address.string());
     for (size_t i = 0; i < size(); i++) {
-            sp<AudioPolicyMix> policyMix = valueAt(i);
-            const AudioMix *mix = policyMix->getMix();
-            ALOGV("\tmix %zu address=%s", i, mix->mDeviceAddress.string());
+            sp<AudioPolicyMix> audioPolicyMix = valueAt(i);
+            ALOGV("\tmix %zu address=%s", i, audioPolicyMix->mDeviceAddress.string());
     }
 #endif
 
@@ -399,13 +370,14 @@
         return BAD_VALUE;
     }
     sp<AudioPolicyMix> audioPolicyMix = valueAt(index);
-    AudioMix *mix = audioPolicyMix->getMix();
 
-    if (mix->mMixType != MIX_TYPE_PLAYERS) {
+    if (audioPolicyMix->mMixType != MIX_TYPE_PLAYERS) {
         ALOGW("getInputMixForAttr() bad policy mix type for address %s", address.string());
         return BAD_VALUE;
     }
-    *policyMix = mix;
+    if (policyMix != nullptr) {
+        *policyMix = audioPolicyMix;
+    }
     return NO_ERROR;
 }
 
@@ -416,7 +388,7 @@
 
     // for each player mix: add a rule to match or exclude the uid based on the device
     for (size_t i = 0; i < size(); i++) {
-        const AudioMix *mix = valueAt(i)->getMix();
+        const AudioPolicyMix *mix = valueAt(i).get();
         if (mix->mMixType != MIX_TYPE_PLAYERS) {
             continue;
         }
@@ -445,7 +417,7 @@
     // for each player mix: remove existing rules that match or exclude this uid
     for (size_t i = 0; i < size(); i++) {
         bool foundUidRule = false;
-        const AudioMix *mix = valueAt(i)->getMix();
+        const AudioPolicyMix *mix = valueAt(i).get();
         if (mix->mMixType != MIX_TYPE_PLAYERS) {
             continue;
         }
@@ -473,7 +445,7 @@
     // for each player mix: find rules that don't exclude this uid, and add the device to the list
     for (size_t i = 0; i < size(); i++) {
         bool ruleAllowsUid = true;
-        const AudioMix *mix = valueAt(i)->getMix();
+        const AudioPolicyMix *mix = valueAt(i).get();
         if (mix->mMixType != MIX_TYPE_PLAYERS) {
             continue;
         }
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 6ff8512..cedc78f 100644
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -84,10 +84,6 @@
 
     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;
@@ -112,7 +108,7 @@
 
     VolumeSource toVolumeSource(audio_stream_type_t stream) const
     {
-        return static_cast<VolumeSource>(stream);
+        return static_cast<VolumeSource>(getVolumeGroupForStreamType(stream));
     }
 
     status_t switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst);
diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h
index 767a8ed..1a2a198 100644
--- a/services/audiopolicy/engine/common/include/ProductStrategy.h
+++ b/services/audiopolicy/engine/common/include/ProductStrategy.h
@@ -152,6 +152,8 @@
 
     volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const;
 
+    volume_group_t getDefaultVolumeGroup() const;
+
     product_strategy_t getDefault() const;
 
     void dump(String8 *dst, int spaces = 0) const;
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 4fe7b42..07a7e65 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -218,6 +218,9 @@
 VolumeCurves *EngineBase::getVolumeCurvesForStreamType(audio_stream_type_t stream) const
 {
     volume_group_t volGr = mProductStrategies.getVolumeGroupForStreamType(stream);
+    if (volGr == VOLUME_GROUP_NONE) {
+        volGr = mProductStrategies.getDefaultVolumeGroup();
+    }
     const auto &iter = mVolumeGroups.find(volGr);
     LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s",
                 toString(stream).c_str());
@@ -260,20 +263,6 @@
     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) {
diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
index 16e6690..f74f190 100644
--- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp
+++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
@@ -270,11 +270,7 @@
             return group;
         }
     }
-    product_strategy_t defaultStrategy = getDefault();
-    if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
-        return VOLUME_GROUP_NONE;
-    }
-    return at(defaultStrategy)->getDefaultVolumeGroup();
+    return getDefaultVolumeGroup();
 }
 
 volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(audio_stream_type_t stream) const
@@ -285,6 +281,12 @@
             return group;
         }
     }
+    ALOGW("%s: no volume group for %s, using default", __func__, toString(stream).c_str());
+    return getDefaultVolumeGroup();
+}
+
+volume_group_t ProductStrategyMap::getDefaultVolumeGroup() const
+{
     product_strategy_t defaultStrategy = getDefault();
     if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
         return VOLUME_GROUP_NONE;
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/interface/AudioPolicyManagerInterface.h b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
index 38f3401..b7fd031 100644
--- a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
+++ b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
@@ -169,7 +169,7 @@
      * @return selected input device for the audio attributes, may be null if error.
      */
     virtual sp<DeviceDescriptor> getInputDeviceForAttributes(
-            const audio_attributes_t &attr, AudioMix **mix = nullptr) const = 0;
+            const audio_attributes_t &attr, sp<AudioPolicyMix> *mix = nullptr) const = 0;
 
     /**
      * Get the legacy stream type for a given audio attributes.
@@ -283,10 +283,6 @@
      */
     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
diff --git a/services/audiopolicy/engineconfigurable/Android.mk b/services/audiopolicy/engineconfigurable/Android.mk
index 4eff6e6..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/VolumeGroup.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 45419f0..37271b5 100644
--- a/services/audiopolicy/engineconfigurable/config/example/Android.mk
+++ b/services/audiopolicy/engineconfigurable/config/example/Android.mk
@@ -10,16 +10,15 @@
 ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration_phone.xml
-LOCAL_MODULE_STEM := audio_policy_engine_configuration.xml
+LOCAL_MODULE := audio_policy_engine_configuration.xml
 
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE_STEM)
+LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
 
 LOCAL_REQUIRED_MODULES := \
-    audio_policy_engine_product_strategies_phone.xml  \
+    audio_policy_engine_product_strategies.xml  \
     audio_policy_engine_stream_volumes.xml \
     audio_policy_engine_default_stream_volumes.xml \
     audio_policy_engine_criteria.xml \
@@ -28,12 +27,11 @@
 include $(BUILD_PREBUILT)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies_phone.xml
-LOCAL_MODULE_STEM := audio_policy_engine_product_strategies.xml
+LOCAL_MODULE := audio_policy_engine_product_strategies.xml
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE_STEM)
+LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
 
 include $(CLEAR_VARS)
@@ -55,39 +53,40 @@
 endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
 
 
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),automotive_configurable caremu_configurable))
 
 ##################################################################
 # AUTOMOTIVE CONFIGURATION TOP FILE
 ##################################################################
 include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration_automotive.xml
-LOCAL_MODULE_STEM := audio_policy_engine_configuration.xml
-
+LOCAL_MODULE := audio_policy_engine_configuration.xml
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE_STEM)
+LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE)
 
 LOCAL_REQUIRED_MODULES := \
-    audio_policy_engine_product_strategies_automotive.xml \
+    audio_policy_engine_product_strategies.xml \
     audio_policy_engine_criteria.xml \
     audio_policy_engine_criterion_types.xml \
     audio_policy_engine_volumes.xml
 
 include $(BUILD_PREBUILT)
 
+endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),automotive_configurable caremu_configurable))
+
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
+
 ##################################################################
 # CONFIGURATION FILES
 ##################################################################
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies_automotive.xml
-LOCAL_MODULE_STEM := audio_policy_engine_product_strategies.xml
+LOCAL_MODULE := audio_policy_engine_product_strategies.xml
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE_STEM)
+LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
 
 include $(CLEAR_VARS)
@@ -100,7 +99,31 @@
 
 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))
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
+
+##################################################################
+# CONFIGURATION FILES
+##################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := audio_policy_engine_product_strategies.xml
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
+LOCAL_SRC_FILES := caremu/$(LOCAL_MODULE)
+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 := caremu/$(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
+
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := audio_policy_engine_criteria.xml
@@ -123,4 +146,4 @@
 
 include $(PROVISION_CRITERION_TYPES)
 
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable))
+endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
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
index b326b50..9ec3d77 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
@@ -159,7 +159,7 @@
         <name>phone</name>
         <indexMin>1</indexMin>
         <indexMax>40</indexMax>
-        <volume  deviceCategory="DEVICE_CATEGORY_SPEAKER">
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
             <point>0,-4200</point>
             <point>33,-2800</point>
             <point>66,-1400</point>
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
new file mode 100644
index 0000000..c487da9
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
@@ -0,0 +1,170 @@
+<?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.
+-->
+
+<ProductStrategies>
+    <!-- OEM Usages -->
+    <!-- product_strategy will be defined according this order
+    product_strategy is oem_traffic_anouncement if all the conditions are satisfied for
+    AudioAttributes aa
+
+    int type = 0;
+    if (bundle != null) {
+    type = bundle.getInt(KEY_OEM_TYPE, 0);
+    }
+    if(
+    ( aa.mContentType == AudioAttributes.AUDIO_CONTENT_TYPE_SPEECH ) &&
+    ( aa.mUsage == AudioAttributes.AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE ) &&
+    ( type == 1 ) )
+    -->
+
+    <ProductStrategy name="oem_traffic_anouncement">
+        <AttributesGroup volumeGroup="oem_traffic_anouncement">
+            <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
+            <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
+            <!--  traffic_annoucement = 1 -->
+            <Bundle key="oem" value="1"/>
+        </AttributesGroup>
+    </ProductStrategy>
+    <ProductStrategy name="oem_strategy_1">
+        <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 volumeGroup="oem_adas_3">
+            <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
+            <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
+            <Bundle key="oem" value="3"/>
+        </AttributesGroup>
+    </ProductStrategy>
+
+    <!-- Car Usages -->
+    <!-- Keep those lines only for car -->
+    <!-- Check car conditions if any OEM conditions matched -->
+    <!-- As defined by CarAudioAttributesUtil.java -->
+    <!-- product_strategy will be defined according this order
+    product_strategy is radio if all the conditions are satisfied for AudioAttributes aa
+
+        int type = CAR_AUDIO_TYPE_DEFAULT;
+        if (bundle != null) {
+        type = bundle.getInt(KEY_CAR_AUDIO_TYPE, CAR_AUDIO_TYPE_DEFAULT);
+        }
+        if(
+        ( aa.mContentType == AudioAttributes.AUDIO_CONTENT_TYPE_SPEECH ) &&
+        ( aa.mUsage == AudioAttributes.AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE ) &&
+        ( type == CAR_AUDIO_TYPE_RADIO ) )
+        -->
+    <ProductStrategy name="radio">
+        <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 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 volumeGroup="speech">
+            <Attributes>
+                <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
+                <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
+                <!--  CAR_AUDIO_TYPE_VOICE_COMMAND = 1 -->
+                <Bundle key="car_audio_type" value="1"/>
+            </Attributes>
+            <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY"/> </Attributes>
+            <Attributes> <Usage value="AUDIO_USAGE_ASSISTANT"/> </Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
+    <ProductStrategy name="safety_alert">
+        <AttributesGroup volumeGroup="system">
+            <ContentType value="AUDIO_CONTENT_TYPE_SONIFICATION"/>
+            <Usage value="AUDIO_USAGE_NOTIFICATION"/>
+            <!--  CAR_AUDIO_TYPE_SAFETY_ALERT = 2 -->
+            <Bundle key="car_audio_type" value="2"/>
+        </AttributesGroup>
+    </ProductStrategy>
+
+    <!-- To be checked
+    CAR_AUDIO_TYPE_CARSERVICE_BOTTOM
+    CAR_AUDIO_TYPE_CARSERVICE_CAR_PROXY
+    CAR_AUDIO_TYPE_CARSERVICE_MEDIA_MUTE
+    -->
+
+    <!-- Generic Usages -->
+    <ProductStrategy name="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 -->
+            <Attributes></Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
+
+    <ProductStrategy name="nav_guidance">
+        <AttributesGroup volumeGroup="speech">
+            <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
+        </AttributesGroup>
+    </ProductStrategy>
+    <ProductStrategy name="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" volumeGroup="ring">
+            <Usage value="AUDIO_USAGE_ALARM"/>
+        </AttributesGroup>
+    </ProductStrategy>
+    <ProductStrategy name="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" 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>
+            <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/> </Attributes>
+            <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_EVENT"/> </Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
+    <ProductStrategy name="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/caremu/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
new file mode 100644
index 0000000..9ec3d77
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/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/parameter-framework/examples/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
index 060830b..782fe83 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
@@ -9,7 +9,7 @@
 
 LOCAL_PATH := $(call my-dir)
 
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable no-output_configurable no-input_configurable))
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable no-output_configurable no-input_configurable))
 
 PFW_CORE := external/parameter-framework
 #@TODO: upstream new domain generator
@@ -20,6 +20,8 @@
 TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
 BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
 
+PROVISION_STRATEGIES_STRUCTURE := $(TOOLS)/provision_strategies_structure.mk
+
 endif
 
 ##################################################################
@@ -27,7 +29,7 @@
 ##################################################################
 ######### Policy PFW top level file #########
 
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable))
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := ParameterFrameworkConfigurationPolicy.xml
@@ -52,12 +54,27 @@
 ########## Policy PFW Common Structures #########
 
 include $(CLEAR_VARS)
+LOCAL_MODULE := PolicySubsystem.xml
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
+LOCAL_REQUIRED_MODULES := \
+    PolicySubsystem-CommonTypes.xml \
+    ProductStrategies.xml \
+    PolicySubsystem-Volume.xml \
+    libpolicy-subsystem \
+
+LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
+LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
 LOCAL_MODULE := PolicySubsystem-CommonTypes.xml
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE)
+LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
 
 include $(CLEAR_VARS)
@@ -66,16 +83,29 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE)
+LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
 
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable))
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := ProductStrategies.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_configuration.xml
+AUDIO_POLICY_ENGINE_CONFIGURATION_FILE := \
+    $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_configuration.xml
+STRATEGIES_STRUCTURE_FILE := $(LOCAL_PATH)/common/Structure/$(LOCAL_MODULE).in
+
+include $(PROVISION_STRATEGIES_STRUCTURE)
+
+endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
 
 ########## Policy PFW Example Structures #########
 ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable no-input_configurable))
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem.xml.common
+LOCAL_MODULE := PolicySubsystem-no-strategy.xml
 LOCAL_MODULE_STEM := PolicySubsystem.xml
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
@@ -86,7 +116,7 @@
     libpolicy-subsystem \
 
 LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE_STEM)
+LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE_STEM)
 include $(BUILD_PREBUILT)
 
 endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable no-input_configurable))
@@ -95,7 +125,7 @@
 ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy.no-output
+LOCAL_MODULE := parameter-framework.policy
 LOCAL_MODULE_STEM := PolicyConfigurableDomains-NoOutputDevice.xml
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
@@ -103,7 +133,7 @@
 LOCAL_REQUIRED_MODULES := \
     audio_policy_engine_criteria.xml \
     audio_policy_engine_criterion_types.xml \
-    PolicySubsystem.xml.common \
+    PolicySubsystem-no-strategy.xml \
     PolicyClass.xml \
     ParameterFrameworkConfigurationPolicy.xml
 
@@ -121,7 +151,7 @@
 ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-input_configurable)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy.no-input
+LOCAL_MODULE := parameter-framework.policy
 LOCAL_MODULE_STEM := PolicyConfigurableDomains-NoInputDevice.xml
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
@@ -129,7 +159,7 @@
 LOCAL_REQUIRED_MODULES := \
     audio_policy_engine_criteria.xml \
     audio_policy_engine_criterion_types.xml \
-    PolicySubsystem.xml.common \
+    PolicySubsystem-no-strategy.xml \
     PolicyClass.xml \
     ParameterFrameworkConfigurationPolicy.xml
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
index ea4a58f..20ca8e2 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
@@ -23,37 +23,9 @@
 ##################################################################
 
 ########## Policy PFW Structures #########
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem.xml.car
-LOCAL_MODULE_STEM := PolicySubsystem.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_REQUIRED_MODULES := \
-    ProductStrategies.xml.car \
-    PolicySubsystem-Volume.xml \
-    PolicySubsystem-CommonTypes.xml \
-    libpolicy-subsystem
-
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE_STEM)
-include $(BUILD_PREBUILT)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ProductStrategies.xml.car
-LOCAL_MODULE_STEM := ProductStrategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE_STEM)
-include $(BUILD_PREBUILT)
-
 ######### Policy PFW Settings #########
 include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy.car
+LOCAL_MODULE := parameter-framework.policy
 LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
@@ -68,7 +40,7 @@
     $(PFW_EDD_FILES)
 
 LOCAL_REQUIRED_MODULES := \
-    PolicySubsystem.xml.car \
+    PolicySubsystem.xml \
     PolicyClass.xml \
     audio_policy_engine_criteria.xml \
     audio_policy_engine_criterion_types.xml \
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw
index 196d82c..57ad592 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw
@@ -714,4 +714,47 @@
 					speaker = 0
 					bus = 0
 
+	supDomain: Tts
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/tts/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/tts/device_address = BUS00_MEDIA
 
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+				component: /Policy/policy/product_strategies/tts/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/tts/selected_output_devices/mask
+					bus = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Structure/ProductStrategies.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Structure/ProductStrategies.xml
deleted file mode 100644
index 53bba03..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Structure/ProductStrategies.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?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.
--->
-<ComponentTypeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-              xmlns:xi="http://www.w3.org/2001/XInclude"
-              xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
-
-  <ComponentType Name="ProductStrategies" Description="">
-      <Component Name="oem_traffic_anouncement" Type="ProductStrategy"/>
-      <Component Name="oem_strategy_1" Type="ProductStrategy"/>
-      <Component Name="oem_strategy_2" Type="ProductStrategy"/>
-
-      <Component Name="radio" Type="ProductStrategy"/>
-      <Component Name="ext_audio_source" Type="ProductStrategy"/>
-      <Component Name="voice_command" Type="ProductStrategy"/>
-      <Component Name="safety_alert" Type="ProductStrategy"/>
-
-      <Component Name="music" Type="ProductStrategy"/>
-      <Component Name="nav_guidance" Type="ProductStrategy"/>
-      <Component Name="voice_call" Type="ProductStrategy"/>
-      <Component Name="alarm" Type="ProductStrategy"/>
-      <Component Name="ring" Type="ProductStrategy"/>
-      <Component Name="notification" Type="ProductStrategy"/>
-      <Component Name="system" Type="ProductStrategy"/>
-  </ComponentType>
-
-</ComponentTypeSet>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk
new file mode 100644
index 0000000..8fa8f0a
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk
@@ -0,0 +1,58 @@
+################################################################################################
+#
+# @NOTE:
+# Audio Policy Engine configurable example for generic device build
+#
+# Any vendor shall have its own configuration within the corresponding device folder
+#
+################################################################################################
+
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
+LOCAL_PATH := $(call my-dir)
+
+PFW_CORE := external/parameter-framework
+PFW_DEFAULT_SCHEMAS_DIR := $(PFW_CORE)/upstream/schemas
+PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
+
+TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
+BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
+
+
+##################################################################
+# CONFIGURATION FILES
+##################################################################
+
+########## Policy PFW Structures #########
+######### Policy PFW Settings #########
+include $(CLEAR_VARS)
+LOCAL_MODULE := parameter-framework.policy
+LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
+
+PFW_EDD_FILES := \
+        $(LOCAL_PATH)/Settings/device_for_product_strategies.pfw \
+        $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
+        $(LOCAL_PATH)/../Settings/volumes.pfw
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+    $(PFW_EDD_FILES)
+
+LOCAL_REQUIRED_MODULES := \
+    PolicySubsystem.xml \
+    PolicyClass.xml \
+    audio_policy_engine_criteria.xml \
+    audio_policy_engine_criterion_types.xml \
+    ParameterFrameworkConfigurationPolicy.xml
+
+PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
+PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
+
+PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
+
+PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
+
+include $(BUILD_PFW_SETTINGS)
+
+endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Settings/device_for_product_strategies.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Settings/device_for_product_strategies.pfw
new file mode 100644
index 0000000..ca3464f
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Settings/device_for_product_strategies.pfw
@@ -0,0 +1,690 @@
+supDomain: DeviceForProductStrategies
+	supDomain: OemTrafficAnouncement
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/oem_traffic_anouncement/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/oem_traffic_anouncement/device_address = BUS00_MEDIA
+
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+				component: /Policy/policy/product_strategies/oem_traffic_anouncement/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/oem_traffic_anouncement/selected_output_devices/mask
+					bus = 0
+
+	supDomain: OemStrategy1
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/oem_strategy_1/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/oem_strategy_1/device_address = BUS02_OEM1
+
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS02_OEM1
+
+				component: /Policy/policy/product_strategies/oem_strategy_1/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/oem_strategy_1/selected_output_devices/mask
+					bus = 0
+
+
+
+	supDomain: OemStrategy2
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/oem_strategy_2/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/oem_strategy_2/device_address = BUS01_NAV_GUIDANCE
+
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS01_NAV_GUIDANCE
+
+				component: /Policy/policy/product_strategies/oem_strategy_2/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/oem_strategy_2/selected_output_devices/mask
+					bus = 0
+
+
+
+	supDomain: Radio
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/radio/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/radio/device_address = BUS00_MEDIA
+
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+				component: /Policy/policy/product_strategies/radio/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/radio/selected_output_devices/mask
+					bus = 0
+
+	supDomain: ExtAudioSource
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/ext_audio_source/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/ext_audio_source/device_address = BUS00_MEDIA
+
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+				component: /Policy/policy/product_strategies/ext_audio_source/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/ext_audio_source/selected_output_devices/mask
+					bus = 0
+
+
+
+	supDomain: VoiceCommand
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/voice_command/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/voice_command/device_address = BUS04_VOICE
+
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS04_VOICE
+
+				component: /Policy/policy/product_strategies/voice_command/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/voice_command/selected_output_devices/mask
+					bus = 0
+
+
+	supDomain: SafetyAlert
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/safety_alert/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/safety_alert/device_address = BUS00_MEDIA
+
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+				component: /Policy/policy/product_strategies/safety_alert/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/safety_alert/selected_output_devices/mask
+					bus = 0
+
+
+	supDomain: Music
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/music/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/music/device_address = BUS00_MEDIA
+
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+				component: /Policy/policy/product_strategies/music/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/music/selected_output_devices/mask
+					bus = 0
+
+
+
+	supDomain: NavGuidance
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/nav_guidance/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/nav_guidance/device_address = BUS01_NAV_GUIDANCE
+
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS01_NAV_GUIDANCE
+
+				component: /Policy/policy/product_strategies/nav_guidance/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/nav_guidance/selected_output_devices/mask
+					bus = 0
+
+
+	supDomain: VoiceCall
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/voice_call/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/voice_call/device_address = BUS04_VOICE
+
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS04_VOICE
+
+				component: /Policy/policy/product_strategies/voice_call/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/voice_call/selected_output_devices/mask
+					bus = 0
+
+
+	supDomain: Alarm
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/alarm/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/alarm/device_address = BUS00_MEDIA
+
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+				component: /Policy/policy/product_strategies/alarm/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/alarm/selected_output_devices/mask
+					bus = 0
+
+
+	supDomain: Ring
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/ring/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/ring/device_address = BUS04_VOICE
+
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS04_VOICE
+
+				component: /Policy/policy/product_strategies/ring/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/ring/selected_output_devices/mask
+					bus = 0
+
+
+	supDomain: Notification
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/notification/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/notification/device_address = BUS00_MEDIA
+
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+				component: /Policy/policy/product_strategies/notification/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/notification/selected_output_devices/mask
+					bus = 0
+
+
+	supDomain: System
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/system/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/system/device_address = BUS03_SYSTEM_SOUND
+
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS03_SYSTEM_SOUND
+
+				component: /Policy/policy/product_strategies/system/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/system/selected_output_devices/mask
+					bus = 0
+
+	supDomain: Tts
+		domain: UnreachableDevices
+			conf: calibration
+				component: /Policy/policy/product_strategies/tts/selected_output_devices/mask
+					earpiece = 0
+					speaker = 0
+					wired_headset = 0
+					wired_headphone = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					hdmi = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					remote_submix = 0
+					telephony_tx = 0
+					line = 0
+					hdmi_arc = 0
+					spdif = 0
+					fm = 0
+					aux_line = 0
+					speaker_safe = 0
+					ip = 0
+					proxy = 0
+					usb_headset = 0
+					stub = 0
+				/Policy/policy/product_strategies/tts/device_address = BUS00_MEDIA
+ 
+		domain: SelectedDevice
+			conf: Bus
+				AvailableOutputDevices Includes Bus
+				AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+				component: /Policy/policy/product_strategies/tts/selected_output_devices/mask
+					bus = 1
+
+			conf: Default
+				component: /Policy/policy/product_strategies/tts/selected_output_devices/mask
+					bus = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
index e9d67e9..d1845b8 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
@@ -22,37 +22,9 @@
 # CONFIGURATION FILES
 ##################################################################
 ########## Policy PFW Structures #########
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem.xml.phone
-LOCAL_MODULE_STEM := PolicySubsystem.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_REQUIRED_MODULES := \
-    PolicySubsystem-CommonTypes.xml \
-    ProductStrategies.xml.phone \
-    PolicySubsystem-Volume.xml \
-    libpolicy-subsystem \
-
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE_STEM)
-include $(BUILD_PREBUILT)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ProductStrategies.xml.phone
-LOCAL_MODULE_STEM := ProductStrategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE_STEM)
-include $(BUILD_PREBUILT)
-
 ######### Policy PFW Settings #########
 include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy.phone
+LOCAL_MODULE := parameter-framework.policy
 LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
@@ -68,15 +40,15 @@
         $(LOCAL_PATH)/Settings/device_for_product_strategy_phone.pfw \
         $(LOCAL_PATH)/Settings/device_for_product_strategy_sonification.pfw \
         $(LOCAL_PATH)/Settings/device_for_product_strategy_sonification_respectful.pfw \
-        $(LOCAL_PATH)/Settings/device_for_product_strategy_rerouting.pfw \
         $(LOCAL_PATH)/Settings/device_for_product_strategy_transmitted_through_speaker.pfw \
-        $(LOCAL_PATH)/Settings/device_for_product_strategy_unknown.pfw
+        $(LOCAL_PATH)/Settings/device_for_product_strategy_rerouting.pfw \
+        $(LOCAL_PATH)/Settings/device_for_product_strategy_patch.pfw
 
 LOCAL_ADDITIONAL_DEPENDENCIES := \
     $(PFW_EDD_FILES)
 
 LOCAL_REQUIRED_MODULES := \
-    PolicySubsystem.xml.phone \
+    PolicySubsystem.xml \
     PolicyClass.xml \
     audio_policy_engine_criteria.xml \
     audio_policy_engine_criterion_types.xml \
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_unknown.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_patch.pfw
similarity index 79%
rename from services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_unknown.pfw
rename to services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_patch.pfw
index c46cf56..d2cc090 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_unknown.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_patch.pfw
@@ -1,8 +1,8 @@
 supDomain: DeviceForProductStrategy
-	supDomain: Unknown
+	supDomain: Patch
 		domain: UnreachableDevices
 			conf: calibration
-				component: /Policy/policy/product_strategies/unknown/selected_output_devices/mask
+				component: /Policy/policy/product_strategies/patch/selected_output_devices/mask
 					earpiece = 0
 					speaker = 0
 					wired_headset = 0
@@ -31,6 +31,6 @@
 					usb_headset = 0
 					bus = 0
 					stub = 0
-				/Policy/policy/product_strategies/unknown/device_address =
+				/Policy/policy/product_strategies/patch/device_address =
 
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw
index c064c18..10f8814 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw
@@ -29,15 +29,8 @@
 					ip = 0
 					proxy = 0
 					usb_headset = 0
+					bus = 0
 					stub = 0
 				/Policy/policy/product_strategies/rerouting/device_address =
 
-		domain: SelectedDevice
-			conf: Bus
-				component: /Policy/policy/product_strategies/rerouting/selected_output_devices/mask
-					bus = 1
-
-			conf: Default
-				component: /Policy/policy/product_strategies/rerouting/selected_output_devices/mask
-					bus = 0
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Structure/PolicySubsystem.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Structure/PolicySubsystem.xml
deleted file mode 100644
index b55ce2c..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Structure/PolicySubsystem.xml
+++ /dev/null
@@ -1,88 +0,0 @@
-<?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.
--->
-<Subsystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-           xmlns:xi="http://www.w3.org/2001/XInclude"
-           xsi:noNamespaceSchemaLocation="Schemas/Subsystem.xsd"
-           Name="policy" Type="Policy">
-
-    <ComponentLibrary>
-        <!--#################### GLOBAL COMPONENTS BEGIN ####################-->
-        <!-- Common Types defintion -->
-        <xi:include href="PolicySubsystem-CommonTypes.xml"/>
-        <xi:include href="ProductStrategies.xml"/>
-
-
-        <!--#################### GLOBAL COMPONENTS END ####################-->
-
-        <!--#################### STREAM BEGIN ####################-->
-
-        <ComponentType Name="Streams" Description="associated to audio_stream_type_t definition">
-            <Component Name="voice_call" Type="Stream" Mapping="Name:AUDIO_STREAM_VOICE_CALL"/>
-            <Component Name="system" Type="Stream" Mapping="Name:AUDIO_STREAM_SYSTEM"/>
-            <Component Name="ring" Type="Stream" Mapping="Name:AUDIO_STREAM_RING"/>
-            <Component Name="music" Type="Stream" Mapping="Name:AUDIO_STREAM_MUSIC"/>
-            <Component Name="alarm" Type="Stream" Mapping="Name:AUDIO_STREAM_ALARM"/>
-            <Component Name="notification" Type="Stream" Mapping="Name:AUDIO_STREAM_NOTIFICATION"/>
-            <Component Name="bluetooth_sco" Type="Stream" Mapping="Name:AUDIO_STREAM_BLUETOOTH_SCO"/>
-            <Component Name="enforced_audible" Type="Stream" Mapping="Name:AUDIO_STREAM_ENFORCED_AUDIBLE"
-                       Description="Sounds that cannot be muted by user and must be routed to speaker"/>
-            <Component Name="dtmf" Type="Stream" Mapping="Name:AUDIO_STREAM_DTMF"/>
-            <Component Name="tts" Type="Stream" Mapping="Name:AUDIO_STREAM_TTS"
-                             Description="Transmitted Through Speaker. Plays over speaker only, silent on other devices"/>
-            <Component Name="accessibility" Type="Stream" Mapping="Name:AUDIO_STREAM_ACCESSIBILITY"
-                             Description="For accessibility talk back prompts"/>
-            <Component Name="rerouting" Type="Stream" Mapping="Name:AUDIO_STREAM_REROUTING"
-                             Description="For dynamic policy output mixes"/>
-            <Component Name="patch" Type="Stream" Mapping="Name:AUDIO_STREAM_PATCH"
-                             Description="For internal audio flinger tracks. Fixed volume"/>
-        </ComponentType>
-
-        <!--#################### STREAM END ####################-->
-
-        <!--#################### INPUT SOURCE BEGIN ####################-->
-
-        <ComponentType Name="InputSources" Description="associated to audio_source_t definition,
-                             identifier mapping must match the value of the enum">
-            <Component Name="default" Type="InputSource" Mapping="Name:AUDIO_SOURCE_DEFAULT"/>
-            <Component Name="mic" Type="InputSource" Mapping="Name:AUDIO_SOURCE_MIC"/>
-            <Component Name="voice_uplink" Type="InputSource"
-                                           Mapping="Name:AUDIO_SOURCE_VOICE_UPLINK"/>
-            <Component Name="voice_downlink" Type="InputSource"
-                                             Mapping="Name:AUDIO_SOURCE_VOICE_DOWNLINK"/>
-            <Component Name="voice_call" Type="InputSource"
-                                         Mapping="Name:AUDIO_SOURCE_VOICE_CALL"/>
-            <Component Name="camcorder" Type="InputSource" Mapping="Name:AUDIO_SOURCE_CAMCORDER"/>
-            <Component Name="voice_recognition" Type="InputSource"
-                                                Mapping="Name:AUDIO_SOURCE_VOICE_RECOGNITION"/>
-            <Component Name="voice_communication" Type="InputSource"
-                                                  Mapping="Name:AUDIO_SOURCE_VOICE_COMMUNICATION"/>
-            <Component Name="remote_submix" Type="InputSource"
-                                            Mapping="Name:AUDIO_SOURCE_REMOTE_SUBMIX"/>
-            <Component Name="unprocessed" Type="InputSource"
-                                            Mapping="Name:AUDIO_SOURCE_UNPROCESSED"/>
-            <Component Name="fm_tuner" Type="InputSource" Mapping="Name:AUDIO_SOURCE_FM_TUNER"/>
-            <Component Name="hotword" Type="InputSource" Mapping="Name:AUDIO_SOURCE_HOTWORD"/>
-        </ComponentType>
-
-        <!--#################### INPUT SOURCE END ####################-->
-    </ComponentLibrary>
-
-    <InstanceDefinition>
-        <Component Name="streams" Type="Streams"/>
-        <Component Name="input_sources" Type="InputSources"/>
-        <Component Name="product_strategies" Type="ProductStrategies"/>
-    </InstanceDefinition>
-</Subsystem>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Structure/ProductStrategies.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Structure/ProductStrategies.xml
deleted file mode 100644
index 4cbb3da..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Structure/ProductStrategies.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
--->
-<ComponentTypeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-              xmlns:xi="http://www.w3.org/2001/XInclude"
-              xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
-
-  <ComponentType Name="ProductStrategies" Description="">
-      <Component Name="accessibility" Type="ProductStrategy"/>
-      <Component Name="enforced_audible" Type="ProductStrategy"/>
-      <Component Name="transmitted_through_speaker" Type="ProductStrategy"/>
-
-      <Component Name="media" Type="ProductStrategy"/>
-      <Component Name="phone" Type="ProductStrategy"/>
-      <Component Name="dtmf" Type="ProductStrategy"/>
-
-      <Component Name="sonification" Type="ProductStrategy"/>
-      <Component Name="sonification_respectful" Type="ProductStrategy"/>
-      <Component Name="rerouting" Type="ProductStrategy"/>
-      <Component Name="unknown" Type="ProductStrategy"/>
-  </ComponentType>
-
-</ComponentTypeSet>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicyClass.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicyClass.xml
similarity index 100%
rename from services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicyClass.xml
rename to services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicyClass.xml
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem-CommonTypes.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml
similarity index 100%
rename from services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem-CommonTypes.xml
rename to services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-no-strategy.xml
similarity index 100%
rename from services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem.xml
rename to services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-no-strategy.xml
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Structure/PolicySubsystem.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
similarity index 100%
rename from services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Structure/PolicySubsystem.xml
rename to services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/ProductStrategies.xml.in b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/ProductStrategies.xml.in
new file mode 100644
index 0000000..2760b25
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/ProductStrategies.xml.in
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+     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.
+-->
+<ComponentTypeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xi="http://www.w3.org/2001/XInclude"
+              xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
+
+  <!-- automatically populate the strategy structure plugin file from Engine Configuration XML file
+        Component Name="xxx" Type="ProductStrategy"/-->
+  <ComponentType Name="ProductStrategies" Description="">
+  </ComponentType>
+
+</ComponentTypeSet>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
index 65dc9af..4706d7d 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
@@ -36,7 +36,9 @@
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
-LOCAL_STATIC_LIBRARIES := libpfw_utility
+LOCAL_STATIC_LIBRARIES := \
+    libpfw_utility \
+    libaudiopolicycomponents
 
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := libpolicy-subsystem
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
index bfc1bca..8bd7f66 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
@@ -72,7 +72,7 @@
         );
     addSubsystemObjectFactory(
         new TSubsystemObjectFactory<ProductStrategy>(
-            mProductStrategyComponentName, 0)
+            mProductStrategyComponentName, (1 << MappingKeyName))
         );
 }
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp
index bb29ef1..ebd9456 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp
@@ -32,6 +32,8 @@
                                 (MappingKeyAmendEnd - MappingKeyAmend1 + 1),
                                 context)
 {
+    std::string name(context.getItem(MappingKeyName));
+
     ALOG_ASSERT(instanceConfigurableElement != nullptr, "Invalid Configurable Element");
     mPolicySubsystem = static_cast<const PolicySubsystem *>(
                 instanceConfigurableElement->getBelongingSubsystem());
@@ -40,7 +42,6 @@
     mPolicyPluginInterface = mPolicySubsystem->getPolicyPluginInterface();
     ALOG_ASSERT(mPolicyPluginInterface != nullptr, "Invalid Policy Plugin Interface");
 
-    std::string name(instanceConfigurableElement->getName());
     mId = mPolicyPluginInterface->getProductStrategyByName(name);
 
     ALOG_ASSERT(mId != PRODUCT_STRATEGY_INVALID, "Product Strategy %s not found", name.c_str());
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 89a1694..89aaa84 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -295,7 +295,7 @@
 }
 
 sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
-                                                         AudioMix **mix) const
+                                                         sp<AudioPolicyMix> *mix) const
 {
     const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
     const auto &availableInputDevices = getApmObserver()->getAvailableInputDevices();
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index 5553994..4662e7e 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -62,7 +62,7 @@
                                            bool fromCache = false) const override;
 
     sp<DeviceDescriptor> getInputDeviceForAttributes(
-            const audio_attributes_t &attr, AudioMix **mix = nullptr) const override;
+            const audio_attributes_t &attr, sp<AudioPolicyMix> *mix = nullptr) const override;
 
     void updateDeviceSelectionCache() override;
 
diff --git a/services/audiopolicy/engineconfigurable/tools/Android.bp b/services/audiopolicy/engineconfigurable/tools/Android.bp
index d8f29dc..8c16972 100644
--- a/services/audiopolicy/engineconfigurable/tools/Android.bp
+++ b/services/audiopolicy/engineconfigurable/tools/Android.bp
@@ -12,13 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-python_binary_host {
-    name: "buildPolicyCriterionTypes.py",
-    owner: "renault",
-    main: "buildPolicyCriterionTypes.py",
-    srcs: [
-        "buildPolicyCriterionTypes.py",
-    ],
+python_defaults {
+    name: "tools_default",
     version: {
         py2: {
             enabled: true,
@@ -29,3 +24,37 @@
     },
 }
 
+python_binary_host {
+    name: "buildPolicyCriterionTypes.py",
+    main: "buildPolicyCriterionTypes.py",
+    srcs: [
+        "buildPolicyCriterionTypes.py",
+    ],
+    defaults: ["tools_default"],
+}
+
+python_binary_host {
+    name: "domainGeneratorPolicy.py",
+    main: "domainGeneratorPolicy.py",
+    srcs: [
+        "domainGeneratorPolicy.py",
+    ],
+    defaults: ["tools_default"],
+    libs: [
+        "EddParser.py",
+        "hostConfig.py",
+        "PFWScriptGenerator.py",
+    ],
+    required: [
+        "domainGeneratorConnector",
+    ],
+}
+
+python_binary_host {
+    name: "buildStrategiesStructureFile.py",
+    main: "buildStrategiesStructureFile.py",
+    srcs: [
+        "buildStrategiesStructureFile.py",
+    ],
+    defaults: ["tools_default"],
+}
diff --git a/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
new file mode 100755
index 0000000..ee70b26
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
@@ -0,0 +1,139 @@
+#!/usr/bin/python
+
+#
+# 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.
+# 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.
+#
+
+import argparse
+import re
+import sys
+import tempfile
+import os
+import logging
+import subprocess
+import xml.etree.ElementTree as ET
+import xml.etree.ElementInclude as EI
+import xml.dom.minidom as MINIDOM
+from collections import OrderedDict
+
+#
+# Helper script that helps to feed at build time the XML Product Strategies Structure file file used
+# by the engineconfigurable to start the parameter-framework.
+# It prevents to fill them manually and avoid divergences with android.
+#
+# The Product Strategies Structure file is fed from the audio policy engine configuration file
+# in order to discover all the strategies available for the current platform.
+#           --audiopolicyengineconfigurationfile <path/to/audio_policy_engine_configuration.xml>
+#
+# The reference file of ProductStrategies structure must also be set as an input of the script:
+#           --productstrategiesstructurefile <path/to/structure/file/ProductStrategies.xml.in>
+#
+# At last, the output of the script shall be set also:
+#           --outputfile <path/to/out/<system|vendor|odm>/etc/ProductStrategies.xml>
+#
+
+def parseArgs():
+    argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
+        product strategies structure file generator.\n\
+        Exit with the number of (recoverable or not) error that occured.")
+    argparser.add_argument('--audiopolicyengineconfigurationfile',
+            help="Android Audio Policy Engine Configuration file, Mandatory.",
+            metavar="(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)",
+            type=argparse.FileType('r'),
+            required=True)
+    argparser.add_argument('--productstrategiesstructurefile',
+            help="Product Strategies Structure XML base file, Mandatory.",
+            metavar="STRATEGIES_STRUCTURE_FILE",
+            type=argparse.FileType('r'),
+            required=True)
+    argparser.add_argument('--outputfile',
+            help="Product Strategies Structure output file, Mandatory.",
+            metavar="STRATEGIES_STRUCTURE_OUTPUT_FILE",
+            type=argparse.FileType('w'),
+            required=True)
+    argparser.add_argument('--verbose',
+            action='store_true')
+
+    return argparser.parse_args()
+
+
+def generateXmlStructureFile(strategies, strategyStructureInFile, outputFile):
+
+    logging.info("Importing strategyStructureInFile {}".format(strategyStructureInFile))
+    strategies_in_tree = ET.parse(strategyStructureInFile)
+
+    strategies_root = strategies_in_tree.getroot()
+    strategy_components = strategies_root.find('ComponentType')
+
+    for strategy_name in strategies:
+        context_mapping = "".join(map(str, ["Name:", strategy_name]))
+        strategy_pfw_name = strategy_name.replace('STRATEGY_', '').lower()
+        strategy_component_node = ET.SubElement(strategy_components, "Component", Name=strategy_pfw_name, Type="ProductStrategy", Mapping=context_mapping)
+
+    xmlstr = ET.tostring(strategies_root, encoding='utf8', method='xml')
+    reparsed = MINIDOM.parseString(xmlstr)
+    prettyXmlStr = reparsed.toprettyxml(newl='\r\n')
+    prettyXmlStr = os.linesep.join([s for s in prettyXmlStr.splitlines() if s.strip()])
+    outputFile.write(prettyXmlStr.encode('utf-8'))
+
+def capitalizeLine(line):
+    return ' '.join((w.capitalize() for w in line.split(' ')))
+
+
+#
+# Parse the audio policy configuration file and output a dictionary of device criteria addresses
+#
+def parseAndroidAudioPolicyEngineConfigurationFile(audiopolicyengineconfigurationfile):
+
+    logging.info("Checking Audio Policy Engine Configuration file {}".format(audiopolicyengineconfigurationfile))
+    #
+    # extract all product strategies name from audio policy engine configuration file
+    #
+    strategy_names = []
+
+    oldWorkingDir = os.getcwd()
+    print "Current working directory %s" % oldWorkingDir
+
+    newDir = os.path.join(oldWorkingDir , audiopolicyengineconfigurationfile.name)
+
+    policy_engine_in_tree = ET.parse(audiopolicyengineconfigurationfile)
+    os.chdir(os.path.dirname(os.path.normpath(newDir)))
+
+    print "new working directory %s" % os.getcwd()
+
+    policy_engine_root = policy_engine_in_tree.getroot()
+    EI.include(policy_engine_root)
+
+    os.chdir(oldWorkingDir)
+
+    for strategy in policy_engine_root.iter('ProductStrategy'):
+        strategy_names.append(strategy.get('name'))
+
+    return strategy_names
+
+
+def main():
+    logging.root.setLevel(logging.INFO)
+    args = parseArgs()
+
+    strategies = parseAndroidAudioPolicyEngineConfigurationFile(args.audiopolicyengineconfigurationfile)
+
+    product_strategies_structure = args.productstrategiesstructurefile
+
+    generateXmlStructureFile(strategies, product_strategies_structure, args.outputfile)
+
+# If this file is directly executed
+if __name__ == "__main__":
+    exit(main())
diff --git a/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk b/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk
new file mode 100644
index 0000000..72c938c
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk
@@ -0,0 +1,21 @@
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): MY_STRATEGIES_STRUCTURE_FILE := $(STRATEGIES_STRUCTURE_FILE)
+$(LOCAL_BUILT_MODULE): MY_AUDIO_POLICY_ENGINE_CONFIGURATION_FILE := $(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)
+$(LOCAL_BUILT_MODULE): MY_PROVISION_TOOL := $(HOST_OUT)/bin/buildStrategiesStructureFile.py
+$(LOCAL_BUILT_MODULE): $(LOCAL_REQUIRED_MODULES) $(LOCAL_ADDITIONAL_DEPENDENCIES) \
+    buildStrategiesStructureFile.py \
+    $(STRATEGIES_STRUCTURE_FILE) \
+    $(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)
+
+	"$(MY_PROVISION_TOOL)" \
+		--audiopolicyengineconfigurationfile "$(MY_AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)" \
+		--productstrategiesstructurefile "$(MY_STRATEGIES_STRUCTURE_FILE)" \
+		--outputfile "$(@)"
+
+# Clear variables for further use
+STRATEGIES_STRUCTURE_FILE :=
+AUDIO_POLICY_ENGINE_CONFIGURATION_FILE :=
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 ebf383b..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/ProductStrategy.cpp \
-    ../engine/common/src/EngineBase.cpp \
-    ../engine/common/src/VolumeGroup.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/Android.mk b/services/audiopolicy/enginedefault/config/example/Android.mk
index f06ee4c..0badac8 100644
--- a/services/audiopolicy/enginedefault/config/example/Android.mk
+++ b/services/audiopolicy/enginedefault/config/example/Android.mk
@@ -7,28 +7,26 @@
 ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_default)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration_phone.xml
-LOCAL_MODULE_STEM := audio_policy_engine_configuration.xml
+LOCAL_MODULE := audio_policy_engine_configuration.xml
 
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE_STEM)
+LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
 
 LOCAL_REQUIRED_MODULES := \
-    audio_policy_engine_product_strategies_phone.xml \
+    audio_policy_engine_product_strategies.xml \
     audio_policy_engine_stream_volumes.xml \
     audio_policy_engine_default_stream_volumes.xml
 
 include $(BUILD_PREBUILT)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies_phone.xml
-LOCAL_MODULE_STEM := audio_policy_engine_product_strategies.xml
+LOCAL_MODULE := audio_policy_engine_product_strategies.xml
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE_STEM)
+LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
 
 include $(CLEAR_VARS)
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index f191738..66a6965 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -727,7 +727,7 @@
 }
 
 sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
-                                                         AudioMix **mix) const
+                                                         sp<AudioPolicyMix> *mix) const
 {
     const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
     const auto &availableInputDevices = getApmObserver()->getAvailableInputDevices();
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index d8a3698..d5dfacc 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -66,7 +66,7 @@
                                            bool fromCache = false) const override;
 
     sp<DeviceDescriptor> getInputDeviceForAttributes(
-            const audio_attributes_t &attr, AudioMix **mix = nullptr) const override;
+            const audio_attributes_t &attr, sp<AudioPolicyMix> *mix = nullptr) const override;
 
     void updateDeviceSelectionCache() override;
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index c969af3..e8e9fa6 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -217,10 +217,11 @@
                 && strncmp(device_address, "0", AUDIO_DEVICE_MAX_ADDRESS_LEN) != 0) {
             for (audio_io_handle_t output : outputs) {
                 sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output);
-                if (desc->mPolicyMix != nullptr
-                        && desc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS
+                sp<AudioPolicyMix> policyMix = desc->mPolicyMix.promote();
+                if (policyMix != nullptr
+                        && policyMix->mMixType == MIX_TYPE_RECORDERS
                         && strncmp(device_address,
-                                   desc->mPolicyMix->mDeviceAddress.string(),
+                                   policyMix->mDeviceAddress.string(),
                                    AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0) {
                     doCheckForDeviceAndOutputChanges = false;
                     break;
@@ -968,7 +969,7 @@
     }
     if (usePrimaryOutputFromPolicyMixes) {
         *output = policyDesc->mIoHandle;
-        AudioMix *mix = policyDesc->mPolicyMix;
+        sp<AudioPolicyMix> mix = policyDesc->mPolicyMix.promote();
         sp<DeviceDescriptor> deviceDesc =
                 mAvailableOutputDevices.getDevice(mix->mDeviceType,
                                                   mix->mDeviceAddress,
@@ -1022,7 +1023,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;
@@ -1083,7 +1085,7 @@
         new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig,
                                   sanitizedRequestedPortId, *stream,
                                   mEngine->getProductStrategyForAttributes(resultAttr),
-                                  streamToVolumeSource(*stream),
+                                  toVolumeSource(resultAttr),
                                   *flags, isRequestedDeviceForExclusiveUse,
                                   std::move(weakSecondaryOutputDescs));
     sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
@@ -1100,11 +1102,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
@@ -1141,7 +1148,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;
     }
 
@@ -1157,7 +1164,7 @@
         profile = getProfileForOutput(devices,
                                    config->sample_rate,
                                    config->format,
-                                   config->channel_mask,
+                                   channelMask,
                                    (audio_output_flags_t)*flags,
                                    true /* directOnly */);
     }
@@ -1171,7 +1178,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__, 
@@ -1213,11 +1220,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();
             }
@@ -1258,12 +1265,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;
 }
@@ -1597,10 +1603,9 @@
             (outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
 
     DeviceVector devices;
-    AudioMix *policyMix = NULL;
+    sp<AudioPolicyMix> policyMix = outputDesc->mPolicyMix.promote();
     const char *address = NULL;
-    if (outputDesc->mPolicyMix != NULL) {
-        policyMix = outputDesc->mPolicyMix;
+    if (policyMix != NULL) {
         audio_devices_t newDeviceType;
         address = policyMix->mDeviceAddress.string();
         if ((policyMix->mRouteFlags & MIX_ROUTE_FLAG_LOOP_BACK) == MIX_ROUTE_FLAG_LOOP_BACK) {
@@ -1689,8 +1694,9 @@
                 setOutputDevices(outputDesc, devices, force, 0, NULL, requiresMuteCheck);
 
         // apply volume rules for current stream and device if necessary
-        checkAndSetVolume(stream,
-                          getVolumeCurves(stream).getVolumeIndex(outputDesc->devices().types()),
+        auto &curves = getVolumeCurves(client->attributes());
+        checkAndSetVolume(curves, client->volumeSource(),
+                          curves.getVolumeIndex(outputDesc->devices().types()),
                           outputDesc,
                           outputDesc->devices().types());
 
@@ -1770,12 +1776,13 @@
         if (outputDesc->getActivityCount(clientVolSrc) == 1) {
             // Automatically disable the remote submix input when output is stopped on a
             // re routing mix of type MIX_TYPE_RECORDERS
+            sp<AudioPolicyMix> policyMix = outputDesc->mPolicyMix.promote();
             if (audio_is_remote_submix_device(outputDesc->devices().types()) &&
-                outputDesc->mPolicyMix != NULL &&
-                outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
+                policyMix != NULL &&
+                policyMix->mMixType == MIX_TYPE_RECORDERS) {
                 setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
                                             AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
-                                            outputDesc->mPolicyMix->mDeviceAddress,
+                                            policyMix->mDeviceAddress,
                                             "remote-submix", AUDIO_FORMAT_DEFAULT);
             }
         }
@@ -1890,7 +1897,7 @@
     status_t status = NO_ERROR;
     audio_source_t halInputSource;
     audio_attributes_t attributes = *attr;
-    AudioMix *policyMix = NULL;
+    sp<AudioPolicyMix> policyMix;
     sp<DeviceDescriptor> device;
     sp<AudioInputDescriptor> inputDesc;
     sp<RecordClientDescriptor> clientDesc;
@@ -1987,7 +1994,7 @@
             status = BAD_VALUE;
             goto error;
         }
-        if (policyMix != nullptr) {
+        if (policyMix) {
             ALOG_ASSERT(policyMix->mMixType == MIX_TYPE_RECORDERS, "Invalid Mix Type");
             // there is an external policy, but this input is attached to a mix of recorders,
             // meaning it receives audio injected into the framework, so the recorder doesn't
@@ -2039,7 +2046,7 @@
                                                         const audio_attributes_t &attributes,
                                                         const audio_config_base_t *config,
                                                         audio_input_flags_t flags,
-                                                        AudioMix *policyMix)
+                                                        const sp<AudioPolicyMix> &policyMix)
 {
     audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
     audio_source_t halInputSource = attributes.source;
@@ -2199,10 +2206,11 @@
     setInputDevice(input, device, true /* force */);
 
     if (inputDesc->activeCount()  == 1) {
+        sp<AudioPolicyMix> policyMix = inputDesc->mPolicyMix.promote();
         // if input maps to a dynamic policy with an activity listener, notify of state change
-        if ((inputDesc->mPolicyMix != NULL)
-                && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
-            mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
+        if ((policyMix != NULL)
+                && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+            mpClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
                     MIX_STATE_MIXING);
         }
 
@@ -2217,10 +2225,10 @@
         // For remote submix (a virtual device), we open only one input per capture request.
         if (audio_is_remote_submix_device(inputDesc->getDeviceType())) {
             String8 address = String8("");
-            if (inputDesc->mPolicyMix == NULL) {
+            if (policyMix == NULL) {
                 address = String8("0");
-            } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
-                address = inputDesc->mPolicyMix->mDeviceAddress;
+            } else if (policyMix->mMixType == MIX_TYPE_PLAYERS) {
+                address = policyMix->mDeviceAddress;
             }
             if (address != "") {
                 setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
@@ -2257,10 +2265,11 @@
     if (inputDesc->isActive()) {
         setInputDevice(input, getNewInputDevice(inputDesc), false /* force */);
     } else {
+        sp<AudioPolicyMix> policyMix = inputDesc->mPolicyMix.promote();
         // if input maps to a dynamic policy with an activity listener, notify of state change
-        if ((inputDesc->mPolicyMix != NULL)
-                && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
-            mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
+        if ((policyMix != NULL)
+                && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+            mpClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
                     MIX_STATE_IDLE);
         }
 
@@ -2268,10 +2277,10 @@
         // used by a policy mix of type MIX_TYPE_RECORDERS
         if (audio_is_remote_submix_device(inputDesc->getDeviceType())) {
             String8 address = String8("");
-            if (inputDesc->mPolicyMix == NULL) {
+            if (policyMix == NULL) {
                 address = String8("0");
-            } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
-                address = inputDesc->mPolicyMix->mDeviceAddress;
+            } else if (policyMix->mMixType == MIX_TYPE_PLAYERS) {
+                address = policyMix->mDeviceAddress;
             }
             if (address != "") {
                 setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
@@ -2379,131 +2388,60 @@
                                                   int index,
                                                   audio_devices_t device)
 {
-    auto &curves = getVolumeCurves(stream);
-    // VOICE_CALL and BLUETOOTH_SCO stream have minVolumeIndex > 0 but
-    // can be muted directly by an app that has MODIFY_PHONE_STATE permission.
-    if (((index < curves.getVolumeIndexMin()) &&
-            !((stream == AUDIO_STREAM_VOICE_CALL || stream == AUDIO_STREAM_BLUETOOTH_SCO) &&
-            index == 0)) ||
-            (index > curves.getVolumeIndexMax())) {
-        return BAD_VALUE;
-    }
-    if (!audio_is_output_device(device)) {
-        return BAD_VALUE;
-    }
-
-    // Force max volume if stream cannot be muted
-    if (!curves.canBeMuted()) index = curves.getVolumeIndexMax();
-
-    ALOGV("setStreamVolumeIndex() stream %d, device %08x, index %d",
-          stream, device, index);
-
-    // update other private stream volumes which follow this one
-    for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
-        if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
-            continue;
-        }
-        auto &curCurves = getVolumeCurves(static_cast<audio_stream_type_t>(curStream));
-        curCurves.addCurrentVolumeIndex(device, index);
-    }
-
-    // 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.
-    status_t status = NO_ERROR;
-    for (size_t i = 0; i < mOutputs.size(); i++) {
-        sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
-        audio_devices_t curDevice = desc->devices().types();
-        for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
-            if (!(streamsMatchForvolume(stream, (audio_stream_type_t)curStream))) {
-                continue;
-            }
-            if (!(desc->isActive(streamToVolumeSource((audio_stream_type_t)curStream)) || isInCall())) {
-                continue;
-            }
-            audio_devices_t curStreamDevice = Volume::getDeviceForVolume(
-                        mEngine->getOutputDevicesForStream((audio_stream_type_t)curStream,
-                                                           false /*fromCache*/).types());
-            if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) &&
-                    ((curStreamDevice & device) == 0)) {
-                continue;
-            }
-            bool applyVolume;
-            if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
-                curStreamDevice |= device;
-                applyVolume = (Volume::getDeviceForVolume(curDevice) & curStreamDevice) != 0;
-            } else {
-                applyVolume = !curves.hasVolumeIndexForDevice(curStreamDevice);
-            }
-            // rescale index before applying to curStream as ranges may be different for
-            // stream and curStream
-            int idx = rescaleVolumeIndex(index, stream, (audio_stream_type_t)curStream);
-            if (applyVolume) {
-                //FIXME: workaround for truncated touch sounds
-                // delayed volume change for system stream to be removed when the problem is
-                // handled by system UI
-                status_t volStatus = checkAndSetVolume(
-                            (audio_stream_type_t)curStream, idx, desc, curDevice,
-                            (stream == AUDIO_STREAM_SYSTEM) ?
-                                TOUCH_SOUND_FIXED_DELAY_MS : 0);
-                if (volStatus != NO_ERROR) {
-                    status = volStatus;
-                }
-            }
-        }
-    }
-    return status;
+    auto attributes = mEngine->getAttributesForStreamType(stream);
+    ALOGV("%s: stream %s attributes=%s", __func__,
+          toString(stream).c_str(), toString(attributes).c_str());
+    return setVolumeIndexForAttributes(attributes, index, device);
 }
 
 status_t AudioPolicyManager::getStreamVolumeIndex(audio_stream_type_t stream,
-                                                      int *index,
-                                                      audio_devices_t device)
+                                                  int *index,
+                                                  audio_devices_t device)
 {
-    if (index == NULL) {
-        return BAD_VALUE;
-    }
-    if (!audio_is_output_device(device)) {
-        return BAD_VALUE;
-    }
     // 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->getOutputDevicesForStream(stream, true /*fromCache*/).types();
     }
-    device = Volume::getDeviceForVolume(device);
-
-    *index =  getVolumeCurves(stream).getVolumeIndex(device);
-    ALOGV("getStreamVolumeIndex() stream %d device %08x index %d", stream, device, *index);
-    return NO_ERROR;
+    return getVolumeIndex(getVolumeCurves(stream), *index, device);
 }
 
-status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attr,
+status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attributes,
                                                          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());
+    auto group = mEngine->getVolumeGroupForAttributes(attributes);
+    if (group == VOLUME_GROUP_NONE) {
+        ALOGD("%s: no group matching with %s", __FUNCTION__, toString(attributes).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);
+    ALOGV("%s: group %d matching with %s", __FUNCTION__, group, toString(attributes).c_str());
     status_t status = NO_ERROR;
-    setVolumeCurveIndex(group, index, device, curves);
+    IVolumeCurves &curves = getVolumeCurves(attributes);
+    VolumeSource vs = toVolumeSource(group);
+    product_strategy_t strategy = mEngine->getProductStrategyForAttributes(attributes);
+
+    status = setVolumeCurveIndex(index, device, curves);
+    if (status != NO_ERROR) {
+        ALOGE("%s failed to set curve index for group %d device 0x%X", __func__, group, device);
+        return status;
+    }
+
+    audio_devices_t curSrcDevice;
+    auto curCurvAttrs = curves.getAttributes();
+    if (!curCurvAttrs.empty() && curCurvAttrs.front() != defaultAttr) {
+        auto attr = curCurvAttrs.front();
+        curSrcDevice = mEngine->getOutputDevicesForAttributes(attr, nullptr, false).types();
+    } else if (!curves.getStreamTypes().empty()) {
+        auto stream = curves.getStreamTypes().front();
+        curSrcDevice = mEngine->getOutputDevicesForStream(stream, false).types();
+    } else {
+        ALOGE("%s: Invalid src %d: no valid attributes nor stream",__func__, vs);
+        return BAD_VALUE;
+    }
+    curSrcDevice = Volume::getDeviceForVolume(curSrcDevice);
+
     // 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
@@ -2512,21 +2450,96 @@
     // 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
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+        audio_devices_t curDevice = desc->devices().types();
+
+        // Inter / intra volume group priority management: Loop on strategies arranged by priority
+        // If a higher priority strategy is active, and the output is routed to a device with a
+        // HW Gain management, do not change the volume
+        bool applyVolume = false;
+        if (desc->useHwGain()) {
+            if (!(desc->isActive(group) || isInCall())) {
+                continue;
+            }
+            for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
+                auto activeClients = desc->clientsList(true /*activeOnly*/, productStrategy,
+                                                       false /*preferredDevice*/);
+                if (activeClients.empty()) {
+                    continue;
+                }
+                bool isPreempted = false;
+                bool isHigherPriority = productStrategy < strategy;
+                for (const auto &client : activeClients) {
+                    if (isHigherPriority && (client->volumeSource() != vs)) {
+                        ALOGV("%s: Strategy=%d (\nrequester:\n"
+                              " group %d, volumeGroup=%d attributes=%s)\n"
+                              " higher priority source active:\n"
+                              " volumeGroup=%d attributes=%s) \n"
+                              " on output %zu, bailing out", __func__, productStrategy,
+                              group, group, toString(attributes).c_str(),
+                              client->volumeSource(), toString(client->attributes()).c_str(), i);
+                        applyVolume = false;
+                        isPreempted = true;
+                        break;
+                    }
+                    // However, continue for loop to ensure no higher prio clients running on output
+                    if (client->volumeSource() == vs) {
+                        applyVolume = true;
+                    }
+                }
+                if (isPreempted || applyVolume) {
+                    break;
+                }
+            }
+            if (!applyVolume) {
+                continue; // next output
+            }
+            status_t volStatus = checkAndSetVolume(curves, vs, index, desc, curDevice,
+                                                   (vs == toVolumeSource(AUDIO_STREAM_SYSTEM)?
+                                                        TOUCH_SOUND_FIXED_DELAY_MS : 0));
+            if (volStatus != NO_ERROR) {
+                status = volStatus;
+            }
+            continue;
+        }
+        if (!(desc->isActive(vs) || isInCall())) {
+            continue;
+        }
+        if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) && ((curDevice & device) == 0)) {
+            continue;
+        }
+        if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
+            curSrcDevice |= device;
+            applyVolume = (Volume::getDeviceForVolume(curDevice) & curSrcDevice) != 0;
+        } else {
+            applyVolume = !curves.hasVolumeIndexForDevice(curSrcDevice);
+        }
+        if (applyVolume) {
+            //FIXME: workaround for truncated touch sounds
+            // delayed volume change for system stream to be removed when the problem is
+            // handled by system UI
+            status_t volStatus = checkAndSetVolume(
+                        curves, vs, index, desc, curDevice,
+                        ((vs == toVolumeSource(AUDIO_STREAM_SYSTEM))?
+                             TOUCH_SOUND_FIXED_DELAY_MS : 0));
+            if (volStatus != NO_ERROR) {
+                status = volStatus;
+            }
+        }
+    }
     mpClientInterface->onAudioVolumeGroupChanged(group, 0 /*flags*/);
     return status;
 }
 
-status_t AudioPolicyManager::setVolumeCurveIndex(volume_group_t volumeGroup,
-                                                 int index,
+status_t AudioPolicyManager::setVolumeCurveIndex(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)) ||
+    bool hasVoice = hasVoiceStream(volumeCurves.getStreamTypes());
+    if (((index < volumeCurves.getVolumeIndexMin()) && !(hasVoice && index == 0)) ||
             (index > volumeCurves.getVolumeIndexMax())) {
         ALOGD("%s: wrong index %d min=%d max=%d", __FUNCTION__, index,
               volumeCurves.getVolumeIndexMin(), volumeCurves.getVolumeIndexMax());
@@ -2539,7 +2552,7 @@
     // Force max volume if stream cannot be muted
     if (!volumeCurves.canBeMuted()) index = volumeCurves.getVolumeIndexMax();
 
-    ALOGD("%s device %08x, index %d", __FUNCTION__ , device, index);
+    ALOGV("%s device %08x, index %d", __FUNCTION__ , device, index);
     volumeCurves.addCurrentVolumeIndex(device, index);
     return NO_ERROR;
 }
@@ -2701,19 +2714,12 @@
 
 bool AudioPolicyManager::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
 {
-    bool active = false;
-    for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT && !active; curStream++) {
-        if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
-            continue;
-        }
-        active = mOutputs.isActive(streamToVolumeSource((audio_stream_type_t)curStream), inPastMs);
-    }
-    return active;
+    return mOutputs.isActive(toVolumeSource(stream), inPastMs);
 }
 
 bool AudioPolicyManager::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const
 {
-    return mOutputs.isActiveRemotely(streamToVolumeSource((audio_stream_type_t)stream), inPastMs);
+    return mOutputs.isActiveRemotely(toVolumeSource(stream), inPastMs);
 }
 
 bool AudioPolicyManager::isSourceActive(audio_source_t source) const
@@ -3742,11 +3748,11 @@
     struct audio_patch dummyPatch = {};
     sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
 
-    sp<SourceClientDescriptor> sourceDesc = new SourceClientDescriptor(
-                *portId, uid, *attributes, patchDesc, srcDevice,
-                mEngine->getStreamTypeForAttributes(*attributes),
-                mEngine->getProductStrategyForAttributes(*attributes),
-                streamToVolumeSource(mEngine->getStreamTypeForAttributes(*attributes)));
+    sp<SourceClientDescriptor> sourceDesc =
+        new SourceClientDescriptor(*portId, uid, *attributes, patchDesc, srcDevice,
+                                   mEngine->getStreamTypeForAttributes(*attributes),
+                                   mEngine->getProductStrategyForAttributes(*attributes),
+                                   toVolumeSource(*attributes));
 
     status_t status = connectAudioSource(sourceDesc);
     if (status == NO_ERROR) {
@@ -3911,7 +3917,7 @@
 float AudioPolicyManager::getStreamVolumeDB(
         audio_stream_type_t stream, int index, audio_devices_t device)
 {
-    return computeVolume(stream, index, device);
+    return computeVolume(getVolumeCurves(stream), toVolumeSource(stream), index, device);
 }
 
 status_t AudioPolicyManager::getSurroundFormats(unsigned int *numSurroundFormats,
@@ -4577,7 +4583,7 @@
                         sp<AudioPolicyMix> policyMix;
                         if (mPolicyMixes.getAudioPolicyMix(address, policyMix) == NO_ERROR) {
                             policyMix->setOutput(desc);
-                            desc->mPolicyMix = policyMix->getMix();
+                            desc->mPolicyMix = policyMix;
                         } else {
                             ALOGW("checkOutputsForDevice() cannot find policy for address %s",
                                   address.string());
@@ -5287,11 +5293,10 @@
         // mute/unmute AUDIO_STREAM_TTS on all outputs
         ALOGV("\t muting %d", mute);
         uint32_t maxLatency = 0;
+        auto ttsVolumeSource = toVolumeSource(AUDIO_STREAM_TTS);
         for (size_t i = 0; i < mOutputs.size(); i++) {
             sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
-            setStreamMute(AUDIO_STREAM_TTS, mute/*on*/,
-                    desc,
-                    0 /*delay*/, AUDIO_DEVICE_NONE);
+            setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, AUDIO_DEVICE_NONE);
             const uint32_t latency = desc->latency() * 2;
             if (latency > maxLatency) {
                 maxLatency = latency;
@@ -5375,15 +5380,12 @@
         if (muteWaitMs < tempMuteWaitMs) {
             muteWaitMs = tempMuteWaitMs;
         }
-
-        for (const auto &productStrategy : productStrategies) {
-            if (outputDesc->isStrategyActive(productStrategy)) {
-                // make sure that we do not start the temporary mute period too early in case of
-                // delayed device change
-                setStrategyMute(productStrategy, true, outputDesc, delayMs);
-                setStrategyMute(productStrategy, false, outputDesc, delayMs + tempMuteDurationMs,
+        for (const auto &activeVs : outputDesc->getActiveVolumeSources()) {
+            // make sure that we do not start the temporary mute period too early in case of
+            // delayed device change
+            setVolumeSourceMute(activeVs, true, outputDesc, delayMs);
+            setVolumeSourceMute(activeVs, false, outputDesc, delayMs + tempMuteDurationMs,
                                 devices.types());
-            }
         }
     }
 
@@ -5607,51 +5609,51 @@
     return NULL;
 }
 
-float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
+float AudioPolicyManager::computeVolume(IVolumeCurves &curves,
+                                        VolumeSource volumeSource,
                                         int index,
                                         audio_devices_t device)
 {
-    auto &curves = getVolumeCurves(stream);
     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
     // exploration of the dialer UI. In this situation, bring the accessibility volume closer to
     // the ringtone volume
-    if ((stream == AUDIO_STREAM_ACCESSIBILITY)
-            && (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;
+    const auto callVolumeSrc = toVolumeSource(AUDIO_STREAM_VOICE_CALL);
+    const auto ringVolumeSrc = toVolumeSource(AUDIO_STREAM_RING);
+    const auto musicVolumeSrc = toVolumeSource(AUDIO_STREAM_MUSIC);
+    const auto alarmVolumeSrc = toVolumeSource(AUDIO_STREAM_ALARM);
+
+    if (volumeSource == toVolumeSource(AUDIO_STREAM_ACCESSIBILITY)
+            && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState()) &&
+            mOutputs.isActive(ringVolumeSrc, 0)) {
+        auto &ringCurves = getVolumeCurves(AUDIO_STREAM_RING);
+        const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, device);
+        return ringVolumeDb - 4 > volumeDb ? ringVolumeDb - 4 : volumeDb;
     }
 
     // in-call: always cap volume by voice volume + some low headroom
-    if ((stream != AUDIO_STREAM_VOICE_CALL) &&
-            (isInCall() || mOutputs.isActiveLocally(streamToVolumeSource(AUDIO_STREAM_VOICE_CALL)))) {
-        switch (stream) {
-        case AUDIO_STREAM_SYSTEM:
-        case AUDIO_STREAM_RING:
-        case AUDIO_STREAM_MUSIC:
-        case AUDIO_STREAM_ALARM:
-        case AUDIO_STREAM_NOTIFICATION:
-        case AUDIO_STREAM_ENFORCED_AUDIBLE:
-        case AUDIO_STREAM_DTMF:
-        case AUDIO_STREAM_ACCESSIBILITY: {
-            int voiceVolumeIndex = getVolumeCurves(AUDIO_STREAM_VOICE_CALL).getVolumeIndex(device);
-            const float maxVoiceVolDb =
-                computeVolume(AUDIO_STREAM_VOICE_CALL, voiceVolumeIndex, device)
+    if ((volumeSource != callVolumeSrc && (isInCall() ||
+                                           mOutputs.isActiveLocally(callVolumeSrc))) &&
+            (volumeSource == toVolumeSource(AUDIO_STREAM_SYSTEM) ||
+             volumeSource == ringVolumeSrc || volumeSource == musicVolumeSrc ||
+             volumeSource == alarmVolumeSrc ||
+             volumeSource == toVolumeSource(AUDIO_STREAM_NOTIFICATION) ||
+             volumeSource == toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE) ||
+             volumeSource == toVolumeSource(AUDIO_STREAM_DTMF) ||
+             volumeSource == toVolumeSource(AUDIO_STREAM_ACCESSIBILITY))) {
+        auto &voiceCurves = getVolumeCurves(callVolumeSrc);
+        int voiceVolumeIndex = voiceCurves.getVolumeIndex(device);
+        const float maxVoiceVolDb =
+                computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, device)
                 + IN_CALL_EARPIECE_HEADROOM_DB;
-            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;
-            }
-            } break;
-        default:
-            break;
+        if (volumeDb > maxVoiceVolDb) {
+            ALOGV("%s volume source %d at vol=%f overriden by volume group %d at vol=%f", __func__,
+                  volumeSource, volumeDb, callVolumeSrc, maxVoiceVolDb);
+            volumeDb = maxVoiceVolDb;
         }
     }
-
     // if a headset is connected, apply the following rules to ring tones and notifications
     // to avoid sound level bursts in user's ears:
     // - always attenuate notifications volume by 6dB
@@ -5659,19 +5661,17 @@
     // speaker is part of the select devices
     // - if music is playing, always limit the volume to current music volume,
     // with a minimum threshold at -36dB so that notification is always perceived.
-    if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
-            AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
-            AUDIO_DEVICE_OUT_WIRED_HEADSET |
-            AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
-            AUDIO_DEVICE_OUT_USB_HEADSET |
-            AUDIO_DEVICE_OUT_HEARING_AID)) &&
-        ((stream == AUDIO_STREAM_ALARM || stream == AUDIO_STREAM_RING)
-                || (stream == AUDIO_STREAM_NOTIFICATION)
-                || (stream == AUDIO_STREAM_SYSTEM)
-                || ((stream == AUDIO_STREAM_ENFORCED_AUDIBLE) &&
-                    (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) ==
-                     AUDIO_POLICY_FORCE_NONE))) &&
-            getVolumeCurves(stream).canBeMuted()) {
+    if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+                   AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+                   AUDIO_DEVICE_OUT_USB_HEADSET | AUDIO_DEVICE_OUT_HEARING_AID)) &&
+            ((volumeSource == alarmVolumeSrc ||
+              volumeSource == ringVolumeSrc) ||
+             (volumeSource == toVolumeSource(AUDIO_STREAM_NOTIFICATION)) ||
+             (volumeSource == toVolumeSource(AUDIO_STREAM_SYSTEM)) ||
+             ((volumeSource == toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE)) &&
+              (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) &&
+            curves.canBeMuted()) {
+
         // when the phone is ringing we must consider that music could have been paused just before
         // by the music application and behave as if music was active if the last music track was
         // just stopped
@@ -5681,29 +5681,29 @@
             audio_devices_t musicDevice =
                     mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA),
                                                            nullptr, true /*fromCache*/).types();
-            float musicVolDB = computeVolume(AUDIO_STREAM_MUSIC,
-                                   getVolumeCurves(AUDIO_STREAM_MUSIC).getVolumeIndex(musicDevice),
-                                   musicDevice);
-            float minVolDB = (musicVolDB > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
-                    musicVolDB : SONIFICATION_HEADSET_VOLUME_MIN_DB;
-            if (volumeDb > minVolDB) {
-                volumeDb = minVolDB;
-                ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDB, musicVolDB);
+            auto &musicCurves = getVolumeCurves(AUDIO_STREAM_MUSIC);
+            float musicVolDb = computeVolume(musicCurves, musicVolumeSrc,
+                                             musicCurves.getVolumeIndex(musicDevice), musicDevice);
+            float minVolDb = (musicVolDb > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
+                        musicVolDb : SONIFICATION_HEADSET_VOLUME_MIN_DB;
+            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)) {
+                          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)) {
-                    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;
+                        (musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDb)) {
+                    ALOGV("%s increasing volume for volume source=%d device=0x%X from %f to %f",
+                          __func__, volumeSource, device, 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)) {
+                   (!(volumeSource == alarmVolumeSrc || volumeSource == ringVolumeSrc))) {
             volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
         }
     }
@@ -5712,14 +5712,14 @@
 }
 
 int AudioPolicyManager::rescaleVolumeIndex(int srcIndex,
-                                           audio_stream_type_t srcStream,
-                                           audio_stream_type_t dstStream)
+                                           VolumeSource fromVolumeSource,
+                                           VolumeSource toVolumeSource)
 {
-    if (srcStream == dstStream) {
+    if (fromVolumeSource == toVolumeSource) {
         return srcIndex;
     }
-    auto &srcCurves = getVolumeCurves(srcStream);
-    auto &dstCurves = getVolumeCurves(dstStream);
+    auto &srcCurves = getVolumeCurves(fromVolumeSource);
+    auto &dstCurves = getVolumeCurves(toVolumeSource);
     float minSrc = (float)srcCurves.getVolumeIndexMin();
     float maxSrc = (float)srcCurves.getVolumeIndexMax();
     float minDst = (float)dstCurves.getVolumeIndexMin();
@@ -5737,58 +5737,61 @@
     return (int)(minDst + ((srcIndex - minSrc) * (maxDst - minDst)) / (maxSrc - minSrc));
 }
 
-status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,
+status_t AudioPolicyManager::checkAndSetVolume(IVolumeCurves &curves,
+                                               VolumeSource volumeSource,
                                                int index,
                                                const sp<AudioOutputDescriptor>& outputDesc,
                                                audio_devices_t device,
                                                int delayMs,
                                                bool force)
 {
-    // do not change actual stream volume if the stream is muted
-    if (outputDesc->isMuted(streamToVolumeSource(stream))) {
-        ALOGVV("%s() stream %d muted count %d", __func__, stream, outputDesc->getMuteCount(stream));
+    // do not change actual attributes volume if the attributes is muted
+    if (outputDesc->isMuted(volumeSource)) {
+        ALOGVV("%s: volume source %d muted count %d active=%d", __func__, volumeSource,
+               outputDesc->getMuteCount(volumeSource), outputDesc->isActive(volumeSource));
         return NO_ERROR;
     }
+    VolumeSource callVolSrc = toVolumeSource(AUDIO_STREAM_VOICE_CALL);
+    VolumeSource btScoVolSrc = toVolumeSource(AUDIO_STREAM_BLUETOOTH_SCO);
+    bool isVoiceVolSrc = callVolSrc == volumeSource;
+    bool isBtScoVolSrc = btScoVolSrc == volumeSource;
+
     audio_policy_forced_cfg_t forceUseForComm =
             mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION);
     // do not change in call volume if bluetooth is connected and vice versa
-    if ((stream == AUDIO_STREAM_VOICE_CALL && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) ||
-        (stream == AUDIO_STREAM_BLUETOOTH_SCO && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO)) {
-        ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
-             stream, forceUseForComm);
+    // if sco and call follow same curves, bypass forceUseForComm
+    if ((callVolSrc != btScoVolSrc) &&
+            ((isVoiceVolSrc && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) ||
+             (isBtScoVolSrc && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO))) {
+        ALOGV("%s cannot set volume group %d volume with force use = %d for comm", __func__,
+             volumeSource, forceUseForComm);
         return INVALID_OPERATION;
     }
-
     if (device == AUDIO_DEVICE_NONE) {
         device = outputDesc->devices().types();
     }
 
-    float volumeDb = computeVolume(stream, index, device);
+    float volumeDb = computeVolume(curves, volumeSource, index, device);
     if (outputDesc->isFixedVolume(device) ||
             // Force VoIP volume to max for bluetooth SCO
-            ((stream == AUDIO_STREAM_VOICE_CALL || stream == AUDIO_STREAM_BLUETOOTH_SCO) &&
-             (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) {
+            ((isVoiceVolSrc || isBtScoVolSrc) && (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) {
         volumeDb = 0.0f;
     }
+    outputDesc->setVolume(volumeDb, volumeSource, curves.getStreamTypes(), device, delayMs, force);
 
-    outputDesc->setVolume(volumeDb, stream, device, delayMs, force);
-
-    if (stream == AUDIO_STREAM_VOICE_CALL ||
-        stream == AUDIO_STREAM_BLUETOOTH_SCO) {
+    if (isVoiceVolSrc || isBtScoVolSrc) {
         float voiceVolume;
         // Force voice volume to max for bluetooth SCO as volume is managed by the headset
-        if (stream == AUDIO_STREAM_VOICE_CALL) {
-            voiceVolume = (float)index/(float)getVolumeCurves(stream).getVolumeIndexMax();
+        if (isVoiceVolSrc) {
+            voiceVolume = (float)index/(float)curves.getVolumeIndexMax();
         } else {
             voiceVolume = 1.0;
         }
-
         if (voiceVolume != mLastVoiceVolume) {
             mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
             mLastVoiceVolume = voiceVolume;
         }
     }
-
     return NO_ERROR;
 }
 
@@ -5798,14 +5801,10 @@
                                                 bool force)
 {
     ALOGVV("applyStreamVolumes() for device %08x", device);
-
-    for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++) {
-        checkAndSetVolume((audio_stream_type_t)stream,
-                          getVolumeCurves((audio_stream_type_t)stream).getVolumeIndex(device),
-                          outputDesc,
-                          device,
-                          delayMs,
-                          force);
+    for (const auto &volumeGroup : mEngine->getVolumeGroups()) {
+        auto &curves = getVolumeCurves(toVolumeSource(volumeGroup));
+        checkAndSetVolume(curves, toVolumeSource(volumeGroup),
+                          curves.getVolumeIndex(device), outputDesc, device, delayMs, force);
     }
 }
 
@@ -5815,43 +5814,50 @@
                                          int delayMs,
                                          audio_devices_t device)
 {
-    for (auto stream: mEngine->getStreamTypesForProductStrategy(strategy)) {
-        ALOGVV("%s() stream %d, mute %d, output ID %d", __FUNCTION__, stream, on,
-               outputDesc->getId());
-        setStreamMute(stream, on, outputDesc, delayMs, device);
+    std::vector<VolumeSource> sourcesToMute;
+    for (auto attributes: mEngine->getAllAttributesForProductStrategy(strategy)) {
+        ALOGVV("%s() attributes %s, mute %d, output ID %d", __func__,
+               toString(attributes).c_str(), on, outputDesc->getId());
+        VolumeSource source = toVolumeSource(attributes);
+        if (std::find(begin(sourcesToMute), end(sourcesToMute), source) == end(sourcesToMute)) {
+            sourcesToMute.push_back(source);
+        }
     }
+    for (auto source : sourcesToMute) {
+        setVolumeSourceMute(source, on, outputDesc, delayMs, device);
+    }
+
 }
 
-void AudioPolicyManager::setStreamMute(audio_stream_type_t stream,
-                                           bool on,
-                                           const sp<AudioOutputDescriptor>& outputDesc,
-                                           int delayMs,
-                                           audio_devices_t device)
+void AudioPolicyManager::setVolumeSourceMute(VolumeSource volumeSource,
+                                             bool on,
+                                             const sp<AudioOutputDescriptor>& outputDesc,
+                                             int delayMs,
+                                             audio_devices_t device)
 {
     if (device == AUDIO_DEVICE_NONE) {
         device = outputDesc->devices().types();
     }
-
-    ALOGVV("setStreamMute() stream %d, mute %d, mMuteCount %d device %04x",
-          stream, on, outputDesc->getMuteCount(stream), device);
-    auto &curves = getVolumeCurves(stream);
+    auto &curves = getVolumeCurves(volumeSource);
     if (on) {
-        if (!outputDesc->isMuted(streamToVolumeSource(stream))) {
+        if (!outputDesc->isMuted(volumeSource)) {
             if (curves.canBeMuted() &&
-                    ((stream != AUDIO_STREAM_ENFORCED_AUDIBLE) ||
-                     (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) {
-                checkAndSetVolume(stream, 0, outputDesc, device, delayMs);
+                    (volumeSource != toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE) ||
+                     (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) ==
+                      AUDIO_POLICY_FORCE_NONE))) {
+                checkAndSetVolume(curves, volumeSource, 0, outputDesc, device, delayMs);
             }
         }
-        // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored
-        outputDesc->incMuteCount(streamToVolumeSource(stream));
+        // increment mMuteCount after calling checkAndSetVolume() so that volume change is not
+        // ignored
+        outputDesc->incMuteCount(volumeSource);
     } else {
-        if (!outputDesc->isMuted(streamToVolumeSource(stream))) {
-            ALOGV("setStreamMute() unmuting non muted stream!");
+        if (!outputDesc->isMuted(volumeSource)) {
+            ALOGV("%s unmuting non muted attributes!", __func__);
             return;
         }
-        if (outputDesc->decMuteCount(streamToVolumeSource(stream)) == 0) {
-            checkAndSetVolume(stream,
+        if (outputDesc->decMuteCount(volumeSource) == 0) {
+            checkAndSetVolume(curves, volumeSource,
                               curves.getVolumeIndex(device),
                               outputDesc,
                               device,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 641a03a..1c98684 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -171,11 +171,7 @@
 
         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,
+        status_t setVolumeCurveIndex(int index,
                                      audio_devices_t device,
                                      IVolumeCurves &volumeCurves);
 
@@ -358,6 +354,30 @@
             return mDefaultOutputDevice;
         }
 
+        std::vector<volume_group_t> getVolumeGroups() const
+        {
+            return mEngine->getVolumeGroups();
+        }
+
+        VolumeSource toVolumeSource(volume_group_t volumeGroup) const
+        {
+            return static_cast<VolumeSource>(volumeGroup);
+        }
+        VolumeSource toVolumeSource(const audio_attributes_t &attributes) const
+        {
+            return toVolumeSource(mEngine->getVolumeGroupForAttributes(attributes));
+        }
+        VolumeSource toVolumeSource(audio_stream_type_t stream) const
+        {
+            return toVolumeSource(mEngine->getVolumeGroupForStreamType(stream));
+        }
+        IVolumeCurves &getVolumeCurves(VolumeSource volumeSource)
+        {
+          auto *curves = mEngine->getVolumeCurvesForVolumeGroup(
+              static_cast<volume_group_t>(volumeSource));
+          ALOG_ASSERT(curves != nullptr, "No curves for volume source %d", volumeSource);
+          return *curves;
+        }
         IVolumeCurves &getVolumeCurves(const audio_attributes_t &attr)
         {
             auto *curves = mEngine->getVolumeCurvesForAttributes(attr);
@@ -395,16 +415,18 @@
 
         // compute the actual volume for a given stream according to the requested index and a particular
         // device
-        virtual float computeVolume(audio_stream_type_t stream,
+        virtual float computeVolume(IVolumeCurves &curves,
+                                    VolumeSource volumeSource,
                                     int index,
                                     audio_devices_t device);
 
         // rescale volume index from srcStream within range of dstStream
         int rescaleVolumeIndex(int srcIndex,
-                               audio_stream_type_t srcStream,
-                               audio_stream_type_t dstStream);
+                               VolumeSource fromVolumeSource,
+                               VolumeSource toVolumeSource);
         // check that volume change is permitted, compute and send new volume to audio hardware
-        virtual status_t checkAndSetVolume(audio_stream_type_t stream, int index,
+        virtual status_t checkAndSetVolume(IVolumeCurves &curves,
+                                           VolumeSource volumeSource, int index,
                                            const sp<AudioOutputDescriptor>& outputDesc,
                                            audio_devices_t device,
                                            int delayMs = 0, bool force = false);
@@ -428,12 +450,20 @@
                              int delayMs = 0,
                              audio_devices_t device = AUDIO_DEVICE_NONE);
 
-        // Mute or unmute the stream on the specified output
-        void setStreamMute(audio_stream_type_t stream,
-                           bool on,
-                           const sp<AudioOutputDescriptor>& outputDesc,
-                           int delayMs = 0,
-                           audio_devices_t device = (audio_devices_t)0);
+        /**
+         * @brief setVolumeSourceMute Mute or unmute the volume source on the specified output
+         * @param volumeSource to be muted/unmute (may host legacy streams or by extension set of
+         * audio attributes)
+         * @param on true to mute, false to umute
+         * @param outputDesc on which the client following the volume group shall be muted/umuted
+         * @param delayMs
+         * @param device
+         */
+        void setVolumeSourceMute(VolumeSource volumeSource,
+                                 bool on,
+                                 const sp<AudioOutputDescriptor>& outputDesc,
+                                 int delayMs = 0,
+                                 audio_devices_t device = AUDIO_DEVICE_NONE);
 
         audio_mode_t getPhoneState();
 
@@ -779,7 +809,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
@@ -798,7 +829,7 @@
                 const audio_attributes_t &attributes,
                 const audio_config_base_t *config,
                 audio_input_flags_t flags,
-                AudioMix *policyMix);
+                const sp<AudioPolicyMix> &policyMix);
 
         // event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON
         // returns 0 if no mute/unmute event happened, the largest latency of the device where
diff --git a/services/camera/OWNERS b/services/camera/OWNERS
index 18acfee..f48a95c 100644
--- a/services/camera/OWNERS
+++ b/services/camera/OWNERS
@@ -1,6 +1 @@
-cychen@google.com
-epeev@google.com
-etalvala@google.com
-shuzhenwang@google.com
-yinchiayeh@google.com
-zhijunhe@google.com
+include platform/frameworks/av:/camera/OWNERS
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 62ec955..51d0682 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2180,31 +2180,37 @@
     return mp;
 }
 
-void CameraService::loadSound() {
+void CameraService::increaseSoundRef() {
+    Mutex::Autolock lock(mSoundLock);
+    mSoundRef++;
+}
+
+void CameraService::loadSoundLocked(sound_kind kind) {
     ATRACE_CALL();
 
-    Mutex::Autolock lock(mSoundLock);
-    LOG1("CameraService::loadSound ref=%d", mSoundRef);
-    if (mSoundRef++) return;
-
-    mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/product/media/audio/ui/camera_click.ogg");
-    if (mSoundPlayer[SOUND_SHUTTER] == nullptr) {
-        mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
-    }
-    mSoundPlayer[SOUND_RECORDING_START] = newMediaPlayer("/product/media/audio/ui/VideoRecord.ogg");
-    if (mSoundPlayer[SOUND_RECORDING_START] == nullptr) {
-        mSoundPlayer[SOUND_RECORDING_START] =
+    LOG1("CameraService::loadSoundLocked ref=%d", mSoundRef);
+    if (SOUND_SHUTTER == kind && mSoundPlayer[SOUND_SHUTTER] == NULL) {
+        mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/product/media/audio/ui/camera_click.ogg");
+        if (mSoundPlayer[SOUND_SHUTTER] == nullptr) {
+            mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
+        }
+    } else if (SOUND_RECORDING_START == kind && mSoundPlayer[SOUND_RECORDING_START] ==  NULL) {
+        mSoundPlayer[SOUND_RECORDING_START] = newMediaPlayer("/product/media/audio/ui/VideoRecord.ogg");
+        if (mSoundPlayer[SOUND_RECORDING_START] == nullptr) {
+            mSoundPlayer[SOUND_RECORDING_START] =
                 newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg");
-    }
-    mSoundPlayer[SOUND_RECORDING_STOP] = newMediaPlayer("/product/media/audio/ui/VideoStop.ogg");
-    if (mSoundPlayer[SOUND_RECORDING_STOP] == nullptr) {
-        mSoundPlayer[SOUND_RECORDING_STOP] = newMediaPlayer("/system/media/audio/ui/VideoStop.ogg");
+        }
+    } else if (SOUND_RECORDING_STOP == kind && mSoundPlayer[SOUND_RECORDING_STOP] == NULL) {
+        mSoundPlayer[SOUND_RECORDING_STOP] = newMediaPlayer("/product/media/audio/ui/VideoStop.ogg");
+        if (mSoundPlayer[SOUND_RECORDING_STOP] == nullptr) {
+            mSoundPlayer[SOUND_RECORDING_STOP] = newMediaPlayer("/system/media/audio/ui/VideoStop.ogg");
+        }
     }
 }
 
-void CameraService::releaseSound() {
+void CameraService::decreaseSoundRef() {
     Mutex::Autolock lock(mSoundLock);
-    LOG1("CameraService::releaseSound ref=%d", mSoundRef);
+    LOG1("CameraService::decreaseSoundRef ref=%d", mSoundRef);
     if (--mSoundRef) return;
 
     for (int i = 0; i < NUM_SOUNDS; i++) {
@@ -2220,6 +2226,7 @@
 
     LOG1("playSound(%d)", kind);
     Mutex::Autolock lock(mSoundLock);
+    loadSoundLocked(kind);
     sp<MediaPlayer> player = mSoundPlayer[kind];
     if (player != 0) {
         player->seekTo(0);
@@ -2249,7 +2256,7 @@
 
     mRemoteCallback = cameraClient;
 
-    cameraService->loadSound();
+    cameraService->increaseSoundRef();
 
     LOG1("Client::Client X (pid %d, id %d)", callingPid, mCameraId);
 }
@@ -2259,7 +2266,7 @@
     ALOGV("~Client");
     mDestructionStarted = true;
 
-    sCameraService->releaseSound();
+    sCameraService->decreaseSoundRef();
     // unconditionally disconnect. function is idempotent
     Client::disconnect();
 }
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 65727ec..344dd92 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -192,10 +192,10 @@
         NUM_SOUNDS
     };
 
-    void                loadSound();
     void                playSound(sound_kind kind);
-    void                releaseSound();
-
+    void                loadSoundLocked(sound_kind kind);
+    void                decreaseSoundRef();
+    void                increaseSoundRef();
     /**
      * Update the state of a given camera device (open/close/active/idle) with
      * the camera proxy service in the system service
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index b512f2b..c7a4f2b 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -604,6 +604,7 @@
     stream->v3_2.usage = Camera3Device::mapToConsumerUsage(u);
     stream->v3_2.dataSpace = Camera3Device::mapToHidlDataspace(streamInfo.dataSpace);
     stream->v3_2.rotation = Camera3Device::mapToStreamRotation(rotation);
+    stream->v3_2.id = -1; // Invalid stream id
     stream->physicalCameraId = std::string(physicalId.string());
     stream->bufferSize = 0;
 }
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 9fd0e8b..743c816 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -1177,7 +1177,7 @@
     outputFormat->setInt32(KEY_BITRATE_MODE, BITRATE_MODE_CQ);
     outputFormat->setInt32(KEY_QUALITY, kDefaultJpegQuality);
     // Ask codec to skip timestamp check and encode all frames.
-    outputFormat->setInt64("max-pts-gap-to-encoder", kNoFrameDropMaxPtsGap);
+    outputFormat->setInt64(KEY_MAX_PTS_GAP_TO_ENCODER, kNoFrameDropMaxPtsGap);
 
     int32_t gridWidth, gridHeight, gridRows, gridCols;
     if (useGrid || mUseHeic) {
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
index 8c8b97a..d6bf83e 100644
--- a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
@@ -237,7 +237,7 @@
 }
 
 status_t Camera3BufferManager::getBufferForStream(int streamId, int streamSetId,
-        sp<GraphicBuffer>* gb, int* fenceFd) {
+        sp<GraphicBuffer>* gb, int* fenceFd, bool noFreeBufferAtConsumer) {
     ATRACE_CALL();
 
     Mutex::Autolock l(mLock);
@@ -253,14 +253,19 @@
     StreamSet &streamSet = mStreamSetMap.editValueFor(streamSetId);
     BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap;
     size_t& bufferCount = handOutBufferCounts.editValueFor(streamId);
+    BufferCountMap& attachedBufferCounts = streamSet.attachedBufferCountMap;
+    size_t& attachedBufferCount = attachedBufferCounts.editValueFor(streamId);
+
+    if (noFreeBufferAtConsumer) {
+        attachedBufferCount = bufferCount;
+    }
+
     if (bufferCount >= streamSet.maxAllowedBufferCount) {
         ALOGE("%s: bufferCount (%zu) exceeds the max allowed buffer count (%zu) of this stream set",
                 __FUNCTION__, bufferCount, streamSet.maxAllowedBufferCount);
         return INVALID_OPERATION;
     }
 
-    BufferCountMap& attachedBufferCounts = streamSet.attachedBufferCountMap;
-    size_t& attachedBufferCount = attachedBufferCounts.editValueFor(streamId);
     if (attachedBufferCount > bufferCount) {
         // We've already attached more buffers to this stream than we currently have
         // outstanding, so have the stream just use an already-attached buffer
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.h b/services/camera/libcameraservice/device3/Camera3BufferManager.h
index 025062e..f0de1c1 100644
--- a/services/camera/libcameraservice/device3/Camera3BufferManager.h
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.h
@@ -112,6 +112,10 @@
      *
      * After this call, the client takes over the ownership of this buffer if it is not freed.
      *
+     * Sometimes free buffers are discarded from consumer side and the dequeueBuffer call returns
+     * TIMED_OUT, in this case calling getBufferForStream again with noFreeBufferAtConsumer set to
+     * true will notify buffer manager to update its states and also tries to allocate a new buffer.
+     *
      * Return values:
      *
      *  OK:        Getting buffer for this stream was successful.
@@ -122,7 +126,9 @@
      *             to this buffer manager before.
      *  NO_MEMORY: Unable to allocate a buffer for this stream at this time.
      */
-    status_t getBufferForStream(int streamId, int streamSetId, sp<GraphicBuffer>* gb, int* fenceFd);
+    status_t getBufferForStream(
+            int streamId, int streamSetId, sp<GraphicBuffer>* gb, int* fenceFd,
+            bool noFreeBufferAtConsumer = false);
 
     /**
      * This method notifies the manager that a buffer has been released by the consumer.
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 2794324..22e09e4 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -4391,8 +4391,11 @@
             dst.status = BufferStatus::OK;
             dst.releaseFence = nullptr;
 
-            pushInflightBufferLocked(captureRequest->frameNumber, streamId,
-                    src->buffer, src->acquire_fence);
+            // Output buffers are empty when using HAL buffer manager
+            if (!mUseHalBufManager) {
+                pushInflightBufferLocked(captureRequest->frameNumber, streamId,
+                        src->buffer, src->acquire_fence);
+            }
         }
     }
     return OK;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 8cd575d..baba856 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -359,7 +359,18 @@
     // Set dequeueBuffer/attachBuffer timeout if the consumer is not hw composer or hw texture.
     // We need skip these cases as timeout will disable the non-blocking (async) mode.
     if (!(isConsumedByHWComposer() || isConsumedByHWTexture())) {
-        mConsumer->setDequeueTimeout(kDequeueBufferTimeout);
+        if (mUseBufferManager) {
+            // When buffer manager is handling the buffer, we should have available buffers in
+            // buffer queue before we calls into dequeueBuffer because buffer manager is tracking
+            // free buffers.
+            // There are however some consumer side feature (ImageReader::discardFreeBuffers) that
+            // can discard free buffers without notifying buffer manager. We want the timeout to
+            // happen immediately here so buffer manager can try to update its internal state and
+            // try to allocate a buffer instead of waiting.
+            mConsumer->setDequeueTimeout(0);
+        } else {
+            mConsumer->setDequeueTimeout(kDequeueBufferTimeout);
+        }
     }
 
     return OK;
@@ -526,6 +537,8 @@
             if (res != OK) {
                 ALOGE("%s: Stream %d: Can't attach the output buffer to this surface: %s (%d)",
                         __FUNCTION__, mId, strerror(-res), res);
+
+                checkRetAndSetAbandonedLocked(res);
                 return res;
             }
             gotBufferFromManager = true;
@@ -562,35 +575,70 @@
         mDequeueBufferLatency.add(dequeueStart, dequeueEnd);
 
         mLock.lock();
-        if (res != OK) {
+
+        if (mUseBufferManager && res == TIMED_OUT) {
+            checkRemovedBuffersLocked();
+
+            sp<GraphicBuffer> gb;
+            res = mBufferManager->getBufferForStream(
+                    getId(), getStreamSetId(), &gb, fenceFd, /*noFreeBuffer*/true);
+
+            if (res == OK) {
+                // Attach this buffer to the bufferQueue: the buffer will be in dequeue state after
+                // a successful return.
+                *anb = gb.get();
+                res = mConsumer->attachBuffer(*anb);
+                gotBufferFromManager = true;
+                ALOGV("Stream %d: Attached new buffer", getId());
+
+                if (res != OK) {
+                    ALOGE("%s: Stream %d: Can't attach the output buffer to this surface: %s (%d)",
+                            __FUNCTION__, mId, strerror(-res), res);
+
+                    checkRetAndSetAbandonedLocked(res);
+                    return res;
+                }
+            } else {
+                ALOGE("%s: Stream %d: Can't get next output buffer from buffer manager:"
+                        " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
+                return res;
+            }
+        } else if (res != OK) {
             ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
                     __FUNCTION__, mId, strerror(-res), res);
 
-            // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
-            // let prepareNextBuffer handle the error.)
-            if ((res == NO_INIT || res == DEAD_OBJECT) && mState == STATE_CONFIGURED) {
-                mState = STATE_ABANDONED;
-            }
-
+            checkRetAndSetAbandonedLocked(res);
             return res;
         }
     }
 
     if (res == OK) {
-        std::vector<sp<GraphicBuffer>> removedBuffers;
-        res = mConsumer->getAndFlushRemovedBuffers(&removedBuffers);
-        if (res == OK) {
-            onBuffersRemovedLocked(removedBuffers);
-
-            if (mUseBufferManager && removedBuffers.size() > 0) {
-                mBufferManager->onBuffersRemoved(getId(), getStreamSetId(), removedBuffers.size());
-            }
-        }
+        checkRemovedBuffersLocked();
     }
 
     return res;
 }
 
+void Camera3OutputStream::checkRemovedBuffersLocked(bool notifyBufferManager) {
+    std::vector<sp<GraphicBuffer>> removedBuffers;
+    status_t res = mConsumer->getAndFlushRemovedBuffers(&removedBuffers);
+    if (res == OK) {
+        onBuffersRemovedLocked(removedBuffers);
+
+        if (notifyBufferManager && mUseBufferManager && removedBuffers.size() > 0) {
+            mBufferManager->onBuffersRemoved(getId(), getStreamSetId(), removedBuffers.size());
+        }
+    }
+}
+
+void Camera3OutputStream::checkRetAndSetAbandonedLocked(status_t res) {
+    // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is
+    // STATE_PREPARING, let prepareNextBuffer handle the error.)
+    if ((res == NO_INIT || res == DEAD_OBJECT) && mState == STATE_CONFIGURED) {
+        mState = STATE_ABANDONED;
+    }
+}
+
 status_t Camera3OutputStream::disconnectLocked() {
     status_t res;
 
@@ -803,11 +851,8 @@
         }
     }
 
-    std::vector<sp<GraphicBuffer>> removedBuffers;
-    res = mConsumer->getAndFlushRemovedBuffers(&removedBuffers);
-    if (res == OK) {
-        onBuffersRemovedLocked(removedBuffers);
-    }
+    // Here we assume detachBuffer is called by buffer manager so it doesn't need to be notified
+    checkRemovedBuffersLocked(/*notifyBufferManager*/false);
     return res;
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 2128da2..30fc2f7 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -309,6 +309,13 @@
      */
     void onBuffersRemovedLocked(const std::vector<sp<GraphicBuffer>>&);
     status_t detachBufferLocked(sp<GraphicBuffer>* buffer, int* fenceFd);
+    // Call this after each dequeueBuffer/attachBuffer/detachNextBuffer call to get update on
+    // removed buffers. Set notifyBufferManager to false when the call is initiated by buffer
+    // manager so buffer manager doesn't need to be notified.
+    void checkRemovedBuffersLocked(bool notifyBufferManager = true);
+
+    // Check return status of IGBP calls and set abandoned state accordingly
+    void checkRetAndSetAbandonedLocked(status_t res);
 
     static const int32_t kDequeueLatencyBinSize = 5; // in ms
     CameraLatencyHistogram mDequeueBufferLatency;
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 4f3ac1b..06baac9 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -76,9 +76,6 @@
 
 namespace android {
 
-    using namespace android::base;
-    using namespace android::content::pm;
-
 // individual records kept in memory: age or count
 // age: <= 28 hours (1 1/6 days)
 // count: hard limit of # records
@@ -649,7 +646,8 @@
         }
 
         if (binder != NULL) {
-            sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
+            sp<content::pm::IPackageManagerNative> package_mgr =
+                            interface_cast<content::pm::IPackageManagerNative>(binder);
             binder::Status status;
 
             std::vector<int> uids;
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
new file mode 100644
index 0000000..25c36fa
--- /dev/null
+++ b/services/mediacodec/Android.bp
@@ -0,0 +1,62 @@
+cc_binary {
+    name: "mediaswcodec",
+    vendor_available: true,
+
+    srcs: [
+        "main_swcodecservice.cpp",
+    ],
+
+    shared_libs: [
+        "libavservices_minijail",
+        "libbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libmedia_codecserviceregistrant",
+    ],
+
+    target: {
+        vendor: {
+            exclude_shared_libs: ["libavservices_minijail"],
+            shared_libs: ["libavservices_minijail_vendor"],
+        },
+    },
+
+    header_libs: [
+        "libmedia_headers",
+    ],
+
+    init_rc: ["mediaswcodec.rc"],
+
+    required: ["mediaswcodec.policy"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-Wno-error=deprecated-declarations",
+    ],
+
+    sanitize: {
+        scudo: true,
+    },
+}
+
+prebuilt_etc {
+    name: "mediaswcodec.policy",
+    sub_dir: "seccomp_policy",
+    arch: {
+        arm: {
+            src: "seccomp_policy/mediaswcodec-arm.policy",
+        },
+        arm64: {
+            src: "seccomp_policy/mediaswcodec-arm64.policy",
+        },
+        x86: {
+            src: "seccomp_policy/mediacodec-x86.policy",
+        },
+        x86_64: {
+            src: "seccomp_policy/mediacodec-x86.policy",
+        },
+    },
+    required: ["crash_dump.policy"],
+}
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index f78c671..9cc19a3 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -27,8 +27,8 @@
 include $(CLEAR_VARS)
 # seccomp is not required for coverage build.
 ifneq ($(NATIVE_COVERAGE),true)
-LOCAL_REQUIRED_MODULES_arm := crash_dump.policy mediacodec.policy
-LOCAL_REQUIRED_MODULES_x86 := crash_dump.policy mediacodec.policy
+LOCAL_REQUIRED_MODULES_arm := mediacodec.policy
+LOCAL_REQUIRED_MODULES_x86 := mediacodec.policy
 endif
 LOCAL_SRC_FILES := main_codecservice.cpp
 LOCAL_SHARED_LIBRARIES := \
@@ -65,74 +65,13 @@
 
 ####################################################################
 
-# service executable
-include $(CLEAR_VARS)
-# seccomp is not required for coverage build.
-ifneq ($(NATIVE_COVERAGE),true)
-LOCAL_REQUIRED_MODULES_arm := crash_dump.policy mediaswcodec.policy
-LOCAL_REQUIRED_MODULES_arm64 := crash_dump.policy mediaswcodec.policy
-LOCAL_REQUIRED_MODULES_x86 := crash_dump.policy mediaswcodec.policy
-LOCAL_REQUIRED_MODULES_x86_64 := crash_dump.policy mediaswcodec.policy
-endif
-
-LOCAL_SRC_FILES := \
-    main_swcodecservice.cpp \
-    MediaCodecUpdateService.cpp \
-
-sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
-  $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
-  $(UBSAN_RUNTIME_LIBRARY) \
-  $(TSAN_RUNTIME_LIBRARY) \
-  $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
-  $(2ND_UBSAN_RUNTIME_LIBRARY) \
-  $(2ND_TSAN_RUNTIME_LIBRARY)))
-
-# $(info Sanitizer:  $(sanitizer_runtime_libraries))
-
-llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\
-  $(LLNDK_LIBRARIES)))
-
-# $(info LLNDK:  $(llndk_libraries))
-
-LOCAL_CFLAGS := -DLINKED_LIBRARIES='"$(sanitizer_runtime_libraries):$(llndk_libraries)"'
-
-LOCAL_SHARED_LIBRARIES := \
-    libavservices_minijail \
-    libbase \
-    libbinder \
-    libcutils \
-    libhidltransport \
-    libhwbinder \
-    liblog \
-    libmedia \
-    libutils \
-    libziparchive \
-
-LOCAL_HEADER_LIBRARIES := \
-    libnativeloader-dummy-headers \
-
-LOCAL_MODULE := mediaswcodec
-LOCAL_INIT_RC := mediaswcodec.rc
-LOCAL_SANITIZE := scudo
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86_64 arm64))
-  LOCAL_MULTILIB := both
-  LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-  LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)
-endif
-
-sanitizer_runtime_libraries :=
-llndk_libraries :=
-
-include $(BUILD_EXECUTABLE)
-
-####################################################################
-
 # service seccomp policy
 ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64 arm arm64))
 include $(CLEAR_VARS)
 LOCAL_MODULE := mediacodec.policy
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
+LOCAL_REQUIRED_MODULES := crash_dump.policy
 # mediacodec runs in 32-bit combatibility mode. For 64 bit architectures,
 # use the 32 bit policy
 ifdef TARGET_2ND_ARCH
@@ -149,14 +88,5 @@
 
 ####################################################################
 
-# sw service seccomp policy
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64 arm arm64))
-include $(CLEAR_VARS)
-LOCAL_MODULE := mediaswcodec.policy
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
-LOCAL_SRC_FILES := seccomp_policy/mediaswcodec-$(TARGET_ARCH).policy
-include $(BUILD_PREBUILT)
-endif
 
 include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/mediacodec/MediaCodecUpdateService.cpp b/services/mediacodec/MediaCodecUpdateService.cpp
deleted file mode 100644
index 50ccbce..0000000
--- a/services/mediacodec/MediaCodecUpdateService.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "MediaCodecUpdateService"
-//#define LOG_NDEBUG 0
-
-#include <android/dlext.h>
-#include <dlfcn.h>
-#include <media/CodecServiceRegistrant.h>
-#include <nativeloader/dlext_namespaces.h>
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include "MediaCodecUpdateService.h"
-
-namespace android {
-
-void loadFromApex(const char *libDirPath) {
-    ALOGV("loadFromApex: path=%s", libDirPath);
-
-    String8 libPath = String8(libDirPath) + "/libmedia_codecserviceregistrant.so";
-
-    android_namespace_t *codecNs = android_create_namespace("codecs",
-            nullptr,  // ld_library_path
-            libDirPath,
-            ANDROID_NAMESPACE_TYPE_ISOLATED,
-            nullptr,  // permitted_when_isolated_path
-            nullptr); // parent
-
-    if (codecNs == nullptr) {
-        ALOGE("Failed to create codec namespace");
-        return;
-    }
-
-    String8 linked_libraries(LINKED_LIBRARIES);
-    if (!android_link_namespaces(codecNs, nullptr, linked_libraries.c_str())) {
-        ALOGE("Failed to link namespace");
-        return;
-    }
-
-    const android_dlextinfo dlextinfo = {
-            .flags = ANDROID_DLEXT_USE_NAMESPACE,
-            .library_namespace = codecNs,
-    };
-
-    void *registrantLib = android_dlopen_ext(
-            libPath.string(),
-            RTLD_NOW | RTLD_LOCAL, &dlextinfo);
-
-    if (registrantLib == nullptr) {
-        ALOGE("Failed to load lib from archive: %s", dlerror());
-    }
-
-    RegisterCodecServicesFunc registerCodecServices =
-            reinterpret_cast<RegisterCodecServicesFunc>(
-            dlsym(registrantLib, "RegisterCodecServices"));
-
-    if (registerCodecServices == nullptr) {
-        ALOGE("Cannot register codec services -- corrupted library.");
-        return;
-    }
-
-    registerCodecServices();
-}
-
-}   // namespace android
diff --git a/services/mediacodec/MediaCodecUpdateService.h b/services/mediacodec/MediaCodecUpdateService.h
deleted file mode 100644
index 09d6dbe..0000000
--- a/services/mediacodec/MediaCodecUpdateService.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
-#define ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
-
-namespace android {
-
-void loadFromApex(const char *libDirPath);
-
-}   // namespace android
-
-#endif  // ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
diff --git a/services/mediacodec/main_swcodecservice.cpp b/services/mediacodec/main_swcodecservice.cpp
index 05b5695..c44be28 100644
--- a/services/mediacodec/main_swcodecservice.cpp
+++ b/services/mediacodec/main_swcodecservice.cpp
@@ -19,24 +19,26 @@
 
 // from LOCAL_C_INCLUDES
 #include "minijail.h"
-
 #include <hidl/HidlTransportSupport.h>
 
-#include "MediaCodecUpdateService.h"
-
 using namespace android;
 
+// kSystemSeccompPolicyPath points to the policy for the swcodecs themselves and
+// is part of the updates. kVendorSeccompPolicyPath points to any additional
+// policies that the vendor may need for the device.
 static const char kSystemSeccompPolicyPath[] =
-        "/system/etc/seccomp_policy/mediaswcodec.policy";
+        "/apex/com.android.media.swcodec/etc/seccomp_policy/mediaswcodec.policy";
 static const char kVendorSeccompPolicyPath[] =
         "/vendor/etc/seccomp_policy/mediaswcodec.policy";
 
 // Disable Scudo's mismatch allocation check, as it is being triggered
 // by some third party code.
 extern "C" const char *__scudo_default_options() {
-  return "DeallocationTypeMismatch=false";
+    return "DeallocationTypeMismatch=false";
 }
 
+extern "C" void RegisterCodecServices();
+
 int main(int argc __unused, char** /*argv*/)
 {
     LOG(INFO) << "media swcodec service starting";
@@ -45,11 +47,7 @@
 
     ::android::hardware::configureRpcThreadpool(64, false);
 
-#ifdef __LP64__
-    loadFromApex("/apex/com.android.media.swcodec/lib64");
-#else
-    loadFromApex("/apex/com.android.media.swcodec/lib");
-#endif
+    RegisterCodecServices();
 
     ::android::hardware::joinRpcThreadpool();
 }
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index 661a475..fd34d5b 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -22,7 +22,6 @@
 LOCAL_SRC_FILES := main_extractorservice.cpp
 LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils \
     liblog libandroidicu libavservices_minijail
-LOCAL_STATIC_LIBRARIES := libicuandroid_utils
 LOCAL_MODULE:= mediaextractor
 LOCAL_INIT_RC := mediaextractor.rc
 LOCAL_C_INCLUDES := frameworks/av/media/libmedia
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
index 3c15bfd..06b532d 100644
--- a/services/mediaextractor/main_extractorservice.cpp
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -15,6 +15,7 @@
 ** limitations under the License.
 */
 
+#include <aicu/AIcu.h>
 #include <fcntl.h>
 #include <sys/prctl.h>
 #include <sys/wait.h>
@@ -29,7 +30,6 @@
 #include <utils/misc.h>
 
 // from LOCAL_C_INCLUDES
-#include "IcuUtils.h"
 #include "MediaExtractorService.h"
 #include "MediaUtils.h"
 #include "minijail.h"
@@ -64,7 +64,7 @@
 
     SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
 
-    InitializeIcuOrDie();
+    AIcu_initializeIcuOrDie();
 
     strcpy(argv[0], "media.extractor");
     sp<ProcessState> proc(ProcessState::self());
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index 87018ed..964acf4 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -14,6 +14,7 @@
 setpriority: 1
 sigaltstack: 1
 openat: 1
+open: 1
 clone: 1
 read: 1
 clock_gettime: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
index d739ba1..56ad8df 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
@@ -11,6 +11,7 @@
 mmap2: 1
 madvise: 1
 openat: 1
+open: 1
 clock_gettime: 1
 writev: 1
 brk: 1