Merge "aaudio: call stop() from the callback"
diff --git a/apex/Android.bp b/apex/Android.bp
index 05cc2c5..51e4c23 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -27,12 +27,31 @@
         "libmpeg2extractor",
         "liboggextractor",
         "libwavextractor",
+        // MediaPlayer2
+        "libmediaplayer2_jni",
     ],
     key: "com.android.media.key",
 }
 
+apex {
+    name: "com.android.media.swcodec",
+    compile_multilib: "32",
+    manifest: "manifest_codec.json",
+    native_shared_libs: [
+        "libmedia_codecserviceregistrant",
+    ],
+    use_vendor: true,
+    key: "com.android.media.swcodec.key",
+}
+
 apex_key {
     name: "com.android.media.key",
     public_key: "com.android.media.avbpubkey",
     private_key: "com.android.media.pem",
 }
+
+apex_key {
+    name: "com.android.media.swcodec.key",
+    public_key: "com.android.media.swcodec.avbpubkey",
+    private_key: "com.android.media.swcodec.pem",
+}
diff --git a/apex/com.android.media.swcodec.avbpubkey b/apex/com.android.media.swcodec.avbpubkey
new file mode 100644
index 0000000..0459723
--- /dev/null
+++ b/apex/com.android.media.swcodec.avbpubkey
Binary files differ
diff --git a/apex/com.android.media.swcodec.pem b/apex/com.android.media.swcodec.pem
new file mode 100644
index 0000000..e379cd3
--- /dev/null
+++ b/apex/com.android.media.swcodec.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKgIBAAKCAgEAvB6lOEEOR58KMcFlayEZjsXuPgcfHi/OPxcvfpiGLCpOcK3l
+OPChWUvDRcIHMB7BO+Csfxs0HgsHvvZfNyoNIm99WcjFbboiO7WrBBArIszPr14X
+cfY2NxzT9LBj+EqAnbdL+4OQW1/npLHNE0qtDcxL71ipbjSuKNb58E9qGL0KwvkS
+fwwueWj++bg/iz7dq0mz7iKpnxYscNm4RhJjqcG2Usmg4Ejhr8h5UmOUmTJbObC/
+vzClXQqeeuzS8NTtGVgQ/CI9gC2WN9upq2p/2T7P4U3o3CWvBytUoLKR0UyC83ey
+S8XJgOa42uWR3T/eJOI1ZS4H6Srg1o2XC8Yb8EprFI/NM6/+/5DX/FgDimsslAP6
+Qq4+pSte9v/FjWGqy7QBQaefFRGRuS63xHcSZhXC9J2CFdnxo8+65QT8r4yfQEei
+Ax/0Q94yB7VIL1pIJxHEonKjtd3iKdFEKQzADJ3edsmtHybERdJKCxcm9QIrDCsC
+4YVT9nX0OoC9RD5d5EVD7W5I6eEnRu6igrKIKgUVppeYFQNZD+o+eiNJa4yoggRl
+h8sT0/xLKjMRxAQ7fafi1j+LB2O7UgJmIDDAnidq8Aoz7h3pNi139rNWrjNfwhus
+nMcZvL9dTVv26JWeESHP/zAfAX7j1rfkDwR02ocRLquwEUs1+UHA27Wi1bMCAwEA
+AQKCAgAO3PT83tb7/arWh4s1zaWxTB4otHNW9Tv8bB6KiA6Bys3rxTGJMCnvXjcN
+eekLekKWMoguer3BaemwwtJ/D0l+YQSsZVqD8uLliNL8PTLLSxdVqb98d5GNBTAR
+8yXS5kAHNgZA1wI+1fL9ZjbnwUyu/Gc7f+vTE0J3Y5TX0c52KemBwiAd/Z5mZU9P
+96i9nbfx4p7ev8pbEWttdyZCEw3gybdYDyowzlFWjCZZxhhlij7+7eIYfwVxtncT
+C0cXVBtvly+wXBwz1mY5/5cGPiHfzkCqcndlfWy4ykmjcLhoqvzls51Ys0Xac2BD
+m0PNEVDB5UWGuv5RA9xD12gJvBtU3D7ggMw6C5RcXJT+jSYmSFtD2klWi+It8A/N
+Hv42soKskt6JqYAWE1cvJ3PEqH9ASEJNq2R0Z/PmuM000UJyzU9KId3SNwjXA1Xc
+Kn9hRga4uf9elHTjkTDt79/8+Xv7hjer9sF/S/np7g04rUjIWkuFkC/7NK2tQSh1
+mljV1sD9SF4DPfVK75LwJJaQUlI7TtGd5KJ7FzZwvb+w8ODrpW3hkt6FcI6KwE/a
+QT1T2Z9DknXJSYNdWGrj6vMHsYMiyz8IdAHSCrOB6eXCQxpitbn6W71Raw7f9UaZ
+VDK5AhTU493hkGj1no4cJwecXInMigg/c4ywk2Ibh6IV8O0nkQKCAQEA2+dQQ0IF
+vvVgmQ2WxHBD7M2mbOyf43YBY6Ka6oPBNGPVpZE8X8LoTavQLV+SgCkH8T6gY7XS
+5L4Ze0JFxfua0o1rm6+L2XrOx5F/A2Y40YcPclEik5h1woSwH/J1iHGiEhY8Nqeu
+9GCvjQojkgXx/Rn3Nz+lpvZ329O3H85RWWGF0l60RwLOkig0ZwUb619t8affmGIl
+sxdDv2nfy7OtJX8iGDua7Kf64dvVWQKKtACWkARrlkcWX3uoESxkpSDxue+z7ndH
+o7uHLfM8Tx+Rn+QvYWuRW5TPLbEDMbIYrX65ISt2r/T7v/04XdAC8YpCQRytlqPI
+fpDm15htyHBizQKCAQEA2v+5otRoY56JduISaVGlsJ/IbvKzDAIyWmM14EpRCR5E
+lu+MpTcRAiFQAbHGXr1tMlTFdVFD090WAzIKaKtADFVLXobIHeGspnRCq5OpVp9W
+RvLtVwLxflHAc2yN9/LNtnBqHUgt+S01LBPElybdGHQRTtqAKXhkp31sM21O34Go
+Pri/IxgupWxykMaW44Kig1Cr5DKvc8cwUsGuyDdJm8oBQeNPTMWqSnXtqoTWSaYg
+2kxiMTFokrkSXgufb8wng6OXt/QelywrhG3hAsldPO3GdKidDSxhWZSgpUXXFdAX
+y4GO0IcRJBF/WJtYTYtR+l84nQA2/1Ye4ujFlT0afwKCAQEAmXrXpSm2cvI2CnzW
+hqJIdkWOa6W3bn1VOOIrt5Rfy54GZnl4pumVU2igcpqq2HJKzdDFBvLHj8kyZbn6
+ktUp2NzFhzK9q/uvyNA+0vOMoojeeg4w0MzvG+WaO6Hw8FtHH9KPEiJ01LGKtSin
+bOpjXCC8T75HcsHBJBefTz6jvnt3eD2LG6jU3mPbNy/0rZG8XZaqU2PlJhsNuNI/
+VaBBL9OMy1cGqTgQvYS+YlKI1ls2uqurH4bcEaZvxhSy5iGZNQodDkoIITnofmSu
+6haBgBQ2EYuPN1kkRKKwNQY1fRneQk1gmCynbPdiWO+urkCuP12xtlr3u4aM51rG
+/Meb3QKCAQEA12SxZm9XhLOHLIBJ74A4YLGm50iZxXPbpn7xnHo7naZBe9p8EHtK
+pTeygxggrUnOPrSVyT92YMiQP/BVwIC+a+LwUDZsWMd/ke/DKxH+eY4Zw4pm2S+x
+6bXqfRwFvhr3LTr/g3FcljlalNGUh73Xs5dk9pN9fkxFY16+rw4Rh0709Uur4o6E
+QnuZar+H5Ji10kXj6nvXiR4ebybEC3QlV66k8fLqKe44AShf61jfkmxs34hFA3E/
+EyAn6ouv8rtvGdArBuh5teHho0yXBLCcnbKXgGHepfhCf2LpZeR9GZ0j6iqxFnPh
+7gGvqKyReyNOK9y/x9tQPG6tzit3OcNxbQKCAQEAuDheDOSkXPopXMvLAKOHBIdZ
+rbQ7oFTDHt59gbucM7U8/l2YtaxuKOQFBLnzQa/amIkkrtklYwOsz8E24d7Nm39w
+ykLHwX0XrmjAm6M4XKmDv66a+kSnSV6LEbKZdjvXP02DV+tGeZ5VsnNvJDquxMsD
+fvRTspB8j8CpU96szekxl/tCRhqbdw/4kVTSj5BF++OaRRcJrAyj1B2qf1ynAZE1
+gUvVPkEYa914zcrxg9XIXT4M7yqB7i8KJegOtOtcWjJ7uTiP+638AvygJLMJnSrV
++HjFZWG6P9btZmLHSEBRvwGOAilp0qejXo866l0fmnlGy7ehKz8u3PzvnlPYjQ==
+-----END RSA PRIVATE KEY-----
diff --git a/apex/manifest_codec.json b/apex/manifest_codec.json
new file mode 100644
index 0000000..e2bceec
--- /dev/null
+++ b/apex/manifest_codec.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.media.swcodec",
+  "version": 1
+}
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 60c9f85..d96f403 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -137,6 +137,7 @@
     shared_libs: [
         "libhwbinder",
         "libcamera2ndk_vendor",
+        "libcamera_metadata",
         "libmediandk",
         "libnativewindow",
         "libutils",
@@ -144,6 +145,9 @@
         "libcutils",
         "liblog",
     ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+    ],
     cflags: [
         "-D__ANDROID_VNDK__",
     ],
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
index 540d84e..ab796fb 100644
--- a/camera/ndk/NdkCameraCaptureSession.cpp
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -80,7 +80,9 @@
 
     if (session->isClosed()) {
         ALOGE("%s: session %p is already closed", __FUNCTION__, session);
-        *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+        if (captureSequenceId != nullptr) {
+            *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+        }
         return ACAMERA_ERROR_SESSION_CLOSED;
     }
 
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
index f395b44..575ee9d 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -34,7 +34,10 @@
 namespace android {
 namespace acam {
 
-using CameraStatusAndId = frameworks::cameraservice::service::V2_0::CameraStatusAndId;
+using frameworks::cameraservice::service::V2_0::CameraStatusAndId;
+using frameworks::cameraservice::common::V2_0::ProviderIdAndVendorTagSections;
+using android::hardware::camera::common::V1_0::helper::VendorTagDescriptor;
+using android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
 
 // Static member definitions
 const char* CameraManagerGlobal::kCameraIdKey   = "CameraId";
@@ -43,6 +46,104 @@
 Mutex                CameraManagerGlobal::sLock;
 CameraManagerGlobal* CameraManagerGlobal::sInstance = nullptr;
 
+/**
+ * The vendor tag descriptor class that takes HIDL vendor tag information as
+ * input. Not part of vendor available VendorTagDescriptor class because that class is used by
+ * default HAL implementation code as well.
+ */
+class HidlVendorTagDescriptor : public VendorTagDescriptor {
+public:
+    /**
+     * Create a VendorTagDescriptor object from the HIDL VendorTagSection
+     * vector.
+     *
+     * Returns OK on success, or a negative error code.
+     */
+    static status_t createDescriptorFromHidl(const hidl_vec<VendorTagSection>& vts,
+                                             /*out*/ sp<VendorTagDescriptor> *descriptor);
+};
+
+status_t HidlVendorTagDescriptor::createDescriptorFromHidl(const hidl_vec<VendorTagSection> &vts,
+                                                           sp<VendorTagDescriptor> *descriptor) {
+    int tagCount = 0;
+
+    for (size_t s = 0; s < vts.size(); s++) {
+        tagCount += vts[s].tags.size();
+    }
+
+    if (tagCount < 0 || tagCount > INT32_MAX) {
+        ALOGE("%s: tag count %d from vendor tag sections is invalid.", __FUNCTION__, tagCount);
+        return BAD_VALUE;
+    }
+
+    Vector<uint32_t> tagArray;
+    LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
+            "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
+
+    sp<HidlVendorTagDescriptor> desc = new HidlVendorTagDescriptor();
+    desc->mTagCount = tagCount;
+
+    KeyedVector<uint32_t, String8> tagToSectionMap;
+
+    int idx = 0;
+    for (size_t s = 0; s < vts.size(); s++) {
+        const VendorTagSection& section = vts[s];
+        const char *sectionName = section.sectionName.c_str();
+        if (sectionName == NULL) {
+            ALOGE("%s: no section name defined for vendor tag section %zu.", __FUNCTION__, s);
+            return BAD_VALUE;
+        }
+        String8 sectionString(sectionName);
+        desc->mSections.add(sectionString);
+
+        for (size_t j = 0; j < section.tags.size(); j++) {
+            uint32_t tag = section.tags[j].tagId;
+            if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
+                ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
+                return BAD_VALUE;
+            }
+
+            tagArray.editItemAt(idx++) = section.tags[j].tagId;
+
+            const char *tagName = section.tags[j].tagName.c_str();
+            if (tagName == NULL) {
+                ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
+                return BAD_VALUE;
+            }
+            desc->mTagToNameMap.add(tag, String8(tagName));
+            tagToSectionMap.add(tag, sectionString);
+
+            int tagType = (int) section.tags[j].tagType;
+            if (tagType < 0 || tagType >= NUM_TYPES) {
+                ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
+                return BAD_VALUE;
+            }
+            desc->mTagToTypeMap.emplace(tag, tagType);
+        }
+    }
+
+    for (size_t i = 0; i < tagArray.size(); ++i) {
+        uint32_t tag = tagArray[i];
+        String8 sectionString = tagToSectionMap.valueFor(tag);
+
+        // Set up tag to section index map
+        ssize_t index = desc->mSections.indexOf(sectionString);
+        LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
+        desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
+
+        // Set up reverse mapping
+        ssize_t reverseIndex = -1;
+        if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
+            KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+            reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
+        }
+        desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
+    }
+
+    *descriptor = std::move(desc);
+    return OK;
+}
+
 CameraManagerGlobal&
 CameraManagerGlobal::getInstance() {
     Mutex::Autolock _l(sLock);
@@ -80,8 +181,34 @@
     return (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0);
 }
 
-// TODO: Add back when vendor tags are supported for libcamera2ndk_vendor when
-//       the HIDL interface supports querying by vendor id.
+bool CameraManagerGlobal::setupVendorTags() {
+    sp<VendorTagDescriptorCache> tagCache = new VendorTagDescriptorCache();
+    Status status = Status::NO_ERROR;
+    std::vector<ProviderIdAndVendorTagSections> providerIdsAndVts;
+    auto remoteRet = mCameraService->getCameraVendorTagSections([&status, &providerIdsAndVts]
+                                                                 (Status s,
+                                                                  auto &IdsAndVts) {
+                                                         status = s;
+                                                         providerIdsAndVts = IdsAndVts; });
+
+    if (!remoteRet.isOk() || status != Status::NO_ERROR) {
+        ALOGE("Failed to retrieve VendorTagSections %s", remoteRet.description().c_str());
+        return false;
+    }
+    // Convert each providers VendorTagSections into a VendorTagDescriptor and
+    // add it to the cache
+    for (auto &providerIdAndVts : providerIdsAndVts) {
+        sp<VendorTagDescriptor> vendorTagDescriptor;
+        if (HidlVendorTagDescriptor::createDescriptorFromHidl(providerIdAndVts.vendorTagSections,
+                                                              &vendorTagDescriptor) != OK) {
+            ALOGE("Failed to convert from Hidl: VendorTagDescriptor");
+            return false;
+        }
+        tagCache->addVendorDescriptor(providerIdAndVts.providerId, vendorTagDescriptor);
+    }
+    VendorTagDescriptorCache::setAsGlobalVendorTagCache(tagCache);
+    return true;
+}
 
 sp<ICameraService> CameraManagerGlobal::getCameraService() {
     Mutex::Autolock _l(mLock);
@@ -140,6 +267,13 @@
         if (!remoteRet.isOk() || status != Status::NO_ERROR) {
             ALOGE("Failed to add listener to camera service %s", remoteRet.description().c_str());
         }
+
+        // Setup vendor tags
+        if (!setupVendorTags()) {
+            ALOGE("Unable to set up vendor tags");
+            return nullptr;
+        }
+
         for (auto& c : cameraStatuses) {
             onStatusChangedLocked(c);
         }
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
index c8d640f..6b1365a 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -142,6 +142,8 @@
 
     void onStatusChanged(const CameraStatusAndId &statusAndId);
     void onStatusChangedLocked(const CameraStatusAndId &statusAndId);
+    bool setupVendorTags();
+
     // Utils for status
     static bool validStatus(CameraDeviceStatus status);
     static bool isStatusAvailable(CameraDeviceStatus status);
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
index 579412e..93108b0 100644
--- a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -37,12 +37,7 @@
 #include <media/NdkImage.h>
 #include <media/NdkImageReader.h>
 #include <cutils/native_handle.h>
-
-//#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
-//#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
-#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
-#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
-#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+#include <VendorTagDescriptor.h>
 
 namespace {
 
@@ -53,40 +48,31 @@
 static constexpr int kTestImageHeight = 480;
 static constexpr int kTestImageFormat = AIMAGE_FORMAT_YUV_420_888;
 
+using android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
+
 class CameraHelper {
    public:
-    CameraHelper(native_handle_t* imgReaderAnw) : mImgReaderAnw(imgReaderAnw) {}
+    CameraHelper(const char* id, ACameraManager *manager) :
+            mImgReaderAnw(nullptr), mCameraId(id), mCameraManager(manager) {}
     ~CameraHelper() { closeCamera(); }
 
-    int initCamera() {
-        if (mImgReaderAnw == nullptr) {
+    struct PhysicalImgReaderInfo {
+        const char* physicalCameraId;
+        native_handle_t* anw;
+    };
+    int initCamera(native_handle_t* imgReaderAnw,
+            const std::vector<PhysicalImgReaderInfo>& physicalImgReaders) {
+        if (imgReaderAnw == nullptr) {
             ALOGE("Cannot initialize camera before image reader get initialized.");
             return -1;
         }
+        if (mIsCameraReady) {
+            ALOGE("initCamera should only be called once.");
+            return -1;
+        }
+
         int ret;
-
-        mCameraManager = ACameraManager_create();
-        if (mCameraManager == nullptr) {
-            ALOGE("Failed to create ACameraManager.");
-            return -1;
-        }
-
-        ret = ACameraManager_getCameraIdList(mCameraManager, &mCameraIdList);
-        if (ret != AMEDIA_OK) {
-            ALOGE("Failed to get cameraIdList: ret=%d", ret);
-            return ret;
-        }
-        if (mCameraIdList->numCameras < 1) {
-            ALOGW("Device has no camera on board.");
-            return 0;
-        }
-
-        // We always use the first camera.
-        mCameraId = mCameraIdList->cameraIds[0];
-        if (mCameraId == nullptr) {
-            ALOGE("Failed to get cameraId.");
-            return -1;
-        }
+        mImgReaderAnw = imgReaderAnw;
 
         ret = ACameraManager_openCamera(mCameraManager, mCameraId, &mDeviceCb, &mDevice);
         if (ret != AMEDIA_OK || mDevice == nullptr) {
@@ -94,18 +80,6 @@
             return -1;
         }
 
-        ret = ACameraManager_getCameraCharacteristics(mCameraManager, mCameraId, &mCameraMetadata);
-        if (ret != ACAMERA_OK || mCameraMetadata == nullptr) {
-            ALOGE("Get camera %s characteristics failure. ret %d, metadata %p", mCameraId, ret,
-                  mCameraMetadata);
-            return -1;
-        }
-
-        if (!isCapabilitySupported(ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE)) {
-            ALOGW("Camera does not support BACKWARD_COMPATIBLE.");
-            return 0;
-        }
-
         // Create capture session
         ret = ACaptureSessionOutputContainer_create(&mOutputs);
         if (ret != AMEDIA_OK) {
@@ -122,6 +96,25 @@
             ALOGE("ACaptureSessionOutputContainer_add failed, ret=%d", ret);
             return ret;
         }
+
+        for (auto& physicalStream : physicalImgReaders) {
+            ACaptureSessionOutput* sessionOutput = nullptr;
+            ret = ACaptureSessionPhysicalOutput_create(physicalStream.anw,
+                    physicalStream.physicalCameraId, &sessionOutput);
+            if (ret != ACAMERA_OK) {
+                ALOGE("ACaptureSessionPhysicalOutput_create failed, ret=%d", ret);
+                return ret;
+            }
+            ret = ACaptureSessionOutputContainer_add(mOutputs, sessionOutput);
+            if (ret != AMEDIA_OK) {
+                ALOGE("ACaptureSessionOutputContainer_add failed, ret=%d", ret);
+                return ret;
+            }
+            mExtraOutputs.push_back(sessionOutput);
+            // Assume that at most one physical stream per physical camera.
+            mPhysicalCameraIds.push_back(physicalStream.physicalCameraId);
+        }
+
         ret = ACameraDevice_createCaptureSession(mDevice, mOutputs, &mSessionCb, &mSession);
         if (ret != AMEDIA_OK) {
             ALOGE("ACameraDevice_createCaptureSession failed, ret=%d", ret);
@@ -145,21 +138,25 @@
             return ret;
         }
 
+        for (auto& physicalStream : physicalImgReaders) {
+            ACameraOutputTarget* outputTarget = nullptr;
+            ret = ACameraOutputTarget_create(physicalStream.anw, &outputTarget);
+            if (ret != AMEDIA_OK) {
+                ALOGE("ACameraOutputTarget_create failed, ret=%d", ret);
+                return ret;
+            }
+            ret = ACaptureRequest_addTarget(mStillRequest, outputTarget);
+            if (ret != AMEDIA_OK) {
+                ALOGE("ACaptureRequest_addTarget failed, ret=%d", ret);
+                return ret;
+            }
+            mReqExtraOutputs.push_back(outputTarget);
+        }
+
         mIsCameraReady = true;
         return 0;
     }
 
-    bool isCapabilitySupported(acamera_metadata_enum_android_request_available_capabilities_t cap) {
-        ACameraMetadata_const_entry entry;
-        ACameraMetadata_getConstEntry(
-                mCameraMetadata, ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, &entry);
-        for (uint32_t i = 0; i < entry.count; i++) {
-            if (entry.data.u8[i] == cap) {
-                return true;
-            }
-        }
-        return false;
-    }
 
     bool isCameraReady() { return mIsCameraReady; }
 
@@ -169,6 +166,10 @@
             ACameraOutputTarget_free(mReqImgReaderOutput);
             mReqImgReaderOutput = nullptr;
         }
+        for (auto& outputTarget : mReqExtraOutputs) {
+            ACameraOutputTarget_free(outputTarget);
+        }
+        mReqExtraOutputs.clear();
         if (mStillRequest) {
             ACaptureRequest_free(mStillRequest);
             mStillRequest = nullptr;
@@ -182,6 +183,10 @@
             ACaptureSessionOutput_free(mImgReaderOutput);
             mImgReaderOutput = nullptr;
         }
+        for (auto& extraOutput : mExtraOutputs) {
+            ACaptureSessionOutput_free(extraOutput);
+        }
+        mExtraOutputs.clear();
         if (mOutputs) {
             ACaptureSessionOutputContainer_free(mOutputs);
             mOutputs = nullptr;
@@ -191,19 +196,6 @@
             ACameraDevice_close(mDevice);
             mDevice = nullptr;
         }
-        if (mCameraMetadata) {
-          ACameraMetadata_free(mCameraMetadata);
-          mCameraMetadata = nullptr;
-        }
-        // Destroy camera manager
-        if (mCameraIdList) {
-            ACameraManager_deleteCameraIdList(mCameraIdList);
-            mCameraIdList = nullptr;
-        }
-        if (mCameraManager) {
-            ACameraManager_delete(mCameraManager);
-            mCameraManager = nullptr;
-        }
         mIsCameraReady = false;
     }
 
@@ -213,6 +205,12 @@
                                              &seqId);
     }
 
+    int takeLogicalCameraPicture() {
+        int seqId;
+        return ACameraCaptureSession_logicalCamera_capture(mSession, &mLogicalCaptureCallbacks,
+                1, &mStillRequest, &seqId);
+    }
+
     bool checkCallbacks(int pictureCount) {
         std::lock_guard<std::mutex> lock(mMutex);
         if (mCompletedCaptureCallbackCount != pictureCount) {
@@ -241,22 +239,22 @@
 
     native_handle_t* mImgReaderAnw = nullptr;  // not owned by us.
 
-    // Camera manager
-    ACameraManager* mCameraManager = nullptr;
-    ACameraIdList* mCameraIdList = nullptr;
     // Camera device
-    ACameraMetadata* mCameraMetadata = nullptr;
     ACameraDevice* mDevice = nullptr;
     // Capture session
     ACaptureSessionOutputContainer* mOutputs = nullptr;
     ACaptureSessionOutput* mImgReaderOutput = nullptr;
+    std::vector<ACaptureSessionOutput*> mExtraOutputs;
+
     ACameraCaptureSession* mSession = nullptr;
     // Capture request
     ACaptureRequest* mStillRequest = nullptr;
     ACameraOutputTarget* mReqImgReaderOutput = nullptr;
+    std::vector<ACameraOutputTarget*> mReqExtraOutputs;
 
     bool mIsCameraReady = false;
     const char* mCameraId;
+    ACameraManager* mCameraManager;
     int mCompletedCaptureCallbackCount = 0;
     std::mutex mMutex;
     ACameraCaptureSession_captureCallbacks mCaptureCallbacks = {
@@ -264,7 +262,6 @@
         this, // context
         nullptr, // onCaptureStarted
         nullptr, // onCaptureProgressed
-        // onCaptureCompleted, called serially, so no lock needed.
         [](void* ctx , ACameraCaptureSession *, ACaptureRequest *,
                                           const ACameraMetadata *) {
             CameraHelper *ch = static_cast<CameraHelper *>(ctx);
@@ -275,8 +272,44 @@
         nullptr, // onCaptureSequenceCompleted
         nullptr, // onCaptureSequenceAborted
         nullptr, // onCaptureBufferLost
-  };
+    };
 
+    std::vector<std::string> mPhysicalCameraIds;
+    ACameraCaptureSession_logicalCamera_captureCallbacks mLogicalCaptureCallbacks = {
+        // TODO: Add tests for other callbacks
+        this, // context
+        nullptr, // onCaptureStarted
+        nullptr, // onCaptureProgressed
+        [](void* ctx , ACameraCaptureSession *, ACaptureRequest *,
+                const ACameraMetadata *, size_t physicalResultCount,
+                const char** physicalCameraIds, const ACameraMetadata** physicalResults) {
+            CameraHelper *ch = static_cast<CameraHelper *>(ctx);
+            std::lock_guard<std::mutex> lock(ch->mMutex);
+            ASSERT_EQ(physicalResultCount, ch->mPhysicalCameraIds.size());
+            for (size_t i = 0; i < physicalResultCount; i++) {
+                ASSERT_TRUE(physicalCameraIds[i] != nullptr);
+                ASSERT_TRUE(physicalResults[i] != nullptr);
+                ASSERT_NE(std::find(ch->mPhysicalCameraIds.begin(),
+                        ch->mPhysicalCameraIds.end(), physicalCameraIds[i]),
+                        ch->mPhysicalCameraIds.end());
+
+                // Verify frameNumber and sensorTimestamp exist in physical
+                // result metadata
+                ACameraMetadata_const_entry entry;
+                ACameraMetadata_getConstEntry(
+                        physicalResults[i], ACAMERA_SYNC_FRAME_NUMBER, &entry);
+                ASSERT_EQ(entry.count, 1);
+                ACameraMetadata_getConstEntry(
+                        physicalResults[i], ACAMERA_SENSOR_TIMESTAMP, &entry);
+                ASSERT_EQ(entry.count, 1);
+            }
+            ch->mCompletedCaptureCallbackCount++;
+        },
+        nullptr, // onCaptureFailed
+        nullptr, // onCaptureSequenceCompleted
+        nullptr, // onCaptureSequenceAborted
+        nullptr, // onCaptureBufferLost
+    };
 };
 
 class ImageReaderTestCase {
@@ -476,84 +509,278 @@
     AImageReader_BufferRemovedListener mReaderDetachedCb{this, onBufferRemoved};
 };
 
-bool takePictures(uint64_t readerUsage, int readerMaxImages, bool readerAsync, int pictureCount) {
-    int ret = 0;
-    ImageReaderTestCase testCase(
-            kTestImageWidth, kTestImageHeight, kTestImageFormat, readerUsage, readerMaxImages,
-            readerAsync);
-    ret = testCase.initImageReader();
-    if (ret < 0) {
-        ALOGE("Unable to initialize ImageReader");
+
+class AImageReaderVendorTest : public ::testing::Test {
+  public:
+    void SetUp() override {
+        mCameraManager = ACameraManager_create();
+        if (mCameraManager == nullptr) {
+            ALOGE("Failed to create ACameraManager.");
+            return;
+        }
+
+        camera_status_t ret = ACameraManager_getCameraIdList(mCameraManager, &mCameraIdList);
+        if (ret != ACAMERA_OK) {
+            ALOGE("Failed to get cameraIdList: ret=%d", ret);
+            return;
+        }
+        // TODO: Add more rigorous tests for vendor tags
+        ASSERT_NE(VendorTagDescriptorCache::getGlobalVendorTagCache(), nullptr);
+        if (mCameraIdList->numCameras < 1) {
+            ALOGW("Device has no camera on board.");
+            return;
+        }
+    }
+    void TearDown() override {
+        // Destroy camera manager
+        if (mCameraIdList) {
+            ACameraManager_deleteCameraIdList(mCameraIdList);
+            mCameraIdList = nullptr;
+        }
+        if (mCameraManager) {
+            ACameraManager_delete(mCameraManager);
+            mCameraManager = nullptr;
+        }
+    }
+
+    bool takePictures(const char* id, uint64_t readerUsage, int readerMaxImages,
+            bool readerAsync, int pictureCount) {
+        int ret = 0;
+
+        ImageReaderTestCase testCase(
+                kTestImageWidth, kTestImageHeight, kTestImageFormat, readerUsage, readerMaxImages,
+                readerAsync);
+        ret = testCase.initImageReader();
+        if (ret < 0) {
+            ALOGE("Unable to initialize ImageReader");
+            return false;
+        }
+
+        CameraHelper cameraHelper(id, mCameraManager);
+        ret = cameraHelper.initCamera(testCase.getNativeWindow(), {});
+        if (ret < 0) {
+            ALOGE("Unable to initialize camera helper");
+            return false;
+        }
+
+        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 true;
+        }
+
+        for (int i = 0; i < pictureCount; i++) {
+            ret = cameraHelper.takePicture();
+            if (ret < 0) {
+                ALOGE("Unable to take picture");
+                return false;
+            }
+        }
+
+        // Sleep until all capture finished
+        for (int i = 0; i < kCaptureWaitRetry * pictureCount; i++) {
+            usleep(kCaptureWaitUs);
+            if (testCase.getAcquiredImageCount() == pictureCount) {
+                ALOGI("Session take ~%d ms to capture %d images", i * kCaptureWaitUs / 1000,
+                      pictureCount);
+                break;
+            }
+        }
+        return testCase.getAcquiredImageCount() == pictureCount &&
+                cameraHelper.checkCallbacks(pictureCount);
+    }
+
+    bool testTakePicturesNative(const char* id) {
+        for (auto& readerUsage :
+             {AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN}) {
+            for (auto& readerMaxImages : {1, 4, 8}) {
+                for (auto& readerAsync : {true, false}) {
+                    for (auto& pictureCount : {1, 4, 8}) {
+                        if (!takePictures(id, readerUsage, readerMaxImages,
+                                readerAsync, pictureCount)) {
+                            ALOGE("Test takePictures failed for test case usage=%" PRIu64
+                                  ", maxImages=%d, async=%d, pictureCount=%d",
+                                  readerUsage, readerMaxImages, readerAsync, pictureCount);
+                            return false;
+                        }
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    // Camera manager
+    ACameraManager* mCameraManager = nullptr;
+    ACameraIdList* mCameraIdList = nullptr;
+
+    bool isCapabilitySupported(ACameraMetadata* staticInfo,
+            acamera_metadata_enum_android_request_available_capabilities_t cap) {
+        ACameraMetadata_const_entry entry;
+        ACameraMetadata_getConstEntry(
+                staticInfo, ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+        for (uint32_t i = 0; i < entry.count; i++) {
+            if (entry.data.u8[i] == cap) {
+                return true;
+            }
+        }
         return false;
     }
 
-    CameraHelper cameraHelper(testCase.getNativeWindow());
-    ret = cameraHelper.initCamera();
-    if (ret < 0) {
-        ALOGE("Unable to initialize camera helper");
+    bool isSizeSupportedForFormat(ACameraMetadata* staticInfo,
+            int32_t format, int32_t width, int32_t height) {
+        ACameraMetadata_const_entry entry;
+        ACameraMetadata_getConstEntry(staticInfo,
+                ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry);
+        for (uint32_t i = 0; i < entry.count; i += 4) {
+            if (entry.data.i32[i] == format &&
+                    entry.data.i32[i+3] == ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    entry.data.i32[i+1] == width &&
+                    entry.data.i32[i+2] == height) {
+                return true;
+            }
+        }
         return false;
     }
 
+    void findCandidateLogicalCamera(const char **cameraId,
+            ACameraMetadata** staticMetadata,
+            std::vector<const char*>* candidatePhysicalIds) {
+        // Find first available logical camera
+        for (int i = 0; i < mCameraIdList->numCameras; i++) {
+            camera_status_t ret;
+            ret = ACameraManager_getCameraCharacteristics(
+                    mCameraManager, mCameraIdList->cameraIds[i], staticMetadata);
+            ASSERT_EQ(ret, ACAMERA_OK);
+            ASSERT_NE(*staticMetadata, nullptr);
+
+            if (!isCapabilitySupported(*staticMetadata,
+                    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA)) {
+                ACameraMetadata_free(*staticMetadata);
+                *staticMetadata = nullptr;
+                continue;
+            }
+
+            // Check returned physical camera Ids are valid
+            size_t physicalCameraIdCnt = 0;
+            const char*const* physicalCameraIds = nullptr;
+            bool isLogicalCamera = ACameraMetadata_isLogicalMultiCamera(*staticMetadata,
+                    &physicalCameraIdCnt, &physicalCameraIds);
+            ASSERT_TRUE(isLogicalCamera);
+            ASSERT_GE(physicalCameraIdCnt, 2);
+            ACameraMetadata* physicalCameraMetadata = nullptr;
+            candidatePhysicalIds->clear();
+            for (size_t j = 0; j < physicalCameraIdCnt && candidatePhysicalIds->size() < 2; j++) {
+                ASSERT_GT(strlen(physicalCameraIds[j]), 0);
+                ret = ACameraManager_getCameraCharacteristics(
+                        mCameraManager, physicalCameraIds[j], &physicalCameraMetadata);
+                ASSERT_EQ(ret, ACAMERA_OK);
+                ASSERT_NE(physicalCameraMetadata, nullptr);
+
+                if (isSizeSupportedForFormat(physicalCameraMetadata, kTestImageFormat,
+                        kTestImageWidth, kTestImageHeight)) {
+                    candidatePhysicalIds->push_back(physicalCameraIds[j]);
+                }
+                ACameraMetadata_free(physicalCameraMetadata);
+            }
+            if (candidatePhysicalIds->size() == 2) {
+                *cameraId = mCameraIdList->cameraIds[i];
+                return;
+            } else {
+                ACameraMetadata_free(*staticMetadata);
+                *staticMetadata = nullptr;
+            }
+        }
+        *cameraId = nullptr;
+        return;
+    }
+};
+
+TEST_F(AImageReaderVendorTest, CreateWindowNativeHandle) {
+    // We always use the first camera.
+    const char* cameraId = mCameraIdList->cameraIds[0];
+    ASSERT_TRUE(cameraId != nullptr);
+
+    ACameraMetadata* staticMetadata = nullptr;
+    camera_status_t ret = ACameraManager_getCameraCharacteristics(
+            mCameraManager, cameraId, &staticMetadata);
+    ASSERT_EQ(ret, ACAMERA_OK);
+    ASSERT_NE(staticMetadata, nullptr);
+
+    bool isBC = isCapabilitySupported(staticMetadata,
+            ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
+
+    ACameraMetadata_free(staticMetadata);
+
+    if (!isBC) {
+        ALOGW("Camera does not support BACKWARD_COMPATIBLE.");
+        return;
+    }
+
+    EXPECT_TRUE(testTakePicturesNative(cameraId));
+}
+
+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 true;
+        return;
     }
 
     for (int i = 0; i < pictureCount; i++) {
-        ret = cameraHelper.takePicture();
-        if (ret < 0) {
-            ALOGE("Unable to take picture");
-            return false;
-        }
+        ret = cameraHelper.takeLogicalCameraPicture();
+        ASSERT_EQ(ret, 0);
     }
 
     // Sleep until all capture finished
     for (int i = 0; i < kCaptureWaitRetry * pictureCount; i++) {
         usleep(kCaptureWaitUs);
-        if (testCase.getAcquiredImageCount() == pictureCount) {
+        if (testCases[0]->getAcquiredImageCount() == pictureCount) {
             ALOGI("Session take ~%d ms to capture %d images", i * kCaptureWaitUs / 1000,
                   pictureCount);
             break;
         }
     }
-    return testCase.getAcquiredImageCount() == pictureCount &&
-            cameraHelper.checkCallbacks(pictureCount);
-}
+    ASSERT_EQ(testCases[0]->getAcquiredImageCount(), pictureCount);
+    ASSERT_EQ(testCases[1]->getAcquiredImageCount(), pictureCount);
+    ASSERT_EQ(testCases[2]->getAcquiredImageCount(), pictureCount);
+    ASSERT_TRUE(cameraHelper.checkCallbacks(pictureCount));
 
-class AImageReaderWindowHandleTest : public ::testing::Test {
-   public:
-    void SetUp() override {
-    }
-    void TearDown() override {
-
-    }
-
-};
-
-bool testTakePicturesNative() {
-    for (auto& readerUsage :
-         {AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN}) {
-        for (auto& readerMaxImages : {1, 4, 8}) {
-            for (auto& readerAsync : {true, false}) {
-                for (auto& pictureCount : {1, 4, 8}) {
-                    if (!takePictures(readerUsage, readerMaxImages, readerAsync, pictureCount)) {
-                        ALOGE("Test takePictures failed for test case usage=%" PRIu64 ", maxImages=%d, "
-                              "async=%d, pictureCount=%d",
-                              readerUsage, readerMaxImages, readerAsync, pictureCount);
-                        return false;
-                    }
-                }
-            }
-        }
-    }
-    return true;
-}
-
-
-TEST_F(AImageReaderWindowHandleTest, CreateWindowNativeHandle) {
-    EXPECT_TRUE(testTakePicturesNative());
+    ACameraMetadata_free(staticMetadata);
 }
 
 }  // namespace
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 7a10302..6eb2e9f 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -8,7 +8,7 @@
         SineSource.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libmedia libmedia_omx libmediaextractor libutils libbinder \
+        libstagefright libmedia libmedia_omx libutils libbinder \
         libstagefright_foundation libjpeg libui libgui libcutils liblog \
         libhidlbase \
         android.hardware.media.omx@1.0 \
@@ -36,7 +36,7 @@
         record.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libmedia libmediaextractor liblog libutils libbinder \
+        libstagefright libmedia liblog libutils libbinder \
         libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
@@ -61,7 +61,7 @@
         recordvideo.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libmedia libmediaextractor liblog libutils libbinder \
+        libstagefright libmedia liblog libutils libbinder \
         libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
@@ -87,7 +87,7 @@
         audioloop.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libmedia libmediaextractor liblog libutils libbinder \
+        libstagefright libmedia liblog libutils libbinder \
         libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
@@ -111,7 +111,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
         libstagefright liblog libutils libbinder libui libgui \
-        libstagefright_foundation libmedia libcutils libmediaextractor
+        libstagefright_foundation libmedia libcutils
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
@@ -203,7 +203,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
         libstagefright liblog libutils libbinder libstagefright_foundation \
-        libcutils libc libmediaextractor
+        libcutils libc
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 86e9040..34a9a40 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -224,11 +224,15 @@
         player->setSource(rawSource);
         rawSource.clear();
 
-        player->start(true /* sourceAlreadyStarted */);
+        err = player->start(true /* sourceAlreadyStarted */);
 
-        status_t finalStatus;
-        while (!player->reachedEOS(&finalStatus)) {
-            usleep(100000ll);
+        if (err == OK) {
+            status_t finalStatus;
+            while (!player->reachedEOS(&finalStatus)) {
+                usleep(100000ll);
+            }
+        } else {
+            fprintf(stderr, "unable to start playback err=%d (0x%08x)\n", err, err);
         }
 
         delete player;
@@ -651,7 +655,8 @@
         MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
         MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9,
         MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, MEDIA_MIMETYPE_VIDEO_HEVC,
-        MEDIA_MIMETYPE_AUDIO_EAC3, MEDIA_MIMETYPE_AUDIO_AC4
+        MEDIA_MIMETYPE_AUDIO_EAC3, MEDIA_MIMETYPE_AUDIO_AC4,
+        MEDIA_MIMETYPE_VIDEO_AV1
     };
 
     const char *codecType = queryDecoders? "decoder" : "encoder";
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index 2532275..2600a2c 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -58,22 +58,26 @@
     return drm_perm_labels[index];
 }
 
-bool DrmManagerService::selinuxIsProtectedCallAllowed(pid_t spid, drm_perm_t perm) {
+bool DrmManagerService::selinuxIsProtectedCallAllowed(pid_t spid, const char* ssid, drm_perm_t perm) {
     if (selinux_enabled <= 0) {
         return true;
     }
 
-    char *sctx;
+    char *sctx = NULL;
     const char *selinux_class = "drmservice";
     const char *str_perm = get_perm_label(perm);
 
-    if (getpidcon(spid, &sctx) != 0) {
-        ALOGE("SELinux: getpidcon(pid=%d) failed.\n", spid);
-        return false;
+    if (ssid == NULL) {
+        android_errorWriteLog(0x534e4554, "121035042");
+
+        if (getpidcon(spid, &sctx) != 0) {
+            ALOGE("SELinux: getpidcon(pid=%d) failed.\n", spid);
+            return false;
+        }
     }
 
-    bool allowed = (selinux_check_access(sctx, drmserver_context, selinux_class,
-            str_perm, NULL) == 0);
+    bool allowed = (selinux_check_access(ssid ? ssid : sctx, drmserver_context,
+            selinux_class, str_perm, NULL) == 0);
     freecon(sctx);
 
     return allowed;
@@ -86,10 +90,11 @@
     IPCThreadState* ipcState = IPCThreadState::self();
     uid_t uid = ipcState->getCallingUid();
     pid_t spid = ipcState->getCallingPid();
+    const char* ssid = ipcState->getCallingSid();
 
     for (unsigned int i = 0; i < trustedUids.size(); ++i) {
         if (trustedUids[i] == uid) {
-            return selinuxIsProtectedCallAllowed(spid, perm);
+            return selinuxIsProtectedCallAllowed(spid, ssid, perm);
         }
     }
     return false;
@@ -97,7 +102,9 @@
 
 void DrmManagerService::instantiate() {
     ALOGV("instantiate");
-    defaultServiceManager()->addService(String16("drm.drmManager"), new DrmManagerService());
+    sp<DrmManagerService> service = new DrmManagerService();
+    service->setRequestingSid(true);
+    defaultServiceManager()->addService(String16("drm.drmManager"), service);
 
     if (0 >= trustedUids.size()) {
         // TODO
diff --git a/drm/drmserver/DrmManagerService.h b/drm/drmserver/DrmManagerService.h
index 7aaeab5..2e27a3c 100644
--- a/drm/drmserver/DrmManagerService.h
+++ b/drm/drmserver/DrmManagerService.h
@@ -60,7 +60,7 @@
 
     static const char *get_perm_label(drm_perm_t perm);
 
-    static bool selinuxIsProtectedCallAllowed(pid_t spid, drm_perm_t perm);
+    static bool selinuxIsProtectedCallAllowed(pid_t spid, const char* ssid, drm_perm_t perm);
 
     static bool isProtectedCallAllowed(drm_perm_t perm);
 
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
index 28a78aa..bb9d7ec 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
@@ -29,8 +29,7 @@
     srcs: ["src/FwdLockEngine.cpp"],
 
     shared_libs: [
-        "libicui18n",
-        "libicuuc",
+        "libandroidicu",
         "libutils",
         "liblog",
         "libdl",
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index 3035c5a..4dda5d7 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -30,16 +30,16 @@
 #include <media/stagefright/MediaErrors.h>
 #include <mediadrm/CryptoHal.h>
 
+using drm::V1_0::BufferType;
+using drm::V1_0::DestinationBuffer;
+using drm::V1_0::ICryptoFactory;
+using drm::V1_0::ICryptoPlugin;
+using drm::V1_0::Mode;
+using drm::V1_0::Pattern;
+using drm::V1_0::SharedBuffer;
+using drm::V1_0::Status;
+using drm::V1_0::SubSample;
 
-using ::android::hardware::drm::V1_0::BufferType;
-using ::android::hardware::drm::V1_0::DestinationBuffer;
-using ::android::hardware::drm::V1_0::ICryptoFactory;
-using ::android::hardware::drm::V1_0::ICryptoPlugin;
-using ::android::hardware::drm::V1_0::Mode;
-using ::android::hardware::drm::V1_0::Pattern;
-using ::android::hardware::drm::V1_0::SharedBuffer;
-using ::android::hardware::drm::V1_0::Status;
-using ::android::hardware::drm::V1_0::SubSample;
 using ::android::hardware::hidl_array;
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_memory;
@@ -50,6 +50,7 @@
 using ::android::hidl::manager::V1_0::IServiceManager;
 using ::android::sp;
 
+typedef drm::V1_2::Status Status_V1_2;
 
 namespace android {
 
@@ -76,6 +77,18 @@
     }
 }
 
+static status_t toStatusT_1_2(Status_V1_2 status) {
+    switch (status) {
+    case Status_V1_2::ERROR_DRM_SESSION_LOST_STATE:
+        return ERROR_DRM_SESSION_LOST_STATE;;
+    case Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE:
+        return ERROR_DRM_FRAME_TOO_LARGE;
+    case Status_V1_2::ERROR_DRM_INSUFFICIENT_SECURITY:
+        return ERROR_DRM_INSUFFICIENT_SECURITY;
+    default:
+        return toStatusT(static_cast<Status>(status));
+    }
+}
 
 static hidl_vec<uint8_t> toHidlVec(const Vector<uint8_t> &vector) {
     hidl_vec<uint8_t> vec;
@@ -196,6 +209,9 @@
     for (size_t i = 0; i < mFactories.size(); i++) {
         if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
             mPlugin = makeCryptoPlugin(mFactories[i], uuid, data, size);
+            if (mPlugin != NULL) {
+                mPluginV1_2 = drm::V1_2::ICryptoPlugin::castFrom(mPlugin);
+            }
         }
     }
 
@@ -216,6 +232,7 @@
     }
 
     mPlugin.clear();
+    mPluginV1_2.clear();
     return OK;
 }
 
@@ -389,21 +406,33 @@
     status_t err = UNKNOWN_ERROR;
     uint32_t bytesWritten = 0;
 
-    Return<void> hResult = mPlugin->decrypt(secure, toHidlArray16(keyId), toHidlArray16(iv), hMode,
-            hPattern, hSubSamples, hSource, offset, hDestination,
-            [&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) {
-                if (status == Status::OK) {
-                    bytesWritten = hBytesWritten;
-                    *errorDetailMsg = toString8(hDetailedError);
-                }
-                err = toStatusT(status);
-            }
-        );
+    Return<void> hResult;
 
-    if (!hResult.isOk()) {
-        err = DEAD_OBJECT;
+    if (mPluginV1_2 != NULL) {
+        hResult = mPluginV1_2->decrypt_1_2(secure, toHidlArray16(keyId), toHidlArray16(iv),
+                hMode, hPattern, hSubSamples, hSource, offset, hDestination,
+                [&](Status_V1_2 status, uint32_t hBytesWritten, hidl_string hDetailedError) {
+                    if (status == Status_V1_2::OK) {
+                        bytesWritten = hBytesWritten;
+                        *errorDetailMsg = toString8(hDetailedError);
+                    }
+                    err = toStatusT_1_2(status);
+                }
+            );
+    } else {
+        hResult = mPlugin->decrypt(secure, toHidlArray16(keyId), toHidlArray16(iv),
+                hMode, hPattern, hSubSamples, hSource, offset, hDestination,
+                [&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) {
+                    if (status == Status::OK) {
+                        bytesWritten = hBytesWritten;
+                        *errorDetailMsg = toString8(hDetailedError);
+                    }
+                    err = toStatusT(status);
+                }
+            );
     }
 
+    err = hResult.isOk() ? err : DEAD_OBJECT;
     if (err == OK) {
         return bytesWritten;
     }
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 14ff493..f4c0341 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -24,7 +24,7 @@
 #include <binder/IServiceManager.h>
 
 #include <android/hardware/drm/1.2/types.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
 #include <hidl/ServiceManagement.h>
 
 #include <media/EventMetric.h>
@@ -41,6 +41,7 @@
 
 using drm::V1_0::KeyedVector;
 using drm::V1_0::KeyStatusType;
+using drm::V1_0::KeyRequestType;
 using drm::V1_0::KeyType;
 using drm::V1_0::KeyValue;
 using drm::V1_0::SecureStop;
@@ -60,6 +61,9 @@
 using ::android::os::PersistableBundle;
 using ::android::sp;
 
+typedef drm::V1_1::KeyRequestType KeyRequestType_V1_1;
+typedef drm::V1_2::Status Status_V1_2;
+
 namespace {
 
 // This constant corresponds to the PROPERTY_DEVICE_UNIQUE_ID constant
@@ -239,7 +243,7 @@
         return ERROR_DRM_CANNOT_HANDLE;
         break;
     case Status::ERROR_DRM_INVALID_STATE:
-        return ERROR_DRM_TAMPER_DETECTED;
+        return ERROR_DRM_INVALID_STATE;
         break;
     case Status::BAD_VALUE:
         return BAD_VALUE;
@@ -260,6 +264,19 @@
     }
 }
 
+static status_t toStatusT_1_2(Status_V1_2 status) {
+    switch (status) {
+    case Status_V1_2::ERROR_DRM_RESOURCE_CONTENTION:
+        return ERROR_DRM_RESOURCE_CONTENTION;
+    case Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE:
+        return ERROR_DRM_FRAME_TOO_LARGE;
+    case Status_V1_2::ERROR_DRM_INSUFFICIENT_SECURITY:
+        return ERROR_DRM_INSUFFICIENT_SECURITY;
+    default:
+        return toStatusT(static_cast<Status>(status));
+    }
+}
+
 
 Mutex DrmHal::mLock;
 
@@ -319,8 +336,11 @@
 
     setListener(NULL);
     mInitCheck = NO_INIT;
-
-    if (mPlugin != NULL) {
+    if (mPluginV1_2 != NULL) {
+        if (!mPluginV1_2->setListener(NULL).isOk()) {
+            mInitCheck = DEAD_OBJECT;
+        }
+    } else if (mPlugin != NULL) {
         if (!mPlugin->setListener(NULL).isOk()) {
             mInitCheck = DEAD_OBJECT;
         }
@@ -333,10 +353,10 @@
 Vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
     Vector<sp<IDrmFactory>> factories;
 
-    auto manager = hardware::defaultServiceManager();
+    auto manager = hardware::defaultServiceManager1_2();
 
     if (manager != NULL) {
-        manager->listByInterface(drm::V1_0::IDrmFactory::descriptor,
+        manager->listManifestByInterface(drm::V1_0::IDrmFactory::descriptor,
                 [&factories](const hidl_vec<hidl_string> &registered) {
                     for (const auto &instance : registered) {
                         auto factory = drm::V1_0::IDrmFactory::getService(instance);
@@ -346,7 +366,7 @@
                     }
                 }
             );
-        manager->listByInterface(drm::V1_1::IDrmFactory::descriptor,
+        manager->listManifestByInterface(drm::V1_1::IDrmFactory::descriptor,
                 [&factories](const hidl_vec<hidl_string> &registered) {
                     for (const auto &instance : registered) {
                         auto factory = drm::V1_1::IDrmFactory::getService(instance);
@@ -532,6 +552,22 @@
     return Void();
 }
 
+Return<void> DrmHal::sendSessionLostState(
+        const hidl_vec<uint8_t>& sessionId) {
+
+    mEventLock.lock();
+    sp<IDrmClient> listener = mListener;
+    mEventLock.unlock();
+
+    if (listener != NULL) {
+        Parcel obj;
+        writeByteArray(obj, sessionId);
+        Mutex::Autolock lock(mNotifyLock);
+        listener->notify(DrmPlugin::kDrmPluginEventSessionLostState, 0, &obj);
+    }
+    return Void();
+}
+
 bool DrmHal::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
     Mutex::Autolock autoLock(mLock);
 
@@ -553,12 +589,14 @@
         const String8& appPackageName) {
     Mutex::Autolock autoLock(mLock);
 
-    for (size_t i = 0; i < mFactories.size(); i++) {
+    for (size_t i = mFactories.size() - 1; i >= 0; i--) {
         if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
-            mPlugin = makeDrmPlugin(mFactories[i], uuid, appPackageName);
-            if (mPlugin != NULL) {
+            auto plugin = makeDrmPlugin(mFactories[i], uuid, appPackageName);
+            if (plugin != NULL) {
+                mPlugin = plugin;
                 mPluginV1_1 = drm::V1_1::IDrmPlugin::castFrom(mPlugin);
                 mPluginV1_2 = drm::V1_2::IDrmPlugin::castFrom(mPlugin);
+                break;
             }
         }
     }
@@ -566,13 +604,22 @@
     if (mPlugin == NULL) {
         mInitCheck = ERROR_UNSUPPORTED;
     } else {
-        if (!mPlugin->setListener(this).isOk()) {
+        mInitCheck = OK;
+        if (mPluginV1_2 != NULL) {
+            if (!mPluginV1_2->setListener(this).isOk()) {
+                mInitCheck = DEAD_OBJECT;
+            }
+        } else if (!mPlugin->setListener(this).isOk()) {
             mInitCheck = DEAD_OBJECT;
-        } else {
-            mInitCheck = OK;
+        }
+        if (mInitCheck != OK) {
+            mPlugin.clear();
+            mPluginV1_1.clear();
+            mPluginV1_2.clear();
         }
     }
 
+
     return mInitCheck;
 }
 
@@ -689,6 +736,39 @@
     return DEAD_OBJECT;
 }
 
+static DrmPlugin::KeyRequestType toKeyRequestType(
+        KeyRequestType keyRequestType) {
+    switch (keyRequestType) {
+        case KeyRequestType::INITIAL:
+            return DrmPlugin::kKeyRequestType_Initial;
+            break;
+        case KeyRequestType::RENEWAL:
+            return DrmPlugin::kKeyRequestType_Renewal;
+            break;
+        case KeyRequestType::RELEASE:
+            return DrmPlugin::kKeyRequestType_Release;
+            break;
+        default:
+            return DrmPlugin::kKeyRequestType_Unknown;
+            break;
+    }
+}
+
+static DrmPlugin::KeyRequestType toKeyRequestType_1_1(
+        KeyRequestType_V1_1 keyRequestType) {
+    switch (keyRequestType) {
+        case KeyRequestType_V1_1::NONE:
+            return DrmPlugin::kKeyRequestType_None;
+            break;
+        case KeyRequestType_V1_1::UPDATE:
+            return DrmPlugin::kKeyRequestType_Update;
+            break;
+        default:
+            return toKeyRequestType(static_cast<KeyRequestType>(keyRequestType));
+            break;
+    }
+}
+
 status_t DrmHal::getKeyRequest(Vector<uint8_t> const &sessionId,
         Vector<uint8_t> const &initData, String8 const &mimeType,
         DrmPlugin::KeyType keyType, KeyedVector<String8,
@@ -715,73 +795,51 @@
     ::KeyedVector hOptionalParameters = toHidlKeyedVector(optionalParameters);
 
     status_t err = UNKNOWN_ERROR;
+    Return<void> hResult;
 
-    if (mPluginV1_1 != NULL) {
-        Return<void> hResult =
-            mPluginV1_1->getKeyRequest_1_1(
+    if (mPluginV1_2 != NULL) {
+        hResult = mPluginV1_2->getKeyRequest_1_2(
+                toHidlVec(sessionId), toHidlVec(initData),
+                toHidlString(mimeType), hKeyType, hOptionalParameters,
+                [&](Status_V1_2 status, const hidl_vec<uint8_t>& hRequest,
+                        KeyRequestType_V1_1 hKeyRequestType,
+                        const hidl_string& hDefaultUrl) {
+                    if (status == Status_V1_2::OK) {
+                        request = toVector(hRequest);
+                        defaultUrl = toString8(hDefaultUrl);
+                        *keyRequestType = toKeyRequestType_1_1(hKeyRequestType);
+                    }
+                    err = toStatusT_1_2(status);
+                });
+    } else if (mPluginV1_1 != NULL) {
+        hResult = mPluginV1_1->getKeyRequest_1_1(
                 toHidlVec(sessionId), toHidlVec(initData),
                 toHidlString(mimeType), hKeyType, hOptionalParameters,
                 [&](Status status, const hidl_vec<uint8_t>& hRequest,
-                    drm::V1_1::KeyRequestType hKeyRequestType,
-                    const hidl_string& hDefaultUrl) {
-
-            if (status == Status::OK) {
-                request = toVector(hRequest);
-                defaultUrl = toString8(hDefaultUrl);
-
-                switch (hKeyRequestType) {
-                    case drm::V1_1::KeyRequestType::INITIAL:
-                        *keyRequestType = DrmPlugin::kKeyRequestType_Initial;
-                        break;
-                    case drm::V1_1::KeyRequestType::RENEWAL:
-                        *keyRequestType = DrmPlugin::kKeyRequestType_Renewal;
-                        break;
-                    case drm::V1_1::KeyRequestType::RELEASE:
-                        *keyRequestType = DrmPlugin::kKeyRequestType_Release;
-                        break;
-                    case drm::V1_1::KeyRequestType::NONE:
-                        *keyRequestType = DrmPlugin::kKeyRequestType_None;
-                        break;
-                    case drm::V1_1::KeyRequestType::UPDATE:
-                        *keyRequestType = DrmPlugin::kKeyRequestType_Update;
-                        break;
-                    default:
-                        *keyRequestType = DrmPlugin::kKeyRequestType_Unknown;
-                        break;
-                }
-                err = toStatusT(status);
-            }
-        });
-        return hResult.isOk() ? err : DEAD_OBJECT;
-    }
-
-    Return<void> hResult = mPlugin->getKeyRequest(toHidlVec(sessionId),
-            toHidlVec(initData), toHidlString(mimeType), hKeyType, hOptionalParameters,
-            [&](Status status, const hidl_vec<uint8_t>& hRequest,
-                    drm::V1_0::KeyRequestType hKeyRequestType,
-                    const hidl_string& hDefaultUrl) {
-
-                if (status == Status::OK) {
-                    request = toVector(hRequest);
-                    defaultUrl = toString8(hDefaultUrl);
-
-                    switch (hKeyRequestType) {
-                    case drm::V1_0::KeyRequestType::INITIAL:
-                        *keyRequestType = DrmPlugin::kKeyRequestType_Initial;
-                        break;
-                    case drm::V1_0::KeyRequestType::RENEWAL:
-                        *keyRequestType = DrmPlugin::kKeyRequestType_Renewal;
-                        break;
-                    case drm::V1_0::KeyRequestType::RELEASE:
-                        *keyRequestType = DrmPlugin::kKeyRequestType_Release;
-                        break;
-                    default:
-                        *keyRequestType = DrmPlugin::kKeyRequestType_Unknown;
-                        break;
+                        KeyRequestType_V1_1 hKeyRequestType,
+                        const hidl_string& hDefaultUrl) {
+                    if (status == Status::OK) {
+                        request = toVector(hRequest);
+                        defaultUrl = toString8(hDefaultUrl);
+                        *keyRequestType = toKeyRequestType_1_1(hKeyRequestType);
                     }
                     err = toStatusT(status);
-                }
-            });
+                });
+    } else {
+        hResult = mPlugin->getKeyRequest(
+                toHidlVec(sessionId), toHidlVec(initData),
+                toHidlString(mimeType), hKeyType, hOptionalParameters,
+                [&](Status status, const hidl_vec<uint8_t>& hRequest,
+                        KeyRequestType hKeyRequestType,
+                        const hidl_string& hDefaultUrl) {
+                    if (status == Status::OK) {
+                        request = toVector(hRequest);
+                        defaultUrl = toString8(hDefaultUrl);
+                        *keyRequestType = toKeyRequestType(hKeyRequestType);
+                    }
+                    err = toStatusT(status);
+                });
+    }
 
     err = hResult.isOk() ? err : DEAD_OBJECT;
     keyRequestTimer.SetAttribute(err);
@@ -863,18 +921,33 @@
     INIT_CHECK();
 
     status_t err = UNKNOWN_ERROR;
+    Return<void> hResult;
 
-    Return<void> hResult = mPlugin->getProvisionRequest(
-            toHidlString(certType), toHidlString(certAuthority),
-            [&](Status status, const hidl_vec<uint8_t>& hRequest,
-                    const hidl_string& hDefaultUrl) {
-                if (status == Status::OK) {
-                    request = toVector(hRequest);
-                    defaultUrl = toString8(hDefaultUrl);
+    if (mPluginV1_2 != NULL) {
+        Return<void> hResult = mPluginV1_2->getProvisionRequest_1_2(
+                toHidlString(certType), toHidlString(certAuthority),
+                [&](Status_V1_2 status, const hidl_vec<uint8_t>& hRequest,
+                        const hidl_string& hDefaultUrl) {
+                    if (status == Status_V1_2::OK) {
+                        request = toVector(hRequest);
+                        defaultUrl = toString8(hDefaultUrl);
+                    }
+                    err = toStatusT_1_2(status);
                 }
-                err = toStatusT(status);
-            }
-        );
+            );
+    } else {
+        Return<void> hResult = mPlugin->getProvisionRequest(
+                toHidlString(certType), toHidlString(certAuthority),
+                [&](Status status, const hidl_vec<uint8_t>& hRequest,
+                        const hidl_string& hDefaultUrl) {
+                    if (status == Status::OK) {
+                        request = toVector(hRequest);
+                        defaultUrl = toString8(hDefaultUrl);
+                    }
+                    err = toStatusT(status);
+                }
+            );
+    }
 
     err = hResult.isOk() ? err : DEAD_OBJECT;
     mMetrics.mGetProvisionRequestCounter.Increment(err);
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
index a488f86..fc0cceb 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
@@ -42,10 +42,42 @@
     return Void();
 }
 
+Return<void> CryptoPlugin::decrypt(
+    bool secure,
+    const hidl_array<uint8_t, 16>& keyId,
+    const hidl_array<uint8_t, 16>& iv,
+    Mode mode,
+    const Pattern& pattern,
+    const hidl_vec<SubSample>& subSamples,
+    const SharedBuffer& source,
+    uint64_t offset,
+    const DestinationBuffer& destination,
+    decrypt_cb _hidl_cb) {
+
+  Status status = Status::ERROR_DRM_UNKNOWN;
+  hidl_string detailedError;
+  uint32_t bytesWritten = 0;
+
+  Return<void> hResult = decrypt_1_2(
+      secure, keyId, iv, mode, pattern, subSamples, source, offset, destination,
+      [&](Status_V1_2 hStatus, uint32_t hBytesWritten, hidl_string hDetailedError) {
+        status = toStatus_1_0(hStatus);
+        if (status == Status::OK) {
+          bytesWritten = hBytesWritten;
+          detailedError = hDetailedError;
+        }
+      }
+    );
+
+  status = hResult.isOk() ? status : Status::ERROR_DRM_CANNOT_HANDLE;
+  _hidl_cb(status, bytesWritten, detailedError);
+  return Void();
+}
+
 // Returns negative values for error code and positive values for the size of
 // decrypted data.  In theory, the output size can be larger than the input
 // size, but in practice this will never happen for AES-CTR.
-Return<void> CryptoPlugin::decrypt(
+Return<void> CryptoPlugin::decrypt_1_2(
         bool secure,
         const hidl_array<uint8_t, KEY_ID_SIZE>& keyId,
         const hidl_array<uint8_t, KEY_IV_SIZE>& iv,
@@ -55,17 +87,17 @@
         const SharedBuffer& source,
         uint64_t offset,
         const DestinationBuffer& destination,
-        decrypt_cb _hidl_cb) {
+        decrypt_1_2_cb _hidl_cb) {
     UNUSED(pattern);
 
     if (secure) {
-        _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
+        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
             "Secure decryption is not supported with ClearKey.");
         return Void();
     }
 
     if (mSharedBufferMap.find(source.bufferId) == mSharedBufferMap.end()) {
-      _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
+      _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
                "source decrypt buffer base not set");
       return Void();
     }
@@ -73,7 +105,7 @@
     if (destination.type == BufferType::SHARED_MEMORY) {
       const SharedBuffer& dest = destination.nonsecureMemory;
       if (mSharedBufferMap.find(dest.bufferId) == mSharedBufferMap.end()) {
-        _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
+        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
                  "destination decrypt buffer base not set");
         return Void();
       }
@@ -81,12 +113,12 @@
 
     sp<IMemory> sourceBase = mSharedBufferMap[source.bufferId];
     if (sourceBase == nullptr) {
-        _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "source is a nullptr");
+        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "source is a nullptr");
         return Void();
     }
 
     if (source.offset + offset + source.size > sourceBase->getSize()) {
-        _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
+        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
         return Void();
     }
 
@@ -98,12 +130,12 @@
         const SharedBuffer& destBuffer = destination.nonsecureMemory;
         sp<IMemory> destBase = mSharedBufferMap[destBuffer.bufferId];
         if (destBase == nullptr) {
-            _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "destination is a nullptr");
+            _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "destination is a nullptr");
             return Void();
         }
 
         if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
-            _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
+            _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
             return Void();
         }
         destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
@@ -128,7 +160,7 @@
 
     if (mode == Mode::UNENCRYPTED) {
         if (haveEncryptedSubsamples) {
-            _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
+            _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
                     "Encrypted subsamples found in allegedly unencrypted data.");
             return Void();
         }
@@ -144,22 +176,21 @@
             }
         }
 
-        _hidl_cb(Status::OK, static_cast<ssize_t>(offset), "");
+        _hidl_cb(Status_V1_2::OK, static_cast<ssize_t>(offset), "");
         return Void();
     } else if (mode == Mode::AES_CTR) {
         size_t bytesDecrypted;
-        Status res = mSession->decrypt(keyId.data(), iv.data(), srcPtr,
+        Status_V1_2 res = mSession->decrypt(keyId.data(), iv.data(), srcPtr,
                 static_cast<uint8_t*>(destPtr), toVector(subSamples), &bytesDecrypted);
-        if (res == Status::OK) {
-            _hidl_cb(Status::OK, static_cast<ssize_t>(bytesDecrypted), "");
+        if (res == Status_V1_2::OK) {
+            _hidl_cb(Status_V1_2::OK, static_cast<ssize_t>(bytesDecrypted), "");
             return Void();
         } else {
-            _hidl_cb(Status::ERROR_DRM_DECRYPT, static_cast<ssize_t>(res),
-                    "Decryption Error");
+            _hidl_cb(res, 0, "Decryption Error");
             return Void();
         }
     } else {
-        _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
+        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
                 "Selected encryption mode is not supported by the ClearKey DRM Plugin.");
         return Void();
     }
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index 7184b53..badb99e 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -61,15 +61,23 @@
 namespace V1_2 {
 namespace clearkey {
 
-using ::android::hardware::drm::V1_2::KeySetId;
-using ::android::hardware::drm::V1_2::OfflineLicenseState;
+KeyRequestType toKeyRequestType_V1_0(KeyRequestType_V1_1 keyRequestType) {
+  switch (keyRequestType) {
+    case KeyRequestType_V1_1::NONE:
+    case KeyRequestType_V1_1::UPDATE:
+      return KeyRequestType::UNKNOWN;
+    default:
+      return static_cast<KeyRequestType>(keyRequestType);
+  }
+}
 
 DrmPlugin::DrmPlugin(SessionLibrary* sessionLibrary)
         : mSessionLibrary(sessionLibrary),
           mOpenSessionOkCount(0),
           mCloseSessionOkCount(0),
           mCloseSessionNotOpenedCount(0),
-          mNextSecureStopId(kSecureStopIdStart) {
+          mNextSecureStopId(kSecureStopIdStart),
+          mMockError(Status_V1_2::OK) {
     mPlayPolicy.clear();
     initProperties();
     mSecureStops.clear();
@@ -84,6 +92,7 @@
     mStringProperties[kPluginDescriptionKey] = kPluginDescriptionValue;
     mStringProperties[kAlgorithmsKey] = kAlgorithmsValue;
     mStringProperties[kListenerTestSupportKey] = kListenerTestSupportValue;
+    mStringProperties[kDrmErrorTestKey] = kDrmErrorTestValue;
 
     std::vector<uint8_t> valueVector;
     valueVector.clear();
@@ -112,6 +121,7 @@
 
 Return<void> DrmPlugin::openSession(openSession_cb _hidl_cb) {
     sp<Session> session = mSessionLibrary->createSession();
+    processMockError(session);
     std::vector<uint8_t> sessionId = session->sessionId();
 
     Status status = setSecurityLevel(sessionId, SecurityLevel::SW_SECURE_CRYPTO);
@@ -123,6 +133,7 @@
 Return<void> DrmPlugin::openSession_1_1(SecurityLevel securityLevel,
         openSession_1_1_cb _hidl_cb) {
     sp<Session> session = mSessionLibrary->createSession();
+    processMockError(session);
     std::vector<uint8_t> sessionId = session->sessionId();
 
     Status status = setSecurityLevel(sessionId, securityLevel);
@@ -138,6 +149,10 @@
 
     sp<Session> session = mSessionLibrary->findSession(toVector(sessionId));
     if (session.get()) {
+        if (session->getMockError() != Status_V1_2::OK) {
+            sendSessionLostState(sessionId);
+            return Status::ERROR_DRM_INVALID_STATE;
+        }
         mCloseSessionOkCount++;
         mSessionLibrary->destroySession(session);
         return Status::OK;
@@ -146,13 +161,13 @@
     return Status::ERROR_DRM_SESSION_NOT_OPENED;
 }
 
-Status DrmPlugin::getKeyRequestCommon(const hidl_vec<uint8_t>& scope,
+Status_V1_2 DrmPlugin::getKeyRequestCommon(const hidl_vec<uint8_t>& scope,
         const hidl_vec<uint8_t>& initData,
         const hidl_string& mimeType,
         KeyType keyType,
         const hidl_vec<KeyValue>& optionalParameters,
         std::vector<uint8_t> *request,
-        KeyRequestType *keyRequestType,
+        KeyRequestType_V1_1 *keyRequestType,
         std::string *defaultUrl) {
         UNUSED(optionalParameters);
 
@@ -161,18 +176,18 @@
     // Those tests pass in an empty initData, we use the empty initData to
     // signal such specific use case.
     if (keyType == KeyType::OFFLINE && 0 == initData.size()) {
-        return Status::ERROR_DRM_CANNOT_HANDLE;
+        return Status_V1_2::ERROR_DRM_CANNOT_HANDLE;
     }
 
     *defaultUrl = "";
-    *keyRequestType = KeyRequestType::UNKNOWN;
+    *keyRequestType = KeyRequestType_V1_1::UNKNOWN;
     *request = std::vector<uint8_t>();
 
     if (scope.size() == 0 ||
             (keyType != KeyType::STREAMING &&
             keyType != KeyType::OFFLINE &&
             keyType != KeyType::RELEASE)) {
-        return Status::BAD_VALUE;
+        return Status_V1_2::BAD_VALUE;
     }
 
     const std::vector<uint8_t> scopeId = toVector(scope);
@@ -181,12 +196,16 @@
         std::vector<uint8_t> sessionId(scopeId.begin(), scopeId.end());
         session = mSessionLibrary->findSession(sessionId);
         if (!session.get()) {
-            return Status::ERROR_DRM_SESSION_NOT_OPENED;
+            return Status_V1_2::ERROR_DRM_SESSION_NOT_OPENED;
+        } else if (session->getMockError() != Status_V1_2::OK) {
+            return session->getMockError();
         }
-        *keyRequestType = KeyRequestType::INITIAL;
+
+        *keyRequestType = KeyRequestType_V1_1::INITIAL;
     }
 
-    Status status = session->getKeyRequest(initData, mimeType, keyType, request);
+    Status_V1_2 status = static_cast<Status_V1_2>(
+            session->getKeyRequest(initData, mimeType, keyType, request));
 
     if (keyType == KeyType::RELEASE) {
         std::vector<uint8_t> keySetId(scopeId.begin(), scopeId.end());
@@ -198,7 +217,7 @@
                     DeviceFiles::kLicenseStateReleasing,
                     emptyResponse)) {
                 ALOGE("Problem releasing offline license");
-                return Status::ERROR_DRM_UNKNOWN;
+                return Status_V1_2::ERROR_DRM_UNKNOWN;
             }
             if (mReleaseKeysMap.find(keySetIdString) == mReleaseKeysMap.end()) {
                 sp<Session> session = mSessionLibrary->createSession();
@@ -209,7 +228,7 @@
         } else {
             ALOGE("Offline license not found, nothing to release");
         }
-        *keyRequestType = KeyRequestType::RELEASE;
+        *keyRequestType = KeyRequestType_V1_1::RELEASE;
     }
     return status;
 }
@@ -223,15 +242,15 @@
         getKeyRequest_cb _hidl_cb) {
     UNUSED(optionalParameters);
 
-    KeyRequestType keyRequestType = KeyRequestType::UNKNOWN;
+    KeyRequestType_V1_1 keyRequestType = KeyRequestType_V1_1::UNKNOWN;
     std::string defaultUrl("");
     std::vector<uint8_t> request;
-    Status status = getKeyRequestCommon(
+    Status_V1_2 status = getKeyRequestCommon(
             scope, initData, mimeType, keyType, optionalParameters,
             &request, &keyRequestType, &defaultUrl);
 
-    _hidl_cb(status, toHidlVec(request),
-            static_cast<drm::V1_0::KeyRequestType>(keyRequestType),
+    _hidl_cb(toStatus_1_0(status), toHidlVec(request),
+            toKeyRequestType_V1_0(keyRequestType),
             hidl_string(defaultUrl));
     return Void();
 }
@@ -245,10 +264,31 @@
         getKeyRequest_1_1_cb _hidl_cb) {
     UNUSED(optionalParameters);
 
-    KeyRequestType keyRequestType = KeyRequestType::UNKNOWN;
+    KeyRequestType_V1_1 keyRequestType = KeyRequestType_V1_1::UNKNOWN;
     std::string defaultUrl("");
     std::vector<uint8_t> request;
-    Status status = getKeyRequestCommon(
+    Status_V1_2 status = getKeyRequestCommon(
+            scope, initData, mimeType, keyType, optionalParameters,
+            &request, &keyRequestType, &defaultUrl);
+
+    _hidl_cb(toStatus_1_0(status), toHidlVec(request),
+            keyRequestType, hidl_string(defaultUrl));
+    return Void();
+}
+
+Return<void> DrmPlugin::getKeyRequest_1_2(
+        const hidl_vec<uint8_t>& scope,
+        const hidl_vec<uint8_t>& initData,
+        const hidl_string& mimeType,
+        KeyType keyType,
+        const hidl_vec<KeyValue>& optionalParameters,
+        getKeyRequest_1_2_cb _hidl_cb) {
+    UNUSED(optionalParameters);
+
+    KeyRequestType_V1_1 keyRequestType = KeyRequestType_V1_1::UNKNOWN;
+    std::string defaultUrl("");
+    std::vector<uint8_t> request;
+    Status_V1_2 status = getKeyRequestCommon(
             scope, initData, mimeType, keyType, optionalParameters,
             &request, &keyRequestType, &defaultUrl);
 
@@ -434,6 +474,8 @@
         value = mStringProperties[kAlgorithmsKey];
     } else if (name == kListenerTestSupportKey) {
         value = mStringProperties[kListenerTestSupportKey];
+    } else if (name == kDrmErrorTestKey) {
+        value = mStringProperties[kDrmErrorTestKey];
     } else {
         ALOGE("App requested unknown string property %s", name.c_str());
         _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, "");
@@ -478,6 +520,16 @@
         return Status::BAD_VALUE;
     }
 
+    if (name == kDrmErrorTestKey) {
+        if (value == kResourceContentionValue) {
+            mMockError = Status_V1_2::ERROR_DRM_RESOURCE_CONTENTION;
+        } else if (value == kLostStateValue) {
+            mMockError = Status_V1_2::ERROR_DRM_SESSION_LOST_STATE;
+        } else if (value == kFrameTooLargeValue) {
+            mMockError = Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE;
+        }
+    }
+
     mStringProperties[key] = std::string(value.c_str());
     return Status::OK;
 }
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Session.cpp b/drm/mediadrm/plugins/clearkey/hidl/Session.cpp
index f4c49b9..a9d7016 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Session.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Session.cpp
@@ -68,25 +68,30 @@
     }
 }
 
-Status Session::decrypt(
+Status_V1_2 Session::decrypt(
         const KeyId keyId, const Iv iv, const uint8_t* srcPtr,
         uint8_t* destPtr, const std::vector<SubSample> subSamples,
         size_t* bytesDecryptedOut) {
     Mutex::Autolock lock(mMapLock);
 
+    if (getMockError() != Status_V1_2::OK) {
+        return getMockError();
+    }
+
     std::vector<uint8_t> keyIdVector;
     keyIdVector.clear();
     keyIdVector.insert(keyIdVector.end(), keyId, keyId + kBlockSize);
     std::map<std::vector<uint8_t>, std::vector<uint8_t> >::iterator itr;
     itr = mKeyMap.find(keyIdVector);
     if (itr == mKeyMap.end()) {
-        return Status::ERROR_DRM_NO_LICENSE;
+        return Status_V1_2::ERROR_DRM_NO_LICENSE;
     }
 
     AesCtrDecryptor decryptor;
-    return decryptor.decrypt(
+    Status status = decryptor.decrypt(
             itr->second /*key*/, iv, srcPtr, destPtr, subSamples,
             subSamples.size(), bytesDecryptedOut);
+    return static_cast<Status_V1_2>(status);
 }
 
 } // namespace clearkey
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
index f83903c..1bbc822 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
@@ -35,6 +35,11 @@
 static const std::string kAlgorithmsValue("");
 static const std::string kListenerTestSupportKey("listenerTestSupport");
 static const std::string kListenerTestSupportValue("true");
+static const std::string kDrmErrorTestKey("drmErrorTest");
+static const std::string kDrmErrorTestValue("");
+static const std::string kResourceContentionValue("resourceContention");
+static const std::string kLostStateValue("lostState");
+static const std::string kFrameTooLargeValue("frameTooLarge");
 
 static const std::string kDeviceIdKey("deviceId");
 static const uint8_t kTestDeviceIdData[] =
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyTypes.h b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyTypes.h
index 7e9b6bd..2dafa36 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyTypes.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyTypes.h
@@ -17,7 +17,7 @@
 #ifndef CLEARKEY_MACROS_H_
 #define CLEARKEY_MACROS_H_
 
-#include <android/hardware/drm/1.0/types.h>
+#include <android/hardware/drm/1.2/types.h>
 
 #include <map>
 
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h
index 480dc7e..8680f0c 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h
@@ -17,7 +17,7 @@
 #ifndef CLEARKEY_CRYPTO_PLUGIN_H_
 #define CLEARKEY_CRYPTO_PLUGIN_H_
 
-#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.2/ICryptoPlugin.h>
 #include <android/hidl/memory/1.0/IMemory.h>
 
 #include "ClearKeyTypes.h"
@@ -35,13 +35,14 @@
 namespace V1_2 {
 namespace clearkey {
 
-using ::android::hardware::drm::V1_0::DestinationBuffer;
-using ::android::hardware::drm::V1_0::ICryptoPlugin;
-using ::android::hardware::drm::V1_0::Mode;
-using ::android::hardware::drm::V1_0::Pattern;
-using ::android::hardware::drm::V1_0::SharedBuffer;
-using ::android::hardware::drm::V1_0::Status;
-using ::android::hardware::drm::V1_0::SubSample;
+namespace drm = ::android::hardware::drm;
+using drm::V1_0::DestinationBuffer;
+using drm::V1_0::Mode;
+using drm::V1_0::Pattern;
+using drm::V1_0::SharedBuffer;
+using drm::V1_0::Status;
+using drm::V1_0::SubSample;
+
 using ::android::hardware::hidl_array;
 using ::android::hardware::hidl_memory;
 using ::android::hardware::hidl_string;
@@ -51,7 +52,9 @@
 using ::android::hidl::memory::V1_0::IMemory;
 using ::android::sp;
 
-struct CryptoPlugin : public ICryptoPlugin {
+typedef drm::V1_2::Status Status_V1_2;
+
+struct CryptoPlugin : public drm::V1_2::ICryptoPlugin {
     explicit CryptoPlugin(const hidl_vec<uint8_t>& sessionId) {
         mInitStatus = setMediaDrmSession(sessionId);
     }
@@ -80,6 +83,18 @@
             const DestinationBuffer& destination,
             decrypt_cb _hidl_cb);
 
+    Return<void> decrypt_1_2(
+            bool secure,
+            const hidl_array<uint8_t, KEY_ID_SIZE>& keyId,
+            const hidl_array<uint8_t, KEY_IV_SIZE>& iv,
+            Mode mode,
+            const Pattern& pattern,
+            const hidl_vec<SubSample>& subSamples,
+            const SharedBuffer& source,
+            uint64_t offset,
+            const DestinationBuffer& destination,
+            decrypt_1_2_cb _hidl_cb);
+
     Return<void> setSharedBufferBase(const hidl_memory& base,
             uint32_t bufferId);
 
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
index 256c5d6..a9b897b 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -18,6 +18,7 @@
 #define CLEARKEY_DRM_PLUGIN_H_
 
 #include <android/hardware/drm/1.2/IDrmPlugin.h>
+#include <android/hardware/drm/1.2/IDrmPluginListener.h>
 
 #include <map>
 #include <stdio.h>
@@ -34,22 +35,24 @@
 namespace V1_2 {
 namespace clearkey {
 
-using ::android::hardware::drm::V1_0::EventType;
-using ::android::hardware::drm::V1_0::IDrmPluginListener;
-using ::android::hardware::drm::V1_0::KeyStatus;
-using ::android::hardware::drm::V1_0::KeyType;
-using ::android::hardware::drm::V1_0::KeyValue;
-using ::android::hardware::drm::V1_0::SecureStop;
-using ::android::hardware::drm::V1_0::SecureStopId;
-using ::android::hardware::drm::V1_0::SessionId;
-using ::android::hardware::drm::V1_0::Status;
-using ::android::hardware::drm::V1_1::DrmMetricGroup;
-using ::android::hardware::drm::V1_1::HdcpLevel;
-using ::android::hardware::drm::V1_1::KeyRequestType;
-using ::android::hardware::drm::V1_1::SecureStopRelease;
-using ::android::hardware::drm::V1_1::SecurityLevel;
-using ::android::hardware::drm::V1_2::IDrmPlugin;
-using ::android::hardware::drm::V1_2::OfflineLicenseState;
+namespace drm = ::android::hardware::drm;
+using drm::V1_0::EventType;
+using drm::V1_0::IDrmPluginListener;
+using drm::V1_0::KeyRequestType;
+using drm::V1_0::KeyStatus;
+using drm::V1_0::KeyType;
+using drm::V1_0::KeyValue;
+using drm::V1_0::SecureStop;
+using drm::V1_0::SecureStopId;
+using drm::V1_0::SessionId;
+using drm::V1_0::Status;
+using drm::V1_1::DrmMetricGroup;
+using drm::V1_1::HdcpLevel;
+using drm::V1_1::SecureStopRelease;
+using drm::V1_1::SecurityLevel;
+using drm::V1_2::IDrmPlugin;
+using drm::V1_2::KeySetId;
+using drm::V1_2::OfflineLicenseState;
 
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
@@ -57,6 +60,10 @@
 using ::android::hardware::Void;
 using ::android::sp;
 
+typedef drm::V1_1::KeyRequestType KeyRequestType_V1_1;
+typedef drm::V1_2::IDrmPluginListener IDrmPluginListener_V1_2;
+typedef drm::V1_2::Status Status_V1_2;
+
 struct DrmPlugin : public IDrmPlugin {
     explicit DrmPlugin(SessionLibrary* sessionLibrary);
 
@@ -84,6 +91,14 @@
         const hidl_vec<KeyValue>& optionalParameters,
         getKeyRequest_1_1_cb _hidl_cb) override;
 
+    Return<void> getKeyRequest_1_2(
+        const hidl_vec<uint8_t>& scope,
+        const hidl_vec<uint8_t>& initData,
+        const hidl_string& mimeType,
+        KeyType keyType,
+        const hidl_vec<KeyValue>& optionalParameters,
+        getKeyRequest_1_2_cb _hidl_cb) override;
+
     Return<void> provideKeyResponse(
         const hidl_vec<uint8_t>& scope,
         const hidl_vec<uint8_t>& response,
@@ -116,6 +131,18 @@
         return Void();
     }
 
+    Return<void> getProvisionRequest_1_2(
+        const hidl_string& certificateType,
+        const hidl_string& certificateAuthority,
+        getProvisionRequest_1_2_cb _hidl_cb) {
+        UNUSED(certificateType);
+        UNUSED(certificateAuthority);
+
+        hidl_string defaultUrl;
+        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, hidl_vec<uint8_t>(), defaultUrl);
+        return Void();
+    }
+
     Return<void> provideProvisionResponse(
         const hidl_vec<uint8_t>& response,
         provideProvisionResponse_cb _hidl_cb) {
@@ -256,12 +283,17 @@
 
     Return<void> setListener(const sp<IDrmPluginListener>& listener) {
         mListener = listener;
+        mListenerV1_2 = IDrmPluginListener_V1_2::castFrom(listener);
         return Void();
     };
 
-    Return<void> sendEvent(EventType eventType, const hidl_vec<uint8_t>& sessionId,
+    Return<void> sendEvent(
+            EventType eventType,
+            const hidl_vec<uint8_t>& sessionId,
             const hidl_vec<uint8_t>& data) {
-        if (mListener != NULL) {
+        if (mListenerV1_2 != NULL) {
+            mListenerV1_2->sendEvent(eventType, sessionId, data);
+        } else if (mListener != NULL) {
             mListener->sendEvent(eventType, sessionId, data);
         } else {
             ALOGE("Null event listener, event not sent");
@@ -269,8 +301,12 @@
         return Void();
     }
 
-    Return<void> sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId, int64_t expiryTimeInMS) {
-        if (mListener != NULL) {
+    Return<void> sendExpirationUpdate(
+            const hidl_vec<uint8_t>& sessionId,
+            int64_t expiryTimeInMS) {
+        if (mListenerV1_2 != NULL) {
+            mListenerV1_2->sendExpirationUpdate(sessionId, expiryTimeInMS);
+        } else if (mListener != NULL) {
             mListener->sendExpirationUpdate(sessionId, expiryTimeInMS);
         } else {
             ALOGE("Null event listener, event not sent");
@@ -278,9 +314,12 @@
         return Void();
     }
 
-    Return<void> sendKeysChange(const hidl_vec<uint8_t>& sessionId,
+    Return<void> sendKeysChange(
+            const hidl_vec<uint8_t>& sessionId,
             const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey) {
-        if (mListener != NULL) {
+        if (mListenerV1_2 != NULL) {
+            mListenerV1_2->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
+        } else if (mListener != NULL) {
             mListener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
         } else {
             ALOGE("Null event listener, event not sent");
@@ -288,6 +327,14 @@
         return Void();
     }
 
+    Return<void> sendSessionLostState(
+            const hidl_vec<uint8_t>& sessionId) {
+        if (mListenerV1_2 != NULL) {
+            mListenerV1_2->sendSessionLostState(sessionId);
+        }
+        return Void();
+    }
+
     Return<void> getSecureStops(getSecureStops_cb _hidl_cb);
 
     Return<void> getSecureStop(const hidl_vec<uint8_t>& secureStopId,
@@ -314,13 +361,13 @@
     Return<Status> setSecurityLevel(const hidl_vec<uint8_t>& sessionId,
             SecurityLevel level);
 
-    Status getKeyRequestCommon(const hidl_vec<uint8_t>& scope,
+    Status_V1_2 getKeyRequestCommon(const hidl_vec<uint8_t>& scope,
             const hidl_vec<uint8_t>& initData,
             const hidl_string& mimeType,
             KeyType keyType,
             const hidl_vec<KeyValue>& optionalParameters,
             std::vector<uint8_t> *request,
-            KeyRequestType *getKeyRequestType,
+            KeyRequestType_V1_1 *getKeyRequestType,
             std::string *defaultUrl);
 
     struct ClearkeySecureStop {
@@ -335,12 +382,21 @@
     std::map<std::string, std::vector<uint8_t> > mReleaseKeysMap;
     std::map<std::vector<uint8_t>, SecurityLevel> mSecurityLevel;
     sp<IDrmPluginListener> mListener;
+    sp<IDrmPluginListener_V1_2> mListenerV1_2;
     SessionLibrary *mSessionLibrary;
     int64_t mOpenSessionOkCount;
     int64_t mCloseSessionOkCount;
     int64_t mCloseSessionNotOpenedCount;
     uint32_t mNextSecureStopId;
 
+    // set by property to mock error scenarios
+    Status_V1_2 mMockError;
+
+    void processMockError(const sp<Session> &session) {
+        session->setMockError(mMockError);
+        mMockError = Status_V1_2::OK;
+    }
+
     DeviceFiles mFileHandle;
 
     CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(DrmPlugin);
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/Session.h b/drm/mediadrm/plugins/clearkey/hidl/include/Session.h
index f35560d..a159e5a 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/Session.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/Session.h
@@ -30,13 +30,16 @@
 namespace V1_2 {
 namespace clearkey {
 
-using ::android::hardware::drm::V1_0::Status;
-using ::android::hardware::drm::V1_0::SubSample;
+namespace drm = ::android::hardware::drm;
+using drm::V1_0::Status;
+using drm::V1_0::SubSample;
+
+typedef drm::V1_2::Status Status_V1_2;
 
 class Session : public RefBase {
 public:
     explicit Session(const std::vector<uint8_t>& sessionId)
-            : mSessionId(sessionId) {}
+        : mSessionId(sessionId), mMockError(Status_V1_2::OK) {}
     virtual ~Session() {}
 
     const std::vector<uint8_t>& sessionId() const { return mSessionId; }
@@ -50,17 +53,23 @@
     Status provideKeyResponse(
             const std::vector<uint8_t>& response);
 
-    Status decrypt(
+    Status_V1_2 decrypt(
             const KeyId keyId, const Iv iv, const uint8_t* srcPtr,
             uint8_t* dstPtr, const std::vector<SubSample> subSamples,
             size_t* bytesDecryptedOut);
 
+    void setMockError(Status_V1_2 error) {mMockError = error;}
+    Status_V1_2 getMockError() const {return mMockError;}
+
 private:
     CLEARKEY_DISALLOW_COPY_AND_ASSIGN(Session);
 
     const std::vector<uint8_t> mSessionId;
     KeyMap mKeyMap;
     Mutex mMapLock;
+
+    // For mocking error return scenarios
+    Status_V1_2 mMockError;
 };
 
 } // namespace clearkey
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/TypeConvert.h b/drm/mediadrm/plugins/clearkey/hidl/include/TypeConvert.h
index f6d30c9..b0f8607 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/TypeConvert.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/TypeConvert.h
@@ -68,6 +68,17 @@
     return vec;
 }
 
+inline Status toStatus_1_0(Status_V1_2 status) {
+  switch (status) {
+    case Status_V1_2::ERROR_DRM_INSUFFICIENT_SECURITY:
+    case Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE:
+    case Status_V1_2::ERROR_DRM_SESSION_LOST_STATE:
+      return Status::ERROR_DRM_UNKNOWN;
+    default:
+      return static_cast<Status>(status);
+  }
+}
+
 }  // namespace clearkey
 }  // namespace V1_2
 }  // namespace drm
diff --git a/include/media/DataSource.h b/include/media/DataSource.h
index 905bec1..198b27e 120000
--- a/include/media/DataSource.h
+++ b/include/media/DataSource.h
@@ -1 +1 @@
-../../media/libmediaextractor/include/media/DataSource.h
\ No newline at end of file
+stagefright/DataSource.h
\ No newline at end of file
diff --git a/include/media/DataSourceBase.h b/include/media/DataSourceBase.h
index 54c8047..d2ab2f1 120000
--- a/include/media/DataSourceBase.h
+++ b/include/media/DataSourceBase.h
@@ -1 +1 @@
-../../media/libmediaextractor/include/media/DataSourceBase.h
\ No newline at end of file
+stagefright/DataSourceBase.h
\ No newline at end of file
diff --git a/include/media/ExtractorUtils.h b/include/media/ExtractorUtils.h
deleted file mode 120000
index e2dd082..0000000
--- a/include/media/ExtractorUtils.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmediaextractor/include/media/ExtractorUtils.h
\ No newline at end of file
diff --git a/media/libmediaextractor/include/media/ExtractorUtils.h b/include/media/ExtractorUtils.h
similarity index 100%
rename from media/libmediaextractor/include/media/ExtractorUtils.h
rename to include/media/ExtractorUtils.h
diff --git a/include/media/MediaExtractorPluginApi.h b/include/media/MediaExtractorPluginApi.h
index 854bf83..916472c 100644
--- a/include/media/MediaExtractorPluginApi.h
+++ b/include/media/MediaExtractorPluginApi.h
@@ -135,8 +135,16 @@
     const char *extractor_name;
 
     union {
-        SnifferFunc v2;
-    } sniff;
+        struct {
+            SnifferFunc sniff;
+        } v2;
+        struct {
+            SnifferFunc sniff;
+            // a NULL terminated list of container mime types and/or file extensions
+            // that this extractor supports
+            const char **supported_types;
+        } v3;
+    } u;
 };
 
 // the C++ based API which first shipped in P and is no longer supported
@@ -145,7 +153,10 @@
 // the first C/NDK based API
 const uint32_t EXTRACTORDEF_VERSION_NDK_V1 = 2;
 
-const uint32_t EXTRACTORDEF_VERSION = EXTRACTORDEF_VERSION_NDK_V1;
+// the second C/NDK based API
+const uint32_t EXTRACTORDEF_VERSION_NDK_V2 = 3;
+
+const uint32_t EXTRACTORDEF_VERSION = EXTRACTORDEF_VERSION_NDK_V2;
 
 // each plugin library exports one function of this type
 typedef ExtractorDef (*GetExtractorDef)();
diff --git a/include/media/MediaSource.h b/include/media/MediaSource.h
index 2e147c4..34bf65d 120000
--- a/include/media/MediaSource.h
+++ b/include/media/MediaSource.h
@@ -1 +1 @@
-../../media/libmediaextractor/include/media/MediaSource.h
\ No newline at end of file
+../../media/libstagefright/include/media/stagefright/MediaSource.h
\ No newline at end of file
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index f1e815b..dfb1a3f 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -16,3 +16,6 @@
     stop audioserver
 on property:vts.native_server.on=0
     start audioserver
+
+on init
+    mkdir /dev/socket/audioserver 0775 audioserver audioserver
diff --git a/media/codec2/components/aac/C2SoftAacEnc.cpp b/media/codec2/components/aac/C2SoftAacEnc.cpp
index aeefbdb..87730ae 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.cpp
+++ b/media/codec2/components/aac/C2SoftAacEnc.cpp
@@ -468,7 +468,8 @@
 
             if (outargs.numOutBytes > 0) {
                 mInputSize = 0;
-                int consumed = ((capacity / sizeof(int16_t)) - inargs.numInSamples);
+                int consumed = (capacity / sizeof(int16_t)) - inargs.numInSamples
+                        + outargs.numInSamples;
                 mInputTimeUs = work->input.ordinal.timestamp
                         + (consumed * 1000000ll / channelCount / sampleRate);
                 buffer = createLinearBuffer(block, 0, outargs.numOutBytes);
diff --git a/media/codec2/components/aom/Android.bp b/media/codec2/components/aom/Android.bp
new file mode 100644
index 0000000..0fabf5c
--- /dev/null
+++ b/media/codec2/components/aom/Android.bp
@@ -0,0 +1,14 @@
+cc_library_shared {
+    name: "libcodec2_soft_av1dec",
+    defaults: [
+        "libcodec2_soft-defaults",
+        "libcodec2_soft_sanitize_all-defaults",
+    ],
+
+    srcs: ["C2SoftAomDec.cpp"],
+    static_libs: ["libaom"],
+
+    include_dirs: [
+        "external/libaom/",
+    ],
+}
diff --git a/media/codec2/components/aom/C2SoftAomDec.cpp b/media/codec2/components/aom/C2SoftAomDec.cpp
new file mode 100644
index 0000000..6be1807
--- /dev/null
+++ b/media/codec2/components/aom/C2SoftAomDec.cpp
@@ -0,0 +1,750 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2SoftAomDec"
+#include <log/log.h>
+
+#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/MediaDefs.h>
+
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+#include <SimpleC2Interface.h>
+
+#include "C2SoftAomDec.h"
+
+namespace android {
+
+constexpr char COMPONENT_NAME[] = "c2.android.av1.decoder";
+
+class C2SoftAomDec::IntfImpl : public SimpleInterface<void>::BaseParams {
+  public:
+    explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper>& helper)
+        : SimpleInterface<void>::BaseParams(
+              helper, COMPONENT_NAME, C2Component::KIND_DECODER,
+              C2Component::DOMAIN_VIDEO, MEDIA_MIMETYPE_VIDEO_AV1) {
+        noPrivateBuffers();  // TODO: account for our buffers here
+        noInputReferences();
+        noOutputReferences();
+        noInputLatency();
+        noTimeStretch();
+
+        addParameter(DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
+                         .withConstValue(new C2ComponentAttributesSetting(
+                             C2Component::ATTRIB_IS_TEMPORAL))
+                         .build());
+
+        addParameter(
+            DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
+                .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
+                .withFields({
+                    C2F(mSize, width).inRange(2, 2048, 2),
+                    C2F(mSize, height).inRange(2, 2048, 2),
+                })
+                .withSetter(SizeSetter)
+                .build());
+
+        addParameter(
+                DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
+                .withDefault(new C2StreamProfileLevelInfo::input(0u,
+                        C2Config::PROFILE_AV1_0, C2Config::LEVEL_AV1_2_1))
+                .withFields({
+                    C2F(mProfileLevel, profile).oneOf({
+                            C2Config::PROFILE_AV1_0,
+                            C2Config::PROFILE_AV1_1}),
+                    C2F(mProfileLevel, level).oneOf({
+                            C2Config::LEVEL_AV1_2,
+                            C2Config::LEVEL_AV1_2_1,
+                            C2Config::LEVEL_AV1_2_2,
+                            C2Config::LEVEL_AV1_3,
+                            C2Config::LEVEL_AV1_3_1,
+                            C2Config::LEVEL_AV1_3_2,
+                    })
+                })
+                .withSetter(ProfileLevelSetter, mSize)
+                .build());
+
+        addParameter(DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
+                         .withDefault(new C2StreamMaxPictureSizeTuning::output(
+                             0u, 320, 240))
+                         .withFields({
+                             C2F(mSize, width).inRange(2, 2048, 2),
+                             C2F(mSize, height).inRange(2, 2048, 2),
+                         })
+                         .withSetter(MaxPictureSizeSetter, mSize)
+                         .build());
+
+        addParameter(
+            DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
+                .withDefault(
+                    new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 4))
+                .withFields({
+                    C2F(mMaxInputSize, value).any(),
+                })
+                .calculatedAs(MaxInputSizeSetter, mMaxSize)
+                .build());
+
+        C2ChromaOffsetStruct locations[1] = {
+            C2ChromaOffsetStruct::ITU_YUV_420_0()};
+        std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
+            C2StreamColorInfo::output::AllocShared(1u, 0u, 8u /* bitDepth */,
+                                                   C2Color::YUV_420);
+        memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
+
+        defaultColorInfo = C2StreamColorInfo::output::AllocShared(
+            {C2ChromaOffsetStruct::ITU_YUV_420_0()}, 0u, 8u /* bitDepth */,
+            C2Color::YUV_420);
+        helper->addStructDescriptors<C2ChromaOffsetStruct>();
+
+        addParameter(DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
+                         .withConstValue(defaultColorInfo)
+                         .build());
+
+        addParameter(
+                DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
+                .withDefault(new C2StreamColorAspectsTuning::output(
+                        0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
+                        C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
+                .withFields({
+                    C2F(mDefaultColorAspects, range).inRange(
+                                C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER),
+                    C2F(mDefaultColorAspects, primaries).inRange(
+                                C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
+                    C2F(mDefaultColorAspects, transfer).inRange(
+                                C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER),
+                    C2F(mDefaultColorAspects, matrix).inRange(
+                                C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER)
+                })
+                .withSetter(DefaultColorAspectsSetter)
+                .build());
+
+        // TODO: support more formats?
+        addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
+                         .withConstValue(new C2StreamPixelFormatInfo::output(
+                             0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
+                         .build());
+    }
+
+    static C2R SizeSetter(bool mayBlock,
+                          const C2P<C2StreamPictureSizeInfo::output>& oldMe,
+                          C2P<C2VideoSizeStreamInfo::output>& me) {
+        (void)mayBlock;
+        C2R res = C2R::Ok();
+        if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
+            res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
+            me.set().width = oldMe.v.width;
+        }
+        if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
+            res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
+            me.set().height = oldMe.v.height;
+        }
+        return res;
+    }
+
+    static C2R MaxPictureSizeSetter(
+        bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output>& me,
+        const C2P<C2StreamPictureSizeInfo::output>& size) {
+        (void)mayBlock;
+        // TODO: get max width/height from the size's field helpers vs.
+        // hardcoding
+        me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4096u);
+        me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4096u);
+        return C2R::Ok();
+    }
+
+    static C2R MaxInputSizeSetter(
+        bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input>& me,
+        const C2P<C2StreamMaxPictureSizeTuning::output>& maxSize) {
+        (void)mayBlock;
+        // assume compression ratio of 2
+        me.set().value = (((maxSize.v.width + 63) / 64) *
+                          ((maxSize.v.height + 63) / 64) * 3072);
+        return C2R::Ok();
+    }
+    static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) {
+        (void)mayBlock;
+        if (me.v.range > C2Color::RANGE_OTHER) {
+            me.set().range = C2Color::RANGE_OTHER;
+        }
+        if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
+            me.set().primaries = C2Color::PRIMARIES_OTHER;
+        }
+        if (me.v.transfer > C2Color::TRANSFER_OTHER) {
+            me.set().transfer = C2Color::TRANSFER_OTHER;
+        }
+        if (me.v.matrix > C2Color::MATRIX_OTHER) {
+            me.set().matrix = C2Color::MATRIX_OTHER;
+        }
+        return C2R::Ok();
+    }
+
+    static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
+                                  const C2P<C2StreamPictureSizeInfo::output> &size) {
+        (void)mayBlock;
+        (void)size;
+        (void)me;  // TODO: validate
+        return C2R::Ok();
+    }
+    std::shared_ptr<C2StreamColorAspectsTuning::output> getDefaultColorAspects_l() {
+        return mDefaultColorAspects;
+    }
+
+  private:
+    std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
+    std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
+    std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
+    std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
+    std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
+    std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
+    std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
+};
+
+C2SoftAomDec::C2SoftAomDec(const char* name, c2_node_id_t id,
+                           const std::shared_ptr<IntfImpl>& intfImpl)
+    : SimpleC2Component(
+          std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
+      mIntf(intfImpl),
+      mCodecCtx(nullptr){
+
+    GENERATE_FILE_NAMES();
+    CREATE_DUMP_FILE(mInFile);
+    CREATE_DUMP_FILE(mOutFile);
+
+    gettimeofday(&mTimeStart, nullptr);
+    gettimeofday(&mTimeEnd, nullptr);
+}
+
+C2SoftAomDec::~C2SoftAomDec() {
+    onRelease();
+}
+
+c2_status_t C2SoftAomDec::onInit() {
+    status_t err = initDecoder();
+    return err == OK ? C2_OK : C2_CORRUPTED;
+}
+
+c2_status_t C2SoftAomDec::onStop() {
+    mSignalledError = false;
+    mSignalledOutputEos = false;
+    return C2_OK;
+}
+
+void C2SoftAomDec::onReset() {
+    (void)onStop();
+    c2_status_t err = onFlush_sm();
+    if (err != C2_OK) {
+        ALOGW("Failed to flush decoder. Try to hard reset decoder.");
+        destroyDecoder();
+        (void)initDecoder();
+    }
+}
+
+void C2SoftAomDec::onRelease() {
+    destroyDecoder();
+}
+
+c2_status_t C2SoftAomDec::onFlush_sm() {
+    if (aom_codec_decode(mCodecCtx, nullptr, 0, nullptr)) {
+        ALOGE("Failed to flush av1 decoder.");
+        return C2_CORRUPTED;
+    }
+
+    aom_codec_iter_t iter = nullptr;
+    while (aom_codec_get_frame(mCodecCtx, &iter)) {
+    }
+
+    mSignalledError = false;
+    mSignalledOutputEos = false;
+
+    return C2_OK;
+}
+
+static int GetCPUCoreCount() {
+    int cpuCoreCount = 1;
+#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: %d", cpuCoreCount);
+    return cpuCoreCount;
+}
+
+status_t C2SoftAomDec::initDecoder() {
+    mSignalledError = false;
+    mSignalledOutputEos = false;
+    if (!mCodecCtx) {
+        mCodecCtx = new aom_codec_ctx_t;
+    }
+
+    if (!mCodecCtx) {
+        ALOGE("mCodecCtx is null");
+        return NO_MEMORY;
+    }
+
+    aom_codec_dec_cfg_t cfg;
+    memset(&cfg, 0, sizeof(aom_codec_dec_cfg_t));
+    cfg.threads = GetCPUCoreCount();
+    cfg.allow_lowbitdepth = 1;
+
+    aom_codec_flags_t flags;
+    memset(&flags, 0, sizeof(aom_codec_flags_t));
+
+    aom_codec_err_t err;
+    if ((err = aom_codec_dec_init(mCodecCtx, aom_codec_av1_dx(), &cfg, 0))) {
+        ALOGE("av1 decoder failed to initialize. (%d)", err);
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+status_t C2SoftAomDec::destroyDecoder() {
+    if (mCodecCtx) {
+        aom_codec_destroy(mCodecCtx);
+        delete mCodecCtx;
+        mCodecCtx = nullptr;
+    }
+    return OK;
+}
+
+void fillEmptyWork(const std::unique_ptr<C2Work>& work) {
+    uint32_t flags = 0;
+    if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
+        flags |= C2FrameData::FLAG_END_OF_STREAM;
+        ALOGV("signalling eos");
+    }
+    work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
+    work->worklets.front()->output.buffers.clear();
+    work->worklets.front()->output.ordinal = work->input.ordinal;
+    work->workletsProcessed = 1u;
+}
+
+void C2SoftAomDec::finishWork(uint64_t index,
+                              const std::unique_ptr<C2Work>& work,
+                              const std::shared_ptr<C2GraphicBlock>& block) {
+    std::shared_ptr<C2Buffer> buffer =
+        createGraphicBuffer(block, C2Rect(mWidth, mHeight));
+    auto fillWork = [buffer, index](const std::unique_ptr<C2Work>& work) {
+        uint32_t flags = 0;
+        if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
+            (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
+            flags |= C2FrameData::FLAG_END_OF_STREAM;
+            ALOGV("signalling eos");
+        }
+        work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
+        work->worklets.front()->output.buffers.clear();
+        work->worklets.front()->output.buffers.push_back(buffer);
+        work->worklets.front()->output.ordinal = work->input.ordinal;
+        work->workletsProcessed = 1u;
+    };
+    if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
+        fillWork(work);
+    } else {
+        finish(index, fillWork);
+    }
+}
+
+void C2SoftAomDec::process(const std::unique_ptr<C2Work>& work,
+                           const std::shared_ptr<C2BlockPool>& pool) {
+    work->result = C2_OK;
+    work->workletsProcessed = 0u;
+    work->worklets.front()->output.configUpdate.clear();
+    work->worklets.front()->output.flags = work->input.flags;
+    if (mSignalledError || mSignalledOutputEos) {
+        work->result = C2_BAD_VALUE;
+        return;
+    }
+
+    size_t inOffset = 0u;
+    size_t inSize = 0u;
+    C2ReadView rView = mDummyReadView;
+    if (!work->input.buffers.empty()) {
+        rView =
+            work->input.buffers[0]->data().linearBlocks().front().map().get();
+        inSize = rView.capacity();
+        if (inSize && rView.error()) {
+            ALOGE("read view map failed %d", rView.error());
+            work->result = C2_CORRUPTED;
+            return;
+        }
+    }
+
+    bool codecConfig =
+        ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0);
+    bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
+
+    ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
+          inSize, (int)work->input.ordinal.timestamp.peeku(),
+          (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
+
+    if (codecConfig) {
+        fillEmptyWork(work);
+        return;
+    }
+
+    int64_t frameIndex = work->input.ordinal.frameIndex.peekll();
+    if (inSize) {
+        uint8_t* bitstream = const_cast<uint8_t*>(rView.data() + inOffset);
+        int32_t decodeTime = 0;
+        int32_t delay = 0;
+
+        DUMP_TO_FILE(mOutFile, bitstream, inSize);
+        GETTIME(&mTimeStart, nullptr);
+        TIME_DIFF(mTimeEnd, mTimeStart, delay);
+
+        aom_codec_err_t err =
+            aom_codec_decode(mCodecCtx, bitstream, inSize, &frameIndex);
+
+        GETTIME(&mTimeEnd, nullptr);
+        TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
+        ALOGV("decodeTime=%4d delay=%4d\n", decodeTime, delay);
+
+        if (err != AOM_CODEC_OK) {
+            ALOGE("av1 decoder failed to decode frame err: %d", err);
+            work->result = C2_CORRUPTED;
+            work->workletsProcessed = 1u;
+            mSignalledError = true;
+            return;
+        }
+
+    } else {
+        if (aom_codec_decode(mCodecCtx, nullptr, 0, nullptr)) {
+            ALOGE("Failed to flush av1 decoder.");
+            work->result = C2_CORRUPTED;
+            work->workletsProcessed = 1u;
+            mSignalledError = true;
+            return;
+        }
+    }
+
+    (void)outputBuffer(pool, work);
+
+    if (eos) {
+        drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
+        mSignalledOutputEos = true;
+    } else if (!inSize) {
+        fillEmptyWork(work);
+    }
+}
+
+static void copyOutputBufferToYV12Frame(uint8_t *dst,
+        const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
+        size_t srcYStride, size_t srcUStride, size_t srcVStride,
+        uint32_t width, uint32_t height) {
+    size_t dstYStride = align(width, 16);
+    size_t dstUVStride = align(dstYStride / 2, 16);
+    uint8_t* dstStart = dst;
+
+
+    for (size_t i = 0; i < height; ++i) {
+        memcpy(dst, srcY, width);
+        srcY += srcYStride;
+        dst += dstYStride;
+    }
+
+    dst = dstStart + dstYStride * height;
+    for (size_t i = 0; i < height / 2; ++i) {
+         memcpy(dst, srcV, width / 2);
+        srcV += srcVStride;
+        dst += dstUVStride;
+    }
+
+    dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2);
+    for (size_t i = 0; i < height / 2; ++i) {
+         memcpy(dst, srcU, width / 2);
+        srcU += srcUStride;
+        dst += dstUVStride;
+    }
+}
+
+static void convertYUV420Planar16ToY410(uint32_t *dst,
+        const uint16_t *srcY, const uint16_t *srcU, const uint16_t *srcV,
+        size_t srcYStride, size_t srcUStride, size_t srcVStride,
+        size_t dstStride, size_t width, size_t height) {
+
+    // Converting two lines at a time, slightly faster
+    for (size_t y = 0; y < height; y += 2) {
+        uint32_t *dstTop = (uint32_t *) dst;
+        uint32_t *dstBot = (uint32_t *) (dst + dstStride);
+        uint16_t *ySrcTop = (uint16_t*) srcY;
+        uint16_t *ySrcBot = (uint16_t*) (srcY + srcYStride);
+        uint16_t *uSrc = (uint16_t*) srcU;
+        uint16_t *vSrc = (uint16_t*) srcV;
+
+        uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
+        size_t x = 0;
+        for (; x < width - 3; x += 4) {
+
+            u01 = *((uint32_t*)uSrc); uSrc += 2;
+            v01 = *((uint32_t*)vSrc); vSrc += 2;
+
+            y01 = *((uint32_t*)ySrcTop); ySrcTop += 2;
+            y23 = *((uint32_t*)ySrcTop); ySrcTop += 2;
+            y45 = *((uint32_t*)ySrcBot); ySrcBot += 2;
+            y67 = *((uint32_t*)ySrcBot); ySrcBot += 2;
+
+            uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
+            uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
+
+            *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0;
+            *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0;
+            *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1;
+            *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1;
+
+            *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0;
+            *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0;
+            *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1;
+            *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1;
+        }
+
+        // There should be at most 2 more pixels to process. Note that we don't
+        // need to consider odd case as the buffer is always aligned to even.
+        if (x < width) {
+            u01 = *uSrc;
+            v01 = *vSrc;
+            y01 = *((uint32_t*)ySrcTop);
+            y45 = *((uint32_t*)ySrcBot);
+            uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
+            *dstTop++ = ((y01 & 0x3FF) << 10) | uv0;
+            *dstTop++ = ((y01 >> 16) << 10) | uv0;
+            *dstBot++ = ((y45 & 0x3FF) << 10) | uv0;
+            *dstBot++ = ((y45 >> 16) << 10) | uv0;
+        }
+
+        srcY += srcYStride * 2;
+        srcU += srcUStride;
+        srcV += srcVStride;
+        dst += dstStride * 2;
+    }
+
+    return;
+}
+
+static void convertYUV420Planar16ToYUV420Planar(uint8_t *dst,
+        const uint16_t *srcY, const uint16_t *srcU, const uint16_t *srcV,
+        size_t srcYStride, size_t srcUStride, size_t srcVStride,
+        size_t dstStride, size_t width, size_t height) {
+
+    uint8_t *dstY = (uint8_t *)dst;
+    size_t dstYSize = dstStride * height;
+    size_t dstUVStride = align(dstStride / 2, 16);
+    size_t dstUVSize = dstUVStride * height / 2;
+    uint8_t *dstV = dstY + dstYSize;
+    uint8_t *dstU = dstV + dstUVSize;
+
+    for (size_t y = 0; y < height; ++y) {
+        for (size_t x = 0; x < width; ++x) {
+            dstY[x] = (uint8_t)(srcY[x] >> 2);
+        }
+
+        srcY += srcYStride;
+        dstY += dstStride;
+    }
+
+    for (size_t y = 0; y < (height + 1) / 2; ++y) {
+        for (size_t x = 0; x < (width + 1) / 2; ++x) {
+            dstU[x] = (uint8_t)(srcU[x] >> 2);
+            dstV[x] = (uint8_t)(srcV[x] >> 2);
+        }
+
+        srcU += srcUStride;
+        srcV += srcVStride;
+        dstU += dstUVStride;
+        dstV += dstUVStride;
+    }
+    return;
+}
+bool C2SoftAomDec::outputBuffer(
+        const std::shared_ptr<C2BlockPool> &pool,
+        const std::unique_ptr<C2Work> &work)
+{
+    if (!(work && pool)) return false;
+
+    aom_codec_iter_t iter = nullptr;
+    aom_image_t* img = aom_codec_get_frame(mCodecCtx, &iter);
+
+    if (!img) return false;
+
+    if (img->d_w != mWidth || img->d_h != mHeight) {
+        mWidth = img->d_w;
+        mHeight = img->d_h;
+
+        C2VideoSizeStreamInfo::output size(0u, mWidth, mHeight);
+        std::vector<std::unique_ptr<C2SettingResult>> failures;
+        c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
+        if (err == C2_OK) {
+            work->worklets.front()->output.configUpdate.push_back(
+                C2Param::Copy(size));
+        } else {
+            ALOGE("Config update size failed");
+            mSignalledError = true;
+            work->result = C2_CORRUPTED;
+            work->workletsProcessed = 1u;
+            return false;
+        }
+    }
+
+    CHECK(img->fmt == AOM_IMG_FMT_I420 || img->fmt == AOM_IMG_FMT_I42016);
+
+    std::shared_ptr<C2GraphicBlock> block;
+    uint32_t format = HAL_PIXEL_FORMAT_YV12;
+    if (img->fmt == AOM_IMG_FMT_I42016) {
+        IntfImpl::Lock lock = mIntf->lock();
+        std::shared_ptr<C2StreamColorAspectsTuning::output> defaultColorAspects = mIntf->getDefaultColorAspects_l();
+
+        if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
+            defaultColorAspects->matrix == C2Color::MATRIX_BT2020 &&
+            defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) {
+            format = HAL_PIXEL_FORMAT_RGBA_1010102;
+        }
+    }
+    C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
+
+    c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight,
+                                              format, usage, &block);
+
+    if (err != C2_OK) {
+        ALOGE("fetchGraphicBlock for Output failed with status %d", err);
+        work->result = err;
+        return false;
+    }
+
+    C2GraphicView wView = block->map().get();
+
+    if (wView.error()) {
+        ALOGE("graphic view map failed %d", wView.error());
+        work->result = C2_CORRUPTED;
+        return false;
+    }
+
+    ALOGV("provided (%dx%d) required (%dx%d), out frameindex %d",
+          block->width(), block->height(), mWidth, mHeight,
+          (int)*(int64_t*)img->user_priv);
+
+    uint8_t* dst = const_cast<uint8_t*>(wView.data()[C2PlanarLayout::PLANE_Y]);
+    size_t srcYStride = img->stride[AOM_PLANE_Y];
+    size_t srcUStride = img->stride[AOM_PLANE_U];
+    size_t srcVStride = img->stride[AOM_PLANE_V];
+
+    if (img->fmt == AOM_IMG_FMT_I42016) {
+        const uint16_t *srcY = (const uint16_t *)img->planes[AOM_PLANE_Y];
+        const uint16_t *srcU = (const uint16_t *)img->planes[AOM_PLANE_U];
+        const uint16_t *srcV = (const uint16_t *)img->planes[AOM_PLANE_V];
+
+        if (format == HAL_PIXEL_FORMAT_RGBA_1010102) {
+            convertYUV420Planar16ToY410((uint32_t *)dst, srcY, srcU, srcV, srcYStride / 2,
+                                    srcUStride / 2, srcVStride / 2,
+                                    align(mWidth, 16),
+                                    mWidth, mHeight);
+        } else {
+            convertYUV420Planar16ToYUV420Planar(dst, srcY, srcU, srcV, srcYStride / 2,
+                                    srcUStride / 2, srcVStride / 2,
+                                    align(mWidth, 16),
+                                    mWidth, mHeight);
+        }
+    } else {
+        const uint8_t *srcY = (const uint8_t *)img->planes[AOM_PLANE_Y];
+        const uint8_t *srcU = (const uint8_t *)img->planes[AOM_PLANE_U];
+        const uint8_t *srcV = (const uint8_t *)img->planes[AOM_PLANE_V];
+        copyOutputBufferToYV12Frame(dst, srcY, srcU, srcV,
+                                srcYStride, srcUStride, srcVStride, mWidth, mHeight);
+    }
+    finishWork(*(int64_t*)img->user_priv, work, std::move(block));
+    block = nullptr;
+    return true;
+}
+
+c2_status_t C2SoftAomDec::drainInternal(
+    uint32_t drainMode, const std::shared_ptr<C2BlockPool>& pool,
+    const std::unique_ptr<C2Work>& work) {
+    if (drainMode == NO_DRAIN) {
+        ALOGW("drain with NO_DRAIN: no-op");
+        return C2_OK;
+    }
+    if (drainMode == DRAIN_CHAIN) {
+        ALOGW("DRAIN_CHAIN not supported");
+        return C2_OMITTED;
+    }
+
+    if (aom_codec_decode(mCodecCtx, nullptr, 0, nullptr)) {
+        ALOGE("Failed to flush av1 decoder.");
+        return C2_CORRUPTED;
+    }
+
+    while ((outputBuffer(pool, work))) {
+    }
+
+    if (drainMode == DRAIN_COMPONENT_WITH_EOS && work &&
+        work->workletsProcessed == 0u) {
+        fillEmptyWork(work);
+    }
+
+    return C2_OK;
+}
+
+c2_status_t C2SoftAomDec::drain(uint32_t drainMode,
+                                const std::shared_ptr<C2BlockPool>& pool) {
+    return drainInternal(drainMode, pool, nullptr);
+}
+
+class C2SoftAomFactory : public C2ComponentFactory {
+   public:
+    C2SoftAomFactory()
+        : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
+              GetCodec2PlatformComponentStore()->getParamReflector())) {}
+
+    virtual 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 C2SoftAomDec(COMPONENT_NAME, id,
+                             std::make_shared<C2SoftAomDec::IntfImpl>(mHelper)),
+            deleter);
+        return C2_OK;
+    }
+
+    virtual 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<C2SoftAomDec::IntfImpl>(
+                COMPONENT_NAME, id,
+                std::make_shared<C2SoftAomDec::IntfImpl>(mHelper)),
+            deleter);
+        return C2_OK;
+    }
+
+    virtual ~C2SoftAomFactory() override = default;
+
+   private:
+    std::shared_ptr<C2ReflectorHelper> mHelper;
+};
+
+}  // namespace android
+
+extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
+    ALOGV("in %s", __func__);
+    return new ::android::C2SoftAomFactory();
+}
+
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
+    ALOGV("in %s", __func__);
+    delete factory;
+}
diff --git a/media/codec2/components/aom/C2SoftAomDec.h b/media/codec2/components/aom/C2SoftAomDec.h
new file mode 100644
index 0000000..4c82647
--- /dev/null
+++ b/media/codec2/components/aom/C2SoftAomDec.h
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_C2_SOFT_AV1_DEC_H_
+#define ANDROID_C2_SOFT_AV1_DEC_H_
+
+#include <SimpleC2Component.h>
+#include "aom/aom_decoder.h"
+#include "aom/aomdx.h"
+
+#define GETTIME(a, b) gettimeofday(a, b);
+#define TIME_DIFF(start, end, diff)     \
+    diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \
+            ((end).tv_usec - (start).tv_usec);
+
+namespace android {
+
+struct C2SoftAomDec : public SimpleC2Component {
+    class IntfImpl;
+
+    C2SoftAomDec(const char* name, c2_node_id_t id,
+                 const std::shared_ptr<IntfImpl>& intfImpl);
+    virtual ~C2SoftAomDec();
+
+    // From SimpleC2Component
+    c2_status_t onInit() override;
+    c2_status_t onStop() override;
+    void onReset() override;
+    void onRelease() override;
+    c2_status_t onFlush_sm() override;
+    void process(const std::unique_ptr<C2Work>& work,
+                 const std::shared_ptr<C2BlockPool>& pool) override;
+    c2_status_t drain(uint32_t drainMode,
+                      const std::shared_ptr<C2BlockPool>& pool) override;
+
+   private:
+    std::shared_ptr<IntfImpl> mIntf;
+    aom_codec_ctx_t* mCodecCtx;
+
+    uint32_t mWidth;
+    uint32_t mHeight;
+    bool mSignalledOutputEos;
+    bool mSignalledError;
+
+    #ifdef FILE_DUMP_ENABLE
+    char mInFile[200];
+    char mOutFile[200];
+    #endif /* FILE_DUMP_ENABLE */
+
+    struct timeval mTimeStart;   // Time at the start of decode()
+    struct timeval mTimeEnd;     // Time at the end of decode()
+
+    status_t initDecoder();
+    status_t destroyDecoder();
+    void finishWork(uint64_t index, const std::unique_ptr<C2Work>& work,
+                    const std::shared_ptr<C2GraphicBlock>& block);
+    bool outputBuffer(const std::shared_ptr<C2BlockPool>& pool,
+                      const std::unique_ptr<C2Work>& work);
+
+    c2_status_t drainInternal(uint32_t drainMode,
+                              const std::shared_ptr<C2BlockPool>& pool,
+                              const std::unique_ptr<C2Work>& work);
+
+    C2_DO_NOT_COPY(C2SoftAomDec);
+};
+
+#ifdef FILE_DUMP_ENABLE
+
+#define INPUT_DUMP_PATH "/data/local/tmp/temp/av1"
+#define INPUT_DUMP_EXT "webm"
+#define OUTPUT_DUMP_PATH "/data/local/tmp/temp/av1"
+#define OUTPUT_DUMP_EXT "av1"
+#define GENERATE_FILE_NAMES()                                                 \
+    {                                                                         \
+        GETTIME(&mTimeStart, NULL);                                           \
+        strcpy(mInFile, "");                                                  \
+        ALOGD("GENERATE_FILE_NAMES");                                         \
+        sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH, mTimeStart.tv_sec, \
+                mTimeStart.tv_usec, INPUT_DUMP_EXT);                          \
+        strcpy(mOutFile, "");                                                 \
+        sprintf(mOutFile, "%s_%ld.%ld.%s", OUTPUT_DUMP_PATH,                  \
+                mTimeStart.tv_sec, mTimeStart.tv_usec, OUTPUT_DUMP_EXT);      \
+    }
+
+#define CREATE_DUMP_FILE(m_filename)                     \
+    {                                                    \
+        FILE* fp = fopen(m_filename, "wb");              \
+        if (fp != NULL) {                                \
+            ALOGD("Opened file %s", m_filename);         \
+            fclose(fp);                                  \
+        } else {                                         \
+            ALOGD("Could not open file %s", m_filename); \
+        }                                                \
+    }
+#define DUMP_TO_FILE(m_filename, m_buf, m_size)              \
+    {                                                        \
+        FILE* fp = fopen(m_filename, "ab");                  \
+        if (fp != NULL && m_buf != NULL) {                   \
+            int i;                                           \
+            ALOGD("Dump to file!");                          \
+            i = fwrite(m_buf, 1, m_size, fp);                \
+            if (i != (int)m_size) {                          \
+                ALOGD("Error in fwrite, returned %d", i);    \
+                perror("Error in write to file");            \
+            }                                                \
+            fclose(fp);                                      \
+        } else {                                             \
+            ALOGD("Could not write to file %s", m_filename); \
+            if (fp != NULL) fclose(fp);                      \
+        }                                                    \
+    }
+#else /* FILE_DUMP_ENABLE */
+#define INPUT_DUMP_PATH
+#define INPUT_DUMP_EXT
+#define OUTPUT_DUMP_PATH
+#define OUTPUT_DUMP_EXT
+#define GENERATE_FILE_NAMES()
+#define CREATE_DUMP_FILE(m_filename)
+#define DUMP_TO_FILE(m_filename, m_buf, m_size)
+#endif /* FILE_DUMP_ENABLE */
+
+}  // namespace android
+
+#endif  // ANDROID_C2_SOFT_AV1_DEC_H_
diff --git a/media/codec2/components/base/SimpleC2Component.cpp b/media/codec2/components/base/SimpleC2Component.cpp
index 50b4d20..b8baec8 100644
--- a/media/codec2/components/base/SimpleC2Component.cpp
+++ b/media/codec2/components/base/SimpleC2Component.cpp
@@ -132,6 +132,56 @@
     }
 }
 
+class SimpleC2Component::BlockingBlockPool : public C2BlockPool {
+public:
+    BlockingBlockPool(const std::shared_ptr<C2BlockPool>& base): mBase{base} {}
+
+    virtual local_id_t getLocalId() const override {
+        return mBase->getLocalId();
+    }
+
+    virtual C2Allocator::id_t getAllocatorId() const override {
+        return mBase->getAllocatorId();
+    }
+
+    virtual c2_status_t fetchLinearBlock(
+            uint32_t capacity,
+            C2MemoryUsage usage,
+            std::shared_ptr<C2LinearBlock>* block) {
+        c2_status_t status;
+        do {
+            status = mBase->fetchLinearBlock(capacity, usage, block);
+        } while (status == C2_TIMED_OUT);
+        return status;
+    }
+
+    virtual c2_status_t fetchCircularBlock(
+            uint32_t capacity,
+            C2MemoryUsage usage,
+            std::shared_ptr<C2CircularBlock>* block) {
+        c2_status_t status;
+        do {
+            status = mBase->fetchCircularBlock(capacity, usage, block);
+        } while (status == C2_TIMED_OUT);
+        return status;
+    }
+
+    virtual c2_status_t fetchGraphicBlock(
+            uint32_t width, uint32_t height, uint32_t format,
+            C2MemoryUsage usage,
+            std::shared_ptr<C2GraphicBlock>* block) {
+        c2_status_t status;
+        do {
+            status = mBase->fetchGraphicBlock(width, height, format, usage,
+                                              block);
+        } while (status == C2_TIMED_OUT);
+        return status;
+    }
+
+private:
+    std::shared_ptr<C2BlockPool> mBase;
+};
+
 ////////////////////////////////////////////////////////////////////////////////
 
 namespace {
@@ -446,12 +496,16 @@
                 }
             }
 
-            err = GetCodec2BlockPool(poolId, shared_from_this(), &mOutputBlockPool);
+            std::shared_ptr<C2BlockPool> blockPool;
+            err = GetCodec2BlockPool(poolId, shared_from_this(), &blockPool);
             ALOGD("Using output block pool with poolID %llu => got %llu - %d",
                     (unsigned long long)poolId,
                     (unsigned long long)(
-                            mOutputBlockPool ? mOutputBlockPool->getLocalId() : 111000111),
+                            blockPool ? blockPool->getLocalId() : 111000111),
                     err);
+            if (err == C2_OK) {
+                mOutputBlockPool = std::make_shared<BlockingBlockPool>(blockPool);
+            }
             return err;
         }();
         if (err != C2_OK) {
diff --git a/media/codec2/components/base/include/SimpleC2Component.h b/media/codec2/components/base/include/SimpleC2Component.h
index b3a98f4..43029a9 100644
--- a/media/codec2/components/base/include/SimpleC2Component.h
+++ b/media/codec2/components/base/include/SimpleC2Component.h
@@ -234,7 +234,8 @@
     typedef std::unordered_map<uint64_t, std::unique_ptr<C2Work>> PendingWork;
     Mutexed<PendingWork> mPendingWork;
 
-    std::shared_ptr<C2BlockPool> mOutputBlockPool;
+    class BlockingBlockPool;
+    std::shared_ptr<BlockingBlockPool> mOutputBlockPool;
 
     SimpleC2Component() = delete;
 };
diff --git a/media/codec2/components/cmds/Android.bp b/media/codec2/components/cmds/Android.bp
index 6b0977b..35f689e 100644
--- a/media/codec2/components/cmds/Android.bp
+++ b/media/codec2/components/cmds/Android.bp
@@ -15,7 +15,6 @@
         "libcutils",
         "libgui",
         "liblog",
-        "libmediaextractor",
         "libstagefright",
         "libstagefright_foundation",
         "libui",
diff --git a/media/codec2/components/flac/Android.bp b/media/codec2/components/flac/Android.bp
index d485964..e5eb51d 100644
--- a/media/codec2/components/flac/Android.bp
+++ b/media/codec2/components/flac/Android.bp
@@ -23,5 +23,8 @@
 
     srcs: ["C2SoftFlacEnc.cpp"],
 
-    static_libs: ["libFLAC"],
+    static_libs: [
+        "libaudioutils",
+        "libFLAC",
+    ],
 }
diff --git a/media/codec2/components/flac/C2SoftFlacDec.cpp b/media/codec2/components/flac/C2SoftFlacDec.cpp
index f1e2f51..86b16e8 100644
--- a/media/codec2/components/flac/C2SoftFlacDec.cpp
+++ b/media/codec2/components/flac/C2SoftFlacDec.cpp
@@ -83,8 +83,21 @@
                 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
                 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 32768))
                 .build());
+
+        addParameter(
+                DefineParam(mPcmEncodingInfo, C2_PARAMKEY_PCM_ENCODING)
+                .withDefault(new C2StreamPcmEncodingInfo::output(0u, C2Config::PCM_16))
+                .withFields({C2F(mPcmEncodingInfo, value).oneOf({
+                     C2Config::PCM_16,
+                     // C2Config::PCM_8,
+                     C2Config::PCM_FLOAT})
+                })
+                .withSetter((Setter<decltype(*mPcmEncodingInfo)>::StrictValueWithNoDeps))
+                .build());
     }
 
+    int32_t getPcmEncodingInfo() const { return mPcmEncodingInfo->value; }
+
 private:
     std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
     std::shared_ptr<C2StreamFormatConfig::output> mOutputFormat;
@@ -94,6 +107,7 @@
     std::shared_ptr<C2StreamChannelCountInfo::output> mChannelCount;
     std::shared_ptr<C2BitrateTuning::input> mBitrate;
     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
+    std::shared_ptr<C2StreamPcmEncodingInfo::output> mPcmEncodingInfo;
 };
 
 C2SoftFlacDec::C2SoftFlacDec(
@@ -263,11 +277,11 @@
         return;
     }
 
-    size_t outSize;
-    if (mHasStreamInfo)
-        outSize = mStreamInfo.max_blocksize * mStreamInfo.channels * sizeof(short);
-    else
-        outSize = kMaxBlockSize * FLACDecoder::kMaxChannels * sizeof(short);
+    const bool outputFloat = mIntf->getPcmEncodingInfo() == C2Config::PCM_FLOAT;
+    const size_t sampleSize = outputFloat ? sizeof(float) : sizeof(short);
+    size_t outSize = mHasStreamInfo ?
+            mStreamInfo.max_blocksize * mStreamInfo.channels * sampleSize
+          : kMaxBlockSize * FLACDecoder::kMaxChannels * sampleSize;
 
     std::shared_ptr<C2LinearBlock> block;
     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
@@ -284,9 +298,8 @@
         return;
     }
 
-    short *output = reinterpret_cast<short *>(wView.data());
     status_t decoderErr = mFLACDecoder->decodeOneFrame(
-                            input, inSize, output, &outSize);
+                            input, inSize, wView.data(), &outSize, outputFloat);
     if (decoderErr != OK) {
         ALOGE("process: FLACDecoder decodeOneFrame returns error %d", decoderErr);
         mSignalledError = true;
diff --git a/media/codec2/components/flac/C2SoftFlacEnc.cpp b/media/codec2/components/flac/C2SoftFlacEnc.cpp
index e4192c7..4ea35c2 100644
--- a/media/codec2/components/flac/C2SoftFlacEnc.cpp
+++ b/media/codec2/components/flac/C2SoftFlacEnc.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "C2SoftFlacEnc"
 #include <log/log.h>
 
+#include <audio_utils/primitives.h>
 #include <media/stagefright/foundation/MediaDefs.h>
 
 #include <C2PlatformSupport.h>
@@ -72,11 +73,23 @@
                 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
                 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 4608))
                 .build());
+
+        addParameter(
+                DefineParam(mPcmEncodingInfo, C2_PARAMKEY_PCM_ENCODING)
+                .withDefault(new C2StreamPcmEncodingInfo::input(0u, C2Config::PCM_16))
+                .withFields({C2F(mPcmEncodingInfo, value).oneOf({
+                     C2Config::PCM_16,
+                     // C2Config::PCM_8,
+                     C2Config::PCM_FLOAT})
+                })
+                .withSetter((Setter<decltype(*mPcmEncodingInfo)>::StrictValueWithNoDeps))
+                .build());
     }
 
     uint32_t getSampleRate() const { return mSampleRate->value; }
     uint32_t getChannelCount() const { return mChannelCount->value; }
     uint32_t getBitrate() const { return mBitrate->value; }
+    int32_t getPcmEncodingInfo() const { return mPcmEncodingInfo->value; }
 
 private:
     std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
@@ -87,6 +100,7 @@
     std::shared_ptr<C2StreamChannelCountInfo::input> mChannelCount;
     std::shared_ptr<C2BitrateTuning::output> mBitrate;
     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
+    std::shared_ptr<C2StreamPcmEncodingInfo::input> mPcmEncodingInfo;
 };
 constexpr char COMPONENT_NAME[] = "c2.android.flac.encoder";
 
@@ -224,12 +238,15 @@
         mWroteHeader = true;
     }
 
-    uint32_t sampleRate = mIntf->getSampleRate();
-    uint32_t channelCount = mIntf->getChannelCount();
-    uint64_t outTimeStamp = mProcessedSamples * 1000000ll / sampleRate;
+    const uint32_t sampleRate = mIntf->getSampleRate();
+    const uint32_t channelCount = mIntf->getChannelCount();
+    const bool inputFloat = mIntf->getPcmEncodingInfo() == C2Config::PCM_FLOAT;
+    const unsigned sampleSize = inputFloat ? sizeof(float) : sizeof(int16_t);
+    const unsigned frameSize = channelCount * sampleSize;
+    const uint64_t outTimeStamp = mProcessedSamples * 1000000ll / sampleRate;
 
     size_t outCapacity = inSize;
-    outCapacity += mBlockSize * channelCount * sizeof(int16_t);
+    outCapacity += mBlockSize * frameSize;
 
     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
     c2_status_t err = pool->fetchLinearBlock(outCapacity, usage, &mOutputBlock);
@@ -250,14 +267,19 @@
     size_t inPos = 0;
     while (inPos < inSize) {
         const uint8_t *inPtr = rView.data() + inOffset;
-        size_t processSize = MIN(kInBlockSize * channelCount * sizeof(int16_t), (inSize - inPos));
-        const unsigned nbInputFrames = processSize / (channelCount * sizeof(int16_t));
-        const unsigned nbInputSamples = processSize / sizeof(int16_t);
-        const int16_t *pcm16 = reinterpret_cast<const int16_t *>(inPtr + inPos);
-        ALOGV("about to encode %zu bytes", processSize);
+        const size_t processSize = MIN(kInBlockSize * frameSize, (inSize - inPos));
+        const unsigned nbInputFrames = processSize / frameSize;
+        const unsigned nbInputSamples = processSize / sampleSize;
 
-        for (unsigned i = 0; i < nbInputSamples; i++) {
-            mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
+        ALOGV("about to encode %zu bytes", processSize);
+        if (inputFloat) {
+            const float * const pcmFloat = reinterpret_cast<const float *>(inPtr + inPos);
+            memcpy_to_q8_23_from_float_with_clamp(mInputBufferPcm32, pcmFloat, nbInputSamples);
+        } else {
+            const int16_t * const pcm16 = reinterpret_cast<const int16_t *>(inPtr + inPos);
+            for (unsigned i = 0; i < nbInputSamples; i++) {
+                mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
+            }
         }
 
         FLAC__bool ok = FLAC__stream_encoder_process_interleaved(
@@ -342,10 +364,12 @@
         return UNKNOWN_ERROR;
     }
 
+    const bool inputFloat = mIntf->getPcmEncodingInfo() == C2Config::PCM_FLOAT;
+    const int bitsPerSample = inputFloat ? 24 : 16;
     FLAC__bool ok = true;
     ok = ok && FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mIntf->getChannelCount());
     ok = ok && FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, mIntf->getSampleRate());
-    ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, 16);
+    ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, bitsPerSample);
     ok = ok && FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder, mCompressionLevel);
     ok = ok && FLAC__stream_encoder_set_verify(mFlacStreamEncoder, false);
     if (!ok) {
diff --git a/media/codec2/core/include/C2Component.h b/media/codec2/core/include/C2Component.h
index 8810725..ecf8d2e 100644
--- a/media/codec2/core/include/C2Component.h
+++ b/media/codec2/core/include/C2Component.h
@@ -409,12 +409,13 @@
         kind_t kind; ///< component kind
         rank_t rank; ///< component rank
         C2String mediaType; ///< media type supported by the component
+        C2String owner; ///< name of the component store owning this component
 
         /**
          * name alias(es) for backward compatibility.
          * \note Multiple components can have the same alias as long as their media-type differs.
          */
-        std::vector<C2StringLiteral> aliases; ///< name aliases for backward compatibility
+        std::vector<C2String> aliases; ///< name aliases for backward compatibility
     };
 
     // METHODS AVAILABLE WHEN RUNNING
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 27aa064..cf1f6cf 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -392,6 +392,7 @@
     _C2_PL_HEVC_BASE = 0x6000,
     _C2_PL_VP9_BASE  = 0x7000,
     _C2_PL_DV_BASE   = 0x8000,
+    _C2_PL_AV1_BASE  = 0x9000,
 
     C2_PROFILE_LEVEL_VENDOR_START = 0x70000000,
 };
@@ -539,6 +540,11 @@
     PROFILE_DV_HE_07 = _C2_PL_DV_BASE + 7,      ///< Dolby Vision dvhe.07 profile
     PROFILE_DV_HE_08 = _C2_PL_DV_BASE + 8,      ///< Dolby Vision dvhe.08 profile
     PROFILE_DV_AV_09 = _C2_PL_DV_BASE + 9,      ///< Dolby Vision dvav.09 profile
+
+    // AV1 profiles
+    PROFILE_AV1_0 = _C2_PL_AV1_BASE,            ///< AV1 Profile 0 (4:2:0, 8 to 10 bit)
+    PROFILE_AV1_1,                              ///< AV1 Profile 1 (8 to 10 bit)
+    PROFILE_AV1_2,                              ///< AV1 Profile 2 (8 to 12 bit)
 };
 
 enum C2Config::level_t : uint32_t {
@@ -652,6 +658,31 @@
     LEVEL_DV_HIGH_UHD_30,                       ///< Dolby Vision high tier uhd30
     LEVEL_DV_HIGH_UHD_48,                       ///< Dolby Vision high tier uhd48
     LEVEL_DV_HIGH_UHD_60,                       ///< Dolby Vision high tier uhd60
+
+    LEVEL_AV1_2    = _C2_PL_AV1_BASE ,          ///< AV1 Level 2
+    LEVEL_AV1_2_1,                              ///< AV1 Level 2.1
+    LEVEL_AV1_2_2,                              ///< AV1 Level 2.2
+    LEVEL_AV1_2_3,                              ///< AV1 Level 2.3
+    LEVEL_AV1_3,                                ///< AV1 Level 3
+    LEVEL_AV1_3_1,                              ///< AV1 Level 3.1
+    LEVEL_AV1_3_2,                              ///< AV1 Level 3.2
+    LEVEL_AV1_3_3,                              ///< AV1 Level 3.3
+    LEVEL_AV1_4,                                ///< AV1 Level 4
+    LEVEL_AV1_4_1,                              ///< AV1 Level 4.1
+    LEVEL_AV1_4_2,                              ///< AV1 Level 4.2
+    LEVEL_AV1_4_3,                              ///< AV1 Level 4.3
+    LEVEL_AV1_5,                                ///< AV1 Level 5
+    LEVEL_AV1_5_1,                              ///< AV1 Level 5.1
+    LEVEL_AV1_5_2,                              ///< AV1 Level 5.2
+    LEVEL_AV1_5_3,                              ///< AV1 Level 5.3
+    LEVEL_AV1_6,                                ///< AV1 Level 6
+    LEVEL_AV1_6_1,                              ///< AV1 Level 6.1
+    LEVEL_AV1_6_2,                              ///< AV1 Level 6.2
+    LEVEL_AV1_6_3,                              ///< AV1 Level 6.3
+    LEVEL_AV1_7,                                ///< AV1 Level 7
+    LEVEL_AV1_7_1,                              ///< AV1 Level 7.1
+    LEVEL_AV1_7_2,                              ///< AV1 Level 7.2
+    LEVEL_AV1_7_3,                              ///< AV1 Level 7.3
 };
 
 struct C2ProfileLevelStruct {
diff --git a/media/codec2/core/include/C2Param.h b/media/codec2/core/include/C2Param.h
index 40be3b3..efc5c89 100644
--- a/media/codec2/core/include/C2Param.h
+++ b/media/codec2/core/include/C2Param.h
@@ -988,7 +988,10 @@
     /** specialization for easy enums */
     template<typename E>
     inline static NamedValuesType namedValuesFor(const C2EasyEnum<E> &) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnull-dereference"
         return namedValuesFor(*(E*)nullptr);
+#pragma GCC diagnostic pop
     }
 
 private:
@@ -1104,7 +1107,10 @@
 template<typename B>
 struct C2FieldDescriptor::_NamedValuesGetter<B, true> {
     inline static C2FieldDescriptor::NamedValuesType getNamedValues() {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnull-dereference"
         return C2FieldDescriptor::namedValuesFor(*(B*)nullptr);
+#pragma GCC diagnostic pop
     }
 };
 
@@ -1599,11 +1605,13 @@
     /// \internal
     /// \todo: create separate values vs. flags initializer as for flags we want
     /// to list both allowed and required flags
-    template<typename T, typename E=decltype(C2FieldDescriptor::namedValuesFor(*(T*)0))>
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnull-dereference"
+    template<typename T, typename E=decltype(C2FieldDescriptor::namedValuesFor(*(T*)nullptr))>
     C2FieldSupportedValues(bool flags, const T*)
         : type(flags ? FLAGS : VALUES),
           range{(T)0, (T)0, (T)0, (T)0, (T)0} {
-              C2FieldDescriptor::NamedValuesType named = C2FieldDescriptor::namedValuesFor(*(T*)0);
+              C2FieldDescriptor::NamedValuesType named = C2FieldDescriptor::namedValuesFor(*(T*)nullptr);
         if (flags) {
             values.emplace_back(0); // min-mask defaults to 0
         }
@@ -1612,6 +1620,7 @@
         }
     }
 };
+#pragma GCC diagnostic pop
 
 /**
  * Supported values for a specific field.
diff --git a/media/codec2/hidl/1.0/vts/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
index 1e87f38..d4b973f 100644
--- a/media/codec2/hidl/1.0/vts/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
@@ -330,57 +330,72 @@
     }
 }
 
+// number of elementary streams per component
+#define STREAM_COUNT 2
+
 // LookUpTable of clips and metadata for component testing
 void GetURLForComponent(Codec2AudioDecHidlTest::standardComp comp, char* mURL,
-                        char* info) {
+                        char* info, size_t streamIndex = 0) {
     struct CompToURL {
         Codec2AudioDecHidlTest::standardComp comp;
-        const char* mURL;
-        const char* info;
+        const char mURL[STREAM_COUNT][512];
+        const char info[STREAM_COUNT][512];
     };
+    ASSERT_TRUE(streamIndex < STREAM_COUNT);
+
     static const CompToURL kCompToURL[] = {
         {Codec2AudioDecHidlTest::standardComp::xaac,
-         "bbb_aac_stereo_128kbps_48000hz.aac",
-         "bbb_aac_stereo_128kbps_48000hz.info"},
+         {"bbb_aac_stereo_128kbps_48000hz.aac",
+          "bbb_aac_stereo_128kbps_48000hz.aac"},
+         {"bbb_aac_stereo_128kbps_48000hz.info",
+          "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}},
         {Codec2AudioDecHidlTest::standardComp::mp3,
-         "bbb_mp3_stereo_192kbps_48000hz.mp3",
-         "bbb_mp3_stereo_192kbps_48000hz.info"},
+         {"bbb_mp3_stereo_192kbps_48000hz.mp3",
+          "bbb_mp3_stereo_192kbps_48000hz.mp3"},
+         {"bbb_mp3_stereo_192kbps_48000hz.info",
+          "bbb_mp3_stereo_192kbps_48000hz_multi_frame.info"}},
         {Codec2AudioDecHidlTest::standardComp::aac,
-         "bbb_aac_stereo_128kbps_48000hz.aac",
-         "bbb_aac_stereo_128kbps_48000hz.info"},
+         {"bbb_aac_stereo_128kbps_48000hz.aac",
+          "bbb_aac_stereo_128kbps_48000hz.aac"},
+         {"bbb_aac_stereo_128kbps_48000hz.info",
+          "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}},
         {Codec2AudioDecHidlTest::standardComp::amrnb,
-         "sine_amrnb_1ch_12kbps_8000hz.amrnb",
-         "sine_amrnb_1ch_12kbps_8000hz.info"},
+         {"sine_amrnb_1ch_12kbps_8000hz.amrnb",
+          "sine_amrnb_1ch_12kbps_8000hz.amrnb"},
+         {"sine_amrnb_1ch_12kbps_8000hz.info",
+          "sine_amrnb_1ch_12kbps_8000hz_multi_frame.info"}},
         {Codec2AudioDecHidlTest::standardComp::amrwb,
-         "bbb_amrwb_1ch_14kbps_16000hz.amrwb",
-         "bbb_amrwb_1ch_14kbps_16000hz.info"},
+         {"bbb_amrwb_1ch_14kbps_16000hz.amrwb",
+          "bbb_amrwb_1ch_14kbps_16000hz.amrwb"},
+         {"bbb_amrwb_1ch_14kbps_16000hz.info",
+          "bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info"}},
         {Codec2AudioDecHidlTest::standardComp::vorbis,
-         "bbb_vorbis_stereo_128kbps_48000hz.vorbis",
-         "bbb_vorbis_stereo_128kbps_48000hz.info"},
+         {"bbb_vorbis_stereo_128kbps_48000hz.vorbis", ""},
+         {"bbb_vorbis_stereo_128kbps_48000hz.info", ""}},
         {Codec2AudioDecHidlTest::standardComp::opus,
-         "bbb_opus_stereo_128kbps_48000hz.opus",
-         "bbb_opus_stereo_128kbps_48000hz.info"},
+         {"bbb_opus_stereo_128kbps_48000hz.opus", ""},
+         {"bbb_opus_stereo_128kbps_48000hz.info", ""}},
         {Codec2AudioDecHidlTest::standardComp::g711alaw,
-        "bbb_g711alaw_1ch_8khz.raw",
-         "bbb_g711alaw_1ch_8khz.info"},
+         {"bbb_g711alaw_1ch_8khz.raw", ""},
+         {"bbb_g711alaw_1ch_8khz.info", ""}},
         {Codec2AudioDecHidlTest::standardComp::g711mlaw,
-        "bbb_g711mulaw_1ch_8khz.raw",
-         "bbb_g711mulaw_1ch_8khz.info"},
+         {"bbb_g711mulaw_1ch_8khz.raw", ""},
+         {"bbb_g711mulaw_1ch_8khz.info", ""}},
         {Codec2AudioDecHidlTest::standardComp::gsm,
-        "bbb_gsm_1ch_8khz_13kbps.raw",
-         "bbb_gsm_1ch_8khz_13kbps.info"},
+         {"bbb_gsm_1ch_8khz_13kbps.raw", ""},
+         {"bbb_gsm_1ch_8khz_13kbps.info", ""}},
         {Codec2AudioDecHidlTest::standardComp::raw,
-        "bbb_raw_1ch_8khz_s32le.raw",
-         "bbb_raw_1ch_8khz_s32le.info"},
+         {"bbb_raw_1ch_8khz_s32le.raw", ""},
+         {"bbb_raw_1ch_8khz_s32le.info", ""}},
         {Codec2AudioDecHidlTest::standardComp::flac,
-         "bbb_flac_stereo_680kbps_48000hz.flac",
-         "bbb_flac_stereo_680kbps_48000hz.info"},
+         {"bbb_flac_stereo_680kbps_48000hz.flac", ""},
+         {"bbb_flac_stereo_680kbps_48000hz.info", ""}},
     };
 
     for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
         if (kCompToURL[i].comp == comp) {
-            strcat(mURL, kCompToURL[i].mURL);
-            strcat(info, kCompToURL[i].info);
+            strcat(mURL, kCompToURL[i].mURL[streamIndex]);
+            strcat(info, kCompToURL[i].info[streamIndex]);
             return;
         }
     }
@@ -491,10 +506,15 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-TEST_F(Codec2AudioDecHidlTest, DecodeTest) {
+class Codec2AudioDecDecodeTest : public Codec2AudioDecHidlTest,
+                                 public ::testing::WithParamInterface<int32_t> {
+};
+
+TEST_P(Codec2AudioDecDecodeTest, DecodeTest) {
     description("Decodes input file");
     if (mDisableTest) return;
 
+    uint32_t streamIndex = GetParam();
     ASSERT_EQ(mComponent->start(), C2_OK);
     mTimestampDevTest = true;
     char mURL[512], info[512];
@@ -502,7 +522,12 @@
 
     strcpy(mURL, gEnv->getRes().c_str());
     strcpy(info, gEnv->getRes().c_str());
-    GetURLForComponent(mCompName, mURL, info);
+    GetURLForComponent(mCompName, mURL, info, streamIndex);
+    if (!strcmp(mURL, gEnv->getRes().c_str())) {
+        ALOGV("EMPTY INPUT gEnv->getRes().c_str() %s mURL  %s ",
+              gEnv->getRes().c_str(), mURL);
+        return;
+    }
 
     eleInfo.open(info);
     ASSERT_EQ(eleInfo.is_open(), true);
@@ -521,6 +546,9 @@
         Info.push_back({bytesCount, flags, timestamp});
     }
     eleInfo.close();
+    // Reset total no of frames received
+    mFramesReceived = 0;
+    mTimestampUs = 0;
     int32_t bitStreamInfo[2] = {0};
     if (mCompName == raw) {
         bitStreamInfo[0] = 8000;
@@ -577,6 +605,9 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
+INSTANTIATE_TEST_CASE_P(StreamIndexes, Codec2AudioDecDecodeTest,
+                        ::testing::Values(0, 1));
+
 // thumbnail test
 TEST_F(Codec2AudioDecHidlTest, ThumbnailTest) {
     description("Test Request for thumbnail");
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz_multi_frame.info b/media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz_multi_frame.info
new file mode 100644
index 0000000..182af20
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz_multi_frame.info
@@ -0,0 +1,443 @@
+5 32 0
+5 32 0
+337 1 0
+322 1 21333
+279 1 42666
+563 1 64000
+635 1 106666
+634 1 149333
+629 1 192000
+680 1 234666
+688 1 277333
+1036 1 320000
+1040 1 384000
+1009 1 448000
+1020 1 512000
+1357 1 576000
+1353 1 661333
+1351 1 746666
+1351 1 832000
+343 1 917333
+335 1 938666
+339 1 960000
+342 1 981333
+348 1 1002666
+350 1 1024000
+351 1 1045333
+342 1 1066666
+366 1 1088000
+340 1 1109333
+354 1 1130666
+340 1 1152000
+334 1 1173333
+338 1 1194666
+340 1 1216000
+351 1 1237333
+346 1 1258666
+331 1 1280000
+321 1 1301333
+343 1 1322666
+342 1 1344000
+345 1 1365333
+326 1 1386666
+342 1 1408000
+356 1 1429333
+351 1 1450666
+343 1 1472000
+347 1 1493333
+349 1 1514666
+350 1 1536000
+330 1 1557333
+341 1 1578666
+340 1 1600000
+330 1 1621333
+340 1 1642666
+335 1 1664000
+344 1 1685333
+359 1 1706666
+337 1 1728000
+346 1 1749333
+330 1 1770666
+351 1 1792000
+355 1 1813333
+352 1 1834666
+325 1 1856000
+342 1 1877333
+327 1 1898666
+349 1 1920000
+326 1 1941333
+337 1 1962666
+378 1 1984000
+321 1 2005333
+319 1 2026666
+346 1 2048000
+352 1 2069333
+349 1 2090666
+331 1 2112000
+330 1 2133333
+329 1 2154666
+333 1 2176000
+367 1 2197333
+362 1 2218666
+337 1 2240000
+337 1 2261333
+360 1 2282666
+333 1 2304000
+317 1 2325333
+344 1 2346666
+335 1 2368000
+337 1 2389333
+349 1 2410666
+336 1 2432000
+348 1 2453333
+349 1 2474666
+342 1 2496000
+359 1 2517333
+340 1 2538666
+340 1 2560000
+348 1 2581333
+334 1 2602666
+328 1 2624000
+341 1 2645333
+339 1 2666666
+337 1 2688000
+350 1 2709333
+326 1 2730666
+360 1 2752000
+344 1 2773333
+340 1 2794666
+343 1 2816000
+361 1 2837333
+329 1 2858666
+345 1 2880000
+345 1 2901333
+330 1 2922666
+342 1 2944000
+344 1 2965333
+330 1 2986666
+329 1 3008000
+335 1 3029333
+366 1 3050666
+328 1 3072000
+349 1 3093333
+339 1 3114666
+340 1 3136000
+335 1 3157333
+327 1 3178666
+348 1 3200000
+339 1 3221333
+334 1 3242666
+350 1 3264000
+325 1 3285333
+361 1 3306666
+338 1 3328000
+350 1 3349333
+353 1 3370666
+327 1 3392000
+346 1 3413333
+348 1 3434666
+339 1 3456000
+342 1 3477333
+334 1 3498666
+350 1 3520000
+354 1 3541333
+363 1 3562666
+322 1 3584000
+337 1 3605333
+355 1 3626666
+329 1 3648000
+324 1 3669333
+338 1 3690666
+356 1 3712000
+330 1 3733333
+321 1 3754666
+337 1 3776000
+345 1 3797333
+335 1 3818666
+348 1 3840000
+342 1 3861333
+348 1 3882666
+335 1 3904000
+344 1 3925333
+357 1 3946666
+368 1 3968000
+324 1 3989333
+343 1 4010666
+341 1 4032000
+329 1 4053333
+356 1 4074666
+317 1 4096000
+351 1 4117333
+340 1 4138666
+340 1 4160000
+332 1 4181333
+355 1 4202666
+357 1 4224000
+327 1 4245333
+338 1 4266666
+323 1 4288000
+346 1 4309333
+352 1 4330666
+347 1 4352000
+343 1 4373333
+311 1 4394666
+338 1 4416000
+365 1 4437333
+349 1 4458666
+327 1 4480000
+355 1 4501333
+319 1 4522666
+349 1 4544000
+351 1 4565333
+337 1 4586666
+340 1 4608000
+349 1 4629333
+316 1 4650666
+344 1 4672000
+334 1 4693333
+344 1 4714666
+347 1 4736000
+348 1 4757333
+334 1 4778666
+338 1 4800000
+331 1 4821333
+344 1 4842666
+342 1 4864000
+336 1 4885333
+326 1 4906666
+364 1 4928000
+350 1 4949333
+350 1 4970666
+363 1 4992000
+358 1 5013333
+305 1 5034666
+344 1 5056000
+346 1 5077333
+342 1 5098666
+330 1 5120000
+318 1 5141333
+361 1 5162666
+354 1 5184000
+313 1 5205333
+330 1 5226666
+350 1 5248000
+347 1 5269333
+346 1 5290666
+357 1 5312000
+325 1 5333333
+335 1 5354666
+331 1 5376000
+366 1 5397333
+329 1 5418666
+349 1 5440000
+371 1 5461333
+326 1 5482666
+333 1 5504000
+319 1 5525333
+327 1 5546666
+353 1 5568000
+356 1 5589333
+348 1 5610666
+338 1 5632000
+331 1 5653333
+341 1 5674666
+362 1 5696000
+326 1 5717333
+359 1 5738666
+315 1 5760000
+376 1 5781333
+343 1 5802666
+354 1 5824000
+353 1 5845333
+344 1 5866666
+334 1 5888000
+345 1 5909333
+355 1 5930666
+322 1 5952000
+334 1 5973333
+353 1 5994666
+338 1 6016000
+351 1 6037333
+334 1 6058666
+339 1 6080000
+345 1 6101333
+347 1 6122666
+355 1 6144000
+312 1 6165333
+352 1 6186666
+354 1 6208000
+318 1 6229333
+344 1 6250666
+363 1 6272000
+321 1 6293333
+339 1 6314666
+356 1 6336000
+334 1 6357333
+354 1 6378666
+325 1 6400000
+321 1 6421333
+341 1 6442666
+337 1 6464000
+351 1 6485333
+343 1 6506666
+341 1 6528000
+344 1 6549333
+341 1 6570666
+364 1 6592000
+319 1 6613333
+348 1 6634666
+332 1 6656000
+333 1 6677333
+343 1 6698666
+348 1 6720000
+347 1 6741333
+350 1 6762666
+342 1 6784000
+341 1 6805333
+326 1 6826666
+351 1 6848000
+329 1 6869333
+323 1 6890666
+350 1 6912000
+361 1 6933333
+326 1 6954666
+345 1 6976000
+345 1 6997333
+311 1 7018666
+349 1 7040000
+358 1 7061333
+352 1 7082666
+347 1 7104000
+364 1 7125333
+328 1 7146666
+318 1 7168000
+351 1 7189333
+340 1 7210666
+341 1 7232000
+355 1 7253333
+336 1 7274666
+352 1 7296000
+341 1 7317333
+334 1 7338666
+348 1 7360000
+342 1 7381333
+335 1 7402666
+342 1 7424000
+359 1 7445333
+349 1 7466666
+329 1 7488000
+356 1 7509333
+292 1 7530666
+316 1 7552000
+318 1 7573333
+320 1 7594666
+342 1 7616000
+285 1 7637333
+326 1 7658666
+352 1 7680000
+392 1 7701333
+364 1 7722666
+384 1 7744000
+334 1 7765333
+317 1 7786666
+326 1 7808000
+373 1 7829333
+354 1 7850666
+329 1 7872000
+347 1 7893333
+353 1 7914666
+338 1 7936000
+317 1 7957333
+354 1 7978666
+345 1 8000000
+350 1 8021333
+351 1 8042666
+332 1 8064000
+358 1 8085333
+315 1 8106666
+336 1 8128000
+358 1 8149333
+343 1 8170666
+319 1 8192000
+370 1 8213333
+344 1 8234666
+361 1 8256000
+343 1 8277333
+337 1 8298666
+354 1 8320000
+332 1 8341333
+348 1 8362666
+328 1 8384000
+345 1 8405333
+340 1 8426666
+346 1 8448000
+341 1 8469333
+344 1 8490666
+342 1 8512000
+341 1 8533333
+345 1 8554666
+337 1 8576000
+335 1 8597333
+335 1 8618666
+340 1 8640000
+345 1 8661333
+341 1 8682666
+342 1 8704000
+338 1 8725333
+343 1 8746666
+336 1 8768000
+338 1 8789333
+353 1 8810666
+339 1 8832000
+329 1 8853333
+349 1 8874666
+323 1 8896000
+351 1 8917333
+359 1 8938666
+357 1 8960000
+341 1 8981333
+333 1 9002666
+335 1 9024000
+328 1 9045333
+347 1 9066666
+343 1 9088000
+369 1 9109333
+331 1 9130666
+344 1 9152000
+330 1 9173333
+346 1 9194666
+337 1 9216000
+341 1 9237333
+338 1 9258666
+329 1 9280000
+360 1 9301333
+336 1 9322666
+341 1 9344000
+341 1 9365333
+345 1 9386666
+351 1 9408000
+349 1 9429333
+336 1 9450666
+326 1 9472000
+349 1 9493333
+343 1 9514666
+357 1 9536000
+342 1 9557333
+325 1 9578666
+346 1 9600000
+326 1 9621333
+402 1 9642666
+331 1 9664000
+339 1 9685333
+371 1 9706666
+314 1 9728000
+310 1 9749333
+364 1 9770666
+338 1 9792000
+339 1 9813333
+337 1 9834666
+355 1 9856000
+351 1 9877333
+332 1 9898666
+316 1 9920000
+474 1 9941333
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info b/media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info
new file mode 100644
index 0000000..c420009
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info
@@ -0,0 +1,460 @@
+41 1 0
+41 1 20000
+82 1 40000
+82 1 80000
+82 1 120000
+82 1 160000
+82 1 200000
+82 1 240000
+82 1 280000
+82 1 320000
+82 1 360000
+123 1 400000
+123 1 460000
+123 1 520000
+123 1 580000
+123 1 640000
+164 1 700000
+164 1 780000
+164 1 860000
+164 1 940000
+164 1 1020000
+41 1 1100000
+41 1 1120000
+41 1 1140000
+41 1 1160000
+41 1 1180000
+41 1 1200000
+41 1 1220000
+41 1 1240000
+41 1 1260000
+41 1 1280000
+41 1 1300000
+41 1 1320000
+41 1 1340000
+41 1 1360000
+41 1 1380000
+41 1 1400000
+41 1 1420000
+41 1 1440000
+41 1 1460000
+41 1 1480000
+41 1 1500000
+41 1 1520000
+41 1 1540000
+41 1 1560000
+41 1 1580000
+41 1 1600000
+41 1 1620000
+41 1 1640000
+41 1 1660000
+41 1 1680000
+41 1 1700000
+41 1 1720000
+41 1 1740000
+41 1 1760000
+41 1 1780000
+41 1 1800000
+41 1 1820000
+41 1 1840000
+41 1 1860000
+41 1 1880000
+41 1 1900000
+41 1 1920000
+41 1 1940000
+41 1 1960000
+41 1 1980000
+41 1 2000000
+41 1 2020000
+41 1 2040000
+41 1 2060000
+41 1 2080000
+41 1 2100000
+41 1 2120000
+41 1 2140000
+41 1 2160000
+41 1 2180000
+41 1 2200000
+41 1 2220000
+41 1 2240000
+41 1 2260000
+41 1 2280000
+41 1 2300000
+41 1 2320000
+41 1 2340000
+41 1 2360000
+41 1 2380000
+41 1 2400000
+41 1 2420000
+41 1 2440000
+41 1 2460000
+41 1 2480000
+41 1 2500000
+41 1 2520000
+41 1 2540000
+41 1 2560000
+41 1 2580000
+41 1 2600000
+41 1 2620000
+41 1 2640000
+41 1 2660000
+41 1 2680000
+41 1 2700000
+41 1 2720000
+41 1 2740000
+41 1 2760000
+41 1 2780000
+41 1 2800000
+41 1 2820000
+41 1 2840000
+41 1 2860000
+41 1 2880000
+41 1 2900000
+41 1 2920000
+41 1 2940000
+41 1 2960000
+41 1 2980000
+41 1 3000000
+41 1 3020000
+41 1 3040000
+41 1 3060000
+41 1 3080000
+41 1 3100000
+41 1 3120000
+41 1 3140000
+41 1 3160000
+41 1 3180000
+41 1 3200000
+41 1 3220000
+41 1 3240000
+41 1 3260000
+41 1 3280000
+41 1 3300000
+41 1 3320000
+41 1 3340000
+41 1 3360000
+41 1 3380000
+41 1 3400000
+41 1 3420000
+41 1 3440000
+41 1 3460000
+41 1 3480000
+41 1 3500000
+41 1 3520000
+41 1 3540000
+41 1 3560000
+41 1 3580000
+41 1 3600000
+41 1 3620000
+41 1 3640000
+41 1 3660000
+41 1 3680000
+41 1 3700000
+41 1 3720000
+41 1 3740000
+41 1 3760000
+41 1 3780000
+41 1 3800000
+41 1 3820000
+41 1 3840000
+41 1 3860000
+41 1 3880000
+41 1 3900000
+41 1 3920000
+41 1 3940000
+41 1 3960000
+41 1 3980000
+41 1 4000000
+41 1 4020000
+41 1 4040000
+41 1 4060000
+41 1 4080000
+41 1 4100000
+41 1 4120000
+41 1 4140000
+41 1 4160000
+41 1 4180000
+41 1 4200000
+41 1 4220000
+41 1 4240000
+41 1 4260000
+41 1 4280000
+41 1 4300000
+41 1 4320000
+41 1 4340000
+41 1 4360000
+41 1 4380000
+41 1 4400000
+41 1 4420000
+41 1 4440000
+41 1 4460000
+41 1 4480000
+41 1 4500000
+41 1 4520000
+41 1 4540000
+41 1 4560000
+41 1 4580000
+41 1 4600000
+41 1 4620000
+41 1 4640000
+41 1 4660000
+41 1 4680000
+41 1 4700000
+41 1 4720000
+41 1 4740000
+41 1 4760000
+41 1 4780000
+41 1 4800000
+41 1 4820000
+41 1 4840000
+41 1 4860000
+41 1 4880000
+41 1 4900000
+41 1 4920000
+41 1 4940000
+41 1 4960000
+41 1 4980000
+41 1 5000000
+41 1 5020000
+41 1 5040000
+41 1 5060000
+41 1 5080000
+41 1 5100000
+41 1 5120000
+41 1 5140000
+41 1 5160000
+41 1 5180000
+41 1 5200000
+41 1 5220000
+41 1 5240000
+41 1 5260000
+41 1 5280000
+41 1 5300000
+41 1 5320000
+41 1 5340000
+41 1 5360000
+41 1 5380000
+41 1 5400000
+41 1 5420000
+41 1 5440000
+41 1 5460000
+41 1 5480000
+41 1 5500000
+41 1 5520000
+41 1 5540000
+41 1 5560000
+41 1 5580000
+41 1 5600000
+41 1 5620000
+41 1 5640000
+41 1 5660000
+41 1 5680000
+41 1 5700000
+41 1 5720000
+41 1 5740000
+41 1 5760000
+41 1 5780000
+41 1 5800000
+41 1 5820000
+41 1 5840000
+41 1 5860000
+41 1 5880000
+41 1 5900000
+41 1 5920000
+41 1 5940000
+41 1 5960000
+41 1 5980000
+41 1 6000000
+41 1 6020000
+41 1 6040000
+41 1 6060000
+41 1 6080000
+41 1 6100000
+41 1 6120000
+41 1 6140000
+41 1 6160000
+41 1 6180000
+41 1 6200000
+41 1 6220000
+41 1 6240000
+41 1 6260000
+41 1 6280000
+41 1 6300000
+41 1 6320000
+41 1 6340000
+41 1 6360000
+41 1 6380000
+41 1 6400000
+41 1 6420000
+41 1 6440000
+41 1 6460000
+41 1 6480000
+41 1 6500000
+41 1 6520000
+41 1 6540000
+41 1 6560000
+41 1 6580000
+41 1 6600000
+41 1 6620000
+41 1 6640000
+41 1 6660000
+41 1 6680000
+41 1 6700000
+41 1 6720000
+41 1 6740000
+41 1 6760000
+41 1 6780000
+41 1 6800000
+41 1 6820000
+41 1 6840000
+41 1 6860000
+41 1 6880000
+41 1 6900000
+41 1 6920000
+41 1 6940000
+41 1 6960000
+41 1 6980000
+41 1 7000000
+41 1 7020000
+41 1 7040000
+41 1 7060000
+41 1 7080000
+41 1 7100000
+41 1 7120000
+41 1 7140000
+41 1 7160000
+41 1 7180000
+41 1 7200000
+41 1 7220000
+41 1 7240000
+41 1 7260000
+41 1 7280000
+41 1 7300000
+41 1 7320000
+41 1 7340000
+41 1 7360000
+41 1 7380000
+41 1 7400000
+41 1 7420000
+41 1 7440000
+41 1 7460000
+41 1 7480000
+41 1 7500000
+41 1 7520000
+41 1 7540000
+41 1 7560000
+41 1 7580000
+41 1 7600000
+41 1 7620000
+41 1 7640000
+41 1 7660000
+41 1 7680000
+41 1 7700000
+41 1 7720000
+41 1 7740000
+41 1 7760000
+41 1 7780000
+41 1 7800000
+41 1 7820000
+41 1 7840000
+41 1 7860000
+41 1 7880000
+41 1 7900000
+41 1 7920000
+41 1 7940000
+41 1 7960000
+41 1 7980000
+41 1 8000000
+41 1 8020000
+41 1 8040000
+41 1 8060000
+41 1 8080000
+41 1 8100000
+41 1 8120000
+41 1 8140000
+41 1 8160000
+41 1 8180000
+41 1 8200000
+41 1 8220000
+41 1 8240000
+41 1 8260000
+41 1 8280000
+41 1 8300000
+41 1 8320000
+41 1 8340000
+41 1 8360000
+41 1 8380000
+41 1 8400000
+41 1 8420000
+41 1 8440000
+41 1 8460000
+41 1 8480000
+41 1 8500000
+41 1 8520000
+41 1 8540000
+41 1 8560000
+41 1 8580000
+41 1 8600000
+41 1 8620000
+41 1 8640000
+41 1 8660000
+41 1 8680000
+41 1 8700000
+41 1 8720000
+41 1 8740000
+41 1 8760000
+41 1 8780000
+41 1 8800000
+41 1 8820000
+41 1 8840000
+41 1 8860000
+41 1 8880000
+41 1 8900000
+41 1 8920000
+41 1 8940000
+41 1 8960000
+41 1 8980000
+41 1 9000000
+41 1 9020000
+41 1 9040000
+41 1 9060000
+41 1 9080000
+41 1 9100000
+41 1 9120000
+41 1 9140000
+41 1 9160000
+41 1 9180000
+41 1 9200000
+41 1 9220000
+41 1 9240000
+41 1 9260000
+41 1 9280000
+41 1 9300000
+41 1 9320000
+41 1 9340000
+41 1 9360000
+41 1 9380000
+41 1 9400000
+41 1 9420000
+41 1 9440000
+41 1 9460000
+41 1 9480000
+41 1 9500000
+41 1 9520000
+41 1 9540000
+41 1 9560000
+41 1 9580000
+41 1 9600000
+41 1 9620000
+41 1 9640000
+41 1 9660000
+41 1 9680000
+41 1 9700000
+41 1 9720000
+41 1 9740000
+41 1 9760000
+41 1 9780000
+41 1 9800000
+41 1 9820000
+41 1 9840000
+41 1 9860000
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info b/media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info
new file mode 100644
index 0000000..575c75f
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info
@@ -0,0 +1,385 @@
+576 1 0
+576 1 24000
+1152 1 48000
+1152 1 96000
+1152 1 144000
+1152 1 192000
+1728 1 240000
+1728 1 312000
+1728 1 384000
+1728 1 456000
+1728 1 528000
+2304 1 600000
+2304 1 696000
+2304 1 792000
+2304 1 888000
+2304 1 984000
+576 1 1080000
+576 1 1104000
+576 1 1128000
+576 1 1152000
+576 1 1176000
+576 1 1200000
+576 1 1224000
+576 1 1248000
+576 1 1272000
+576 1 1296000
+576 1 1320000
+576 1 1344000
+576 1 1368000
+576 1 1392000
+576 1 1416000
+576 1 1440000
+576 1 1464000
+576 1 1488000
+576 1 1512000
+576 1 1536000
+576 1 1560000
+576 1 1584000
+576 1 1608000
+576 1 1632000
+576 1 1656000
+576 1 1680000
+576 1 1704000
+576 1 1728000
+576 1 1752000
+576 1 1776000
+576 1 1800000
+576 1 1824000
+576 1 1848000
+576 1 1872000
+576 1 1896000
+576 1 1920000
+576 1 1944000
+576 1 1968000
+576 1 1992000
+576 1 2016000
+576 1 2040000
+576 1 2064000
+576 1 2088000
+576 1 2112000
+576 1 2136000
+576 1 2160000
+576 1 2184000
+576 1 2208000
+576 1 2232000
+576 1 2256000
+576 1 2280000
+576 1 2304000
+576 1 2328000
+576 1 2352000
+576 1 2376000
+576 1 2400000
+576 1 2424000
+576 1 2448000
+576 1 2472000
+576 1 2496000
+576 1 2520000
+576 1 2544000
+576 1 2568000
+576 1 2592000
+576 1 2616000
+576 1 2640000
+576 1 2664000
+576 1 2688000
+576 1 2712000
+576 1 2736000
+576 1 2760000
+576 1 2784000
+576 1 2808000
+576 1 2832000
+576 1 2856000
+576 1 2880000
+576 1 2904000
+576 1 2928000
+576 1 2952000
+576 1 2976000
+576 1 3000000
+576 1 3024000
+576 1 3048000
+576 1 3072000
+576 1 3096000
+576 1 3120000
+576 1 3144000
+576 1 3168000
+576 1 3192000
+576 1 3216000
+576 1 3240000
+576 1 3264000
+576 1 3288000
+576 1 3312000
+576 1 3336000
+576 1 3360000
+576 1 3384000
+576 1 3408000
+576 1 3432000
+576 1 3456000
+576 1 3480000
+576 1 3504000
+576 1 3528000
+576 1 3552000
+576 1 3576000
+576 1 3600000
+576 1 3624000
+576 1 3648000
+576 1 3672000
+576 1 3696000
+576 1 3720000
+576 1 3744000
+576 1 3768000
+576 1 3792000
+576 1 3816000
+576 1 3840000
+576 1 3864000
+576 1 3888000
+576 1 3912000
+576 1 3936000
+576 1 3960000
+576 1 3984000
+576 1 4008000
+576 1 4032000
+576 1 4056000
+576 1 4080000
+576 1 4104000
+576 1 4128000
+576 1 4152000
+576 1 4176000
+576 1 4200000
+576 1 4224000
+576 1 4248000
+576 1 4272000
+576 1 4296000
+576 1 4320000
+576 1 4344000
+576 1 4368000
+576 1 4392000
+576 1 4416000
+576 1 4440000
+576 1 4464000
+576 1 4488000
+576 1 4512000
+576 1 4536000
+576 1 4560000
+576 1 4584000
+576 1 4608000
+576 1 4632000
+576 1 4656000
+576 1 4680000
+576 1 4704000
+576 1 4728000
+576 1 4752000
+576 1 4776000
+576 1 4800000
+576 1 4824000
+576 1 4848000
+576 1 4872000
+576 1 4896000
+576 1 4920000
+576 1 4944000
+576 1 4968000
+576 1 4992000
+576 1 5016000
+576 1 5040000
+576 1 5064000
+576 1 5088000
+576 1 5112000
+576 1 5136000
+576 1 5160000
+576 1 5184000
+576 1 5208000
+576 1 5232000
+576 1 5256000
+576 1 5280000
+576 1 5304000
+576 1 5328000
+576 1 5352000
+576 1 5376000
+576 1 5400000
+576 1 5424000
+576 1 5448000
+576 1 5472000
+576 1 5496000
+576 1 5520000
+576 1 5544000
+576 1 5568000
+576 1 5592000
+576 1 5616000
+576 1 5640000
+576 1 5664000
+576 1 5688000
+576 1 5712000
+576 1 5736000
+576 1 5760000
+576 1 5784000
+576 1 5808000
+576 1 5832000
+576 1 5856000
+576 1 5880000
+576 1 5904000
+576 1 5928000
+576 1 5952000
+576 1 5976000
+576 1 6000000
+576 1 6024000
+576 1 6048000
+576 1 6072000
+576 1 6096000
+576 1 6120000
+576 1 6144000
+576 1 6168000
+576 1 6192000
+576 1 6216000
+576 1 6240000
+576 1 6264000
+576 1 6288000
+576 1 6312000
+576 1 6336000
+576 1 6360000
+576 1 6384000
+576 1 6408000
+576 1 6432000
+576 1 6456000
+576 1 6480000
+576 1 6504000
+576 1 6528000
+576 1 6552000
+576 1 6576000
+576 1 6600000
+576 1 6624000
+576 1 6648000
+576 1 6672000
+576 1 6696000
+576 1 6720000
+576 1 6744000
+576 1 6768000
+576 1 6792000
+576 1 6816000
+576 1 6840000
+576 1 6864000
+576 1 6888000
+576 1 6912000
+576 1 6936000
+576 1 6960000
+576 1 6984000
+576 1 7008000
+576 1 7032000
+576 1 7056000
+576 1 7080000
+576 1 7104000
+576 1 7128000
+576 1 7152000
+576 1 7176000
+576 1 7200000
+576 1 7224000
+576 1 7248000
+576 1 7272000
+576 1 7296000
+576 1 7320000
+576 1 7344000
+576 1 7368000
+576 1 7392000
+576 1 7416000
+576 1 7440000
+576 1 7464000
+576 1 7488000
+576 1 7512000
+576 1 7536000
+576 1 7560000
+576 1 7584000
+576 1 7608000
+576 1 7632000
+576 1 7656000
+576 1 7680000
+576 1 7704000
+576 1 7728000
+576 1 7752000
+576 1 7776000
+576 1 7800000
+576 1 7824000
+576 1 7848000
+576 1 7872000
+576 1 7896000
+576 1 7920000
+576 1 7944000
+576 1 7968000
+576 1 7992000
+576 1 8016000
+576 1 8040000
+576 1 8064000
+576 1 8088000
+576 1 8112000
+576 1 8136000
+576 1 8160000
+576 1 8184000
+576 1 8208000
+576 1 8232000
+576 1 8256000
+576 1 8280000
+576 1 8304000
+576 1 8328000
+576 1 8352000
+576 1 8376000
+576 1 8400000
+576 1 8424000
+576 1 8448000
+576 1 8472000
+576 1 8496000
+576 1 8520000
+576 1 8544000
+576 1 8568000
+576 1 8592000
+576 1 8616000
+576 1 8640000
+576 1 8664000
+576 1 8688000
+576 1 8712000
+576 1 8736000
+576 1 8760000
+576 1 8784000
+576 1 8808000
+576 1 8832000
+576 1 8856000
+576 1 8880000
+576 1 8904000
+576 1 8928000
+576 1 8952000
+576 1 8976000
+576 1 9000000
+576 1 9024000
+576 1 9048000
+576 1 9072000
+576 1 9096000
+576 1 9120000
+576 1 9144000
+576 1 9168000
+576 1 9192000
+576 1 9216000
+576 1 9240000
+576 1 9264000
+576 1 9288000
+576 1 9312000
+576 1 9336000
+576 1 9360000
+576 1 9384000
+576 1 9408000
+576 1 9432000
+576 1 9456000
+576 1 9480000
+576 1 9504000
+576 1 9528000
+576 1 9552000
+576 1 9576000
+576 1 9600000
+576 1 9624000
+576 1 9648000
+576 1 9672000
+576 1 9696000
+576 1 9720000
+576 1 9744000
+576 1 9768000
+576 1 9792000
+576 1 9816000
+576 1 9840000
+576 1 9864000
+576 1 9888000
+576 1 9912000
diff --git a/media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info b/media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info
new file mode 100644
index 0000000..0176eaf4
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info
@@ -0,0 +1,807 @@
+32 1 0
+32 1 20000
+64 1 40000
+64 1 80000
+64 1 120000
+96 1 160000
+96 1 220000
+96 1 280000
+96 1 340000
+128 1 400000
+128 1 480000
+128 1 560000
+128 1 640000
+128 1 720000
+32 1 800000
+32 1 820000
+32 1 840000
+32 1 860000
+32 1 880000
+32 1 900000
+32 1 920000
+32 1 940000
+32 1 960000
+32 1 980000
+32 1 1000000
+32 1 1020000
+32 1 1040000
+32 1 1060000
+32 1 1080000
+32 1 1100000
+32 1 1120000
+32 1 1140000
+32 1 1160000
+32 1 1180000
+32 1 1200000
+32 1 1220000
+32 1 1240000
+32 1 1260000
+32 1 1280000
+32 1 1300000
+32 1 1320000
+32 1 1340000
+32 1 1360000
+32 1 1380000
+32 1 1400000
+32 1 1420000
+32 1 1440000
+32 1 1460000
+32 1 1480000
+32 1 1500000
+32 1 1520000
+32 1 1540000
+32 1 1560000
+32 1 1580000
+32 1 1600000
+32 1 1620000
+32 1 1640000
+32 1 1660000
+32 1 1680000
+32 1 1700000
+32 1 1720000
+32 1 1740000
+32 1 1760000
+32 1 1780000
+32 1 1800000
+32 1 1820000
+32 1 1840000
+32 1 1860000
+32 1 1880000
+32 1 1900000
+32 1 1920000
+32 1 1940000
+32 1 1960000
+32 1 1980000
+32 1 2000000
+32 1 2020000
+32 1 2040000
+32 1 2060000
+32 1 2080000
+32 1 2100000
+32 1 2120000
+32 1 2140000
+32 1 2160000
+32 1 2180000
+32 1 2200000
+32 1 2220000
+32 1 2240000
+32 1 2260000
+32 1 2280000
+32 1 2300000
+32 1 2320000
+32 1 2340000
+32 1 2360000
+32 1 2380000
+32 1 2400000
+32 1 2420000
+32 1 2440000
+32 1 2460000
+32 1 2480000
+32 1 2500000
+32 1 2520000
+32 1 2540000
+32 1 2560000
+32 1 2580000
+32 1 2600000
+32 1 2620000
+32 1 2640000
+32 1 2660000
+32 1 2680000
+32 1 2700000
+32 1 2720000
+32 1 2740000
+32 1 2760000
+32 1 2780000
+32 1 2800000
+32 1 2820000
+32 1 2840000
+32 1 2860000
+32 1 2880000
+32 1 2900000
+32 1 2920000
+32 1 2940000
+32 1 2960000
+32 1 2980000
+32 1 3000000
+32 1 3020000
+32 1 3040000
+32 1 3060000
+32 1 3080000
+32 1 3100000
+32 1 3120000
+32 1 3140000
+32 1 3160000
+32 1 3180000
+32 1 3200000
+32 1 3220000
+32 1 3240000
+32 1 3260000
+32 1 3280000
+32 1 3300000
+32 1 3320000
+32 1 3340000
+32 1 3360000
+32 1 3380000
+32 1 3400000
+32 1 3420000
+32 1 3440000
+32 1 3460000
+32 1 3480000
+32 1 3500000
+32 1 3520000
+32 1 3540000
+32 1 3560000
+32 1 3580000
+32 1 3600000
+32 1 3620000
+32 1 3640000
+32 1 3660000
+32 1 3680000
+32 1 3700000
+32 1 3720000
+32 1 3740000
+32 1 3760000
+32 1 3780000
+32 1 3800000
+32 1 3820000
+32 1 3840000
+32 1 3860000
+32 1 3880000
+32 1 3900000
+32 1 3920000
+32 1 3940000
+32 1 3960000
+32 1 3980000
+32 1 4000000
+32 1 4020000
+32 1 4040000
+32 1 4060000
+32 1 4080000
+32 1 4100000
+32 1 4120000
+32 1 4140000
+32 1 4160000
+32 1 4180000
+32 1 4200000
+32 1 4220000
+32 1 4240000
+32 1 4260000
+32 1 4280000
+32 1 4300000
+32 1 4320000
+32 1 4340000
+32 1 4360000
+32 1 4380000
+32 1 4400000
+32 1 4420000
+32 1 4440000
+32 1 4460000
+32 1 4480000
+32 1 4500000
+32 1 4520000
+32 1 4540000
+32 1 4560000
+32 1 4580000
+32 1 4600000
+32 1 4620000
+32 1 4640000
+32 1 4660000
+32 1 4680000
+32 1 4700000
+32 1 4720000
+32 1 4740000
+32 1 4760000
+32 1 4780000
+32 1 4800000
+32 1 4820000
+32 1 4840000
+32 1 4860000
+32 1 4880000
+32 1 4900000
+32 1 4920000
+32 1 4940000
+32 1 4960000
+32 1 4980000
+32 1 5000000
+32 1 5020000
+32 1 5040000
+32 1 5060000
+32 1 5080000
+32 1 5100000
+32 1 5120000
+32 1 5140000
+32 1 5160000
+32 1 5180000
+32 1 5200000
+32 1 5220000
+32 1 5240000
+32 1 5260000
+32 1 5280000
+32 1 5300000
+32 1 5320000
+32 1 5340000
+32 1 5360000
+32 1 5380000
+32 1 5400000
+32 1 5420000
+32 1 5440000
+32 1 5460000
+32 1 5480000
+32 1 5500000
+32 1 5520000
+32 1 5540000
+32 1 5560000
+32 1 5580000
+32 1 5600000
+32 1 5620000
+32 1 5640000
+32 1 5660000
+32 1 5680000
+32 1 5700000
+32 1 5720000
+32 1 5740000
+32 1 5760000
+32 1 5780000
+32 1 5800000
+32 1 5820000
+32 1 5840000
+32 1 5860000
+32 1 5880000
+32 1 5900000
+32 1 5920000
+32 1 5940000
+32 1 5960000
+32 1 5980000
+32 1 6000000
+32 1 6020000
+32 1 6040000
+32 1 6060000
+32 1 6080000
+32 1 6100000
+32 1 6120000
+32 1 6140000
+32 1 6160000
+32 1 6180000
+32 1 6200000
+32 1 6220000
+32 1 6240000
+32 1 6260000
+32 1 6280000
+32 1 6300000
+32 1 6320000
+32 1 6340000
+32 1 6360000
+32 1 6380000
+32 1 6400000
+32 1 6420000
+32 1 6440000
+32 1 6460000
+32 1 6480000
+32 1 6500000
+32 1 6520000
+32 1 6540000
+32 1 6560000
+32 1 6580000
+32 1 6600000
+32 1 6620000
+32 1 6640000
+32 1 6660000
+32 1 6680000
+32 1 6700000
+32 1 6720000
+32 1 6740000
+32 1 6760000
+32 1 6780000
+32 1 6800000
+32 1 6820000
+32 1 6840000
+32 1 6860000
+32 1 6880000
+32 1 6900000
+32 1 6920000
+32 1 6940000
+32 1 6960000
+32 1 6980000
+32 1 7000000
+32 1 7020000
+32 1 7040000
+32 1 7060000
+32 1 7080000
+32 1 7100000
+32 1 7120000
+32 1 7140000
+32 1 7160000
+32 1 7180000
+32 1 7200000
+32 1 7220000
+32 1 7240000
+32 1 7260000
+32 1 7280000
+32 1 7300000
+32 1 7320000
+32 1 7340000
+32 1 7360000
+32 1 7380000
+32 1 7400000
+32 1 7420000
+32 1 7440000
+32 1 7460000
+32 1 7480000
+32 1 7500000
+32 1 7520000
+32 1 7540000
+32 1 7560000
+32 1 7580000
+32 1 7600000
+32 1 7620000
+32 1 7640000
+32 1 7660000
+32 1 7680000
+32 1 7700000
+32 1 7720000
+32 1 7740000
+32 1 7760000
+32 1 7780000
+32 1 7800000
+32 1 7820000
+32 1 7840000
+32 1 7860000
+32 1 7880000
+32 1 7900000
+32 1 7920000
+32 1 7940000
+32 1 7960000
+32 1 7980000
+32 1 8000000
+32 1 8020000
+32 1 8040000
+32 1 8060000
+32 1 8080000
+32 1 8100000
+32 1 8120000
+32 1 8140000
+32 1 8160000
+32 1 8180000
+32 1 8200000
+32 1 8220000
+32 1 8240000
+32 1 8260000
+32 1 8280000
+32 1 8300000
+32 1 8320000
+32 1 8340000
+32 1 8360000
+32 1 8380000
+32 1 8400000
+32 1 8420000
+32 1 8440000
+32 1 8460000
+32 1 8480000
+32 1 8500000
+32 1 8520000
+32 1 8540000
+32 1 8560000
+32 1 8580000
+32 1 8600000
+32 1 8620000
+32 1 8640000
+32 1 8660000
+32 1 8680000
+32 1 8700000
+32 1 8720000
+32 1 8740000
+32 1 8760000
+32 1 8780000
+32 1 8800000
+32 1 8820000
+32 1 8840000
+32 1 8860000
+32 1 8880000
+32 1 8900000
+32 1 8920000
+32 1 8940000
+32 1 8960000
+32 1 8980000
+32 1 9000000
+32 1 9020000
+32 1 9040000
+32 1 9060000
+32 1 9080000
+32 1 9100000
+32 1 9120000
+32 1 9140000
+32 1 9160000
+32 1 9180000
+32 1 9200000
+32 1 9220000
+32 1 9240000
+32 1 9260000
+32 1 9280000
+32 1 9300000
+32 1 9320000
+32 1 9340000
+32 1 9360000
+32 1 9380000
+32 1 9400000
+32 1 9420000
+32 1 9440000
+32 1 9460000
+32 1 9480000
+32 1 9500000
+32 1 9520000
+32 1 9540000
+32 1 9560000
+32 1 9580000
+32 1 9600000
+32 1 9620000
+32 1 9640000
+32 1 9660000
+32 1 9680000
+32 1 9700000
+32 1 9720000
+32 1 9740000
+32 1 9760000
+32 1 9780000
+32 1 9800000
+32 1 9820000
+32 1 9840000
+32 1 9860000
+32 1 9880000
+32 1 9900000
+32 1 9920000
+32 1 9940000
+32 1 9960000
+32 1 9980000
+32 1 10000000
+32 1 10020000
+32 1 10040000
+32 1 10060000
+32 1 10080000
+32 1 10100000
+32 1 10120000
+32 1 10140000
+32 1 10160000
+32 1 10180000
+32 1 10200000
+32 1 10220000
+32 1 10240000
+32 1 10260000
+32 1 10280000
+32 1 10300000
+32 1 10320000
+32 1 10340000
+32 1 10360000
+32 1 10380000
+32 1 10400000
+32 1 10420000
+32 1 10440000
+32 1 10460000
+32 1 10480000
+32 1 10500000
+32 1 10520000
+32 1 10540000
+32 1 10560000
+32 1 10580000
+32 1 10600000
+32 1 10620000
+32 1 10640000
+32 1 10660000
+32 1 10680000
+32 1 10700000
+32 1 10720000
+32 1 10740000
+32 1 10760000
+32 1 10780000
+32 1 10800000
+32 1 10820000
+32 1 10840000
+32 1 10860000
+32 1 10880000
+32 1 10900000
+32 1 10920000
+32 1 10940000
+32 1 10960000
+32 1 10980000
+32 1 11000000
+32 1 11020000
+32 1 11040000
+32 1 11060000
+32 1 11080000
+32 1 11100000
+32 1 11120000
+32 1 11140000
+32 1 11160000
+32 1 11180000
+32 1 11200000
+32 1 11220000
+32 1 11240000
+32 1 11260000
+32 1 11280000
+32 1 11300000
+32 1 11320000
+32 1 11340000
+32 1 11360000
+32 1 11380000
+32 1 11400000
+32 1 11420000
+32 1 11440000
+32 1 11460000
+32 1 11480000
+32 1 11500000
+32 1 11520000
+32 1 11540000
+32 1 11560000
+32 1 11580000
+32 1 11600000
+32 1 11620000
+32 1 11640000
+32 1 11660000
+32 1 11680000
+32 1 11700000
+32 1 11720000
+32 1 11740000
+32 1 11760000
+32 1 11780000
+32 1 11800000
+32 1 11820000
+32 1 11840000
+32 1 11860000
+32 1 11880000
+32 1 11900000
+32 1 11920000
+32 1 11940000
+32 1 11960000
+32 1 11980000
+32 1 12000000
+32 1 12020000
+32 1 12040000
+32 1 12060000
+32 1 12080000
+32 1 12100000
+32 1 12120000
+32 1 12140000
+32 1 12160000
+32 1 12180000
+32 1 12200000
+32 1 12220000
+32 1 12240000
+32 1 12260000
+32 1 12280000
+32 1 12300000
+32 1 12320000
+32 1 12340000
+32 1 12360000
+32 1 12380000
+32 1 12400000
+32 1 12420000
+32 1 12440000
+32 1 12460000
+32 1 12480000
+32 1 12500000
+32 1 12520000
+32 1 12540000
+32 1 12560000
+32 1 12580000
+32 1 12600000
+32 1 12620000
+32 1 12640000
+32 1 12660000
+32 1 12680000
+32 1 12700000
+32 1 12720000
+32 1 12740000
+32 1 12760000
+32 1 12780000
+32 1 12800000
+32 1 12820000
+32 1 12840000
+32 1 12860000
+32 1 12880000
+32 1 12900000
+32 1 12920000
+32 1 12940000
+32 1 12960000
+32 1 12980000
+32 1 13000000
+32 1 13020000
+32 1 13040000
+32 1 13060000
+32 1 13080000
+32 1 13100000
+32 1 13120000
+32 1 13140000
+32 1 13160000
+32 1 13180000
+32 1 13200000
+32 1 13220000
+32 1 13240000
+32 1 13260000
+32 1 13280000
+32 1 13300000
+32 1 13320000
+32 1 13340000
+32 1 13360000
+32 1 13380000
+32 1 13400000
+32 1 13420000
+32 1 13440000
+32 1 13460000
+32 1 13480000
+32 1 13500000
+32 1 13520000
+32 1 13540000
+32 1 13560000
+32 1 13580000
+32 1 13600000
+32 1 13620000
+32 1 13640000
+32 1 13660000
+32 1 13680000
+32 1 13700000
+32 1 13720000
+32 1 13740000
+32 1 13760000
+32 1 13780000
+32 1 13800000
+32 1 13820000
+32 1 13840000
+32 1 13860000
+32 1 13880000
+32 1 13900000
+32 1 13920000
+32 1 13940000
+32 1 13960000
+32 1 13980000
+32 1 14000000
+32 1 14020000
+32 1 14040000
+32 1 14060000
+32 1 14080000
+32 1 14100000
+32 1 14120000
+32 1 14140000
+32 1 14160000
+32 1 14180000
+32 1 14200000
+32 1 14220000
+32 1 14240000
+32 1 14260000
+32 1 14280000
+32 1 14300000
+32 1 14320000
+32 1 14340000
+32 1 14360000
+32 1 14380000
+32 1 14400000
+32 1 14420000
+32 1 14440000
+32 1 14460000
+32 1 14480000
+32 1 14500000
+32 1 14520000
+32 1 14540000
+32 1 14560000
+32 1 14580000
+32 1 14600000
+32 1 14620000
+32 1 14640000
+32 1 14660000
+32 1 14680000
+32 1 14700000
+32 1 14720000
+32 1 14740000
+32 1 14760000
+32 1 14780000
+32 1 14800000
+32 1 14820000
+32 1 14840000
+32 1 14860000
+32 1 14880000
+32 1 14900000
+32 1 14920000
+32 1 14940000
+32 1 14960000
+32 1 14980000
+32 1 15000000
+32 1 15020000
+32 1 15040000
+32 1 15060000
+32 1 15080000
+32 1 15100000
+32 1 15120000
+32 1 15140000
+32 1 15160000
+32 1 15180000
+32 1 15200000
+32 1 15220000
+32 1 15240000
+32 1 15260000
+32 1 15280000
+32 1 15300000
+32 1 15320000
+32 1 15340000
+32 1 15360000
+32 1 15380000
+32 1 15400000
+32 1 15420000
+32 1 15440000
+32 1 15460000
+32 1 15480000
+32 1 15500000
+32 1 15520000
+32 1 15540000
+32 1 15560000
+32 1 15580000
+32 1 15600000
+32 1 15620000
+32 1 15640000
+32 1 15660000
+32 1 15680000
+32 1 15700000
+32 1 15720000
+32 1 15740000
+32 1 15760000
+32 1 15780000
+32 1 15800000
+32 1 15820000
+32 1 15840000
+32 1 15860000
+32 1 15880000
+32 1 15900000
+32 1 15920000
+32 1 15940000
+32 1 15960000
+32 1 15980000
+32 1 16000000
+32 1 16020000
+32 1 16040000
+32 1 16060000
+32 1 16080000
+32 1 16100000
+32 1 16120000
+32 1 16140000
+32 1 16160000
+32 1 16180000
+32 1 16200000
+32 1 16220000
+32 1 16240000
+32 1 16260000
+32 1 16280000
+32 1 16300000
+32 1 16320000
+32 1 16340000
+32 1 16360000
+32 1 16380000
+32 1 16400000
+32 1 16420000
+32 1 16440000
+32 1 16460000
+32 1 16480000
+32 1 16500000
+32 1 16520000
+32 1 16540000
+32 1 16560000
+32 1 16580000
+32 1 16600000
+32 1 16620000
+32 1 16640000
diff --git a/media/codec2/hidl/1.0/vts/video/VtsHidlC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
index 9a42d72..8cbb7a7 100644
--- a/media/codec2/hidl/1.0/vts/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
@@ -421,17 +421,21 @@
     ASSERT_EQ(mDisableTest, false);
 }
 
+class Codec2VideoDecDecodeTest : public Codec2VideoDecHidlTest,
+                                 public ::testing::WithParamInterface<int32_t> {
+};
+
 // Bitstream Test
-TEST_F(Codec2VideoDecHidlTest, DecodeTest) {
+TEST_P(Codec2VideoDecDecodeTest, DecodeTest) {
     description("Decodes input file");
     if (mDisableTest) return;
 
+    uint32_t streamIndex = GetParam();
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
-
     strcpy(mURL, gEnv->getRes().c_str());
     strcpy(info, gEnv->getRes().c_str());
-    GetURLForComponent(mCompName, mURL, info);
+    GetURLForComponent(mCompName, mURL, info, streamIndex);
 
     eleInfo.open(info);
     ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
@@ -452,6 +456,9 @@
     eleInfo.close();
 
     ASSERT_EQ(mComponent->start(), C2_OK);
+    // Reset total no of frames received
+    mFramesReceived = 0;
+    mTimestampUs = 0;
     ALOGV("mURL : %s", mURL);
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
@@ -476,8 +483,11 @@
     }
 
     if (mTimestampDevTest) EXPECT_EQ(mTimestampUslist.empty(), true);
+    ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
+INSTANTIATE_TEST_CASE_P(StreamIndexes, Codec2VideoDecDecodeTest,
+                        ::testing::Values(0, 1));
 
 // Adaptive Test
 TEST_F(Codec2VideoDecHidlTest, AdaptiveDecodeTest) {
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index ff3e534..f5cc9ff 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -557,6 +557,7 @@
                 for (size_t i = 0; i < t.size(); ++i) {
                     c2_status_t status = objcpy(
                             &mTraitsList[i], &mAliasesBuffer[i], t[i]);
+                    mTraitsList[i].owner = mInstanceName;
                     if (status != C2_OK) {
                         ALOGE("listComponents -- corrupted output.");
                         return;
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index f36027e..a8cc62d 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -73,10 +73,10 @@
 constexpr OMX_U32 kMaxIndicesToCheck = 32;
 
 status_t queryOmxCapabilities(
-        const char* name, const char* mime, bool isEncoder,
+        const char* name, const char* mediaType, bool isEncoder,
         MediaCodecInfo::CapabilitiesWriter* caps) {
 
-    const char *role = GetComponentRole(isEncoder, mime);
+    const char *role = GetComponentRole(isEncoder, mediaType);
     if (role == nullptr) {
         return BAD_VALUE;
     }
@@ -128,8 +128,8 @@
         return err;
     }
 
-    bool isVideo = hasPrefix(mime, "video/") == 0;
-    bool isImage = hasPrefix(mime, "image/") == 0;
+    bool isVideo = hasPrefix(mediaType, "video/") == 0;
+    bool isImage = hasPrefix(mediaType, "image/") == 0;
 
     if (isVideo || isImage) {
         OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
@@ -149,7 +149,7 @@
             // AVC components may not list the constrained profiles explicitly, but
             // decoders that support a profile also support its constrained version.
             // Encoders must explicitly support constrained profiles.
-            if (!isEncoder && strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) == 0) {
+            if (!isEncoder && strcasecmp(mediaType, MEDIA_MIMETYPE_VIDEO_AVC) == 0) {
                 if (param.eProfile == OMX_VIDEO_AVCProfileHigh) {
                     caps->addProfileLevel(OMX_VIDEO_AVCProfileConstrainedHigh, param.eLevel);
                 } else if (param.eProfile == OMX_VIDEO_AVCProfileBaseline) {
@@ -193,7 +193,7 @@
                         asString(portFormat.eColorFormat), portFormat.eColorFormat);
             }
         }
-    } else if (strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC) == 0) {
+    } else if (strcasecmp(mediaType, MEDIA_MIMETYPE_AUDIO_AAC) == 0) {
         // More audio codecs if they have profiles.
         OMX_AUDIO_PARAM_ANDROID_PROFILETYPE param;
         InitOMXParams(&param);
@@ -228,14 +228,17 @@
         if (omxNode->configureVideoTunnelMode(
                 kPortIndexOutput, OMX_TRUE, 0, &sidebandHandle) == OK) {
             // tunneled playback includes adaptive playback
-            caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback
-                    | MediaCodecInfo::Capabilities::kFlagSupportsTunneledPlayback);
-        } else if (omxNode->setPortMode(
-                kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer) == OK ||
-                omxNode->prepareForAdaptivePlayback(
-                kPortIndexOutput, OMX_TRUE,
-                1280 /* width */, 720 /* height */) == OK) {
-            caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback);
+        } else {
+            // tunneled playback is not supported
+            caps->removeDetail(MediaCodecInfo::Capabilities::FEATURE_TUNNELED_PLAYBACK);
+            if (omxNode->setPortMode(
+                    kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer) == OK ||
+                    omxNode->prepareForAdaptivePlayback(
+                            kPortIndexOutput, OMX_TRUE,
+                            1280 /* width */, 720 /* height */) != OK) {
+                // adaptive playback is not supported
+                caps->removeDetail(MediaCodecInfo::Capabilities::FEATURE_ADAPTIVE_PLAYBACK);
+            }
         }
     }
 
@@ -243,11 +246,20 @@
         OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE params;
         InitOMXParams(&params);
         params.nPortIndex = kPortIndexOutput;
-        // TODO: should we verify if fallback is supported?
+
+        OMX_VIDEO_PARAM_INTRAREFRESHTYPE fallbackParams;
+        InitOMXParams(&fallbackParams);
+        fallbackParams.nPortIndex = kPortIndexOutput;
+        fallbackParams.eRefreshMode = OMX_VIDEO_IntraRefreshCyclic;
+
         if (omxNode->getConfig(
                 (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh,
-                &params, sizeof(params)) == OK) {
-            caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsIntraRefresh);
+                &params, sizeof(params)) != OK &&
+                omxNode->getParameter(
+                    OMX_IndexParamVideoIntraRefresh, &fallbackParams,
+                    sizeof(fallbackParams)) != OK) {
+            // intra refresh is not supported
+            caps->removeDetail(MediaCodecInfo::Capabilities::FEATURE_INTRA_REFRESH);
         }
     }
 
@@ -270,12 +282,26 @@
                 writer->addMediaCodecInfo();
         info->setName(name.c_str());
         info->setOwner("default");
-        info->setEncoder(encoder);
+        typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
+        if (encoder) {
+            attrs |= MediaCodecInfo::kFlagIsEncoder;
+        }
+        // NOTE: we don't support software-only codecs in OMX
+        if (!hasPrefix(name, "OMX.google.")) {
+            attrs |= MediaCodecInfo::kFlagIsVendor;
+            if (properties.quirkSet.find("attribute::software-codec")
+                    == properties.quirkSet.end()) {
+                attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
+            }
+        }
+        info->setAttributes(attrs);
         info->setRank(omxRank);
-        for (const MediaCodecsXmlParser::Type& type : properties.typeMap) {
-            const std::string &mime = type.first;
+        // OMX components don't have aliases
+        for (const MediaCodecsXmlParser::Type &type : properties.typeMap) {
+            const std::string &mediaType = type.first;
+
             std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
-                    info->addMime(mime.c_str());
+                    info->addMediaType(mediaType.c_str());
             const MediaCodecsXmlParser::AttributeMap &attrMap = type.second;
             for (const MediaCodecsXmlParser::Attribute& attr : attrMap) {
                 const std::string &key = attr.first;
@@ -289,13 +315,13 @@
             }
             status_t err = queryOmxCapabilities(
                     name.c_str(),
-                    mime.c_str(),
+                    mediaType.c_str(),
                     encoder,
                     caps.get());
             if (err != OK) {
-                ALOGE("Failed to query capabilities for %s (mime: %s). Error: %d",
+                ALOGI("Failed to query capabilities for %s (media type: %s). Error: %d",
                         name.c_str(),
-                        mime.c_str(),
+                        mediaType.c_str(),
                         static_cast<int>(err));
             }
         }
@@ -407,20 +433,40 @@
             break;
         }
 
+        ALOGV("canonName = %s", canonName.c_str());
         std::unique_ptr<MediaCodecInfoWriter> codecInfo = writer->addMediaCodecInfo();
         codecInfo->setName(trait.name.c_str());
-        codecInfo->setOwner("codec2");
+        codecInfo->setOwner(("codec2::" + trait.owner).c_str());
+        const MediaCodecsXmlParser::CodecProperties &codec = parser.getCodecMap().at(canonName);
+
         bool encoder = trait.kind == C2Component::KIND_ENCODER;
-        codecInfo->setEncoder(encoder);
+        typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
+
+        if (encoder) {
+            attrs |= MediaCodecInfo::kFlagIsEncoder;
+        }
+        if (trait.owner == "software") {
+            attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
+        } else {
+            attrs |= MediaCodecInfo::kFlagIsVendor;
+            if (trait.owner == "vendor-software") {
+                attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
+            } else if (codec.quirkSet.find("attribute::software-codec") == codec.quirkSet.end()) {
+                attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
+            }
+        }
+        codecInfo->setAttributes(attrs);
         codecInfo->setRank(rank);
-        const MediaCodecsXmlParser::CodecProperties &codec =
-            parser.getCodecMap().at(canonName);
+
+        for (const std::string &alias : codec.aliases) {
+            codecInfo->addAlias(alias.c_str());
+        }
 
         for (auto typeIt = codec.typeMap.begin(); typeIt != codec.typeMap.end(); ++typeIt) {
             const std::string &mediaType = typeIt->first;
             const MediaCodecsXmlParser::AttributeMap &attrMap = typeIt->second;
             std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
-                codecInfo->addMime(mediaType.c_str());
+                codecInfo->addMediaType(mediaType.c_str());
             for (auto attrIt = attrMap.begin(); attrIt != attrMap.end(); ++attrIt) {
                 std::string key, value;
                 std::tie(key, value) = *attrIt;
@@ -450,6 +496,23 @@
                         asString(err), asString(profileQuery[0].status));
                 if (err == C2_OK && profileQuery[0].status == C2_OK) {
                     if (profileQuery[0].values.type == C2FieldSupportedValues::VALUES) {
+                        std::vector<std::shared_ptr<C2ParamDescriptor>> paramDescs;
+                        c2_status_t err1 = intf->querySupportedParams(&paramDescs);
+                        bool isHdr = false, isHdr10Plus = false;
+                        if (err1 == C2_OK) {
+                            for (const std::shared_ptr<C2ParamDescriptor> &desc : paramDescs) {
+                                if ((uint32_t)desc->index() ==
+                                        C2StreamHdr10PlusInfo::output::PARAM_TYPE) {
+                                    isHdr10Plus = true;
+                                } else if ((uint32_t)desc->index() ==
+                                        C2StreamHdrStaticInfo::output::PARAM_TYPE) {
+                                    isHdr = true;
+                                }
+                            }
+                        }
+                        // For VP9, the static info is always propagated by framework.
+                        isHdr |= (mediaType == MIMETYPE_VIDEO_VP9);
+
                         for (C2Value::Primitive profile : profileQuery[0].values.values) {
                             pl.profile = (C2Config::profile_t)profile.ref<uint32_t>();
                             std::vector<std::unique_ptr<C2SettingResult>> failures;
@@ -473,6 +536,26 @@
                                         caps->addProfileLevel(
                                                 (uint32_t)sdkProfile, (uint32_t)sdkLevel);
                                         gotProfileLevels = true;
+                                        if (isHdr) {
+                                            auto hdrMapper = C2Mapper::GetHdrProfileLevelMapper(
+                                                    trait.mediaType);
+                                            if (hdrMapper && hdrMapper->mapProfile(
+                                                    pl.profile, &sdkProfile)) {
+                                                caps->addProfileLevel(
+                                                        (uint32_t)sdkProfile,
+                                                        (uint32_t)sdkLevel);
+                                            }
+                                            if (isHdr10Plus) {
+                                                hdrMapper = C2Mapper::GetHdrProfileLevelMapper(
+                                                        trait.mediaType, true /*isHdr10Plus*/);
+                                                if (hdrMapper && hdrMapper->mapProfile(
+                                                        pl.profile, &sdkProfile)) {
+                                                    caps->addProfileLevel(
+                                                            (uint32_t)sdkProfile,
+                                                            (uint32_t)sdkLevel);
+                                                }
+                                            }
+                                        }
                                     } else if (!mapper) {
                                         caps->addProfileLevel(pl.profile, pl.level);
                                         gotProfileLevels = true;
@@ -517,6 +600,13 @@
                         caps->addProfileLevel(VP9Profile2,    VP9Level5);
                         caps->addProfileLevel(VP9Profile2HDR, VP9Level5);
                     }
+                } else if (mediaType == MIMETYPE_VIDEO_AV1 && !encoder) {
+                    caps->addProfileLevel(AV1Profile0,      AV1Level2);
+                    caps->addProfileLevel(AV1Profile0,      AV1Level21);
+                    caps->addProfileLevel(AV1Profile1,      AV1Level22);
+                    caps->addProfileLevel(AV1Profile1,      AV1Level3);
+                    caps->addProfileLevel(AV1Profile2,      AV1Level31);
+                    caps->addProfileLevel(AV1Profile2,      AV1Level32);
                 } else if (mediaType == MIMETYPE_VIDEO_HEVC && !encoder) {
                     caps->addProfileLevel(HEVCProfileMain,      HEVCMainTierLevel51);
                     caps->addProfileLevel(HEVCProfileMainStill, HEVCMainTierLevel51);
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index 97e17e8..c369e16 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -253,6 +253,14 @@
     { C2Config::PROFILE_HEVC_MAIN_10_INTRA, HEVCProfileMain10 },
 };
 
+ALookup<C2Config::profile_t, int32_t> sHevcHdrProfiles = {
+    { C2Config::PROFILE_HEVC_MAIN_10, HEVCProfileMain10HDR10 },
+};
+
+ALookup<C2Config::profile_t, int32_t> sHevcHdr10PlusProfiles = {
+    { C2Config::PROFILE_HEVC_MAIN_10, HEVCProfileMain10HDR10Plus },
+};
+
 ALookup<C2Config::level_t, int32_t> sMpeg2Levels = {
     { C2Config::LEVEL_MP2V_LOW,         MPEG2LevelLL },
     { C2Config::LEVEL_MP2V_MAIN,        MPEG2LevelML },
@@ -324,8 +332,57 @@
     { C2Config::PROFILE_VP9_1, VP9Profile1 },
     { C2Config::PROFILE_VP9_2, VP9Profile2 },
     { C2Config::PROFILE_VP9_3, VP9Profile3 },
+    { C2Config::PROFILE_VP9_2, VP9Profile2HDR },
+    { C2Config::PROFILE_VP9_3, VP9Profile3HDR },
+    { C2Config::PROFILE_VP9_2, VP9Profile2HDR10Plus },
+    { C2Config::PROFILE_VP9_3, VP9Profile3HDR10Plus },
 };
 
+ALookup<C2Config::profile_t, int32_t> sVp9HdrProfiles = {
+    { C2Config::PROFILE_VP9_2, VP9Profile2HDR },
+    { C2Config::PROFILE_VP9_3, VP9Profile3HDR },
+};
+
+ALookup<C2Config::profile_t, int32_t> sVp9Hdr10PlusProfiles = {
+    { C2Config::PROFILE_VP9_2, VP9Profile2HDR10Plus },
+    { C2Config::PROFILE_VP9_3, VP9Profile3HDR10Plus },
+};
+
+ALookup<C2Config::level_t, int32_t> sAv1Levels = {
+    { C2Config::LEVEL_AV1_2,    AV1Level2  },
+    { C2Config::LEVEL_AV1_2_1,  AV1Level21 },
+    { C2Config::LEVEL_AV1_2_2,  AV1Level22 },
+    { C2Config::LEVEL_AV1_2_3,  AV1Level23 },
+    { C2Config::LEVEL_AV1_3,    AV1Level3  },
+    { C2Config::LEVEL_AV1_3_1,  AV1Level31 },
+    { C2Config::LEVEL_AV1_3_2,  AV1Level32 },
+    { C2Config::LEVEL_AV1_3_3,  AV1Level33 },
+    { C2Config::LEVEL_AV1_4,    AV1Level4  },
+    { C2Config::LEVEL_AV1_4_1,  AV1Level41 },
+    { C2Config::LEVEL_AV1_4_2,  AV1Level42 },
+    { C2Config::LEVEL_AV1_4_3,  AV1Level43 },
+    { C2Config::LEVEL_AV1_5,    AV1Level5  },
+    { C2Config::LEVEL_AV1_5_1,  AV1Level51 },
+    { C2Config::LEVEL_AV1_5_2,  AV1Level52 },
+    { C2Config::LEVEL_AV1_5_3,  AV1Level53 },
+    { C2Config::LEVEL_AV1_6,    AV1Level6  },
+    { C2Config::LEVEL_AV1_6_1,  AV1Level61 },
+    { C2Config::LEVEL_AV1_6_2,  AV1Level62 },
+    { C2Config::LEVEL_AV1_6_3,  AV1Level63 },
+    { C2Config::LEVEL_AV1_7,    AV1Level7  },
+    { C2Config::LEVEL_AV1_7_1,  AV1Level71 },
+    { C2Config::LEVEL_AV1_7_2,  AV1Level72 },
+    { C2Config::LEVEL_AV1_7_3,  AV1Level73 },
+};
+
+
+ALookup<C2Config::profile_t, int32_t> sAv1Profiles = {
+    { C2Config::PROFILE_AV1_0, AV1Profile0 },
+    { C2Config::PROFILE_AV1_1, AV1Profile1 },
+    { C2Config::PROFILE_AV1_2, AV1Profile2 },
+};
+
+
 /**
  * A helper that passes through vendor extension profile and level values.
  */
@@ -426,6 +483,10 @@
 };
 
 struct HevcProfileLevelMapper : ProfileLevelMapperHelper {
+    HevcProfileLevelMapper(bool isHdr = false, bool isHdr10Plus = false) :
+        ProfileLevelMapperHelper(),
+        mIsHdr(isHdr), mIsHdr10Plus(isHdr10Plus) {}
+
     virtual bool simpleMap(C2Config::level_t from, int32_t *to) {
         return sHevcLevels.map(from, to);
     }
@@ -433,11 +494,19 @@
         return sHevcLevels.map(from, to);
     }
     virtual bool simpleMap(C2Config::profile_t from, int32_t *to) {
-        return sHevcProfiles.map(from, to);
+        return mIsHdr10Plus ? sHevcHdr10PlusProfiles.map(from, to) :
+                     mIsHdr ? sHevcHdrProfiles.map(from, to) :
+                              sHevcProfiles.map(from, to);
     }
     virtual bool simpleMap(int32_t from, C2Config::profile_t *to) {
-        return sHevcProfiles.map(from, to);
+        return mIsHdr10Plus ? sHevcHdr10PlusProfiles.map(from, to) :
+                     mIsHdr ? sHevcHdrProfiles.map(from, to) :
+                              sHevcProfiles.map(from, to);
     }
+
+private:
+    bool mIsHdr;
+    bool mIsHdr10Plus;
 };
 
 struct Mpeg2ProfileLevelMapper : ProfileLevelMapperHelper {
@@ -492,6 +561,10 @@
 };
 
 struct Vp9ProfileLevelMapper : ProfileLevelMapperHelper {
+    Vp9ProfileLevelMapper(bool isHdr = false, bool isHdr10Plus = false) :
+        ProfileLevelMapperHelper(),
+        mIsHdr(isHdr), mIsHdr10Plus(isHdr10Plus) {}
+
     virtual bool simpleMap(C2Config::level_t from, int32_t *to) {
         return sVp9Levels.map(from, to);
     }
@@ -499,11 +572,19 @@
         return sVp9Levels.map(from, to);
     }
     virtual bool simpleMap(C2Config::profile_t from, int32_t *to) {
-        return sVp9Profiles.map(from, to);
+        return mIsHdr10Plus ? sVp9Hdr10PlusProfiles.map(from, to) :
+                     mIsHdr ? sVp9HdrProfiles.map(from, to) :
+                              sVp9Profiles.map(from, to);
     }
     virtual bool simpleMap(int32_t from, C2Config::profile_t *to) {
-        return sVp9Profiles.map(from, to);
+        return mIsHdr10Plus ? sVp9Hdr10PlusProfiles.map(from, to) :
+                     mIsHdr ? sVp9HdrProfiles.map(from, to) :
+                              sVp9Profiles.map(from, to);
     }
+
+private:
+    bool mIsHdr;
+    bool mIsHdr10Plus;
 };
 
 } // namespace
@@ -535,6 +616,18 @@
 }
 
 // static
+std::shared_ptr<C2Mapper::ProfileLevelMapper>
+C2Mapper::GetHdrProfileLevelMapper(std::string mediaType, bool isHdr10Plus) {
+    std::transform(mediaType.begin(), mediaType.begin(), mediaType.end(), ::tolower);
+    if (mediaType == MIMETYPE_VIDEO_HEVC) {
+        return std::make_shared<HevcProfileLevelMapper>(true, isHdr10Plus);
+    } else if (mediaType == MIMETYPE_VIDEO_VP9) {
+        return std::make_shared<Vp9ProfileLevelMapper>(true, isHdr10Plus);
+    }
+    return nullptr;
+}
+
+// static
 bool C2Mapper::map(C2Config::bitrate_mode_t from, int32_t *to) {
     return sBitrateModes.map(from, to);
 }
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.h b/media/codec2/sfplugin/utils/Codec2Mapper.h
index 1eeb92e..cec6f07 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.h
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.h
@@ -40,6 +40,9 @@
         static std::shared_ptr<ProfileLevelMapper>
         GetProfileLevelMapper(std::string mediaType);
 
+        static std::shared_ptr<ProfileLevelMapper>
+        GetHdrProfileLevelMapper(std::string mediaType, bool isHdr10Plus = false);
+
         // convert between bitrates
         static bool map(C2Config::bitrate_mode_t, int32_t*);
         static bool map(int32_t, C2Config::bitrate_mode_t*);
diff --git a/media/codec2/vndk/C2Config.cpp b/media/codec2/vndk/C2Config.cpp
index da12903..782bec5 100644
--- a/media/codec2/vndk/C2Config.cpp
+++ b/media/codec2/vndk/C2Config.cpp
@@ -139,6 +139,9 @@
         { "vp9-1", C2Config::PROFILE_VP9_1 },
         { "vp9-2", C2Config::PROFILE_VP9_2 },
         { "vp9-3", C2Config::PROFILE_VP9_3 },
+        { "av1-0", C2Config::PROFILE_AV1_0 },
+        { "av1-1", C2Config::PROFILE_AV1_1 },
+        { "av1-2", C2Config::PROFILE_AV1_2 },
 }))
 
 DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(C2Config::level_t, ({
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index 2d4e19e..a5dd203 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -821,6 +821,7 @@
     emplace("c2.android.vp9.decoder", "libcodec2_soft_vp9dec.so");
     emplace("c2.android.vp8.encoder", "libcodec2_soft_vp8enc.so");
     emplace("c2.android.vp9.encoder", "libcodec2_soft_vp9enc.so");
+    emplace("c2.android.av1.decoder", "libcodec2_soft_av1dec.so");
     emplace("c2.android.raw.decoder", "libcodec2_soft_rawdec.so");
     emplace("c2.android.flac.decoder", "libcodec2_soft_flacdec.so");
     emplace("c2.android.flac.encoder", "libcodec2_soft_flacenc.so");
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index 4e9ac6e..beddad0 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -377,6 +377,10 @@
     return NULL;
 }
 
+static const char *extensions[] = {
+    "aac",
+    NULL
+};
 
 extern "C" {
 // This is the only symbol that needs to be exported
@@ -387,7 +391,7 @@
         UUID("4fd80eae-03d2-4d72-9eb9-48fa6bb54613"),
         1, // version
         "AAC Extractor",
-        { .v2 = Sniff }
+        { .v3 = {Sniff, extensions} },
     };
 }
 
diff --git a/media/extractors/amr/AMRExtractor.cpp b/media/extractors/amr/AMRExtractor.cpp
index 00d2a92..ffeff42 100644
--- a/media/extractors/amr/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -199,7 +199,7 @@
 
     if (mInitCheck == OK) {
         AMediaFormat_setString(meta,
-                AMEDIAFORMAT_KEY_MIME, mIsWide ? "audio/amr-wb" : "audio/amr");
+                AMEDIAFORMAT_KEY_MIME, mIsWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB : "audio/amr");
     }
 
     return AMEDIA_OK;
@@ -280,8 +280,8 @@
     ReadOptions::SeekMode mode;
     if (mOffsetTableLength > 0 && options && options->getSeekTo(&seekTimeUs, &mode)) {
         size_t size;
-        int64_t seekFrame = seekTimeUs / 20000ll;  // 20ms per frame.
-        mCurrentTimeUs = seekFrame * 20000ll;
+        int64_t seekFrame = seekTimeUs / 20000LL;  // 20ms per frame.
+        mCurrentTimeUs = seekFrame * 20000LL;
 
         size_t index = seekFrame < 0 ? 0 : seekFrame / 50;
         if (index >= mOffsetTableLength) {
@@ -358,6 +358,12 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+static const char *extensions[] = {
+    "amr",
+    "awb",
+    NULL
+};
+
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
@@ -368,21 +374,24 @@
         1,
         "AMR Extractor",
         {
-           .v2 = [](
-                    CDataSource *source,
-                    float *confidence,
-                    void **,
-                    FreeMetaFunc *) -> CreatorFunc {
-                DataSourceHelper helper(source);
-                if (SniffAMR(&helper, nullptr, confidence)) {
-                    return [](
-                            CDataSource *source,
-                            void *) -> CMediaExtractor* {
-                        return wrap(new AMRExtractor(new DataSourceHelper(source)));};
-                }
-                return NULL;
-            }
-        }
+           .v3 = {
+               [](
+                   CDataSource *source,
+                   float *confidence,
+                   void **,
+                   FreeMetaFunc *) -> CreatorFunc {
+                   DataSourceHelper helper(source);
+                   if (SniffAMR(&helper, nullptr, confidence)) {
+                       return [](
+                               CDataSource *source,
+                               void *) -> CMediaExtractor* {
+                           return wrap(new AMRExtractor(new DataSourceHelper(source)));};
+                   }
+                   return NULL;
+               },
+               extensions
+           },
+        },
     };
 }
 
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index b5eaf9b..84fbcee 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -806,14 +806,42 @@
 
 bool SniffFLAC(DataSourceHelper *source, float *confidence)
 {
-    // first 4 is the signature word
-    // second 4 is the sizeof STREAMINFO
-    // 042 is the mandatory STREAMINFO
-    // no need to read rest of the header, as a premature EOF will be caught later
-    uint8_t header[4+4];
-    if (source->readAt(0, header, sizeof(header)) != sizeof(header)
-            || memcmp("fLaC\0\0\0\042", header, 4+4))
-    {
+    // Skip ID3 tags
+    off64_t pos = 0;
+    uint8_t header[10];
+    for (;;) {
+        if (source->readAt(pos, header, sizeof(header)) != sizeof(header)) {
+            return false; // no more file to read.
+        }
+
+        // check for ID3 tag
+        if (memcmp("ID3", header, 3) != 0) {
+            break; // not an ID3 tag.
+        }
+
+        // skip the ID3v2 data and check again
+        const unsigned id3Len = 10 +
+                (((header[6] & 0x7f) << 21)
+                 | ((header[7] & 0x7f) << 14)
+                 | ((header[8] & 0x7f) << 7)
+                 | (header[9] & 0x7f));
+        pos += id3Len;
+
+        ALOGV("skipped ID3 tag of len %u new starting offset is %#016llx",
+                id3Len, (long long)pos);
+    }
+
+    // Check FLAC header.
+    // https://xiph.org/flac/format.html#stream
+    //
+    // Note: content stored big endian.
+    // byte offset  bit size  content
+    // 0            32        fLaC
+    // 4            8         metadata type STREAMINFO (0) (note: OR with 0x80 if last metadata)
+    // 5            24        size of metadata, for STREAMINFO (0x22).
+
+    if (memcmp("fLaC\x00\x00\x00\x22", header, 8) != 0 &&
+        memcmp("fLaC\x80\x00\x00\x22", header, 8) != 0) {
         return false;
     }
 
@@ -822,6 +850,11 @@
     return true;
 }
 
+static const char *extensions[] = {
+    "flac",
+    "fl",
+    NULL
+};
 
 extern "C" {
 // This is the only symbol that needs to be exported
@@ -833,21 +866,24 @@
             1,
             "FLAC Extractor",
             {
-                .v2 = [](
+                .v3 = {
+                    [](
                         CDataSource *source,
                         float *confidence,
                         void **,
                         FreeMetaFunc *) -> CreatorFunc {
-                    DataSourceHelper helper(source);
-                    if (SniffFLAC(&helper, confidence)) {
-                        return [](
-                                CDataSource *source,
-                                void *) -> CMediaExtractor* {
-                            return wrap(new FLACExtractor(new DataSourceHelper(source)));};
-                    }
-                    return NULL;
+                        DataSourceHelper helper(source);
+                        if (SniffFLAC(&helper, confidence)) {
+                            return [](
+                                    CDataSource *source,
+                                    void *) -> CMediaExtractor* {
+                                return wrap(new FLACExtractor(new DataSourceHelper(source)));};
+                        }
+                        return NULL;
+                    },
+                    extensions
                 }
-            }
+            },
      };
 }
 
diff --git a/media/extractors/midi/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
index 0c74376..9f4f9e6 100644
--- a/media/extractors/midi/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -326,6 +326,18 @@
 
 }
 
+static const char *extensions[] = {
+    "imy",
+    "mid",
+    "midi",
+    "mxmf",
+    "ota",
+    "rtttl",
+    "rtx",
+    "smf",
+    "xmf",
+    NULL
+};
 
 extern "C" {
 // This is the only symbol that needs to be exported
@@ -337,20 +349,23 @@
         1,
         "MIDI Extractor",
         {
-            .v2 = [](
+            .v3 = {
+                [](
                 CDataSource *source,
                 float *confidence,
                 void **,
                 FreeMetaFunc *) -> CreatorFunc {
-                if (SniffMidi(source, confidence)) {
-                    return [](
-                            CDataSource *source,
-                            void *) -> CMediaExtractor* {
-                        return wrap(new MidiExtractor(source));};
-                }
-                return NULL;
+                    if (SniffMidi(source, confidence)) {
+                        return [](
+                                CDataSource *source,
+                                void *) -> CMediaExtractor* {
+                            return wrap(new MidiExtractor(source));};
+                    }
+                    return NULL;
+                },
+                extensions
             }
-        }
+        },
     };
 }
 
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 42a9c42..4200a46 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -1463,6 +1463,8 @@
                       AMediaFormat_setBuffer(meta,
                              AMEDIAFORMAT_KEY_CSD_0, codecPrivate, codecPrivateSize);
                     }
+                } else if (!strcmp("V_AV1", codecID)) {
+                    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AV1);
                 } else {
                     ALOGW("%s is not supported.", codecID);
                     continue;
@@ -1667,6 +1669,12 @@
     return true;
 }
 
+static const char *extensions[] = {
+    "mka",
+    "mkv",
+    "webm",
+    NULL
+};
 
 extern "C" {
 // This is the only symbol that needs to be exported
@@ -1678,19 +1686,22 @@
         1,
         "Matroska Extractor",
         {
-            .v2 = [](
+            .v3 = {
+                [](
                     CDataSource *source,
                     float *confidence,
                     void **,
                     FreeMetaFunc *) -> CreatorFunc {
-                DataSourceHelper helper(source);
-                if (SniffMatroska(&helper, confidence)) {
-                    return [](
-                            CDataSource *source,
-                            void *) -> CMediaExtractor* {
-                        return wrap(new MatroskaExtractor(new DataSourceHelper(source)));};
-                }
-                return NULL;
+                    DataSourceHelper helper(source);
+                    if (SniffMatroska(&helper, confidence)) {
+                        return [](
+                                CDataSource *source,
+                                void *) -> CMediaExtractor* {
+                            return wrap(new MatroskaExtractor(new DataSourceHelper(source)));};
+                    }
+                    return NULL;
+                },
+                extensions
             }
         }
     };
diff --git a/media/extractors/mp3/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
index 20bcda8..61838f6 100644
--- a/media/extractors/mp3/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -609,7 +609,7 @@
     if (mInitCheck != OK) {
         return AMEDIA_ERROR_UNKNOWN;
     }
-    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, "audio/mpeg");
+    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG);
 
     DataSourceHelper helper(mDataSource);
     ID3 id3(&helper);
@@ -707,6 +707,14 @@
     return CreateExtractor;
 }
 
+static const char *extensions[] = {
+    "mp3",
+    "mpeg",
+    "mpg",
+    "mpga",
+    NULL
+};
+
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
@@ -716,7 +724,7 @@
         UUID("812a3f6c-c8cf-46de-b529-3774b14103d4"),
         1, // version
         "MP3 Extractor",
-        { .v2 = Sniff }
+        { .v3 = {Sniff, extensions} }
     };
 }
 
diff --git a/media/extractors/mp3/VBRISeeker.cpp b/media/extractors/mp3/VBRISeeker.cpp
index 9eb72a7..ca51b88 100644
--- a/media/extractors/mp3/VBRISeeker.cpp
+++ b/media/extractors/mp3/VBRISeeker.cpp
@@ -71,7 +71,7 @@
     size_t numFrames = U32_AT(&vbriHeader[14]);
 
     int64_t durationUs =
-        numFrames * 1000000ll * (sampleRate >= 32000 ? 1152 : 576) / sampleRate;
+        numFrames * 1000000LL * (sampleRate >= 32000 ? 1152 : 576) / sampleRate;
 
     ALOGV("duration = %.2f secs", durationUs / 1E6);
 
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 253f400..cc1534a 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -343,6 +343,8 @@
         case FOURCC('a', 'l', 'a', 'c'):
             return MEDIA_MIMETYPE_AUDIO_ALAC;
 
+        case FOURCC('a', 'v', '0', '1'):
+            return MEDIA_MIMETYPE_VIDEO_AV1;
         default:
             ALOGW("Unknown fourcc: %c%c%c%c",
                    (fourcc >> 24) & 0xff,
@@ -983,6 +985,22 @@
             off64_t stop_offset = *offset + chunk_size;
             *offset = data_offset;
             while (*offset < stop_offset) {
+
+                // pass udata terminate
+                if (mIsQT && stop_offset - *offset == 4 && chunk_type == FOURCC("udta")) {
+                    // handle the case that udta terminates with terminate code x00000000
+                    // note that 0 terminator is optional and we just handle this case.
+                    uint32_t terminate_code = 1;
+                    mDataSource->readAt(*offset, &terminate_code, 4);
+                    if (0 == terminate_code) {
+                        *offset += 4;
+                        ALOGD("Terminal code for udta");
+                        continue;
+                    } else {
+                        ALOGW("invalid udta Terminal code");
+                    }
+                }
+
                 status_t err = parseChunk(offset, depth + 1);
                 if (err != OK) {
                     if (isTrack) {
@@ -1754,6 +1772,7 @@
         case FOURCC('a', 'v', 'c', '1'):
         case FOURCC('h', 'v', 'c', '1'):
         case FOURCC('h', 'e', 'v', '1'):
+        case FOURCC('a', 'v', '0', '1'):
         {
             uint8_t buffer[78];
             if (chunk_data_size < (ssize_t)sizeof(buffer)) {
@@ -5139,7 +5158,7 @@
         sampleCtsOffset = 0;
     }
 
-    if (size < (off64_t)(sampleCount * bytesPerSample)) {
+    if (size < (off64_t)sampleCount * bytesPerSample) {
         return -EINVAL;
     }
 
@@ -6017,6 +6036,7 @@
         FOURCC('a', 'v', 'c', '1'),
         FOURCC('h', 'v', 'c', '1'),
         FOURCC('h', 'e', 'v', '1'),
+        FOURCC('a', 'v', '0', '1'),
         FOURCC('3', 'g', 'p', '4'),
         FOURCC('m', 'p', '4', '1'),
         FOURCC('m', 'p', '4', '2'),
@@ -6179,6 +6199,19 @@
     return NULL;
 }
 
+static const char *extensions[] = {
+    "3g2",
+    "3gp",
+    "3gpp",
+    "3gpp2",
+    "m4a",
+    "m4r",
+    "m4v",
+    "mov",
+    "mp4",
+    NULL
+};
+
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
@@ -6188,7 +6221,7 @@
         UUID("27575c67-4417-4c54-8d3d-8e626985a164"),
         2, // version
         "MP4 Extractor",
-        { .v2 = Sniff }
+        { .v3 = {Sniff, extensions} },
     };
 }
 
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index b816093..2a94671 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -28,9 +28,8 @@
 
     static_libs: [
         "libcrypto",
-        "libstagefright_foundation",
+        "libstagefright_foundation_without_imemory",
         "libstagefright_mpeg2support",
-        "libmediaextractor",
         "libutils",
         "libstagefright",
         "libstagefright_esds",
diff --git a/media/extractors/mpeg2/ExtractorBundle.cpp b/media/extractors/mpeg2/ExtractorBundle.cpp
index 2f4196c..946a2a9 100644
--- a/media/extractors/mpeg2/ExtractorBundle.cpp
+++ b/media/extractors/mpeg2/ExtractorBundle.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include <media/MediaExtractorPluginHelper.h>
+#include <media/stagefright/MediaDefs.h>
 #include "MPEG2PSExtractor.h"
 #include "MPEG2TSExtractor.h"
 
@@ -26,6 +27,12 @@
 
 struct CDataSource;
 
+static const char *extensions[] = {
+   "m2p",
+   "ts",
+   NULL
+};
+
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
@@ -36,26 +43,29 @@
         1,
         "MPEG2-PS/TS Extractor",
         {
-            .v2 = [](
+            .v3 = {
+                [](
                     CDataSource *source,
                     float *confidence,
                     void **,
                     FreeMetaFunc *) -> CreatorFunc {
-                DataSourceHelper helper(source);
-                if (SniffMPEG2TS(&helper, confidence)) {
-                    return [](
-                            CDataSource *source,
-                            void *) -> CMediaExtractor* {
-                        return wrap(new MPEG2TSExtractor(new DataSourceHelper(source)));};
-                } else if (SniffMPEG2PS(&helper, confidence)) {
-                            return [](
-                                    CDataSource *source,
-                                    void *) -> CMediaExtractor* {
-                                return wrap(new MPEG2PSExtractor(new DataSourceHelper(source)));};
-                }
-                return NULL;
+                    DataSourceHelper helper(source);
+                    if (SniffMPEG2TS(&helper, confidence)) {
+                        return [](
+                                CDataSource *source,
+                                void *) -> CMediaExtractor* {
+                            return wrap(new MPEG2TSExtractor(new DataSourceHelper(source)));};
+                    } else if (SniffMPEG2PS(&helper, confidence)) {
+                        return [](
+                                CDataSource *source,
+                                void *) -> CMediaExtractor* {
+                            return wrap(new MPEG2PSExtractor(new DataSourceHelper(source)));};
+                    }
+                    return NULL;
+                },
+                extensions
             }
-        }
+        },
     };
 }
 
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
index 554d252..731584d 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -734,6 +734,9 @@
     if (inMeta.findData(kKeySEI, &bufType, &bufData, &bufSize)) {
         AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_SEI, bufData, bufSize);
     }
+    if (inMeta.findData(kKeyAudioPresentationInfo, &bufType, &bufData, &bufSize)) {
+        AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_AUDIO_PRESENTATION_INFO, bufData, bufSize);
+    }
     mbuf->release();
     return AMEDIA_OK;
 }
@@ -790,6 +793,7 @@
 }
 
 media_status_t MPEG2PSExtractor::WrappedTrack::start() {
+    mTrack->mBufferGroup = mBufferGroup;
     return mTrack->start();
 }
 
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
index 3bb2af7..e1509ee 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -224,6 +224,9 @@
     if (inMeta.findData(kKeySEI, &bufType, &bufData, &bufSize)) {
         AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_SEI, bufData, bufSize);
     }
+    if (inMeta.findData(kKeyAudioPresentationInfo, &bufType, &bufData, &bufSize)) {
+        AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_AUDIO_PRESENTATION_INFO, bufData, bufSize);
+    }
     mbuf->release();
     return AMEDIA_OK;
 }
@@ -373,7 +376,7 @@
         }
 
         // Wait only for 2 seconds to detect audio/video streams.
-        if (ALooper::GetNowUs() - startTime > 2000000ll) {
+        if (ALooper::GetNowUs() - startTime > 2000000LL) {
             break;
         }
     }
@@ -385,7 +388,7 @@
         List<int64_t> durations;
         // Estimate duration --- stabilize until you get <500ms deviation.
         while (feedMore() == OK
-                && ALooper::GetNowUs() - startTime <= 2000000ll) {
+                && ALooper::GetNowUs() - startTime <= 2000000LL) {
             if (mSeekSyncPoints->size() > prevSyncSize) {
                 prevSyncSize = mSeekSyncPoints->size();
                 int64_t diffUs = mSeekSyncPoints->keyAt(prevSyncSize - 1)
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index c3914f1..596c1c8 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -515,10 +515,10 @@
         ALOGV("failed to read %zu bytes at offset %#016llx, got %zd bytes",
                 sizeof(header), (long long)offset, n);
 
-        if (n < 0) {
-            return n;
-        } else if (n == 0) {
+        if (n == 0 || n == ERROR_END_OF_STREAM) {
             return AMEDIA_ERROR_END_OF_STREAM;
+        } else if (n < 0) {
+            return AMEDIA_ERROR_UNKNOWN;
         } else {
             return AMEDIA_ERROR_IO;
         }
@@ -872,7 +872,7 @@
 
             ALOGV("readPage returned %zd", n);
 
-            return n < 0 ? (media_status_t) n : AMEDIA_ERROR_END_OF_STREAM;
+            return (media_status_t) n;
         }
 
         // Prevent a harmless unsigned integer overflow by clamping to 0
@@ -1379,6 +1379,12 @@
     return CreateExtractor;
 }
 
+static const char *extensions[] = {
+    "oga",
+    "ogg",
+    NULL
+};
+
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
@@ -1388,7 +1394,7 @@
         UUID("8cc5cd06-f772-495e-8a62-cba9649374e9"),
         1, // version
         "Ogg Extractor",
-        { .v2 = Sniff }
+        { .v3 = {Sniff, extensions} },
     };
 }
 
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index 6f9f689..e58bd1f 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -616,6 +616,11 @@
     return CreateExtractor;
 }
 
+static const char *extensions[] = {
+    "wav",
+    NULL
+};
+
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
@@ -625,7 +630,7 @@
         UUID("7d613858-5837-4a38-84c5-332d1cddee27"),
         1, // version
         "WAV Extractor",
-        { .v2 = Sniff }
+        { .v3 = {Sniff, extensions} },
     };
 }
 
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 1493b26..8e36c77 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -373,6 +373,13 @@
      * so the recorded volume may be very low.
      */
     AAUDIO_INPUT_PRESET_UNPROCESSED = 9,
+
+    /**
+     * Use this preset for capturing audio meant to be processed in real time
+     * and played back for live performance (e.g karaoke).
+     * The capture path will minimize latency and coupling with playback path.
+     */
+    AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE = 10,
 };
 typedef int32_t aaudio_input_preset_t;
 
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index bd42697..88da53a 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -158,6 +158,7 @@
         case AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION:
         case AAUDIO_INPUT_PRESET_VOICE_RECOGNITION:
         case AAUDIO_INPUT_PRESET_UNPROCESSED:
+        case AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE:
             break; // valid
         default:
             ALOGE("input preset not valid = %d", mInputPreset);
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 40e22ac..f550089 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -486,6 +486,9 @@
                                                int64_t *framePosition,
                                                int64_t *timeNanoseconds) {
     ExtendedTimestamp extendedTimestamp;
+    if (getState() != AAUDIO_STREAM_STATE_STARTED) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
     status_t status = mAudioRecord->getTimestamp(&extendedTimestamp);
     if (status == WOULD_BLOCK) {
         return AAUDIO_ERROR_INVALID_STATE;
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index f5b3ad4..723cbf1 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -210,6 +210,7 @@
     STATIC_ASSERT(AAUDIO_INPUT_PRESET_VOICE_RECOGNITION == AUDIO_SOURCE_VOICE_RECOGNITION);
     STATIC_ASSERT(AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION == AUDIO_SOURCE_VOICE_COMMUNICATION);
     STATIC_ASSERT(AAUDIO_INPUT_PRESET_UNPROCESSED == AUDIO_SOURCE_UNPROCESSED);
+    STATIC_ASSERT(AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE == AUDIO_SOURCE_VOICE_PERFORMANCE);
     if (preset == AAUDIO_UNSPECIFIED) {
         preset = AAUDIO_INPUT_PRESET_VOICE_RECOGNITION;
     }
diff --git a/media/libaaudio/tests/test_attributes.cpp b/media/libaaudio/tests/test_attributes.cpp
index b01af25..dbf8712 100644
--- a/media/libaaudio/tests/test_attributes.cpp
+++ b/media/libaaudio/tests/test_attributes.cpp
@@ -130,6 +130,7 @@
     AAUDIO_INPUT_PRESET_VOICE_RECOGNITION,
     AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION,
     AAUDIO_INPUT_PRESET_UNPROCESSED,
+    AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE,
 };
 
 static void checkAttributesUsage(aaudio_performance_mode_t perfMode) {
diff --git a/media/libaaudio/tests/test_timestamps.cpp b/media/libaaudio/tests/test_timestamps.cpp
index dfa7815..7b1dfd3 100644
--- a/media/libaaudio/tests/test_timestamps.cpp
+++ b/media/libaaudio/tests/test_timestamps.cpp
@@ -35,6 +35,7 @@
 
 #define NUM_SECONDS             1
 #define NUM_LOOPS               4
+#define MAX_TESTS               20
 
 typedef struct TimestampInfo {
     int64_t         framesTotal;
@@ -53,6 +54,49 @@
     bool           forceUnderruns = false;
 } TimestampCallbackData_t;
 
+struct TimeStampTestLog {
+    aaudio_policy_t           isMmap;
+    aaudio_sharing_mode_t     sharingMode;
+    aaudio_performance_mode_t performanceMode;
+    aaudio_direction_t        direction;
+    aaudio_result_t           result;
+};
+
+static int s_numTests = 0;
+// Use a plain old array because we reference this from the callback and do not want any
+// automatic memory allocation.
+static TimeStampTestLog s_testLogs[MAX_TESTS]{};
+
+static void logTestResult(bool isMmap,
+                          aaudio_sharing_mode_t sharingMode,
+                          aaudio_performance_mode_t performanceMode,
+                          aaudio_direction_t direction,
+                          aaudio_result_t result) {
+    if(s_numTests >= MAX_TESTS) {
+        printf("ERROR - MAX_TESTS too small = %d\n", MAX_TESTS);
+        return;
+    }
+    s_testLogs[s_numTests].isMmap = isMmap;
+    s_testLogs[s_numTests].sharingMode = sharingMode;
+    s_testLogs[s_numTests].performanceMode = performanceMode;
+    s_testLogs[s_numTests].direction = direction;
+    s_testLogs[s_numTests].result = result;
+    s_numTests++;
+}
+
+static void printTestResults() {
+    for (int i = 0; i < s_numTests; i++) {
+        TimeStampTestLog *log = &s_testLogs[i];
+        printf("%2d: mmap = %3s, sharing = %9s, perf = %11s, dir = %6s ---- %4s\n",
+               i,
+               log->isMmap ? "yes" : "no",
+               getSharingModeText(log->sharingMode),
+               getPerformanceModeText(log->performanceMode),
+               getDirectionText(log->direction),
+               log->result ? "FAIL" : "pass");
+    }
+}
+
 // Callback function that fills the audio output buffer.
 aaudio_data_callback_result_t timestampDataCallbackProc(
         AAudioStream *stream,
@@ -115,6 +159,7 @@
     int32_t originalBufferSize = 0;
     int32_t requestedBufferSize = 0;
     int32_t finalBufferSize = 0;
+    bool    isMmap = false;
     aaudio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_FLOAT;
     aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
     aaudio_sharing_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
@@ -124,7 +169,8 @@
 
     memset(&sTimestampData, 0, sizeof(sTimestampData));
 
-    printf("------------ testTimeStamps(policy = %d, sharing = %s, perf = %s, dir = %s) -----------\n",
+    printf("\n=================================================================================\n");
+    printf("--------- testTimeStamps(policy = %d, sharing = %s, perf = %s, dir = %s) --------\n",
            mmapPolicy,
            getSharingModeText(sharingMode),
            getPerformanceModeText(performanceMode),
@@ -177,8 +223,8 @@
 
     printf("    chans = %3d, rate = %6d format = %d\n",
            actualChannelCount, actualSampleRate, actualDataFormat);
-    printf("    Is MMAP used? %s\n", AAudioStream_isMMapUsed(aaudioStream)
-                                     ? "yes" : "no");
+    isMmap = AAudioStream_isMMapUsed(aaudioStream);
+    printf("    Is MMAP used? %s\n", isMmap ? "yes" : "no");
 
     // This is the number of frames that are read in one chunk by a DMA controller
     // or a DSP or a mixer.
@@ -218,7 +264,7 @@
 
         for (int second = 0; second < NUM_SECONDS; second++) {
             // Give AAudio callback time to run in the background.
-            sleep(1);
+            usleep(200 * 1000);
 
             // Periodically print the progress so we know it hasn't died.
             printf("framesWritten = %d, XRuns = %d\n",
@@ -234,18 +280,25 @@
         }
 
         printf("timestampCount = %d\n", sTimestampData.timestampCount);
-        int printed = 0;
-        for (int i = 0; i < sTimestampData.timestampCount; i++) {
+        int printedGood = 0;
+        int printedBad = 0;
+        for (int i = 1; i < sTimestampData.timestampCount; i++) {
             TimestampInfo *timestamp = &sTimestampData.timestamps[i];
-            bool posChanged = (timestamp->timestampPosition != (timestamp - 1)->timestampPosition);
-            bool timeChanged = (timestamp->timestampNanos != (timestamp - 1)->timestampNanos);
-            if ((printed < 20) && ((i < 10) || posChanged || timeChanged)) {
-                printf("  %3d : frames %8lld, xferd %8lld", i,
-                       (long long) timestamp->framesTotal,
-                       (long long) timestamp->appPosition);
-                if (timestamp->result != AAUDIO_OK) {
-                    printf(", result = %s\n", AAudio_convertResultToText(timestamp->result));
-                } else {
+            if (timestamp->result != AAUDIO_OK) {
+                if (printedBad < 5) {
+                    printf("  %3d : frames %8lld, xferd %8lld, result = %s\n",
+                           i,
+                           (long long) timestamp->framesTotal,
+                           (long long) timestamp->appPosition,
+                           AAudio_convertResultToText(timestamp->result));
+                    printedBad++;
+                }
+            } else {
+                const bool posChanged = (timestamp->timestampPosition !=
+                                   (timestamp - 1)->timestampPosition);
+                const bool timeChanged = (timestamp->timestampNanos
+                        != (timestamp - 1)->timestampNanos);
+                if ((printedGood < 20) && (posChanged || timeChanged)) {
                     bool negative = timestamp->timestampPosition < 0;
                     bool retro = (i > 0 && (timestamp->timestampPosition <
                                             (timestamp - 1)->timestampPosition));
@@ -253,17 +306,39 @@
                                                    : (retro ? "  <= RETROGRADE!" : "");
 
                     double latency = calculateLatencyMillis(timestamp->timestampPosition,
-                                             timestamp->timestampNanos,
-                                             timestamp->appPosition,
-                                             timestamp->appNanoseconds,
-                                             actualSampleRate);
-                    printf(", STAMP: pos = %8lld, nanos = %8lld, lat = %7.1f msec %s\n",
+                                                            timestamp->timestampNanos,
+                                                            timestamp->appPosition,
+                                                            timestamp->appNanoseconds,
+                                                            actualSampleRate);
+                    printf("  %3d : frames %8lld, xferd %8lld",
+                           i,
+                           (long long) timestamp->framesTotal,
+                           (long long) timestamp->appPosition);
+                    printf(" STAMP: pos = %8lld, nanos = %8lld, lat = %7.1f msec %s\n",
                            (long long) timestamp->timestampPosition,
                            (long long) timestamp->timestampNanos,
                            latency,
                            message);
+                    printedGood++;
                 }
-                printed++;
+            }
+        }
+
+        if (printedGood == 0) {
+            printf("ERROR - AAudioStream_getTimestamp() never gave us a valid timestamp\n");
+            result = AAUDIO_ERROR_INTERNAL;
+        } else {
+            // Make sure we do not get timestamps when stopped.
+            int64_t position;
+            int64_t time;
+            aaudio_result_t tempResult = AAudioStream_getTimestamp(aaudioStream,
+                                                                   CLOCK_MONOTONIC,
+                                                                   &position, &time);
+            if (tempResult != AAUDIO_ERROR_INVALID_STATE) {
+                printf("ERROR - AAudioStream_getTimestamp() should return"
+                       " INVALID_STATE when stopped! %s\n",
+                       AAudio_convertResultToText(tempResult));
+                result = AAUDIO_ERROR_INTERNAL;
             }
         }
 
@@ -273,12 +348,14 @@
     }
 
 finish:
+
+    logTestResult(isMmap, sharingMode, performanceMode, direction, result);
+
     if (aaudioStream != nullptr) {
         AAudioStream_close(aaudioStream);
     }
     AAudioStreamBuilder_delete(aaudioBuilder);
     printf("result = %d = %s\n", result, AAudio_convertResultToText(result));
-
     return result;
 }
 
@@ -292,7 +369,7 @@
     // in a buffer if we hang or crash.
     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
 
-    printf("Test Timestamps V0.1.3\n");
+    printf("Test Timestamps V0.1.4\n");
 
     // Legacy
     aaudio_policy_t policy = AAUDIO_POLICY_NEVER;
@@ -332,5 +409,7 @@
                             AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
                             AAUDIO_DIRECTION_OUTPUT);
 
+    printTestResults();
+
     return (result == AAUDIO_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 827df6a..1417aaf 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -50,6 +50,7 @@
         "libmediametrics",
         "libmediautils",
         "libnblog",
+        "libprocessgroup",
         "libutils",
     ],
     export_shared_lib_headers: ["libbinder"],
diff --git a/media/libaudioclient/AudioPolicy.cpp b/media/libaudioclient/AudioPolicy.cpp
index d1f7525..3ab38cd 100644
--- a/media/libaudioclient/AudioPolicy.cpp
+++ b/media/libaudioclient/AudioPolicy.cpp
@@ -22,6 +22,22 @@
 namespace android {
 
 //
+//  AudioDeviceTypeAddr implementation
+//
+status_t AudioDeviceTypeAddr::readFromParcel(Parcel *parcel) {
+    mType = (audio_devices_t) parcel->readInt32();
+    mAddress = parcel->readString8();
+    return NO_ERROR;
+}
+
+status_t AudioDeviceTypeAddr::writeToParcel(Parcel *parcel) const {
+    parcel->writeInt32((int32_t) mType);
+    parcel->writeString8(mAddress);
+    return NO_ERROR;
+}
+
+
+//
 //  AudioMixMatchCriterion implementation
 //
 AudioMixMatchCriterion::AudioMixMatchCriterion(audio_usage_t usage,
@@ -40,11 +56,22 @@
 status_t AudioMixMatchCriterion::readFromParcel(Parcel *parcel)
 {
     mRule = parcel->readInt32();
-    if (mRule == RULE_MATCH_ATTRIBUTE_USAGE ||
-            mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) {
-        mValue.mUsage = (audio_usage_t)parcel->readInt32();
-    } else {
-        mValue.mSource = (audio_source_t)parcel->readInt32();
+    switch (mRule) {
+    case RULE_MATCH_ATTRIBUTE_USAGE:
+    case RULE_EXCLUDE_ATTRIBUTE_USAGE:
+        mValue.mUsage = (audio_usage_t) parcel->readInt32();
+        break;
+    case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+    case RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET:
+        mValue.mSource = (audio_source_t) parcel->readInt32();
+        break;
+    case RULE_MATCH_UID:
+    case RULE_EXCLUDE_UID:
+        mValue.mUid = (uid_t) parcel->readInt32();
+        break;
+    default:
+        ALOGE("Trying to build AudioMixMatchCriterion from unknown rule %d", mRule);
+        return BAD_VALUE;
     }
     return NO_ERROR;
 }
@@ -116,4 +143,18 @@
     return NO_ERROR;
 }
 
+void AudioMix::setExcludeUid(uid_t uid) const {
+    AudioMixMatchCriterion crit;
+    crit.mRule = RULE_EXCLUDE_UID;
+    crit.mValue.mUid = uid;
+    mCriteria.add(crit);
+}
+
+void AudioMix::setMatchUid(uid_t uid) const {
+    AudioMixMatchCriterion crit;
+    crit.mRule = RULE_MATCH_UID;
+    crit.mValue.mUid = uid;
+    mCriteria.add(crit);
+}
+
 } // namespace android
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 3223647..72a23e3 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -26,6 +26,7 @@
 #include <media/AudioRecord.h>
 #include <utils/Log.h>
 #include <private/media/AudioTrackShared.h>
+#include <processgroup/sched_policy.h>
 #include <media/IAudioFlinger.h>
 #include <media/MediaAnalyticsItem.h>
 #include <media/TypeConverter.h>
@@ -1398,6 +1399,17 @@
     return mAudioRecord->getActiveMicrophones(activeMicrophones).transactionError();
 }
 
+status_t AudioRecord::setMicrophoneDirection(audio_microphone_direction_t direction)
+{
+    AutoMutex lock(mLock);
+    return mAudioRecord->setMicrophoneDirection(direction).transactionError();
+}
+
+status_t AudioRecord::setMicrophoneFieldDimension(float zoom) {
+    AutoMutex lock(mLock);
+    return mAudioRecord->setMicrophoneFieldDimension(zoom).transactionError();
+}
+
 // =========================================================================
 
 void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index dc7531c..baeae8b 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1236,6 +1236,19 @@
     return aps->registerPolicyMixes(mixes, registration);
 }
 
+status_t AudioSystem::setUidDeviceAffinities(uid_t uid, const Vector<AudioDeviceTypeAddr>& devices)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->setUidDeviceAffinities(uid, devices);
+}
+
+status_t AudioSystem::removeUidDeviceAffinities(uid_t uid) {
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->removeUidDeviceAffinities(uid);
+}
+
 status_t AudioSystem::startAudioSource(const struct audio_port_config *source,
                                        const audio_attributes_t *attributes,
                                        audio_port_handle_t *portId)
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index b444d2d..e9a0e22 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -29,6 +29,7 @@
 #include <media/AudioTrack.h>
 #include <utils/Log.h>
 #include <private/media/AudioTrackShared.h>
+#include <processgroup/sched_policy.h>
 #include <media/IAudioFlinger.h>
 #include <media/IAudioPolicyService.h>
 #include <media/AudioParameter.h>
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 0ce8b16..272415c 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -90,6 +90,8 @@
     SET_ASSISTANT_UID,
     SET_A11Y_SERVICES_UIDS,
     IS_HAPTIC_PLAYBACK_SUPPORTED,
+    SET_UID_DEVICE_AFFINITY,
+    REMOVE_UID_DEVICE_AFFINITY,
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -990,6 +992,50 @@
         return reply.readBool();
     }
 
+    virtual status_t setUidDeviceAffinities(uid_t uid, const Vector<AudioDeviceTypeAddr>& devices)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+
+        data.writeInt32((int32_t) uid);
+        size_t size = devices.size();
+        size_t sizePosition = data.dataPosition();
+        data.writeInt32((int32_t) size);
+        size_t finalSize = size;
+        for (size_t i = 0; i < size; i++) {
+            size_t position = data.dataPosition();
+            if (devices[i].writeToParcel(&data) != NO_ERROR) {
+                data.setDataPosition(position);
+                finalSize--;
+            }
+        }
+        if (size != finalSize) {
+            size_t position = data.dataPosition();
+            data.setDataPosition(sizePosition);
+            data.writeInt32(finalSize);
+            data.setDataPosition(position);
+        }
+
+        status_t status = remote()->transact(SET_UID_DEVICE_AFFINITY, data, &reply);
+        if (status == NO_ERROR) {
+            status = (status_t)reply.readInt32();
+        }
+        return status;
+    }
+
+    virtual status_t removeUidDeviceAffinities(uid_t uid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+
+        data.writeInt32((int32_t) uid);
+
+        status_t status = remote()->transact(REMOVE_UID_DEVICE_AFFINITY, data, &reply);
+        if (status == NO_ERROR) {
+            status = (status_t)reply.readInt32();
+        }
+        return status;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1048,7 +1094,9 @@
         case GET_SURROUND_FORMATS:
         case SET_SURROUND_FORMAT_ENABLED:
         case SET_ASSISTANT_UID:
-        case SET_A11Y_SERVICES_UIDS: {
+        case SET_A11Y_SERVICES_UIDS:
+        case SET_UID_DEVICE_AFFINITY:
+        case REMOVE_UID_DEVICE_AFFINITY: {
             if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
@@ -1811,6 +1859,30 @@
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             bool isSupported = isHapticPlaybackSupported();
             reply->writeBool(isSupported);
+            return NO_ERROR;    
+        }
+
+        case SET_UID_DEVICE_AFFINITY: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            const uid_t uid = (uid_t) data.readInt32();
+            Vector<AudioDeviceTypeAddr> devices;
+            size_t size = (size_t)data.readInt32();
+            for (size_t i = 0; i < size; i++) {
+                AudioDeviceTypeAddr device;
+                if (device.readFromParcel((Parcel*)&data) == NO_ERROR) {
+                    devices.add(device);
+                }
+            }
+            status_t status = setUidDeviceAffinities(uid, devices);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        }
+
+        case REMOVE_UID_DEVICE_AFFINITY: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            const uid_t uid = (uid_t) data.readInt32();
+            status_t status = removeUidDeviceAffinities(uid);
+            reply->writeInt32(status);
             return NO_ERROR;
         }
 
diff --git a/media/libaudioclient/aidl/android/media/IAudioRecord.aidl b/media/libaudioclient/aidl/android/media/IAudioRecord.aidl
index 01e0a71..cf9c7f4 100644
--- a/media/libaudioclient/aidl/android/media/IAudioRecord.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioRecord.aidl
@@ -36,4 +36,12 @@
   /* Get a list of current active microphones.
    */
   void getActiveMicrophones(out MicrophoneInfo[] activeMicrophones);
+
+  /* Set the microphone direction (for processing).
+   */
+  void setMicrophoneDirection(int /*audio_microphone_direction_t*/ direction);
+
+  /* Set the microphone zoom (for processing).
+   */
+  void setMicrophoneFieldDimension(float zoom);
 }
diff --git a/media/libaudioclient/include/media/AudioPolicy.h b/media/libaudioclient/include/media/AudioPolicy.h
index 8da0069..786fb9a 100644
--- a/media/libaudioclient/include/media/AudioPolicy.h
+++ b/media/libaudioclient/include/media/AudioPolicy.h
@@ -56,6 +56,19 @@
 #define MAX_MIXES_PER_POLICY 10
 #define MAX_CRITERIA_PER_MIX 20
 
+class AudioDeviceTypeAddr {
+public:
+    AudioDeviceTypeAddr() {}
+    AudioDeviceTypeAddr(audio_devices_t type, String8 address) :
+        mType(type), mAddress(address) {}
+
+    status_t readFromParcel(Parcel *parcel);
+    status_t writeToParcel(Parcel *parcel) const;
+
+    audio_devices_t mType;
+    String8 mAddress;
+};
+
 class AudioMixMatchCriterion {
 public:
     AudioMixMatchCriterion() {}
@@ -87,7 +100,10 @@
     status_t readFromParcel(Parcel *parcel);
     status_t writeToParcel(Parcel *parcel) const;
 
-    Vector<AudioMixMatchCriterion> mCriteria;
+    void setExcludeUid(uid_t uid) const;
+    void setMatchUid(uid_t uid) const;
+
+    mutable Vector<AudioMixMatchCriterion> mCriteria;
     uint32_t        mMixType;
     audio_config_t  mFormat;
     uint32_t        mRouteFlags;
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index 35a7e05..ebee124 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -534,6 +534,14 @@
      */
             status_t    getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
 
+    /* Set the Microphone direction (for processing purposes).
+     */
+            status_t    setMicrophoneDirection(audio_microphone_direction_t direction);
+
+    /* Set the Microphone zoom factor (for processing purposes).
+     */
+            status_t    setMicrophoneFieldDimension(float zoom);
+
      /* Get the unique port ID assigned to this AudioRecord instance by audio policy manager.
       * The ID is unique across all audioserver clients and can change during the life cycle
       * of a given AudioRecord instance if the connection to audioserver is restored.
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index b0da5b8..781e9df 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -325,6 +325,10 @@
 
     static status_t registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration);
 
+    static status_t setUidDeviceAffinities(uid_t uid, const Vector<AudioDeviceTypeAddr>& devices);
+
+    static status_t removeUidDeviceAffinities(uid_t uid);
+
     static status_t startAudioSource(const struct audio_port_config *source,
                                      const audio_attributes_t *attributes,
                                      audio_port_handle_t *portId);
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 61f3b27..fb4fe93 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -167,6 +167,11 @@
 
     virtual status_t registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration) = 0;
 
+    virtual status_t setUidDeviceAffinities(uid_t uid, const Vector<AudioDeviceTypeAddr>& devices)
+            = 0;
+
+    virtual status_t removeUidDeviceAffinities(uid_t uid) = 0;
+
     virtual status_t startAudioSource(const struct audio_port_config *source,
                                       const audio_attributes_t *attributes,
                                       audio_port_handle_t *portId) = 0;
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index 7a9e843..a1e869f 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -268,6 +268,8 @@
         audio_input_flags_t flags,
         const char *address,
         audio_source_t source,
+        audio_devices_t outputDevice,
+        const char *outputDeviceAddress,
         sp<StreamInHalInterface> *inStream) {
     if (mDevice == 0) return NO_INIT;
     DeviceAddress hidlDevice;
@@ -283,6 +285,17 @@
     //       for now, only send the main source at 1dbfs
     SinkMetadata sinkMetadata = {{{ .source = AudioSource(source), .gain = 1 }}};
 #endif
+#if MAJOR_VERSION < 5
+    (void)outputDevice;
+    (void)outputDeviceAddress;
+#else
+    if (outputDevice != AUDIO_DEVICE_NONE) {
+        DeviceAddress hidlOutputDevice;
+        status = deviceAddressFromHal(outputDevice, outputDeviceAddress, &hidlOutputDevice);
+        if (status != OK) return status;
+        sinkMetadata.tracks[0].destination.device(std::move(hidlOutputDevice));
+    }
+#endif
     Return<void> ret = mDevice->openInputStream(
             handle,
             hidlDevice,
diff --git a/media/libaudiohal/impl/DeviceHalHidl.h b/media/libaudiohal/impl/DeviceHalHidl.h
index 291c88f..f7d465f 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.h
+++ b/media/libaudiohal/impl/DeviceHalHidl.h
@@ -86,6 +86,8 @@
             audio_input_flags_t flags,
             const char *address,
             audio_source_t source,
+            audio_devices_t outputDevice,
+            const char *outputDeviceAddress,
             sp<StreamInHalInterface> *inStream);
 
     // Returns whether createAudioPatch and releaseAudioPatch operations are supported.
diff --git a/media/libaudiohal/impl/DeviceHalLocal.cpp b/media/libaudiohal/impl/DeviceHalLocal.cpp
index dffe9da..ee68252 100644
--- a/media/libaudiohal/impl/DeviceHalLocal.cpp
+++ b/media/libaudiohal/impl/DeviceHalLocal.cpp
@@ -131,6 +131,8 @@
         audio_input_flags_t flags,
         const char *address,
         audio_source_t source,
+        audio_devices_t /*outputDevice*/,
+        const char */*outputDeviceAddress*/,
         sp<StreamInHalInterface> *inStream) {
     audio_stream_in_t *halStream;
     ALOGV("open_input_stream handle: %d devices: %x flags: %#x "
diff --git a/media/libaudiohal/impl/DeviceHalLocal.h b/media/libaudiohal/impl/DeviceHalLocal.h
index 18bd879..36db72e 100644
--- a/media/libaudiohal/impl/DeviceHalLocal.h
+++ b/media/libaudiohal/impl/DeviceHalLocal.h
@@ -79,6 +79,8 @@
             audio_input_flags_t flags,
             const char *address,
             audio_source_t source,
+            audio_devices_t outputDevice,
+            const char *outputDeviceAddress,
             sp<StreamInHalInterface> *inStream);
 
     // Returns whether createAudioPatch and releaseAudioPatch operations are supported.
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index c12b362..2e35be6 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -854,5 +854,29 @@
 }
 #endif
 
+#if MAJOR_VERSION < 5
+status_t StreamInHalHidl::setMicrophoneDirection(audio_microphone_direction_t direction __unused) {
+    if (mStream == 0) return NO_INIT;
+    return INVALID_OPERATION;
+}
+
+status_t StreamInHalHidl::setMicrophoneFieldDimension(float zoom __unused) {
+    if (mStream == 0) return NO_INIT;
+    return INVALID_OPERATION;
+}
+#else
+status_t StreamInHalHidl::setMicrophoneDirection(audio_microphone_direction_t direction) {
+    if (!mStream) return NO_INIT;
+    return processReturn("setMicrophoneDirection",
+                mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
+}
+
+status_t StreamInHalHidl::setMicrophoneFieldDimension(float zoom) {
+    if (!mStream) return NO_INIT;
+    return processReturn("setMicrophoneFieldDimension",
+                mStream->setMicrophoneFieldDimension(zoom));
+}
+#endif
+
 } // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/impl/StreamHalHidl.h b/media/libaudiohal/impl/StreamHalHidl.h
index f7b507e..9ac1067 100644
--- a/media/libaudiohal/impl/StreamHalHidl.h
+++ b/media/libaudiohal/impl/StreamHalHidl.h
@@ -220,6 +220,12 @@
     // Get active microphones
     virtual status_t getActiveMicrophones(std::vector<media::MicrophoneInfo> *microphones);
 
+    // Set microphone direction (for processing)
+    virtual status_t setMicrophoneDirection(audio_microphone_direction_t direction) override;
+
+    // Set microphone zoom (for processing)
+    virtual status_t setMicrophoneFieldDimension(float zoom) override;
+
     // Called when the metadata of the stream's sink has been changed.
     status_t updateSinkMetadata(const SinkMetadata& sinkMetadata) override;
 
diff --git a/media/libaudiohal/impl/StreamHalLocal.cpp b/media/libaudiohal/impl/StreamHalLocal.cpp
index 26d30d4..fcb809b 100644
--- a/media/libaudiohal/impl/StreamHalLocal.cpp
+++ b/media/libaudiohal/impl/StreamHalLocal.cpp
@@ -368,5 +368,26 @@
 }
 #endif
 
+#if MAJOR_VERSION < 5
+status_t StreamInHalLocal::setMicrophoneDirection(audio_microphone_direction_t direction __unused) {
+    return INVALID_OPERATION;
+}
+
+status_t StreamInHalLocal::setMicrophoneFieldDimension(float zoom __unused) {
+    return INVALID_OPERATION;
+}
+#else
+status_t StreamInHalLocal::setMicrophoneDirection(audio_microphone_direction_t direction) {
+    if (mStream->set_microphone_direction == NULL) return INVALID_OPERATION;
+    return mStream->set_microphone_direction(mStream, direction);
+}
+
+status_t StreamInHalLocal::setMicrophoneFieldDimension(float zoom) {
+    if (mStream->set_microphone_field_dimension == NULL) return INVALID_OPERATION;
+    return mStream->set_microphone_field_dimension(mStream, zoom);
+
+}
+#endif
+
 } // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/impl/StreamHalLocal.h b/media/libaudiohal/impl/StreamHalLocal.h
index 4fd1960..3d6c50e 100644
--- a/media/libaudiohal/impl/StreamHalLocal.h
+++ b/media/libaudiohal/impl/StreamHalLocal.h
@@ -204,6 +204,12 @@
     // Get active microphones
     virtual status_t getActiveMicrophones(std::vector<media::MicrophoneInfo> *microphones);
 
+    // Sets microphone direction (for processing)
+    virtual status_t setMicrophoneDirection(audio_microphone_direction_t direction);
+
+    // Sets microphone zoom (for processing)
+    virtual status_t setMicrophoneFieldDimension(float zoom);
+
     // Called when the metadata of the stream's sink has been changed.
     status_t updateSinkMetadata(const SinkMetadata& sinkMetadata) override;
 
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index 7de8eb3..e565237 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -84,6 +84,8 @@
             audio_input_flags_t flags,
             const char *address,
             audio_source_t source,
+            audio_devices_t outputDevice,
+            const char *outputDeviceAddress,
             sp<StreamInHalInterface> *inStream) = 0;
 
     // Returns whether createAudioPatch and releaseAudioPatch operations are supported.
diff --git a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
index bd71dc0..ed8282f 100644
--- a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
@@ -179,6 +179,12 @@
     // Get active microphones
     virtual status_t getActiveMicrophones(std::vector<media::MicrophoneInfo> *microphones) = 0;
 
+    // Set direction for capture processing
+    virtual status_t setMicrophoneDirection(audio_microphone_direction_t) = 0;
+
+    // Set zoom factor for capture stream
+    virtual status_t setMicrophoneFieldDimension(float zoom) = 0;
+
     struct SinkMetadata {
         std::vector<record_track_metadata_t> tracks;
     };
diff --git a/media/libeffects/config/src/EffectsConfig.cpp b/media/libeffects/config/src/EffectsConfig.cpp
index 76b4adc..f39eb0c 100644
--- a/media/libeffects/config/src/EffectsConfig.cpp
+++ b/media/libeffects/config/src/EffectsConfig.cpp
@@ -115,6 +115,7 @@
         {AUDIO_SOURCE_VOICE_RECOGNITION, "voice_recognition"},
         {AUDIO_SOURCE_VOICE_COMMUNICATION, "voice_communication"},
         {AUDIO_SOURCE_UNPROCESSED, "unprocessed"},
+        {AUDIO_SOURCE_VOICE_PERFORMANCE, "voice_performance"},
 };
 
 /** Find the stream type enum corresponding to the stream type name or return false */
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index b5860de..0c6f8de 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -1544,7 +1544,7 @@
 int VirtualizerIsConfigurationSupported(audio_channel_mask_t channelMask,
         audio_devices_t deviceType) {
     uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
-    if (channelCount < 1 || channelCount > LVM_MAX_CHANNELS) {
+    if (channelCount < 1 || channelCount > FCC_2) { // TODO: update to 8 channels when supported.
         return -EINVAL;
     }
     return VirtualizerIsDeviceSupported(deviceType);
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 6002e95..68dae56 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -213,15 +213,14 @@
         "android.hidl.token@1.0-utils",
         "liblog",
         "libcutils",
+        "libprocessgroup",
         "libutils",
         "libbinder",
         "libsonivox",
-        "libicuuc",
-        "libicui18n",
+        "libandroidicu",
         "libexpat",
         "libcamera_client",
         "libstagefright_foundation",
-        "libmediaextractor",
         "libgui",
         "libdl",
         "libaudioutils",
@@ -232,8 +231,7 @@
     export_shared_lib_headers: [
         "libaudioclient",
         "libbinder",
-        "libicuuc",
-        "libicui18n",
+        "libandroidicu",
         "libsonivox",
         "libmedia_omx",
     ],
@@ -279,7 +277,6 @@
         "libbinder",
         "libcutils",
         "liblog",
-        "libmediaextractor",
         "libmediandk",
         "libnativewindow",
         "libmediandk_utils",
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index e9a6230..fb6d3a2 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include <stdint.h>
+#include <time.h>
 #include <sys/types.h>
 
 #include <binder/IPCThreadState.h>
@@ -219,10 +220,16 @@
     Vector<wp<IMediaSource>> tracks;
     Vector<String8> trackDescriptions;
     String8 toString() const;
+    time_t when;
 } ExtractorInstance;
 
 String8 ExtractorInstance::toString() const {
-    String8 str = name;
+    String8 str;
+    char timeString[32];
+    strftime(timeString, sizeof(timeString), "%m-%d %T", localtime(&when));
+    str.append(timeString);
+    str.append(": ");
+    str.append(name);
     str.append(" for mime ");
     str.append(mime);
     str.append(", source ");
@@ -287,6 +294,7 @@
     ex.sourceDescription = source->toString();
     ex.owner = IPCThreadState::self()->getCallingPid();
     ex.extractor = extractor;
+    ex.when = time(NULL);
 
     {
         Mutex::Autolock lock(sExtractorsLock);
diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
index 0295abc..243b09d 100644
--- a/media/libmedia/IMediaExtractorService.cpp
+++ b/media/libmedia/IMediaExtractorService.cpp
@@ -29,6 +29,7 @@
 enum {
     MAKE_EXTRACTOR = IBinder::FIRST_CALL_TRANSACTION,
     MAKE_IDATA_SOURCE_FD,
+    GET_SUPPORTED_TYPES,
 };
 
 class BpMediaExtractorService : public BpInterface<IMediaExtractorService>
@@ -68,6 +69,24 @@
         }
         return nullptr;
     }
+
+    virtual std::unordered_set<std::string> getSupportedTypes() {
+        std::unordered_set<std::string> supportedTypes;
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaExtractorService::getInterfaceDescriptor());
+        status_t ret = remote()->transact(GET_SUPPORTED_TYPES, data, &reply);
+        if (ret == NO_ERROR) {
+            // process reply
+            while(true) {
+                const char *ext = reply.readCString();
+                if (!ext) {
+                    break;
+                }
+                supportedTypes.insert(std::string(ext));
+            }
+        }
+        return supportedTypes;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaExtractorService, "android.media.IMediaExtractorService");
@@ -113,6 +132,15 @@
             return NO_ERROR;
         }
 
+        case GET_SUPPORTED_TYPES:
+        {
+            CHECK_INTERFACE(IMediaExtractorService, data, reply);
+            std::unordered_set<std::string> supportedTypes = getSupportedTypes();
+            for (auto it = supportedTypes.begin(); it != supportedTypes.end(); ++it) {
+                reply->writeCString((*it).c_str());
+            }
+            return NO_ERROR;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 590ba1a..f9fa86e 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -23,6 +23,7 @@
 #include <media/IDataSource.h>
 #include <media/IMediaHTTPService.h>
 #include <media/IMediaMetadataRetriever.h>
+#include <processgroup/sched_policy.h>
 #include <utils/String8.h>
 #include <utils/KeyedVector.h>
 
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index 5308e1c..86ad997 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -28,6 +28,15 @@
 
 namespace android {
 
+/** This redundant redeclaration is needed for C++ pre 14 */
+constexpr char MediaCodecInfo::Capabilities::FEATURE_ADAPTIVE_PLAYBACK[];
+constexpr char MediaCodecInfo::Capabilities::FEATURE_DYNAMIC_TIMESTAMP[];
+constexpr char MediaCodecInfo::Capabilities::FEATURE_FRAME_PARSING[];
+constexpr char MediaCodecInfo::Capabilities::FEATURE_INTRA_REFRESH[];
+constexpr char MediaCodecInfo::Capabilities::FEATURE_MULTIPLE_FRAMES[];
+constexpr char MediaCodecInfo::Capabilities::FEATURE_SECURE_PLAYBACK[];
+constexpr char MediaCodecInfo::Capabilities::FEATURE_TUNNELED_PLAYBACK[];
+
 void MediaCodecInfo::Capabilities::getSupportedProfileLevels(
         Vector<ProfileLevel> *profileLevels) const {
     profileLevels->clear();
@@ -40,16 +49,11 @@
     colorFormats->appendVector(mColorFormats);
 }
 
-uint32_t MediaCodecInfo::Capabilities::getFlags() const {
-    return mFlags;
-}
-
 const sp<AMessage> MediaCodecInfo::Capabilities::getDetails() const {
     return mDetails;
 }
 
-MediaCodecInfo::Capabilities::Capabilities()
-  : mFlags(0) {
+MediaCodecInfo::Capabilities::Capabilities() {
     mDetails = new AMessage;
 }
 
@@ -73,12 +77,10 @@
             caps->mColorFormats.push_back(color);
         }
     }
-    uint32_t flags = static_cast<uint32_t>(parcel.readInt32());
     sp<AMessage> details = AMessage::FromParcel(parcel);
     if (details == NULL)
         return NULL;
     if (caps != NULL) {
-        caps->mFlags = flags;
         caps->mDetails = details;
     }
     return caps;
@@ -96,7 +98,6 @@
     for (size_t i = 0; i < mColorFormats.size(); i++) {
         parcel->writeInt32(mColorFormats.itemAt(i));
     }
-    parcel->writeInt32(mFlags);
     mDetails->writeToParcel(parcel);
     return OK;
 }
@@ -111,6 +112,14 @@
     mCap->mDetails->setInt32(key, value);
 }
 
+void MediaCodecInfo::CapabilitiesWriter::removeDetail(const char* key) {
+    if (mCap->mDetails->removeEntryAt(mCap->mDetails->findEntryByName(key)) == OK) {
+        ALOGD("successfully removed detail %s", key);
+    } else {
+        ALOGD("detail %s wasn't present to remove", key);
+    }
+}
+
 void MediaCodecInfo::CapabilitiesWriter::addProfileLevel(
         uint32_t profile, uint32_t level) {
     ProfileLevel profileLevel;
@@ -129,32 +138,32 @@
     }
 }
 
-void MediaCodecInfo::CapabilitiesWriter::addFlags(uint32_t flags) {
-    mCap->mFlags |= flags;
-}
-
 MediaCodecInfo::CapabilitiesWriter::CapabilitiesWriter(
         MediaCodecInfo::Capabilities* cap) : mCap(cap) {
 }
 
-bool MediaCodecInfo::isEncoder() const {
-    return mIsEncoder;
+MediaCodecInfo::Attributes MediaCodecInfo::getAttributes() const {
+    return mAttributes;
 }
 
-uint32_t MediaCodecInfo::rank() const {
+uint32_t MediaCodecInfo::getRank() const {
     return mRank;
 }
 
-void MediaCodecInfo::getSupportedMimes(Vector<AString> *mimes) const {
-    mimes->clear();
+void MediaCodecInfo::getAliases(Vector<AString> *aliases) const {
+    *aliases = mAliases;
+}
+
+void MediaCodecInfo::getSupportedMediaTypes(Vector<AString> *mediaTypes) const {
+    mediaTypes->clear();
     for (size_t ix = 0; ix < mCaps.size(); ix++) {
-        mimes->push_back(mCaps.keyAt(ix));
+        mediaTypes->push_back(mCaps.keyAt(ix));
     }
 }
 
 const sp<MediaCodecInfo::Capabilities>
-MediaCodecInfo::getCapabilitiesFor(const char *mime) const {
-    ssize_t ix = getCapabilityIndex(mime);
+MediaCodecInfo::getCapabilitiesFor(const char *mediaType) const {
+    ssize_t ix = getCapabilityIndex(mediaType);
     if (ix >= 0) {
         return mCaps.valueAt(ix);
     }
@@ -173,21 +182,26 @@
 sp<MediaCodecInfo> MediaCodecInfo::FromParcel(const Parcel &parcel) {
     AString name = AString::FromParcel(parcel);
     AString owner = AString::FromParcel(parcel);
-    bool isEncoder = static_cast<bool>(parcel.readInt32());
+    Attributes attributes = static_cast<Attributes>(parcel.readInt32());
     uint32_t rank = parcel.readUint32();
     sp<MediaCodecInfo> info = new MediaCodecInfo;
     info->mName = name;
     info->mOwner = owner;
-    info->mIsEncoder = isEncoder;
+    info->mAttributes = attributes;
     info->mRank = rank;
+    size_t numAliases = static_cast<size_t>(parcel.readInt32());
+    for (size_t i = 0; i < numAliases; i++) {
+        AString alias = AString::FromParcel(parcel);
+        info->mAliases.add(alias);
+    }
     size_t size = static_cast<size_t>(parcel.readInt32());
     for (size_t i = 0; i < size; i++) {
-        AString mime = AString::FromParcel(parcel);
+        AString mediaType = AString::FromParcel(parcel);
         sp<Capabilities> caps = Capabilities::FromParcel(parcel);
         if (caps == NULL)
             return NULL;
         if (info != NULL) {
-            info->mCaps.add(mime, caps);
+            info->mCaps.add(mediaType, caps);
         }
     }
     return info;
@@ -196,8 +210,12 @@
 status_t MediaCodecInfo::writeToParcel(Parcel *parcel) const {
     mName.writeToParcel(parcel);
     mOwner.writeToParcel(parcel);
-    parcel->writeInt32(mIsEncoder);
+    parcel->writeInt32(mAttributes);
     parcel->writeUint32(mRank);
+    parcel->writeInt32(mAliases.size());
+    for (const AString &alias : mAliases) {
+        alias.writeToParcel(parcel);
+    }
     parcel->writeInt32(mCaps.size());
     for (size_t i = 0; i < mCaps.size(); i++) {
         mCaps.keyAt(i).writeToParcel(parcel);
@@ -206,10 +224,10 @@
     return OK;
 }
 
-ssize_t MediaCodecInfo::getCapabilityIndex(const char *mime) const {
-    if (mime) {
+ssize_t MediaCodecInfo::getCapabilityIndex(const char *mediaType) const {
+    if (mediaType) {
         for (size_t ix = 0; ix < mCaps.size(); ix++) {
-            if (mCaps.keyAt(ix).equalsIgnoreCase(mime)) {
+            if (mCaps.keyAt(ix).equalsIgnoreCase(mediaType)) {
                 return ix;
             }
         }
@@ -217,19 +235,26 @@
     return -1;
 }
 
-MediaCodecInfo::MediaCodecInfo() : mRank(0x100) {
+MediaCodecInfo::MediaCodecInfo()
+    : mAttributes((MediaCodecInfo::Attributes)0),
+      mRank(0x100) {
 }
 
 void MediaCodecInfoWriter::setName(const char* name) {
     mInfo->mName = name;
 }
 
+void MediaCodecInfoWriter::addAlias(const char* name) {
+    mInfo->mAliases.add(name);
+}
+
 void MediaCodecInfoWriter::setOwner(const char* owner) {
     mInfo->mOwner = owner;
 }
 
-void MediaCodecInfoWriter::setEncoder(bool isEncoder) {
-    mInfo->mIsEncoder = isEncoder;
+void MediaCodecInfoWriter::setAttributes(
+        typename std::underlying_type<MediaCodecInfo::Attributes>::type attributes) {
+    mInfo->mAttributes = (MediaCodecInfo::Attributes)attributes;
 }
 
 void MediaCodecInfoWriter::setRank(uint32_t rank) {
@@ -237,21 +262,21 @@
 }
 
 std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>
-        MediaCodecInfoWriter::addMime(const char *mime) {
-    ssize_t ix = mInfo->getCapabilityIndex(mime);
+        MediaCodecInfoWriter::addMediaType(const char *mediaType) {
+    ssize_t ix = mInfo->getCapabilityIndex(mediaType);
     if (ix >= 0) {
         return std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>(
                 new MediaCodecInfo::CapabilitiesWriter(
                 mInfo->mCaps.valueAt(ix).get()));
     }
     sp<MediaCodecInfo::Capabilities> caps = new MediaCodecInfo::Capabilities();
-    mInfo->mCaps.add(AString(mime), caps);
+    mInfo->mCaps.add(AString(mediaType), caps);
     return std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>(
             new MediaCodecInfo::CapabilitiesWriter(caps.get()));
 }
 
-bool MediaCodecInfoWriter::removeMime(const char *mime) {
-    ssize_t ix = mInfo->getCapabilityIndex(mime);
+bool MediaCodecInfoWriter::removeMediaType(const char *mediaType) {
+    ssize_t ix = mInfo->getCapabilityIndex(mediaType);
     if (ix >= 0) {
         mInfo->mCaps.removeItemsAt(ix);
         return true;
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
index 156991e..6dbc9b8 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -1249,7 +1249,11 @@
     if (mAMediaExtractor == NULL) {
         return NULL;
     }
-    return new AMediaCodecCryptoInfoWrapper(AMediaExtractor_getSampleCryptoInfo(mAMediaExtractor));
+    AMediaCodecCryptoInfo *cryptoInfo = AMediaExtractor_getSampleCryptoInfo(mAMediaExtractor);
+    if (cryptoInfo == NULL) {
+        return NULL;
+    }
+    return new AMediaCodecCryptoInfoWrapper(cryptoInfo);
 }
 
 AMediaDataSourceWrapper::AMediaDataSourceWrapper(const sp<DataSource> &dataSource)
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmedia/TypeConverter.cpp
index b5a7172..c24e046 100644
--- a/media/libmedia/TypeConverter.cpp
+++ b/media/libmedia/TypeConverter.cpp
@@ -74,6 +74,7 @@
     MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
     MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
     MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_HDMI),
+    MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_HDMI_ARC),
     MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TELEPHONY_RX),
     MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
     MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
@@ -93,6 +94,8 @@
     MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BUS),
     MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_PROXY),
     MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_HEADSET),
+    MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_BLE),
+    MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ECHO_REFERENCE),
     MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_DEFAULT),
     // STUB must be after DEFAULT, so the latter is picked up by toString first.
     MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_STUB),
@@ -357,6 +360,8 @@
     MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_VOICE_COMMUNICATION),
     MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_REMOTE_SUBMIX),
     MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_UNPROCESSED),
+    MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_VOICE_PERFORMANCE),
+    MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_ECHO_REFERENCE),
     MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_FM_TUNER),
     MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_HOTWORD),
     TERMINATOR
diff --git a/media/libmedia/include/media/CryptoHal.h b/media/libmedia/include/media/CryptoHal.h
index ff8789d..73c029f 100644
--- a/media/libmedia/include/media/CryptoHal.h
+++ b/media/libmedia/include/media/CryptoHal.h
@@ -21,6 +21,7 @@
 #include <android/hardware/drm/1.0/ICryptoFactory.h>
 #include <android/hardware/drm/1.0/ICryptoPlugin.h>
 #include <android/hardware/drm/1.1/ICryptoFactory.h>
+#include <android/hardware/drm/1.2/ICryptoPlugin.h>
 
 #include <mediadrm/ICrypto.h>
 #include <utils/KeyedVector.h>
@@ -72,6 +73,7 @@
 
     const Vector<sp<ICryptoFactory>> mFactories;
     sp<ICryptoPlugin> mPlugin;
+    sp<drm::V1_2::ICryptoPlugin> mPluginV1_2;
 
     /**
      * mInitCheck is:
diff --git a/media/libmedia/include/media/DrmHal.h b/media/libmedia/include/media/DrmHal.h
index 3302982..de0f3c7 100644
--- a/media/libmedia/include/media/DrmHal.h
+++ b/media/libmedia/include/media/DrmHal.h
@@ -20,11 +20,11 @@
 
 #include <android/hardware/drm/1.0/IDrmFactory.h>
 #include <android/hardware/drm/1.0/IDrmPlugin.h>
-#include <android/hardware/drm/1.0/IDrmPluginListener.h>
 #include <android/hardware/drm/1.1/IDrmFactory.h>
 #include <android/hardware/drm/1.1/IDrmPlugin.h>
 #include <android/hardware/drm/1.2/IDrmFactory.h>
 #include <android/hardware/drm/1.2/IDrmPlugin.h>
+#include <android/hardware/drm/1.2/IDrmPluginListener.h>
 
 #include <media/MediaAnalyticsItem.h>
 #include <mediadrm/DrmMetrics.h>
@@ -43,6 +43,8 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 
+typedef drm::V1_2::IDrmPluginListener IDrmPluginListener_V1_2;
+
 namespace android {
 
 struct DrmSessionClientInterface;
@@ -54,7 +56,7 @@
 
 struct DrmHal : public BnDrm,
              public IBinder::DeathRecipient,
-             public IDrmPluginListener {
+                public IDrmPluginListener_V1_2 {
     DrmHal();
     virtual ~DrmHal();
 
@@ -176,6 +178,8 @@
     Return<void> sendKeysChange(const hidl_vec<uint8_t>& sessionId,
             const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey);
 
+    Return<void> sendSessionLostState(const hidl_vec<uint8_t>& sessionId);
+
     virtual void binderDied(const wp<IBinder> &the_late_who);
 
 private:
diff --git a/media/libmedia/include/media/IMediaExtractorService.h b/media/libmedia/include/media/IMediaExtractorService.h
index 45e9620..5ce2cdb 100644
--- a/media/libmedia/include/media/IMediaExtractorService.h
+++ b/media/libmedia/include/media/IMediaExtractorService.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_IMEDIAEXTRACTORSERVICE_H
 #define ANDROID_IMEDIAEXTRACTORSERVICE_H
 
+#include <unordered_set>
+
 #include <binder/IInterface.h>
 #include <binder/IMemory.h>
 #include <binder/Parcel.h>
@@ -33,6 +35,8 @@
     virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime) = 0;
 
     virtual sp<IDataSource> makeIDataSource(int fd, int64_t offset, int64_t length) = 0;
+
+    virtual std::unordered_set<std::string> getSupportedTypes() = 0;
 };
 
 class BnMediaExtractorService: public BnInterface<IMediaExtractorService>
diff --git a/media/libmedia/include/media/MediaCodecInfo.h b/media/libmedia/include/media/MediaCodecInfo.h
index b3777d3..54f565a 100644
--- a/media/libmedia/include/media/MediaCodecInfo.h
+++ b/media/libmedia/include/media/MediaCodecInfo.h
@@ -30,6 +30,8 @@
 #include <utils/Vector.h>
 #include <utils/StrongPointer.h>
 
+#include <type_traits>
+
 namespace android {
 
 struct AMessage;
@@ -51,21 +53,47 @@
 
     struct CapabilitiesWriter;
 
+    enum Attributes : int32_t {
+        // attribute flags
+        kFlagIsEncoder = 1 << 0,
+        kFlagIsVendor = 1 << 1,
+        kFlagIsSoftwareOnly = 1 << 2,
+        kFlagIsHardwareAccelerated = 1 << 3,
+    };
+
     struct Capabilities : public RefBase {
-        enum {
-            // decoder flags
-            kFlagSupportsAdaptivePlayback = 1 << 0,
-            kFlagSupportsSecurePlayback = 1 << 1,
-            kFlagSupportsTunneledPlayback = 1 << 2,
+        constexpr static char FEATURE_ADAPTIVE_PLAYBACK[] = "feature-adaptive-playback";
+        constexpr static char FEATURE_DYNAMIC_TIMESTAMP[] = "feature-dynamic-timestamp";
+        constexpr static char FEATURE_FRAME_PARSING[] = "feature-frame-parsing";
+        constexpr static char FEATURE_INTRA_REFRESH[] = "feature-frame-parsing";
+        constexpr static char FEATURE_MULTIPLE_FRAMES[] = "feature-multiple-frames";
+        constexpr static char FEATURE_SECURE_PLAYBACK[] = "feature-secure-playback";
+        constexpr static char FEATURE_TUNNELED_PLAYBACK[] = "feature-tunneled-playback";
 
-            // encoder flags
-            kFlagSupportsIntraRefresh = 1 << 0,
-
-        };
-
+        /**
+         * Returns the supported levels for each supported profile in a target array.
+         *
+         * @param profileLevels target array for the profile levels.
+         */
         void getSupportedProfileLevels(Vector<ProfileLevel> *profileLevels) const;
+
+        /**
+         * Returns the supported color formats in a target array. Only used for video/image
+         * components.
+         *
+         * @param colorFormats target array for the color formats.
+         */
         void getSupportedColorFormats(Vector<uint32_t> *colorFormats) const;
-        uint32_t getFlags() const;
+
+        /**
+         * Returns metadata associated with this codec capability.
+         *
+         * This contains:
+         * - features,
+         * - performance data.
+         *
+         * TODO: expose this as separate API-s and wrap here.
+         */
         const sp<AMessage> getDetails() const;
 
     protected:
@@ -73,7 +101,6 @@
         SortedVector<ProfileLevel> mProfileLevelsSorted;
         Vector<uint32_t> mColorFormats;
         SortedVector<uint32_t> mColorFormatsSorted;
-        uint32_t mFlags;
         sp<AMessage> mDetails;
 
         Capabilities();
@@ -93,8 +120,7 @@
     /**
      * This class is used for modifying information inside a `Capabilities`
      * object. An object of type `CapabilitiesWriter` can be obtained by calling
-     * `MediaCodecInfoWriter::addMime()` or
-     * `MediaCodecInfoWriter::updateMime()`.
+     * `MediaCodecInfoWriter::addMediaType()`.
      */
     struct CapabilitiesWriter {
         /**
@@ -122,6 +148,13 @@
          */
         void addDetail(const char* key, int32_t value);
         /**
+         * Removes a key-value pair from the list of details. If the key is not
+         * present, this call does nothing.
+         *
+         * @param key The key.
+         */
+        void removeDetail(const char* key);
+        /**
          * Add a profile-level pair. If this profile-level pair already exists,
          * it will be ignored.
          *
@@ -136,13 +169,7 @@
          * @param format The color format.
          */
         void addColorFormat(uint32_t format);
-        /**
-         * Add flags. The underlying operation is bitwise-or. In other words,
-         * bits that have already been set will be ignored.
-         *
-         * @param flags The additional flags.
-         */
-        void addFlags(uint32_t flags);
+
     private:
         /**
          * The associated `Capabilities` object.
@@ -158,19 +185,42 @@
         friend MediaCodecInfoWriter;
     };
 
-    bool isEncoder() const;
-    void getSupportedMimes(Vector<AString> *mimes) const;
-    const sp<Capabilities> getCapabilitiesFor(const char *mime) const;
+    inline bool isEncoder() const {
+        return getAttributes() & kFlagIsEncoder;
+    }
+
+    Attributes getAttributes() const;
+    void getSupportedMediaTypes(Vector<AString> *mediaTypes) const;
+    const sp<Capabilities> getCapabilitiesFor(const char *mediaType) const;
     const char *getCodecName() const;
 
     /**
+     * Returns a vector containing alternate names for the codec.
+     *
+     * \param aliases the destination array for the aliases. This is cleared.
+     *
+     * Multiple codecs may share alternate names as long as their supported media types are
+     * distinct; however, these will result in different aliases for the MediaCodec user as
+     * the canonical codec has to be resolved without knowing the media type in
+     * MediaCodec::CreateByComponentName.
+     */
+    void getAliases(Vector<AString> *aliases) const;
+
+    /**
      * Return the name of the service that hosts the codec. This value is not
      * visible at the Java level.
      *
      * Currently, this is the "instance name" of the IOmx service.
      */
     const char *getOwnerName() const;
-    uint32_t rank() const;
+
+    /**
+     * Returns the rank of the component.
+     *
+     * Technically this is defined to be per media type, but that makes ordering the MediaCodecList
+     * impossible as MediaCodecList is ordered by codec name.
+     */
+    uint32_t getRank() const;
 
     /**
      * Serialization over Binder
@@ -181,11 +231,12 @@
 private:
     AString mName;
     AString mOwner;
-    bool mIsEncoder;
+    Attributes mAttributes;
     KeyedVector<AString, sp<Capabilities> > mCaps;
+    Vector<AString> mAliases;
     uint32_t mRank;
 
-    ssize_t getCapabilityIndex(const char *mime) const;
+    ssize_t getCapabilityIndex(const char *mediaType) const;
 
     /**
      * Construct an `MediaCodecInfo` object. After the construction, its
@@ -219,6 +270,13 @@
      */
     void setName(const char* name);
     /**
+     * Adds an alias (alternate name) for the codec. Multiple codecs can share an alternate name
+     * as long as their supported media types are distinct.
+     *
+     * @param name an alternate name.
+     */
+    void addAlias(const char* name);
+    /**
      * Set the owner name of the codec.
      *
      * This "owner name" is the name of the `IOmx` instance that supports this
@@ -228,32 +286,32 @@
      */
     void setOwner(const char* owner);
     /**
-     * Set whether this codec is an encoder or a decoder.
+     * Sets codec attributes.
      *
-     * @param isEncoder Whether this codec is an encoder or a decoder.
+     * @param attributes Codec attributes.
      */
-    void setEncoder(bool isEncoder = true);
+    void setAttributes(typename std::underlying_type<MediaCodecInfo::Attributes>::type attributes);
     /**
-     * Add a mime to an indexed list and return a `CapabilitiesWriter` object
+     * Add a media type to an indexed list and return a `CapabilitiesWriter` object
      * that can be used for modifying the associated `Capabilities`.
      *
-     * If the mime already exists, this function will return the
-     * `CapabilitiesWriter` associated with the mime.
+     * If the media type already exists, this function will return the
+     * `CapabilitiesWriter` associated with the media type.
      *
-     * @param[in] mime The name of a new mime to add.
+     * @param[in] mediaType The name of a new media type to add.
      * @return writer The `CapabilitiesWriter` object for modifying the
-     * `Capabilities` associated with the mime. `writer` will be valid
-     * regardless of whether `mime` already exists or not.
+     * `Capabilities` associated with the media type. `writer` will be valid
+     * regardless of whether `mediaType` already exists or not.
      */
-    std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> addMime(
-            const char* mime);
+    std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> addMediaType(
+            const char* mediaType);
     /**
-     * Remove a mime.
+     * Remove a media type.
      *
-     * @param mime The name of the mime to remove.
-     * @return `true` if `mime` is removed; `false` if `mime` is not found.
+     * @param mediaType The name of the media type to remove.
+     * @return `true` if `mediaType` is removed; `false` if `mediaType` is not found.
      */
-    bool removeMime(const char* mime);
+    bool removeMediaType(const char* mediaType);
     /**
      * Set rank of the codec. MediaCodecList will stable-sort the list according
      * to rank in non-descending order.
diff --git a/media/libmedia/include/media/mediarecorder.h b/media/libmedia/include/media/mediarecorder.h
index caa0186..33be559 100644
--- a/media/libmedia/include/media/mediarecorder.h
+++ b/media/libmedia/include/media/mediarecorder.h
@@ -115,9 +115,6 @@
  * The state machine of the media_recorder.
  */
 enum media_recorder_states {
-    // Error state.
-    MEDIA_RECORDER_ERROR                 =      0,
-
     // Recorder was just created.
     MEDIA_RECORDER_IDLE                  = 1 << 0,
 
@@ -132,6 +129,9 @@
 
     // Recording is in progress.
     MEDIA_RECORDER_RECORDING             = 1 << 4,
+
+    // Error state.
+    MEDIA_RECORDER_ERROR                 = 1 << 5,
 };
 
 // The "msg" code passed to the listener in notify.
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
deleted file mode 100644
index 4758cd6..0000000
--- a/media/libmediaextractor/Android.bp
+++ /dev/null
@@ -1,60 +0,0 @@
-cc_library {
-    name: "libmediaextractor",
-
-    include_dirs: [
-        "frameworks/av/include",
-        "frameworks/av/media/libmediaextractor/include",
-    ],
-
-    export_include_dirs: ["include"],
-
-    cflags: [
-        "-Wno-multichar",
-        "-Werror",
-        "-Wall",
-    ],
-
-    static: {
-        cflags: [
-            "-Wno-multichar",
-            "-Werror",
-            "-Wall",
-            "-DNO_IMEMORY",
-        ],
-    },
-
-    shared_libs: [
-        "libbinder",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
-    ],
-
-    header_libs: [
-        "media_ndk_headers",
-    ],
-
-    export_header_lib_headers: [
-        "media_ndk_headers",
-    ],
-
-    srcs: [
-        "DataSourceBase.cpp",
-        "MediaBuffer.cpp",
-        "MediaBufferBase.cpp",
-        "MediaBufferGroup.cpp",
-        "MediaSource.cpp",
-        "MetaData.cpp",
-        "MetaDataBase.cpp",
-    ],
-
-    clang: true,
-
-    sanitize: {
-        misc_undefined: [
-            "unsigned-integer-overflow",
-            "signed-integer-overflow",
-        ],
-        cfi: true,
-    },
-}
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
index 54309ee..b3f7404 100644
--- a/media/libmediaplayer2/Android.bp
+++ b/media/libmediaplayer2/Android.bp
@@ -16,11 +16,11 @@
         "libandroid_runtime",
         "libaudioclient",
         "libbinder",
+        "libbinder_ndk",
         "libcutils",
         "libgui",
         "liblog",
         "libmedia_omx",
-        "libmediaextractor",
         "libstagefright_foundation",
         "libui",
         "libutils",
diff --git a/media/libmediaplayer2/JavaVMHelper.cpp b/media/libmediaplayer2/JavaVMHelper.cpp
index 90aaa7f..8d03ed0 100644
--- a/media/libmediaplayer2/JavaVMHelper.cpp
+++ b/media/libmediaplayer2/JavaVMHelper.cpp
@@ -19,6 +19,7 @@
 #include "mediaplayer2/JavaVMHelper.h"
 
 #include <media/stagefright/foundation/ADebug.h>
+#include <utils/threads.h>
 
 #include <stdlib.h>
 
@@ -27,6 +28,109 @@
 // static
 std::atomic<JavaVM *> JavaVMHelper::sJavaVM(NULL);
 
+/*
+ * Makes the current thread visible to the VM.
+ *
+ * The JNIEnv pointer returned is only valid for the current thread, and
+ * thus must be tucked into thread-local storage.
+ */
+static int javaAttachThread(const char* threadName, JNIEnv** pEnv) {
+    JavaVMAttachArgs args;
+    JavaVM* vm;
+    jint result;
+
+    vm = JavaVMHelper::getJavaVM();
+    if (vm == NULL) {
+        return JNI_ERR;
+    }
+
+    args.version = JNI_VERSION_1_4;
+    args.name = (char*) threadName;
+    args.group = NULL;
+
+    result = vm->AttachCurrentThread(pEnv, (void*) &args);
+    if (result != JNI_OK) {
+        ALOGI("NOTE: attach of thread '%s' failed\n", threadName);
+    }
+
+    return result;
+}
+
+/*
+ * Detach the current thread from the set visible to the VM.
+ */
+static int javaDetachThread(void) {
+    JavaVM* vm;
+    jint result;
+
+    vm = JavaVMHelper::getJavaVM();
+    if (vm == NULL) {
+        return JNI_ERR;
+    }
+
+    result = vm->DetachCurrentThread();
+    if (result != JNI_OK) {
+        ALOGE("ERROR: thread detach failed\n");
+    }
+    return result;
+}
+
+/*
+ * When starting a native thread that will be visible from the VM, we
+ * bounce through this to get the right attach/detach action.
+ * Note that this function calls free(args)
+ */
+static int javaThreadShell(void* args) {
+    void* start = ((void**)args)[0];
+    void* userData = ((void **)args)[1];
+    char* name = (char*) ((void **)args)[2];        // we own this storage
+    free(args);
+    JNIEnv* env;
+    int result;
+
+    /* hook us into the VM */
+    if (javaAttachThread(name, &env) != JNI_OK) {
+        return -1;
+    }
+
+    /* start the thread running */
+    result = (*(android_thread_func_t)start)(userData);
+
+    /* unhook us */
+    javaDetachThread();
+    free(name);
+
+    return result;
+}
+
+/*
+ * This is invoked from androidCreateThreadEtc() via the callback
+ * set with androidSetCreateThreadFunc().
+ *
+ * We need to create the new thread in such a way that it gets hooked
+ * into the VM before it really starts executing.
+ */
+static int javaCreateThreadEtc(
+        android_thread_func_t entryFunction,
+        void* userData,
+        const char* threadName,
+        int32_t threadPriority,
+        size_t threadStackSize,
+        android_thread_id_t* threadId) {
+    void** args = (void**) malloc(3 * sizeof(void*));   // javaThreadShell must free
+    int result;
+
+    LOG_ALWAYS_FATAL_IF(threadName == nullptr, "threadName not provided to javaCreateThreadEtc");
+
+    args[0] = (void*) entryFunction;
+    args[1] = userData;
+    args[2] = (void*) strdup(threadName);   // javaThreadShell must free
+
+    result = androidCreateRawThreadEtc(javaThreadShell, args,
+        threadName, threadPriority, threadStackSize, threadId);
+    return result;
+}
+
 // static
 JNIEnv *JavaVMHelper::getJNIEnv() {
     JNIEnv *env;
@@ -40,9 +144,19 @@
     return env;
 }
 
+//static
+JavaVM *JavaVMHelper::getJavaVM() {
+    return sJavaVM.load();
+}
+
 // static
 void JavaVMHelper::setJavaVM(JavaVM *vm) {
     sJavaVM.store(vm);
+
+    // Ensure that Thread(/*canCallJava*/ true) in libutils is attached to the VM.
+    // This is supposed to be done by runtime, but when libutils is used with linker
+    // namespace, CreateThreadFunc should be initialized separately within the namespace.
+    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
 }
 
 }  // namespace android
diff --git a/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h b/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h
index 35091b7..4b56aca 100644
--- a/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h
+++ b/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h
@@ -26,6 +26,7 @@
 
 struct JavaVMHelper {
     static JNIEnv *getJNIEnv();
+    static JavaVM *getJavaVM();
     static void setJavaVM(JavaVM *vm);
 
 private:
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
index 5e98589..0c8d016 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
@@ -30,7 +30,6 @@
 #include <media/AudioSystem.h>
 #include <media/AudioTimestamp.h>
 #include <media/BufferingSettings.h>
-#include <media/Metadata.h>
 #include <media/stagefright/foundation/AHandler.h>
 #include <mediaplayer2/MediaPlayer2Types.h>
 
@@ -224,18 +223,6 @@
     // @return OK if the call was successful.
     virtual status_t invoke(const PlayerMessage &request, PlayerMessage *reply) = 0;
 
-    // The Client in the MetadataPlayerService calls this method on
-    // the native player to retrieve all or a subset of metadata.
-    //
-    // @param ids SortedList of metadata ID to be fetch. If empty, all
-    //            the known metadata should be returned.
-    // @param[inout] records Parcel where the player appends its metadata.
-    // @return OK if the call was successful.
-    virtual status_t getMetadata(const media::Metadata::Filter& /* ids */,
-                                 Parcel* /* records */) {
-        return INVALID_OPERATION;
-    };
-
     void setListener(const sp<MediaPlayer2InterfaceListener> &listener) {
         Mutex::Autolock autoLock(mListenerLock);
         mListener = listener;
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index a945ffd..78865c4 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -20,7 +20,6 @@
 #include <media/AVSyncSettings.h>
 #include <media/AudioResamplerPublic.h>
 #include <media/BufferingSettings.h>
-#include <media/Metadata.h>
 #include <media/mediaplayer_common.h>
 #include <mediaplayer2/MediaPlayer2Interface.h>
 #include <mediaplayer2/MediaPlayer2Types.h>
@@ -55,7 +54,7 @@
 public:
     ~MediaPlayer2();
 
-    static sp<MediaPlayer2> Create(int32_t sessionId);
+    static sp<MediaPlayer2> Create(int32_t sessionId, jobject context);
     static status_t DumpAll(int fd, const Vector<String16>& args);
 
             void            disconnect();
@@ -118,7 +117,7 @@
             status_t        dump(int fd, const Vector<String16>& args);
 
 private:
-    MediaPlayer2(int32_t sessionId);
+    MediaPlayer2(int32_t sessionId, jobject context);
     bool init();
 
     // Disconnect from the currently connected ANativeWindow.
@@ -154,6 +153,7 @@
     int                         mVideoHeight;
     int32_t                     mAudioSessionId;
     sp<JObjectHolder>           mAudioAttributes;
+    sp<JObjectHolder>           mContext;
     float                       mSendLevel;
     sp<ANativeWindowWrapper>    mConnectedWindow;
 };
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index f432059..f75380c 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -18,14 +18,11 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaPlayer2Native"
 
-#include <binder/IServiceManager.h>
-#include <binder/IPCThreadState.h>
-
+#include <android/binder_ibinder.h>
 #include <media/AudioSystem.h>
 #include <media/DataSourceDesc.h>
 #include <media/MediaAnalyticsItem.h>
 #include <media/MemoryLeakTrackUtil.h>
-#include <media/Metadata.h>
 #include <media/NdkWrapper.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooperRoster.h>
@@ -103,114 +100,110 @@
     String8 result;
     SortedVector< sp<MediaPlayer2> > players; //to serialise the mutex unlock & client destruction.
 
-    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
-        snprintf(buffer, SIZE, "Permission Denial: can't dump MediaPlayer2\n");
-        result.append(buffer);
+    {
+        Mutex::Autolock lock(sRecordLock);
+        ensureInit_l();
+        for (int i = 0, n = sPlayers->size(); i < n; ++i) {
+            sp<MediaPlayer2> p = (*sPlayers)[i].promote();
+            if (p != 0) {
+                p->dump(fd, args);
+            }
+            players.add(p);
+        }
+    }
+
+    result.append(" Files opened and/or mapped:\n");
+    snprintf(buffer, SIZE, "/proc/%d/maps", getpid());
+    FILE *f = fopen(buffer, "r");
+    if (f) {
+        while (!feof(f)) {
+            fgets(buffer, SIZE, f);
+            if (strstr(buffer, " /storage/") ||
+                strstr(buffer, " /system/sounds/") ||
+                strstr(buffer, " /data/") ||
+                strstr(buffer, " /system/media/")) {
+                result.append("  ");
+                result.append(buffer);
+            }
+        }
+        fclose(f);
     } else {
-        {
-            Mutex::Autolock lock(sRecordLock);
-            ensureInit_l();
-            for (int i = 0, n = sPlayers->size(); i < n; ++i) {
-                sp<MediaPlayer2> p = (*sPlayers)[i].promote();
-                if (p != 0) {
-                    p->dump(fd, args);
-                }
-                players.add(p);
-            }
-        }
+        result.append("couldn't open ");
+        result.append(buffer);
+        result.append("\n");
+    }
 
-        result.append(" Files opened and/or mapped:\n");
-        snprintf(buffer, SIZE, "/proc/%d/maps", getpid());
-        FILE *f = fopen(buffer, "r");
-        if (f) {
-            while (!feof(f)) {
-                fgets(buffer, SIZE, f);
-                if (strstr(buffer, " /storage/") ||
-                    strstr(buffer, " /system/sounds/") ||
-                    strstr(buffer, " /data/") ||
-                    strstr(buffer, " /system/media/")) {
-                    result.append("  ");
-                    result.append(buffer);
-                }
-            }
-            fclose(f);
-        } else {
-            result.append("couldn't open ");
-            result.append(buffer);
-            result.append("\n");
-        }
-
-        snprintf(buffer, SIZE, "/proc/%d/fd", getpid());
-        DIR *d = opendir(buffer);
-        if (d) {
-            struct dirent *ent;
-            while((ent = readdir(d)) != NULL) {
-                if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
-                    snprintf(buffer, SIZE, "/proc/%d/fd/%s", getpid(), ent->d_name);
-                    struct stat s;
-                    if (lstat(buffer, &s) == 0) {
-                        if ((s.st_mode & S_IFMT) == S_IFLNK) {
-                            char linkto[256];
-                            int len = readlink(buffer, linkto, sizeof(linkto));
-                            if(len > 0) {
-                                if(len > 255) {
-                                    linkto[252] = '.';
-                                    linkto[253] = '.';
-                                    linkto[254] = '.';
-                                    linkto[255] = 0;
-                                } else {
-                                    linkto[len] = 0;
-                                }
-                                if (strstr(linkto, "/storage/") == linkto ||
-                                    strstr(linkto, "/system/sounds/") == linkto ||
-                                    strstr(linkto, "/data/") == linkto ||
-                                    strstr(linkto, "/system/media/") == linkto) {
-                                    result.append("  ");
-                                    result.append(buffer);
-                                    result.append(" -> ");
-                                    result.append(linkto);
-                                    result.append("\n");
-                                }
+    snprintf(buffer, SIZE, "/proc/%d/fd", getpid());
+    DIR *d = opendir(buffer);
+    if (d) {
+        struct dirent *ent;
+        while((ent = readdir(d)) != NULL) {
+            if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
+                snprintf(buffer, SIZE, "/proc/%d/fd/%s", getpid(), ent->d_name);
+                struct stat s;
+                if (lstat(buffer, &s) == 0) {
+                    if ((s.st_mode & S_IFMT) == S_IFLNK) {
+                        char linkto[256];
+                        int len = readlink(buffer, linkto, sizeof(linkto));
+                        if(len > 0) {
+                            if(len > 255) {
+                                linkto[252] = '.';
+                                linkto[253] = '.';
+                                linkto[254] = '.';
+                                linkto[255] = 0;
+                            } else {
+                                linkto[len] = 0;
                             }
-                        } else {
-                            result.append("  unexpected type for ");
-                            result.append(buffer);
-                            result.append("\n");
+                            if (strstr(linkto, "/storage/") == linkto ||
+                                strstr(linkto, "/system/sounds/") == linkto ||
+                                strstr(linkto, "/data/") == linkto ||
+                                strstr(linkto, "/system/media/") == linkto) {
+                                result.append("  ");
+                                result.append(buffer);
+                                result.append(" -> ");
+                                result.append(linkto);
+                                result.append("\n");
+                            }
                         }
+                    } else {
+                        result.append("  unexpected type for ");
+                        result.append(buffer);
+                        result.append("\n");
                     }
                 }
             }
-            closedir(d);
-        } else {
-            result.append("couldn't open ");
-            result.append(buffer);
-            result.append("\n");
         }
+        closedir(d);
+    } else {
+        result.append("couldn't open ");
+        result.append(buffer);
+        result.append("\n");
+    }
 
-        gLooperRoster.dump(fd, args);
+    gLooperRoster.dump(fd, args);
 
-        bool dumpMem = false;
-        bool unreachableMemory = false;
-        for (size_t i = 0; i < args.size(); i++) {
-            if (args[i] == String16("-m")) {
-                dumpMem = true;
-            } else if (args[i] == String16("--unreachable")) {
-                unreachableMemory = true;
-            }
-        }
-        if (dumpMem) {
-            result.append("\nDumping memory:\n");
-            std::string s = dumpMemoryAddresses(100 /* limit */);
-            result.append(s.c_str(), s.size());
-        }
-        if (unreachableMemory) {
-            result.append("\nDumping unreachable memory:\n");
-            // TODO - should limit be an argument parameter?
-            // TODO: enable GetUnreachableMemoryString if it's part of stable API
-            //std::string s = GetUnreachableMemoryString(true /* contents */, 10000 /* limit */);
-            //result.append(s.c_str(), s.size());
+    bool dumpMem = false;
+    bool unreachableMemory = false;
+    for (size_t i = 0; i < args.size(); i++) {
+        if (args[i] == String16("-m")) {
+            dumpMem = true;
+        } else if (args[i] == String16("--unreachable")) {
+            unreachableMemory = true;
         }
     }
+    if (dumpMem) {
+        result.append("\nDumping memory:\n");
+        std::string s = dumpMemoryAddresses(100 /* limit */);
+        result.append(s.c_str(), s.size());
+    }
+    if (unreachableMemory) {
+        result.append("\nDumping unreachable memory:\n");
+        // TODO - should limit be an argument parameter?
+        // TODO: enable GetUnreachableMemoryString if it's part of stable API
+        //std::string s = GetUnreachableMemoryString(true /* contents */, 10000 /* limit */);
+        //result.append(s.c_str(), s.size());
+    }
+
     write(fd, result.string(), result.size());
     return NO_ERROR;
 }
@@ -218,8 +211,8 @@
 }  // anonymous namespace
 
 //static
-sp<MediaPlayer2> MediaPlayer2::Create(int32_t sessionId) {
-    sp<MediaPlayer2> player = new MediaPlayer2(sessionId);
+sp<MediaPlayer2> MediaPlayer2::Create(int32_t sessionId, jobject context) {
+    sp<MediaPlayer2> player = new MediaPlayer2(sessionId, context);
 
     if (!player->init()) {
         return NULL;
@@ -236,13 +229,14 @@
     return dumpPlayers(fd, args);
 }
 
-MediaPlayer2::MediaPlayer2(int32_t sessionId) {
+MediaPlayer2::MediaPlayer2(int32_t sessionId, jobject context) {
     ALOGV("constructor");
     mSrcId = 0;
     mLockThreadId = 0;
     mListener = NULL;
     mStreamType = AUDIO_STREAM_MUSIC;
     mAudioAttributes = NULL;
+    mContext = new JObjectHolder(context);
     mCurrentPosition = -1;
     mCurrentSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
     mSeekPosition = -1;
@@ -253,9 +247,8 @@
     mVideoWidth = mVideoHeight = 0;
     mSendLevel = 0;
 
-    // TODO: get pid and uid from JAVA
-    mPid = IPCThreadState::self()->getCallingPid();
-    mUid = IPCThreadState::self()->getCallingUid();
+    mPid = AIBinder_getCallingPid();
+    mUid = AIBinder_getCallingUid();
 
     mAudioOutput = new MediaPlayer2AudioOutput(sessionId, mUid, mPid, NULL /*attributes*/);
 }
@@ -334,15 +327,15 @@
 
     sp<MediaPlayer2Interface> oldPlayer;
 
-    Mutex::Autolock _l(mLock);
     {
+        Mutex::Autolock _l(mLock);
         if (!((mCurrentState & MEDIA_PLAYER2_IDLE)
               || mCurrentState == MEDIA_PLAYER2_STATE_ERROR)) {
             ALOGE("setDataSource called in wrong state %d", mCurrentState);
             return INVALID_OPERATION;
         }
 
-        sp<MediaPlayer2Interface> player = new NuPlayer2Driver(mPid, mUid);
+        sp<MediaPlayer2Interface> player = new NuPlayer2Driver(mPid, mUid, mContext);
         status_t err = player->initCheck();
         if (err != NO_ERROR) {
             ALOGE("Failed to create player object, initCheck failed(%d)", err);
diff --git a/media/libmediaplayer2/nuplayer2/JWakeLock.cpp b/media/libmediaplayer2/nuplayer2/JWakeLock.cpp
index c9a1071..983d77e 100644
--- a/media/libmediaplayer2/nuplayer2/JWakeLock.cpp
+++ b/media/libmediaplayer2/nuplayer2/JWakeLock.cpp
@@ -20,55 +20,50 @@
 
 #include "JWakeLock.h"
 
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <powermanager/PowerManager.h>
-
 
 namespace android {
 
-//TODO: use JAVA PowerManager, instead of binder
-JWakeLock::JWakeLock() :
-    mPowerManager(NULL),
-    mWakeLockToken(NULL),
+JWakeLock::JWakeLock(const sp<JObjectHolder> &context) :
     mWakeLockCount(0),
-    mDeathRecipient(new PMDeathRecipient(this)) {}
+    mWakeLock(NULL),
+    mContext(context) {}
 
 JWakeLock::~JWakeLock() {
-    if (mPowerManager != NULL) {
-        sp<IBinder> binder = IInterface::asBinder(mPowerManager);
-        binder->unlinkToDeath(mDeathRecipient);
-    }
-    clearPowerManager();
+    clearJavaWakeLock();
 }
 
 bool JWakeLock::acquire() {
     if (mWakeLockCount == 0) {
-        CHECK(mWakeLockToken == NULL);
-        if (mPowerManager == NULL) {
-            // use checkService() to avoid blocking if power service is not up yet
-            sp<IBinder> binder =
-                defaultServiceManager()->checkService(String16("power"));
-            if (binder == NULL) {
-                ALOGW("could not get the power manager service");
-            } else {
-                mPowerManager = interface_cast<IPowerManager>(binder);
-                binder->linkToDeath(mDeathRecipient);
-            }
+        if (mWakeLock == NULL) {
+            JNIEnv *env = JavaVMHelper::getJNIEnv();
+            jclass jContextCls = env->FindClass("android/content/Context");
+            jclass jPowerManagerCls = env->FindClass("android/os/PowerManager");
+
+            jmethodID jGetSystemService = env->GetMethodID(jContextCls,
+                    "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
+            jobject javaPowerManagerObj = env->CallObjectMethod(mContext->getJObject(),
+                    jGetSystemService, env->NewStringUTF("power"));
+
+            jfieldID jPARTIAL_WAKE_LOCK = env->GetStaticFieldID(jPowerManagerCls,
+                    "PARTIAL_WAKE_LOCK", "I");
+            jint PARTIAL_WAKE_LOCK = env->GetStaticIntField(jPowerManagerCls, jPARTIAL_WAKE_LOCK);
+
+            jmethodID jNewWakeLock = env->GetMethodID(jPowerManagerCls,
+                    "newWakeLock", "(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;");
+            jobject javaWakeLock = env->CallObjectMethod(javaPowerManagerObj,
+                    jNewWakeLock, PARTIAL_WAKE_LOCK, env->NewStringUTF("JWakeLock"));
+            mWakeLock = new JObjectHolder(javaWakeLock);
+            env->DeleteLocalRef(javaPowerManagerObj);
+            env->DeleteLocalRef(javaWakeLock);
         }
-        if (mPowerManager != NULL) {
-            sp<IBinder> binder = new BBinder();
-            int64_t token = IPCThreadState::self()->clearCallingIdentity();
-            status_t status = mPowerManager->acquireWakeLock(
-                    POWERMANAGER_PARTIAL_WAKE_LOCK,
-                    binder, String16("JWakeLock"), String16("media"));
-            IPCThreadState::self()->restoreCallingIdentity(token);
-            if (status == NO_ERROR) {
-                mWakeLockToken = binder;
-                mWakeLockCount++;
-                return true;
-            }
+        if (mWakeLock != NULL) {
+            JNIEnv *env = JavaVMHelper::getJNIEnv();
+            jclass wakeLockCls = env->FindClass("android/os/PowerManager$WakeLock");
+            jmethodID jAcquire = env->GetMethodID(wakeLockCls, "acquire", "()V");
+            env->CallVoidMethod(mWakeLock->getJObject(), jAcquire);
+            mWakeLockCount++;
+            return true;
         }
     } else {
         mWakeLockCount++;
@@ -86,25 +81,17 @@
         mWakeLockCount = 1;
     }
     if (--mWakeLockCount == 0) {
-        CHECK(mWakeLockToken != NULL);
-        if (mPowerManager != NULL) {
-            int64_t token = IPCThreadState::self()->clearCallingIdentity();
-            mPowerManager->releaseWakeLock(mWakeLockToken, 0 /* flags */);
-            IPCThreadState::self()->restoreCallingIdentity(token);
+        if (mWakeLock != NULL) {
+            JNIEnv *env = JavaVMHelper::getJNIEnv();
+            jclass wakeLockCls = env->FindClass("android/os/PowerManager$WakeLock");
+            jmethodID jRelease = env->GetMethodID(wakeLockCls, "release", "()V");
+            env->CallVoidMethod(mWakeLock->getJObject(), jRelease);
         }
-        mWakeLockToken.clear();
     }
 }
 
-void JWakeLock::clearPowerManager() {
+void JWakeLock::clearJavaWakeLock() {
     release(true);
-    mPowerManager.clear();
-}
-
-void JWakeLock::PMDeathRecipient::binderDied(const wp<IBinder>& who __unused) {
-    if (mWakeLock != NULL) {
-        mWakeLock->clearPowerManager();
-    }
 }
 
 }  // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/JWakeLock.h b/media/libmediaplayer2/nuplayer2/JWakeLock.h
index eace87e..36c542e 100644
--- a/media/libmediaplayer2/nuplayer2/JWakeLock.h
+++ b/media/libmediaplayer2/nuplayer2/JWakeLock.h
@@ -18,7 +18,7 @@
 #define J_WAKELOCK_H_
 
 #include <media/stagefright/foundation/ABase.h>
-#include <powermanager/IPowerManager.h>
+#include <mediaplayer2/JObjectHolder.h>
 #include <utils/RefBase.h>
 
 namespace android {
@@ -26,7 +26,7 @@
 class JWakeLock : public RefBase {
 
 public:
-    JWakeLock();
+    JWakeLock(const sp<JObjectHolder> &context);
 
     // NOTE: acquire and release are not thread safe
 
@@ -37,28 +37,11 @@
     virtual ~JWakeLock();
 
 private:
-    sp<IPowerManager> mPowerManager;
-    sp<IBinder>       mWakeLockToken;
-    uint32_t          mWakeLockCount;
+    uint32_t                mWakeLockCount;
+    sp<JObjectHolder>       mWakeLock;
+    const sp<JObjectHolder> mContext;
 
-    class PMDeathRecipient : public IBinder::DeathRecipient {
-    public:
-        explicit PMDeathRecipient(JWakeLock *wakeLock) : mWakeLock(wakeLock) {}
-        virtual ~PMDeathRecipient() {}
-
-        // IBinder::DeathRecipient
-        virtual void binderDied(const wp<IBinder> &who);
-
-    private:
-        PMDeathRecipient(const PMDeathRecipient&);
-        PMDeathRecipient& operator= (const PMDeathRecipient&);
-
-        JWakeLock *mWakeLock;
-    };
-
-    const sp<PMDeathRecipient> mDeathRecipient;
-
-    void clearPowerManager();
+    void clearJavaWakeLock();
 
     DISALLOW_EVIL_CONSTRUCTORS(JWakeLock);
 };
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 080d923..5da6e24 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -209,7 +209,8 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-NuPlayer2::NuPlayer2(pid_t pid, uid_t uid, const sp<MediaClock> &mediaClock)
+NuPlayer2::NuPlayer2(
+        pid_t pid, uid_t uid, const sp<MediaClock> &mediaClock, const sp<JObjectHolder> &context)
     : mPID(pid),
       mUID(uid),
       mMediaClock(mediaClock),
@@ -240,7 +241,8 @@
       mVideoDecoderError(false),
       mPaused(false),
       mPausedByClient(true),
-      mPausedForBuffering(false) {
+      mPausedForBuffering(false),
+      mContext(context) {
     CHECK(mediaClock != NULL);
     clearFlushComplete();
 }
@@ -1738,7 +1740,7 @@
     sp<AMessage> notify = new AMessage(kWhatRendererNotify, this);
     ++mRendererGeneration;
     notify->setInt32("generation", mRendererGeneration);
-    mRenderer = new Renderer(mAudioSink, mMediaClock, notify, flags);
+    mRenderer = new Renderer(mAudioSink, mMediaClock, notify, mContext, flags);
     mRendererLooper = new ALooper;
     mRendererLooper->setName("NuPlayer2Renderer");
     mRendererLooper->start(false, true, ANDROID_PRIORITY_AUDIO);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
index fdc128f..798c725 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
@@ -22,6 +22,7 @@
 #include <media/stagefright/foundation/AHandler.h>
 
 #include <mediaplayer2/MediaPlayer2Interface.h>
+#include <mediaplayer2/JObjectHolder.h>
 
 #include "mediaplayer2.pb.h"
 
@@ -42,7 +43,8 @@
 struct NuPlayer2Driver;
 
 struct NuPlayer2 : public AHandler {
-    explicit NuPlayer2(pid_t pid, uid_t uid, const sp<MediaClock> &mediaClock);
+    explicit NuPlayer2(pid_t pid, uid_t uid,
+            const sp<MediaClock> &mediaClock, const sp<JObjectHolder> &context);
 
     void setDriver(const wp<NuPlayer2Driver> &driver);
 
@@ -272,6 +274,9 @@
     // Pause state as requested by source (internally) due to buffering
     bool mPausedForBuffering;
 
+    // Passed from JAVA
+    const sp<JObjectHolder> mContext;
+
     inline const sp<DecoderBase> &getDecoder(bool audio) {
         return audio ? mAudioDecoder : mVideoDecoder;
     }
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index 2dab2dd..56e9471 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -108,7 +108,7 @@
 static const char *kPlayerRebufferingAtExit = "android.media.mediaplayer.rebufferExit";
 
 
-NuPlayer2Driver::NuPlayer2Driver(pid_t pid, uid_t uid)
+NuPlayer2Driver::NuPlayer2Driver(pid_t pid, uid_t uid, const sp<JObjectHolder> &context)
     : mState(STATE_IDLE),
       mAsyncResult(UNKNOWN_ERROR),
       mSrcId(0),
@@ -123,7 +123,7 @@
       mLooper(new ALooper),
       mNuPlayer2Looper(new ALooper),
       mMediaClock(new MediaClock),
-      mPlayer(new NuPlayer2(pid, uid, mMediaClock)),
+      mPlayer(new NuPlayer2(pid, uid, mMediaClock, context)),
       mPlayerFlags(0),
       mAnalyticsItem(NULL),
       mClientUid(uid),
@@ -662,33 +662,6 @@
     return INVALID_OPERATION;
 }
 
-status_t NuPlayer2Driver::getMetadata(
-        const media::Metadata::Filter& /* ids */, Parcel *records) {
-    Mutex::Autolock autoLock(mLock);
-
-    using media::Metadata;
-
-    Metadata meta(records);
-
-    meta.appendBool(
-            Metadata::kPauseAvailable,
-            mPlayerFlags & NuPlayer2::Source::FLAG_CAN_PAUSE);
-
-    meta.appendBool(
-            Metadata::kSeekBackwardAvailable,
-            mPlayerFlags & NuPlayer2::Source::FLAG_CAN_SEEK_BACKWARD);
-
-    meta.appendBool(
-            Metadata::kSeekForwardAvailable,
-            mPlayerFlags & NuPlayer2::Source::FLAG_CAN_SEEK_FORWARD);
-
-    meta.appendBool(
-            Metadata::kSeekAvailable,
-            mPlayerFlags & NuPlayer2::Source::FLAG_CAN_SEEK);
-
-    return OK;
-}
-
 void NuPlayer2Driver::notifyResetComplete(int64_t /* srcId */) {
     ALOGD("notifyResetComplete(%p)", this);
     Mutex::Autolock autoLock(mLock);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
index bb30c76..0ec3a4b 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
@@ -18,6 +18,7 @@
 
 #include <media/MediaAnalyticsItem.h>
 #include <media/stagefright/foundation/ABase.h>
+#include <mediaplayer2/JObjectHolder.h>
 
 namespace android {
 
@@ -26,7 +27,7 @@
 struct NuPlayer2;
 
 struct NuPlayer2Driver : public MediaPlayer2Interface {
-    explicit NuPlayer2Driver(pid_t pid, uid_t uid);
+    explicit NuPlayer2Driver(pid_t pid, uid_t uid, const sp<JObjectHolder> &context);
 
     virtual status_t initCheck() override;
 
@@ -61,9 +62,6 @@
     virtual status_t setParameter(int key, const Parcel &request) override;
     virtual status_t getParameter(int key, Parcel *reply) override;
 
-    virtual status_t getMetadata(
-            const media::Metadata::Filter& ids, Parcel *records) override;
-
     virtual status_t dump(int fd, const Vector<String16> &args) const override;
 
     virtual void onMessageReceived(const sp<AMessage> &msg) override;
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
index e3c9b4b..3be7e36 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
@@ -26,6 +26,8 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/MediaClock.h>
+#include <media/stagefright/MediaCodecConstants.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/Utils.h>
 #include <media/stagefright/VideoFrameScheduler2.h>
@@ -86,10 +88,25 @@
 // static
 const int64_t NuPlayer2::Renderer::kMinPositionUpdateDelayUs = 100000LL;
 
+static audio_format_t constexpr audioFormatFromEncoding(int32_t pcmEncoding) {
+    switch (pcmEncoding) {
+    case kAudioEncodingPcmFloat:
+        return AUDIO_FORMAT_PCM_FLOAT;
+    case kAudioEncodingPcm16bit:
+        return AUDIO_FORMAT_PCM_16_BIT;
+    case kAudioEncodingPcm8bit:
+        return AUDIO_FORMAT_PCM_8_BIT;  // TODO: do we want to support this?
+    default:
+        ALOGE("%s: Invalid encoding: %d", __func__, pcmEncoding);
+        return AUDIO_FORMAT_INVALID;
+    }
+}
+
 NuPlayer2::Renderer::Renderer(
         const sp<MediaPlayer2Interface::AudioSink> &sink,
         const sp<MediaClock> &mediaClock,
         const sp<AMessage> &notify,
+        const sp<JObjectHolder> &context,
         uint32_t flags)
     : mAudioSink(sink),
       mUseVirtualAudioSink(false),
@@ -131,7 +148,7 @@
       mTotalBuffersQueued(0),
       mLastAudioBufferDrained(0),
       mUseAudioCallback(false),
-      mWakeLock(new JWakeLock()) {
+      mWakeLock(new JWakeLock(context)) {
     CHECK(mediaClock != NULL);
     mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
 }
@@ -1269,10 +1286,10 @@
             mAnchorTimeMediaUs = mediaTimeUs;
         }
     }
-    mNextVideoTimeMediaUs = mediaTimeUs + 100000;
+    mNextVideoTimeMediaUs = mediaTimeUs;
     if (!mHasAudio) {
         // smooth out videos >= 10fps
-        mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
+        mMediaClock->updateMaxTimeMedia(mediaTimeUs + 100000);
     }
 
     if (!mVideoSampleReceived || mediaTimeUs < mAudioFirstAnchorTimeMediaUs) {
@@ -1406,9 +1423,15 @@
         mHasAudio = false;
         if (mNextVideoTimeMediaUs >= 0) {
             int64_t mediaUs = 0;
-            mMediaClock->getMediaTime(ALooper::GetNowUs(), &mediaUs);
-            if (mNextVideoTimeMediaUs > mediaUs) {
-                mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
+            int64_t nowUs = ALooper::GetNowUs();
+            status_t result = mMediaClock->getMediaTime(nowUs, &mediaUs);
+            if (result == OK) {
+                if (mNextVideoTimeMediaUs > mediaUs) {
+                    mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
+                }
+            } else {
+                mMediaClock->updateAnchor(
+                        mNextVideoTimeMediaUs, nowUs, mNextVideoTimeMediaUs + 100000);
             }
         }
     }
@@ -1864,8 +1887,13 @@
     int32_t sampleRate;
     CHECK(format->findInt32("sample-rate", &sampleRate));
 
+    // read pcm encoding from MediaCodec output format, if available
+    int32_t pcmEncoding;
+    audio_format_t audioFormat =
+            format->findInt32(KEY_PCM_ENCODING, &pcmEncoding) ?
+                    audioFormatFromEncoding(pcmEncoding) : AUDIO_FORMAT_PCM_16_BIT;
+
     if (offloadingAudio()) {
-        audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
         AString mime;
         CHECK(format->findString("mime", &mime));
         status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str());
@@ -1966,7 +1994,7 @@
         const PcmInfo info = {
                 (audio_channel_mask_t)channelMask,
                 (audio_output_flags_t)pcmFlags,
-                AUDIO_FORMAT_PCM_16_BIT, // TODO: change to audioFormat
+                audioFormat,
                 numChannels,
                 sampleRate
         };
@@ -1998,7 +2026,7 @@
                     sampleRate,
                     numChannels,
                     (audio_channel_mask_t)channelMask,
-                    AUDIO_FORMAT_PCM_16_BIT,
+                    audioFormat,
                     mUseAudioCallback ? &NuPlayer2::Renderer::AudioSinkCallback : NULL,
                     mUseAudioCallback ? this : NULL,
                     (audio_output_flags_t)pcmFlags,
@@ -2054,4 +2082,3 @@
 }
 
 }  // namespace android
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
index 484d9b7..d065dee 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
@@ -20,6 +20,7 @@
 
 #include <media/AudioResamplerPublic.h>
 #include <media/AVSyncSettings.h>
+#include <mediaplayer2/JObjectHolder.h>
 
 #include "NuPlayer2.h"
 
@@ -38,6 +39,7 @@
     Renderer(const sp<MediaPlayer2Interface::AudioSink> &sink,
              const sp<MediaClock> &mediaClock,
              const sp<AMessage> &notify,
+             const sp<JObjectHolder> &context,
              uint32_t flags = 0);
 
     static size_t AudioSinkCallback(
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 51879fd..55867a5 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -24,7 +24,6 @@
         "liblog",
         "libmedia",
         "libmedia_omx",
-        "libmediaextractor",
         "libmediadrm",
         "libmediametrics",
         "libmediautils",
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index e2aa8f8..1e85804 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -171,6 +171,7 @@
 
     if (extractor == NULL) {
         ALOGE("initFromDataSource, cannot create extractor!");
+        mLock.lock();
         return UNKNOWN_ERROR;
     }
 
@@ -179,6 +180,7 @@
     size_t numtracks = extractor->countTracks();
     if (numtracks == 0) {
         ALOGE("initFromDataSource, source has no track!");
+        mLock.lock();
         return UNKNOWN_ERROR;
     }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index c8f6738..c990b2a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -1299,10 +1299,10 @@
             mAnchorTimeMediaUs = mediaTimeUs;
         }
     }
-    mNextVideoTimeMediaUs = mediaTimeUs + 100000;
+    mNextVideoTimeMediaUs = mediaTimeUs;
     if (!mHasAudio) {
         // smooth out videos >= 10fps
-        mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
+        mMediaClock->updateMaxTimeMedia(mediaTimeUs + 100000);
     }
 
     if (!mVideoSampleReceived || mediaTimeUs < mAudioFirstAnchorTimeMediaUs) {
@@ -1436,9 +1436,15 @@
         mHasAudio = false;
         if (mNextVideoTimeMediaUs >= 0) {
             int64_t mediaUs = 0;
-            mMediaClock->getMediaTime(ALooper::GetNowUs(), &mediaUs);
-            if (mNextVideoTimeMediaUs > mediaUs) {
-                mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
+            int64_t nowUs = ALooper::GetNowUs();
+            status_t result = mMediaClock->getMediaTime(nowUs, &mediaUs);
+            if (result == OK) {
+                if (mNextVideoTimeMediaUs > mediaUs) {
+                    mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
+                }
+            } else {
+                mMediaClock->updateAnchor(
+                        mNextVideoTimeMediaUs, nowUs, mNextVideoTimeMediaUs + 100000);
             }
         }
     }
diff --git a/media/libnblog/Reader.cpp b/media/libnblog/Reader.cpp
index fd53090..f556e37 100644
--- a/media/libnblog/Reader.cpp
+++ b/media/libnblog/Reader.cpp
@@ -284,6 +284,15 @@
 EntryIterator DumpReader::handleFormat(const FormatEntry &fmtEntry,
         String8 *timestamp, String8 *body)
 {
+    String8 timestampLocal;
+    String8 bodyLocal;
+    if (timestamp == nullptr) {
+        timestamp = &timestampLocal;
+    }
+    if (body == nullptr) {
+        body = &bodyLocal;
+    }
+
     // log timestamp
     const int64_t ts = fmtEntry.timestamp();
     timestamp->clear();
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 60b236d..a1a2660 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -566,8 +566,8 @@
       mDequeueCounter(0),
       mMetadataBuffersToSubmit(0),
       mNumUndequeuedBuffers(0),
-      mRepeatFrameDelayUs(-1ll),
-      mMaxPtsGapUs(0ll),
+      mRepeatFrameDelayUs(-1LL),
+      mMaxPtsGapUs(0LL),
       mMaxFps(-1),
       mFps(-1.0),
       mCaptureFps(-1.0),
@@ -1822,15 +1822,15 @@
         if (!msg->findInt64(
                     "repeat-previous-frame-after",
                     &mRepeatFrameDelayUs)) {
-            mRepeatFrameDelayUs = -1ll;
+            mRepeatFrameDelayUs = -1LL;
         }
 
         // only allow 32-bit value, since we pass it as U32 to OMX.
         if (!msg->findInt64("max-pts-gap-to-encoder", &mMaxPtsGapUs)) {
-            mMaxPtsGapUs = 0ll;
+            mMaxPtsGapUs = 0LL;
         } else if (mMaxPtsGapUs > INT32_MAX || mMaxPtsGapUs < INT32_MIN) {
             ALOGW("Unsupported value for max pts gap %lld", (long long) mMaxPtsGapUs);
-            mMaxPtsGapUs = 0ll;
+            mMaxPtsGapUs = 0LL;
         }
 
         if (!msg->findFloat("max-fps-to-encoder", &mMaxFps)) {
@@ -1838,7 +1838,7 @@
         }
 
         // notify GraphicBufferSource to allow backward frames
-        if (mMaxPtsGapUs < 0ll) {
+        if (mMaxPtsGapUs < 0LL) {
             mMaxFps = -1;
         }
 
@@ -2183,7 +2183,8 @@
             err = setupG711Codec(encoder, sampleRate, numChannels);
         }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
-        int32_t numChannels = 0, sampleRate = 0, compressionLevel = -1;
+        // numChannels needs to be set to properly communicate PCM values.
+        int32_t numChannels = 2, sampleRate = 44100, compressionLevel = -1;
         if (encoder &&
                 (!msg->findInt32("channel-count", &numChannels)
                         || !msg->findInt32("sample-rate", &sampleRate))) {
@@ -2209,7 +2210,7 @@
                 }
             }
             err = setupFlacCodec(
-                    encoder, numChannels, sampleRate, compressionLevel);
+                    encoder, numChannels, sampleRate, compressionLevel, pcmEncoding);
         }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
         int32_t numChannels, sampleRate;
@@ -2320,12 +2321,16 @@
             (void)mInputFormat->findInt32("pcm-encoding", (int32_t*)&codecPcmEncoding);
             mConverter[kPortIndexInput] = AudioConverter::Create(pcmEncoding, codecPcmEncoding);
             if (mConverter[kPortIndexInput] != NULL) {
+                ALOGD("%s: encoder %s input format pcm encoding converter from %d to %d",
+                        __func__, mComponentName.c_str(), pcmEncoding, codecPcmEncoding);
                 mInputFormat->setInt32("pcm-encoding", pcmEncoding);
             }
         } else {
             (void)mOutputFormat->findInt32("pcm-encoding", (int32_t*)&codecPcmEncoding);
             mConverter[kPortIndexOutput] = AudioConverter::Create(codecPcmEncoding, pcmEncoding);
             if (mConverter[kPortIndexOutput] != NULL) {
+                ALOGD("%s: decoder %s output format pcm encoding converter from %d to %d",
+                        __func__, mComponentName.c_str(), codecPcmEncoding, pcmEncoding);
                 mOutputFormat->setInt32("pcm-encoding", pcmEncoding);
             }
         }
@@ -3029,8 +3034,8 @@
 }
 
 status_t ACodec::setupFlacCodec(
-        bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel) {
-
+        bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel,
+        AudioEncoding encoding) {
     if (encoder) {
         OMX_AUDIO_PARAM_FLACTYPE def;
         InitOMXParams(&def);
@@ -3053,7 +3058,8 @@
     return setupRawAudioFormat(
             encoder ? kPortIndexInput : kPortIndexOutput,
             sampleRate,
-            numChannels);
+            numChannels,
+            encoding);
 }
 
 status_t ACodec::setupRawAudioFormat(
@@ -3111,6 +3117,7 @@
     pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
 
     if (getOMXChannelMapping(numChannels, pcmParams.eChannelMapping) != OK) {
+        ALOGE("%s: incorrect numChannels: %d", __func__, numChannels);
         return OMX_ErrorNone;
     }
 
@@ -6700,7 +6707,7 @@
 
     mCodec->mDequeueCounter = 0;
     mCodec->mMetadataBuffersToSubmit = 0;
-    mCodec->mRepeatFrameDelayUs = -1ll;
+    mCodec->mRepeatFrameDelayUs = -1LL;
     mCodec->mInputFormat.clear();
     mCodec->mOutputFormat.clear();
     mCodec->mBaseOutputFormat.clear();
@@ -6842,7 +6849,7 @@
         return err;
     }
 
-    if (mCodec->mRepeatFrameDelayUs > 0ll) {
+    if (mCodec->mRepeatFrameDelayUs > 0LL) {
         err = statusFromBinderStatus(
                 mCodec->mGraphicBufferSource->setRepeatPreviousFrameDelayUs(
                         mCodec->mRepeatFrameDelayUs));
@@ -6855,7 +6862,7 @@
         }
     }
 
-    if (mCodec->mMaxPtsGapUs != 0ll) {
+    if (mCodec->mMaxPtsGapUs != 0LL) {
         OMX_PARAM_U32TYPE maxPtsGapParams;
         InitOMXParams(&maxPtsGapParams);
         maxPtsGapParams.nPortIndex = kPortIndexInput;
@@ -8675,14 +8682,17 @@
         if (omxNode->configureVideoTunnelMode(
                 kPortIndexOutput, OMX_TRUE, 0, &sidebandHandle) == OK) {
             // tunneled playback includes adaptive playback
-            caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback
-                    | MediaCodecInfo::Capabilities::kFlagSupportsTunneledPlayback);
-        } else if (omxNode->setPortMode(
-                kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer) == OK ||
-                omxNode->prepareForAdaptivePlayback(
-                kPortIndexOutput, OMX_TRUE,
-                1280 /* width */, 720 /* height */) == OK) {
-            caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback);
+        } else {
+            // tunneled playback is not supported
+            caps->removeDetail(MediaCodecInfo::Capabilities::FEATURE_TUNNELED_PLAYBACK);
+            if (omxNode->setPortMode(
+                    kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer) != OK &&
+                    omxNode->prepareForAdaptivePlayback(
+                        kPortIndexOutput, OMX_TRUE,
+                        1280 /* width */, 720 /* height */) != OK) {
+                // adaptive playback is not supported
+                caps->removeDetail(MediaCodecInfo::Capabilities::FEATURE_ADAPTIVE_PLAYBACK);
+            }
         }
     }
 
@@ -8690,11 +8700,20 @@
         OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE params;
         InitOMXParams(&params);
         params.nPortIndex = kPortIndexOutput;
-        // TODO: should we verify if fallback is supported?
+
+        OMX_VIDEO_PARAM_INTRAREFRESHTYPE fallbackParams;
+        InitOMXParams(&fallbackParams);
+        fallbackParams.nPortIndex = kPortIndexOutput;
+        fallbackParams.eRefreshMode = OMX_VIDEO_IntraRefreshCyclic;
+
         if (omxNode->getConfig(
                 (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh,
-                &params, sizeof(params)) == OK) {
-            caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsIntraRefresh);
+                &params, sizeof(params)) != OK &&
+                omxNode->getParameter(
+                    OMX_IndexParamVideoIntraRefresh, &fallbackParams,
+                    sizeof(fallbackParams)) != OK) {
+            // intra refresh is not supported
+            caps->removeDetail(MediaCodecInfo::Capabilities::FEATURE_INTRA_REFRESH);
         }
     }
 
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 249f2a4..f45cc58 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -94,6 +94,7 @@
         "CameraSource.cpp",
         "CameraSourceTimeLapse.cpp",
         "DataConverter.cpp",
+        "DataSourceBase.cpp",
         "DataSourceFactory.cpp",
         "DataURISource.cpp",
         "ClearFileSource.cpp",
@@ -113,6 +114,7 @@
         "MediaCodecSource.cpp",
         "MediaExtractor.cpp",
         "MediaExtractorFactory.cpp",
+        "MediaSource.cpp",
         "MediaSync.cpp",
         "MediaTrack.cpp",
         "http/ClearMediaHTTP.cpp",
@@ -150,7 +152,6 @@
         "libmedia",
         "libmedia_omx",
         "libaudioclient",
-        "libmediaextractor",
         "libmediametrics",
         "libmediautils",
         "libui",
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index a6f0a0b..199b57b 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -118,6 +118,13 @@
     }
 
     sp<MetaData> format = mSource->getFormat();
+
+    if (format == NULL) {
+        ALOGE("No metadata b/118620871");
+        android_errorWriteLog(0x534e4554, "118620871");
+        return BAD_VALUE;
+    }
+
     const char *mime;
     bool success = format->findCString(kKeyMIMEType, &mime);
     CHECK(success);
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 9de1e22..5027303 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -337,7 +337,7 @@
     } else {
         // This should not happen in normal case.
         ALOGW("Failed to get audio timestamp, fallback to use systemclock");
-        timeUs = systemTime() / 1000ll;
+        timeUs = systemTime() / 1000LL;
         // Estimate the real sampling time of the 1st sample in this buffer
         // from AudioRecord's latency. (Apply this adjustment first so that
         // the start time logic is not affected.)
diff --git a/media/libmediaextractor/DataSourceBase.cpp b/media/libstagefright/DataSourceBase.cpp
similarity index 100%
rename from media/libmediaextractor/DataSourceBase.cpp
rename to media/libstagefright/DataSourceBase.cpp
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index c62c05a..42b98b1 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -39,7 +39,7 @@
 
 namespace android {
 
-static const int64_t kBufferTimeOutUs = 10000ll; // 10 msec
+static const int64_t kBufferTimeOutUs = 10000LL; // 10 msec
 static const size_t kRetryCount = 50; // must be >0
 
 sp<IMemory> allocVideoFrame(const sp<MetaData>& trackMeta,
@@ -274,7 +274,7 @@
     size_t retriesLeft = kRetryCount;
     do {
         size_t index;
-        int64_t ptsUs = 0ll;
+        int64_t ptsUs = 0LL;
         uint32_t flags = 0;
 
         // Queue as many inputs as we possibly can, then block on dequeuing
@@ -406,7 +406,7 @@
     : FrameDecoder(componentName, trackMeta, source),
       mIsAvcOrHevc(false),
       mSeekMode(MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC),
-      mTargetTimeUs(-1ll),
+      mTargetTimeUs(-1LL),
       mNumFrames(0),
       mNumFramesDecoded(0) {
 }
@@ -487,7 +487,7 @@
         const sp<MediaCodecBuffer> &videoFrameBuffer,
         const sp<AMessage> &outputFormat,
         int64_t timeUs, bool *done) {
-    bool shouldOutput = (mTargetTimeUs < 0ll) || (timeUs >= mTargetTimeUs);
+    bool shouldOutput = (mTargetTimeUs < 0LL) || (timeUs >= mTargetTimeUs);
 
     // If this is not the target frame, skip color convert.
     if (!shouldOutput) {
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index 770535c..a9715c9 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -240,7 +240,7 @@
         size -= length;
     }
 
-    out->meta()->setInt64("timeUs", 0ll);
+    out->meta()->setInt64("timeUs", 0LL);
 
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kNotifyBuffer);
@@ -842,7 +842,7 @@
     int64_t timeUs;
     CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
 
-    uint32_t PTS = (timeUs * 9ll) / 100ll;
+    uint32_t PTS = (timeUs * 9LL) / 100LL;
 
     size_t PES_packet_length = accessUnit->size() + 8;
     bool padding = (accessUnit->size() < (188 - 18));
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index b45eb03..7df1a2d 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -487,7 +487,7 @@
 
     mInterleaveDurationUs = 1000000;
 
-    mStartTimestampUs = -1ll;
+    mStartTimestampUs = -1LL;
     mStartTimeOffsetMs = -1;
     mStartTimeOffsetBFramesUs = 0;
     mPaused = false;
@@ -1745,7 +1745,7 @@
 
 void MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
     ALOGI("setStartTimestampUs: %" PRId64, timeUs);
-    CHECK_GE(timeUs, 0ll);
+    CHECK_GE(timeUs, 0LL);
     Mutex::Autolock autoLock(mLock);
     if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
         mStartTimestampUs = timeUs;
@@ -3099,7 +3099,7 @@
 
             if (mResumed) {
                 int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
-                if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) {
+                if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0LL, "for %s track", trackName)) {
                     copy->release();
                     mSource->stop();
                     mIsMalformed = true;
@@ -3120,7 +3120,7 @@
             TimestampDebugHelperEntry timestampDebugEntry;
             timestampUs -= previousPausedDurationUs;
             timestampDebugEntry.pts = timestampUs;
-            if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
+            if (WARN_UNLESS(timestampUs >= 0LL, "for %s track", trackName)) {
                 copy->release();
                 mSource->stop();
                 mIsMalformed = true;
@@ -3159,7 +3159,7 @@
 
                 cttsOffsetTimeUs =
                         timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
-                if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) {
+                if (WARN_UNLESS(cttsOffsetTimeUs >= 0LL, "for %s track", trackName)) {
                     copy->release();
                     mSource->stop();
                     mIsMalformed = true;
@@ -3217,7 +3217,7 @@
                 }
             }
 
-            if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
+            if (WARN_UNLESS(timestampUs >= 0LL, "for %s track", trackName)) {
                 copy->release();
                 mSource->stop();
                 mIsMalformed = true;
@@ -3238,7 +3238,7 @@
             currDurationTicks =
                 ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
                     (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
-            if (currDurationTicks < 0ll) {
+            if (currDurationTicks < 0LL) {
                 ALOGE("do not support out of order frames (timestamp: %lld < last: %lld for %s track",
                         (long long)timestampUs, (long long)lastTimestampUs, trackName);
                 copy->release();
diff --git a/media/libstagefright/MediaClock.cpp b/media/libstagefright/MediaClock.cpp
index 41dbfd4..4f9bc6d 100644
--- a/media/libstagefright/MediaClock.cpp
+++ b/media/libstagefright/MediaClock.cpp
@@ -28,7 +28,7 @@
 
 // Maximum allowed time backwards from anchor change.
 // If larger than this threshold, it's treated as discontinuity.
-static const int64_t kAnchorFluctuationAllowedUs = 10000ll;
+static const int64_t kAnchorFluctuationAllowedUs = 10000LL;
 
 MediaClock::Timer::Timer(const sp<AMessage> &notify, int64_t mediaTimeUs, int64_t adjustRealUs)
     : mNotify(notify),
@@ -110,7 +110,7 @@
     if (mAnchorTimeRealUs != -1) {
         int64_t oldNowMediaUs =
             mAnchorTimeMediaUs + (nowUs - mAnchorTimeRealUs) * (double)mPlaybackRate;
-        if (nowMediaUs < oldNowMediaUs
+        if (nowMediaUs < oldNowMediaUs + kAnchorFluctuationAllowedUs
                 && nowMediaUs > oldNowMediaUs - kAnchorFluctuationAllowedUs) {
             return;
         }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index bd9e2bb..c7da7c7 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -862,9 +862,9 @@
 //static
 sp<CodecBase> MediaCodec::GetCodecBase(const AString &name, const char *owner) {
     if (owner) {
-        if (strncmp(owner, "default", 8) == 0) {
+        if (strcmp(owner, "default") == 0) {
             return new ACodec;
-        } else if (strncmp(owner, "codec2", 7) == 0) {
+        } else if (strncmp(owner, "codec2", 6) == 0) {
             return CreateCCodec();
         }
     }
@@ -911,10 +911,10 @@
             continue;
         }
         mCodecInfo = mcl->getCodecInfo(codecIdx);
-        Vector<AString> mimes;
-        mCodecInfo->getSupportedMimes(&mimes);
-        for (size_t i = 0; i < mimes.size(); i++) {
-            if (mimes[i].startsWith("video/")) {
+        Vector<AString> mediaTypes;
+        mCodecInfo->getSupportedMediaTypes(&mediaTypes);
+        for (size_t i = 0; i < mediaTypes.size(); i++) {
+            if (mediaTypes[i].startsWith("video/")) {
                 mIsVideo = true;
                 break;
             }
@@ -2699,7 +2699,7 @@
             int64_t timeoutUs;
             CHECK(msg->findInt64("timeoutUs", &timeoutUs));
 
-            if (timeoutUs == 0ll) {
+            if (timeoutUs == 0LL) {
                 PostReplyWithError(replyID, -EAGAIN);
                 break;
             }
@@ -2707,7 +2707,7 @@
             mFlags |= kFlagDequeueInputPending;
             mDequeueInputReplyID = replyID;
 
-            if (timeoutUs > 0ll) {
+            if (timeoutUs > 0LL) {
                 sp<AMessage> timeoutMsg =
                     new AMessage(kWhatDequeueInputTimedOut, this);
                 timeoutMsg->setInt32(
@@ -2773,7 +2773,7 @@
             int64_t timeoutUs;
             CHECK(msg->findInt64("timeoutUs", &timeoutUs));
 
-            if (timeoutUs == 0ll) {
+            if (timeoutUs == 0LL) {
                 PostReplyWithError(replyID, -EAGAIN);
                 break;
             }
@@ -2781,7 +2781,7 @@
             mFlags |= kFlagDequeueOutputPending;
             mDequeueOutputReplyID = replyID;
 
-            if (timeoutUs > 0ll) {
+            if (timeoutUs > 0LL) {
                 sp<AMessage> timeoutMsg =
                     new AMessage(kWhatDequeueOutputTimedOut, this);
                 timeoutMsg->setInt32(
@@ -3042,7 +3042,7 @@
     msg->setSize("index", bufferIndex);
     msg->setSize("offset", 0);
     msg->setSize("size", csd->size());
-    msg->setInt64("timeUs", 0ll);
+    msg->setInt64("timeUs", 0LL);
     msg->setInt32("flags", BUFFER_FLAG_CODECCONFIG);
     msg->setPointer("errorDetailMsg", &errorDetailMsg);
 
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index eaff283..93478e9 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -215,13 +215,9 @@
             mCodecInfos.begin(),
             mCodecInfos.end(),
             [](const sp<MediaCodecInfo> &info1, const sp<MediaCodecInfo> &info2) {
-                if (info2 == nullptr) {
-                    return false;
-                } else if (info1 == nullptr) {
-                    return true;
-                } else {
-                    return info1->rank() < info2->rank();
-                }
+                // null is lowest
+                return info1 == nullptr
+                        || (info2 != nullptr && info1->getRank() < info2->getRank());
             });
 }
 
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index cac53f4..dd7c3e6 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -228,18 +228,18 @@
             continue;
         }
 
-        Vector<AString> mimes;
-        info->getSupportedMimes(&mimes);
-        for (size_t i = 0; i < mimes.size(); ++i) {
+        Vector<AString> mediaTypes;
+        info->getSupportedMediaTypes(&mediaTypes);
+        for (size_t i = 0; i < mediaTypes.size(); ++i) {
             const sp<MediaCodecInfo::Capabilities> &caps =
-                    info->getCapabilitiesFor(mimes[i].c_str());
+                    info->getCapabilitiesFor(mediaTypes[i].c_str());
             if (!forceToMeasure &&
                 (caps->getDetails()->contains("max-supported-instances") ||
                  caps->getDetails()->contains("max-concurrent-instances"))) {
                 continue;
             }
 
-            size_t max = doProfileCodecs(info->isEncoder(), name, mimes[i], caps);
+            size_t max = doProfileCodecs(info->isEncoder(), name, mediaTypes[i], caps);
             if (max > 0) {
                 CodecSettings settings;
                 char maxStr[32];
@@ -248,7 +248,7 @@
 
                 AString key = name;
                 key.append(" ");
-                key.append(mimes[i]);
+                key.append(mediaTypes[i]);
 
                 if (info->isEncoder()) {
                     encoder_results->add(key, settings);
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 20881a4..0f75822 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -372,7 +372,7 @@
     msg->postAndAwaitResponse(&response);
     int64_t timeUs;
     if (!response->findInt64("time-us", &timeUs)) {
-        timeUs = -1ll;
+        timeUs = -1LL;
     }
     return timeUs;
 }
@@ -452,9 +452,9 @@
       mEncoderDataSpace(0),
       mPersistentSurface(persistentSurface),
       mInputBufferTimeOffsetUs(0),
-      mFirstSampleSystemTimeUs(-1ll),
+      mFirstSampleSystemTimeUs(-1LL),
       mPausePending(false),
-      mFirstSampleTimeUs(-1ll),
+      mFirstSampleTimeUs(-1LL),
       mGeneration(0) {
     CHECK(mLooper != NULL);
 
@@ -687,13 +687,13 @@
         size_t bufferIndex = *mAvailEncoderInputIndices.begin();
         mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin());
 
-        int64_t timeUs = 0ll;
+        int64_t timeUs = 0LL;
         uint32_t flags = 0;
         size_t size = 0;
 
         if (mbuf != NULL) {
             CHECK(mbuf->meta_data().findInt64(kKeyTime, &timeUs));
-            if (mFirstSampleSystemTimeUs < 0ll) {
+            if (mFirstSampleSystemTimeUs < 0LL) {
                 mFirstSampleSystemTimeUs = systemTime() / 1000;
                 if (mPausePending) {
                     mPausePending = false;
@@ -767,7 +767,7 @@
     }
     int64_t startTimeUs;
     if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
-        startTimeUs = -1ll;
+        startTimeUs = -1LL;
     }
 
     if (mStarted) {
@@ -914,7 +914,7 @@
                 if (mIsVideo) {
                     int64_t decodingTimeUs;
                     if (mFlags & FLAG_USE_SURFACE_INPUT) {
-                        if (mFirstSampleSystemTimeUs < 0ll) {
+                        if (mFirstSampleSystemTimeUs < 0LL) {
                             mFirstSampleSystemTimeUs = systemTime() / 1000;
                             if (mPausePending) {
                                 mPausePending = false;
@@ -926,7 +926,7 @@
                         // Timestamp offset is already adjusted in GraphicBufferSource.
                         // GraphicBufferSource is supposed to discard samples
                         // queued before start, and offset timeUs by start time
-                        CHECK_GE(timeUs, 0ll);
+                        CHECK_GE(timeUs, 0LL);
                         // TODO:
                         // Decoding time for surface source is unavailable,
                         // use presentation time for now. May need to move
@@ -954,7 +954,7 @@
                 }
                 mbuf->meta_data().setInt64(kKeyTime, timeUs);
             } else {
-                mbuf->meta_data().setInt64(kKeyTime, 0ll);
+                mbuf->meta_data().setInt64(kKeyTime, 0LL);
                 mbuf->meta_data().setInt32(kKeyIsCodecConfig, true);
             }
             if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME) {
@@ -1081,7 +1081,7 @@
             MetaData *params = static_cast<MetaData *>(obj.get());
             int64_t pauseStartTimeUs = -1;
             if (params == NULL || !params->findInt64(kKeyTime, &pauseStartTimeUs)) {
-                pauseStartTimeUs = -1ll;
+                pauseStartTimeUs = -1LL;
             }
             onPause(pauseStartTimeUs);
         }
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 2c7a4e5..86402ce 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -30,6 +30,7 @@
 #include <media/stagefright/MediaExtractorFactory.h>
 #include <media/IMediaExtractor.h>
 #include <media/IMediaExtractorService.h>
+#include <private/android_filesystem_config.h>
 #include <cutils/properties.h>
 #include <utils/String8.h>
 #include <ziparchive/zip_archive.h>
@@ -106,7 +107,8 @@
     }
 
     MediaExtractor *ex = nullptr;
-    if (creatorVersion == EXTRACTORDEF_VERSION_NDK_V1) {
+    if (creatorVersion == EXTRACTORDEF_VERSION_NDK_V1 ||
+            creatorVersion == EXTRACTORDEF_VERSION_NDK_V2) {
         CMediaExtractor *ret = ((CreatorFunc)creator)(source->wrap(), meta);
         if (meta != nullptr && freeMeta != nullptr) {
             freeMeta(meta);
@@ -184,7 +186,10 @@
 
         void *curCreator = NULL;
         if ((*it)->def.def_version == EXTRACTORDEF_VERSION_NDK_V1) {
-            curCreator = (void*) (*it)->def.sniff.v2(
+            curCreator = (void*) (*it)->def.u.v2.sniff(
+                    source->wrap(), &newConfidence, &newMeta, &newFreeMeta);
+        } else if ((*it)->def.def_version == EXTRACTORDEF_VERSION_NDK_V2) {
+            curCreator = (void*) (*it)->def.u.v3.sniff(
                     source->wrap(), &newConfidence, &newMeta, &newFreeMeta);
         }
 
@@ -214,7 +219,8 @@
 void MediaExtractorFactory::RegisterExtractor(const sp<ExtractorPlugin> &plugin,
         std::list<sp<ExtractorPlugin>> &pluginList) {
     // sanity check check struct version, uuid, name
-    if (plugin->def.def_version != EXTRACTORDEF_VERSION_NDK_V1) {
+    if (plugin->def.def_version != EXTRACTORDEF_VERSION_NDK_V1 &&
+            plugin->def.def_version != EXTRACTORDEF_VERSION_NDK_V2) {
         ALOGE("don't understand extractor format %u, ignoring.", plugin->def.def_version);
         return;
     }
@@ -394,6 +400,8 @@
     return strcmp(first->def.extractor_name, second->def.extractor_name) < 0;
 }
 
+static std::unordered_set<std::string> gSupportedExtensions;
+
 // static
 void MediaExtractorFactory::UpdateExtractors(const char *newUpdateApkPath) {
     Mutex::Autolock autoLock(gPluginMutex);
@@ -426,9 +434,37 @@
 
     newList->sort(compareFunc);
     gPlugins = newList;
+
+    for (auto it = gPlugins->begin(); it != gPlugins->end(); ++it) {
+        if ((*it)->def.def_version == EXTRACTORDEF_VERSION_NDK_V2) {
+            for (size_t i = 0;; i++) {
+                const char* ext = (*it)->def.u.v3.supported_types[i];
+                if (ext == nullptr) {
+                    break;
+                }
+                gSupportedExtensions.insert(std::string(ext));
+            }
+        }
+    }
+
     gPluginsRegistered = true;
 }
 
+// static
+std::unordered_set<std::string> MediaExtractorFactory::getSupportedTypes() {
+    if (getuid() == AID_MEDIA_EX) {
+        return gSupportedExtensions;
+    }
+    ALOGV("get service manager");
+    sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
+
+    if (binder != 0) {
+        sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
+        return mediaExService->getSupportedTypes();
+    }
+    return std::unordered_set<std::string>();
+}
+
 status_t MediaExtractorFactory::dump(int fd, const Vector<String16>&) {
     Mutex::Autolock autoLock(gPluginMutex);
     String8 out;
@@ -445,13 +481,25 @@
         out.append("Available extractors:\n");
         if (gPluginsRegistered) {
             for (auto it = gPlugins->begin(); it != gPlugins->end(); ++it) {
-                out.appendFormat("  %25s: plugin_version(%d), uuid(%s), version(%u), path(%s)\n",
+                out.appendFormat("  %25s: plugin_version(%d), uuid(%s), version(%u), path(%s)",
                         (*it)->def.extractor_name,
                     (*it)->def.def_version,
                         (*it)->uuidString.c_str(),
                         (*it)->def.extractor_version,
                         (*it)->libPath.c_str());
+                if ((*it)->def.def_version == EXTRACTORDEF_VERSION_NDK_V2) {
+                    out.append(", supports: ");
+                    for (size_t i = 0;; i++) {
+                        const char* mime = (*it)->def.u.v3.supported_types[i];
+                        if (mime == nullptr) {
+                            break;
+                        }
+                        out.appendFormat("%s ", mime);
+                    }
+                }
+                out.append("\n");
             }
+            out.append("\n");
         } else {
             out.append("  (no plugins registered)\n");
         }
diff --git a/media/libmediaextractor/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
similarity index 100%
rename from media/libmediaextractor/MediaSource.cpp
rename to media/libstagefright/MediaSource.cpp
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index ba14e5d..a3f55da 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -36,7 +36,7 @@
 
 // Maximum late time allowed for a video frame to be rendered. When a video
 // frame arrives later than this number, it will be discarded without rendering.
-static const int64_t kMaxAllowedVideoLateTimeUs = 40000ll;
+static const int64_t kMaxAllowedVideoLateTimeUs = 40000LL;
 
 namespace android {
 
diff --git a/media/libstagefright/MediaTrack.cpp b/media/libstagefright/MediaTrack.cpp
index 1c1be30..036e79d 100644
--- a/media/libstagefright/MediaTrack.cpp
+++ b/media/libstagefright/MediaTrack.cpp
@@ -120,7 +120,7 @@
         if (format->mFormat->findInt64("timeUs", &val64)) {
             meta.setInt64(kKeyTime, val64);
         }
-        if (format->mFormat->findInt64("duration", &val64)) {
+        if (format->mFormat->findInt64("durationUs", &val64)) {
             meta.setInt64(kKeyDuration, val64);
         }
         if (format->mFormat->findInt64("target-time", &val64)) {
@@ -172,6 +172,10 @@
             meta.setData(kKeySEI,
                     MetaDataBase::Type::TYPE_NONE, valbuf->data(), valbuf->size());
         }
+        if (format->mFormat->findBuffer("audio-presentation-info", &valbuf)) {
+            meta.setData(kKeyAudioPresentationInfo,
+                    MetaDataBase::Type::TYPE_NONE, valbuf->data(), valbuf->size());
+        }
     } else {
         *buffer = nullptr;
     }
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 7025af7..522c81d 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -440,12 +440,12 @@
     if (mFetching) {
         if (mFinalStatus != OK && mNumRetriesLeft > 0) {
             // We failed this time and will try again in 3 seconds.
-            delayUs = 3000000ll;
+            delayUs = 3000000LL;
         } else {
             delayUs = 0;
         }
     } else {
-        delayUs = 100000ll;
+        delayUs = 100000LL;
     }
 
     (new AMessage(kWhatFetchMore, mReflector))->post(delayUs);
@@ -740,7 +740,7 @@
     }
 
     if (keepAliveSecs >= 0) {
-        mKeepAliveIntervalUs = keepAliveSecs * 1000000ll;
+        mKeepAliveIntervalUs = keepAliveSecs * 1000000LL;
     } else {
         mKeepAliveIntervalUs = kDefaultKeepAliveIntervalUs;
     }
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index f5178dd..83b87d9 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -41,7 +41,7 @@
 
 NuMediaExtractor::Sample::Sample()
     : mBuffer(NULL),
-      mSampleTimeUs(-1ll) {
+      mSampleTimeUs(-1LL) {
 }
 
 NuMediaExtractor::Sample::Sample(MediaBufferBase *buffer, int64_t timeUs)
@@ -50,8 +50,8 @@
 }
 
 NuMediaExtractor::NuMediaExtractor()
-    : mTotalBitrate(-1ll),
-      mDurationUs(-1ll) {
+    : mTotalBitrate(-1LL),
+      mDurationUs(-1LL) {
 }
 
 NuMediaExtractor::~NuMediaExtractor() {
@@ -209,8 +209,8 @@
         return ERROR_UNSUPPORTED;
     }
 
-    mTotalBitrate = 0ll;
-    mDurationUs = -1ll;
+    mTotalBitrate = 0LL;
+    mDurationUs = -1LL;
 
     for (size_t i = 0; i < mImpl->countTracks(); ++i) {
         sp<MetaData> meta = mImpl->getTrackMetaData(i);
@@ -225,8 +225,8 @@
             CHECK(meta->findCString(kKeyMIMEType, &mime));
             ALOGV("track of type '%s' does not publish bitrate", mime);
 
-            mTotalBitrate = -1ll;
-        } else if (mTotalBitrate >= 0ll) {
+            mTotalBitrate = -1LL;
+        } else if (mTotalBitrate >= 0LL) {
             mTotalBitrate += bitrate;
         }
 
@@ -503,7 +503,7 @@
     }
 
     MediaSource::ReadOptions options;
-    if (seekTimeUs >= 0ll) {
+    if (seekTimeUs >= 0LL) {
         options.setSeekTo(seekTimeUs, mode);
         info->mFinalResult = OK;
         releaseTrackSamples(info);
@@ -768,7 +768,7 @@
 
     off64_t size;
     if (mDurationUs > 0 && mDataSource->getSize(&size) == OK) {
-        *bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
+        *bitrate = size * 8000000LL / mDurationUs;  // in bits/sec
         return true;
     }
 
@@ -795,30 +795,34 @@
 }
 
 // Return OK if we have received an audio presentation info.
+// Return ERROR_END_OF_STREAM if no tracks are available.
 // Return ERROR_UNSUPPORTED if the track has no audio presentation.
 // Return INVALID_OPERATION if audio presentation metadata version does not match.
 status_t NuMediaExtractor::getAudioPresentations(
-        size_t trackIndex, AudioPresentationCollection *presentations) const {
+        size_t trackIndex, AudioPresentationCollection *presentations) {
     Mutex::Autolock autoLock(mLock);
-
-    if (mImpl == NULL) {
-        return -EINVAL;
+    ssize_t minIndex = fetchAllTrackSamples();
+    if (minIndex < 0) {
+        return ERROR_END_OF_STREAM;
     }
+    for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
+        TrackInfo *info = &mSelectedTracks.editItemAt(i);
 
-    if (trackIndex >= mImpl->countTracks()) {
-        return -ERANGE;
+        if (info->mTrackIndex == trackIndex) {
+            sp<MetaData> meta = new MetaData(info->mSamples.begin()->mBuffer->meta_data());
+
+            uint32_t type;
+            const void *data;
+            size_t size;
+            if (meta != NULL && meta->findData(kKeyAudioPresentationInfo, &type, &data, &size)) {
+                std::istringstream inStream(std::string(static_cast<const char*>(data), size));
+                return deserializeAudioPresentations(&inStream, presentations);
+            }
+            ALOGV("Track %zu does not contain any audio presentation", trackIndex);
+            return ERROR_UNSUPPORTED;
+        }
     }
-
-    sp<MetaData> meta = mImpl->getTrackMetaData(trackIndex);
-
-    uint32_t type;
-    const void *data;
-    size_t size;
-    if (meta != NULL && meta->findData(kKeyAudioPresentationInfo, &type, &data, &size)) {
-        std::istringstream inStream(std::string(static_cast<const char*>(data), size));
-        return deserializeAudioPresentations(&inStream, presentations);
-    }
-    ALOGE("Source does not contain any audio presentation");
+    ALOGV("Source does not contain any audio presentation");
     return ERROR_UNSUPPORTED;
 }
 
diff --git a/media/libstagefright/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
index 96b896b..382c947 100644
--- a/media/libstagefright/OmxInfoBuilder.cpp
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -57,14 +57,9 @@
 }
 
 status_t queryCapabilities(
-        const IOmxStore::NodeInfo& node, const char* mime, bool isEncoder,
+        const IOmxStore::NodeInfo& node, const char* mediaType, bool isEncoder,
         MediaCodecInfo::CapabilitiesWriter* caps) {
     sp<ACodec> codec = new ACodec();
-    status_t err = codec->queryCapabilities(
-            node.owner.c_str(), node.name.c_str(), mime, isEncoder, caps);
-    if (err != OK) {
-        return err;
-    }
     for (const auto& attribute : node.attributes) {
         // All features have an int32 value except
         // "feature-bitrate-modes", which has a string value.
@@ -81,6 +76,12 @@
                     attribute.key.c_str(), attribute.value.c_str());
         }
     }
+    // query capabilities may remove capabilities that are not actually supported by the codec
+    status_t err = codec->queryCapabilities(
+            node.owner.c_str(), node.name.c_str(), mediaType, isEncoder, caps);
+    if (err != OK) {
+        return err;
+    }
     return OK;
 }
 
@@ -163,7 +164,10 @@
                     info = c2i->second.get();
                     info->setName(nodeName.c_str());
                     info->setOwner(node.owner.c_str());
-                    info->setEncoder(isEncoder);
+                    info->setAttributes(
+                            // all OMX codecs are vendor codecs (in the vendor partition), but
+                            // treat OMX.google codecs as non-hardware-accelerated and  non-vendor
+                            (isEncoder ? MediaCodecInfo::kFlagIsEncoder : 0));
                     info->setRank(defaultRank);
                 } else {
                     // The node has been seen before. Simply retrieve the
@@ -180,7 +184,19 @@
                         info = c2i->second.get();
                         info->setName(nodeName.c_str());
                         info->setOwner(node.owner.c_str());
-                        info->setEncoder(isEncoder);
+                        typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs =
+                            MediaCodecInfo::kFlagIsVendor;
+                        if (isEncoder) {
+                            attrs |= MediaCodecInfo::kFlagIsEncoder;
+                        }
+                        if (std::count_if(
+                                node.attributes.begin(), node.attributes.end(),
+                                [](const IOmxStore::Attribute &i) -> bool {
+                                    return i.key == "attribute::software-codec";
+                                                                          })) {
+                            attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
+                        }
+                        info->setAttributes(attrs);
                         info->setRank(defaultRank);
                     } else {
                         // If preferPlatformNodes is true, this node must be
@@ -195,12 +211,12 @@
                 }
             }
             std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
-                    info->addMime(typeName.c_str());
+                    info->addMediaType(typeName.c_str());
             if (queryCapabilities(
                     node, typeName.c_str(), isEncoder, caps.get()) != OK) {
-                ALOGW("Fail to add mime %s to codec %s",
+                ALOGW("Fail to add media type %s to codec %s",
                         typeName.c_str(), nodeName.c_str());
-                info->removeMime(typeName.c_str());
+                info->removeMediaType(typeName.c_str());
             }
         }
 
@@ -219,7 +235,18 @@
                     info = c2i->second.get();
                     info->setName(nodeName.c_str());
                     info->setOwner(node->owner.c_str());
-                    info->setEncoder(isEncoder);
+                    typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs =
+                        MediaCodecInfo::kFlagIsVendor;
+                    if (isEncoder) {
+                        attrs |= MediaCodecInfo::kFlagIsEncoder;
+                    }
+                    if (std::count_if(
+                            node->attributes.begin(), node->attributes.end(),
+                            [](const IOmxStore::Attribute &i) -> bool {
+                                return i.key == "attribute::software-codec";
+                                                                      })) {
+                        attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
+                    }
                     info->setRank(defaultRank);
                 } else {
                     // The node has been seen before. Simply retrieve the
@@ -227,13 +254,13 @@
                     info = c2i->second.get();
                 }
                 std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
-                        info->addMime(typeName.c_str());
+                        info->addMediaType(typeName.c_str());
                 if (queryCapabilities(
                         *node, typeName.c_str(), isEncoder, caps.get()) != OK) {
-                    ALOGW("Fail to add mime %s to codec %s "
+                    ALOGW("Fail to add media type %s to codec %s "
                           "after software codecs",
                           typeName.c_str(), nodeName.c_str());
-                    info->removeMime(typeName.c_str());
+                    info->removeMediaType(typeName.c_str());
                 }
             }
         }
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 17187a8..cf4edae 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -22,6 +22,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/StagefrightMediaScanner.h>
 
 #include <media/IMediaHTTPService.h>
@@ -34,25 +35,16 @@
 
 StagefrightMediaScanner::~StagefrightMediaScanner() {}
 
-static bool FileHasAcceptableExtension(const char *extension) {
-    static const char *kValidExtensions[] = {
-        ".mp3", ".mp4", ".m4a", ".3gp", ".3gpp", ".3g2", ".3gpp2",
-        ".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
-        ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
-        ".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf",
-        ".avi", ".mpeg", ".mpg", ".awb", ".mpga", ".mov",
-        ".m4v", ".oga", ".m4r"
-    };
-    static const size_t kNumValidExtensions =
-        sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
+static std::unordered_set<std::string> gSupportedExtensions;
 
-    for (size_t i = 0; i < kNumValidExtensions; ++i) {
-        if (!strcasecmp(extension, kValidExtensions[i])) {
-            return true;
-        }
+static bool FileHasAcceptableExtension(const char *extension) {
+
+    if (gSupportedExtensions.empty()) {
+        // get the list from the service
+        gSupportedExtensions = MediaExtractorFactory::getSupportedTypes();
     }
 
-    return false;
+    return  gSupportedExtensions.count(std::string(extension + 1)) != 0;
 }
 
 MediaScanResult StagefrightMediaScanner::processFile(
@@ -135,6 +127,8 @@
         { "colorstandard", METADATA_KEY_COLOR_STANDARD },
         { "colortransfer", METADATA_KEY_COLOR_TRANSFER },
         { "colorrange", METADATA_KEY_COLOR_RANGE },
+        { "samplerate", METADATA_KEY_SAMPLERATE },
+        { "bitspersample", METADATA_KEY_BITS_PER_SAMPLE },
     };
     static const size_t kNumEntries = sizeof(kKeyMap) / sizeof(kKeyMap[0]);
 
diff --git a/media/libstagefright/ThrottledSource.cpp b/media/libstagefright/ThrottledSource.cpp
index 7496752..49cea9e 100644
--- a/media/libstagefright/ThrottledSource.cpp
+++ b/media/libstagefright/ThrottledSource.cpp
@@ -51,7 +51,7 @@
     // How long would it have taken to transfer everything we ever
     // transferred given the limited bandwidth.
     int64_t durationUs =
-        mTotalTransferred * 1000000ll / mBandwidthLimitBytesPerSecond;
+        mTotalTransferred * 1000000LL / mBandwidthLimitBytesPerSecond;
 
     int64_t whenUs = mStartTimeUs + durationUs;
 
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 163cd05..49e485a 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -2020,7 +2020,7 @@
 
 HLSTime::HLSTime(const sp<AMessage>& meta) :
     mSeq(-1),
-    mTimeUs(-1ll),
+    mTimeUs(-1LL),
     mMeta(meta) {
     if (meta != NULL) {
         CHECK(meta->findInt32("discontinuitySeq", &mSeq));
@@ -2029,7 +2029,7 @@
 }
 
 int64_t HLSTime::getSegmentTimeUs() const {
-    int64_t segmentStartTimeUs = -1ll;
+    int64_t segmentStartTimeUs = -1LL;
     if (mMeta != NULL) {
         CHECK(mMeta->findInt64("segmentStartTimeUs", &segmentStartTimeUs));
 
diff --git a/media/libstagefright/VideoFrameScheduler2.cpp b/media/libstagefright/VideoFrameScheduler2.cpp
index e02ae7d..fc76904 100644
--- a/media/libstagefright/VideoFrameScheduler2.cpp
+++ b/media/libstagefright/VideoFrameScheduler2.cpp
@@ -36,7 +36,7 @@
 
 namespace android {
 
-static void getVsyncOffset(long* appVsyncOffsetPtr, long* sfVsyncOffsetPtr);
+static void getVsyncOffset(nsecs_t* appVsyncOffsetPtr, nsecs_t* sfVsyncOffsetPtr);
 
 /* ======================================================================= */
 /*                               VsyncTracker                              */
@@ -46,19 +46,19 @@
 public:
     VsyncTracker();
     ~VsyncTracker() {}
-    long getVsyncPeriod();
-    long getVsyncTime(long periodOffset);
-    void addSample(long timestamp);
+    nsecs_t getVsyncPeriod();
+    nsecs_t getVsyncTime(nsecs_t periodOffset);
+    void addSample(nsecs_t timestamp);
 
 private:
     static const int kMaxSamples = 32;
     static const int kMinSamplesForUpdate = 6;
     int mNumSamples;
     int mFirstSample;
-    long mReferenceTime;
-    long mPhase;
-    long mPeriod;
-    long mTimestampSamples[kMaxSamples];
+    nsecs_t mReferenceTime;
+    nsecs_t mPhase;
+    nsecs_t mPeriod;
+    nsecs_t mTimestampSamples[kMaxSamples];
     Mutex mLock;
 
     void updateModelLocked();
@@ -75,19 +75,39 @@
     }
 }
 
-long VsyncTracker::getVsyncPeriod() {
+nsecs_t VsyncTracker::getVsyncPeriod() {
     Mutex::Autolock dataLock(mLock);
     return mPeriod;
 }
 
-long VsyncTracker::getVsyncTime(long periodOffset) {
+nsecs_t VsyncTracker::getVsyncTime(nsecs_t periodOffset) {
     Mutex::Autolock dataLock(mLock);
-    const long now = systemTime();
-    long phase = mReferenceTime + mPhase;
-    return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase;
+    const nsecs_t now = systemTime();
+    nsecs_t phase = mReferenceTime + mPhase;
+
+    // result = (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase
+    // prevent overflow
+    nsecs_t result = (now - phase) / mPeriod;
+    if (result > LONG_LONG_MAX - periodOffset - 1) {
+        return LONG_LONG_MAX;
+    } else {
+        result += periodOffset + 1;
+    }
+    if (result > LONG_LONG_MAX / mPeriod) {
+        return LONG_LONG_MAX;
+    } else {
+        result *= mPeriod;
+    }
+    if (result > LONG_LONG_MAX - phase) {
+        return LONG_LONG_MAX;
+    } else {
+        result += phase;
+    }
+
+    return result;
 }
 
-void VsyncTracker::addSample(long timestamp) {
+void VsyncTracker::addSample(nsecs_t timestamp) {
     Mutex::Autolock dataLock(mLock);
     if (mNumSamples == 0) {
         mPhase = 0;
@@ -107,17 +127,17 @@
     if (mNumSamples < kMinSamplesForUpdate) {
         return;
     }
-    long durationSum = 0;
-    long minDuration = LONG_MAX;
-    long maxDuration = 0;
+    nsecs_t durationSum = 0;
+    nsecs_t minDuration = LONG_MAX;
+    nsecs_t maxDuration = 0;
 
     for (int i = 1; i < mNumSamples; i++) {
         int idx = (mFirstSample + i) % kMaxSamples;
         int prev = (idx + kMaxSamples - 1) % kMaxSamples;
         long duration = mTimestampSamples[idx] - mTimestampSamples[prev];
         durationSum += duration;
-        minDuration = min(minDuration, duration);
-        maxDuration = max(maxDuration, duration);
+        if (minDuration > duration) { minDuration = duration; }
+        if (maxDuration < duration) { maxDuration = duration; }
     }
 
     durationSum -= (minDuration + maxDuration);
@@ -154,9 +174,9 @@
 /*                                   JNI                                   */
 /* ======================================================================= */
 
-static void getVsyncOffset(long* appVsyncOffsetPtr, long* sfVsyncOffsetPtr) {
-    static const long kOneMillisecInNanosec = 1000000;
-    static const long kOneSecInNanosec = kOneMillisecInNanosec * 1000;
+static void getVsyncOffset(nsecs_t* appVsyncOffsetPtr, nsecs_t* sfVsyncOffsetPtr) {
+    static const nsecs_t kOneMillisecInNanosec = 1000000;
+    static const nsecs_t kOneSecInNanosec = kOneMillisecInNanosec * 1000;
 
     JNIEnv *env = JavaVMHelper::getJNIEnv();
     jclass jDisplayManagerGlobalCls = env->FindClass(
@@ -178,19 +198,19 @@
 
     jmethodID jGetRefreshRate = env->GetMethodID(jDisplayCls, "getRefreshRate", "()F");
     jfloat javaRefreshRate = env->CallFloatMethod(javaDisplayObj, jGetRefreshRate);
-    long vsyncPeriod = (long) (kOneSecInNanosec / (float) javaRefreshRate);
+    nsecs_t vsyncPeriod = (nsecs_t) (kOneSecInNanosec / (float) javaRefreshRate);
 
     jmethodID jGetAppVsyncOffsetNanos = env->GetMethodID(
             jDisplayCls, "getAppVsyncOffsetNanos", "()J");
     jlong javaAppVsyncOffset = env->CallLongMethod(javaDisplayObj, jGetAppVsyncOffsetNanos);
-    *appVsyncOffsetPtr = (long) javaAppVsyncOffset;
+    *appVsyncOffsetPtr = (nsecs_t) javaAppVsyncOffset;
 
     jmethodID jGetPresentationDeadlineNanos = env->GetMethodID(
             jDisplayCls, "getPresentationDeadlineNanos", "()J");
     jlong javaPresentationDeadline = env->CallLongMethod(
             javaDisplayObj, jGetPresentationDeadlineNanos);
 
-    *sfVsyncOffsetPtr = vsyncPeriod - ((long) javaPresentationDeadline - kOneMillisecInNanosec);
+    *sfVsyncOffsetPtr = vsyncPeriod - ((nsecs_t) javaPresentationDeadline - kOneMillisecInNanosec);
 }
 
 /* ======================================================================= */
diff --git a/media/libstagefright/bqhelper/FrameDropper.cpp b/media/libstagefright/bqhelper/FrameDropper.cpp
index d2a2473..387ac5a 100644
--- a/media/libstagefright/bqhelper/FrameDropper.cpp
+++ b/media/libstagefright/bqhelper/FrameDropper.cpp
@@ -35,7 +35,7 @@
 
 status_t FrameDropper::setMaxFrameRate(float maxFrameRate) {
     if (maxFrameRate < 0) {
-        mMinIntervalUs = -1ll;
+        mMinIntervalUs = -1LL;
         return OK;
     }
 
diff --git a/media/libstagefright/bqhelper/GraphicBufferSource.cpp b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
index 8c1da76..a4374c9 100644
--- a/media/libstagefright/bqhelper/GraphicBufferSource.cpp
+++ b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
@@ -292,20 +292,20 @@
     mSuspended(false),
     mLastFrameTimestampUs(-1),
     mStopTimeUs(-1),
-    mLastActionTimeUs(-1ll),
-    mSkipFramesBeforeNs(-1ll),
-    mFrameRepeatIntervalUs(-1ll),
+    mLastActionTimeUs(-1LL),
+    mSkipFramesBeforeNs(-1LL),
+    mFrameRepeatIntervalUs(-1LL),
     mRepeatLastFrameGeneration(0),
     mOutstandingFrameRepeatCount(0),
     mFrameRepeatBlockedOnCodecBuffer(false),
     mFps(-1.0),
     mCaptureFps(-1.0),
-    mBaseCaptureUs(-1ll),
-    mBaseFrameUs(-1ll),
+    mBaseCaptureUs(-1LL),
+    mBaseFrameUs(-1LL),
     mFrameCount(0),
-    mPrevCaptureUs(-1ll),
-    mPrevFrameUs(-1ll),
-    mInputBufferTimeOffsetUs(0ll) {
+    mPrevCaptureUs(-1LL),
+    mPrevFrameUs(-1LL),
+    mInputBufferTimeOffsetUs(0LL) {
     ALOGV("GraphicBufferSource");
 
     String8 name("GraphicBufferSource");
@@ -392,7 +392,7 @@
         submitEndOfInputStream_l();
     }
 
-    if (mFrameRepeatIntervalUs > 0ll && mLooper == NULL) {
+    if (mFrameRepeatIntervalUs > 0LL && mLooper == NULL) {
         mReflector = new AHandlerReflector<GraphicBufferSource>(this);
 
         mLooper = new ALooper;
@@ -655,7 +655,7 @@
 
     // only submit sample if start time is unspecified, or sample
     // is queued after the specified start time
-    if (mSkipFramesBeforeNs < 0ll || item.mTimestampNs >= mSkipFramesBeforeNs) {
+    if (mSkipFramesBeforeNs < 0LL || item.mTimestampNs >= mSkipFramesBeforeNs) {
         // if start time is set, offset time stamp by start time
         if (mSkipFramesBeforeNs > 0) {
             item.mTimestampNs -= mSkipFramesBeforeNs;
@@ -677,7 +677,7 @@
     } else {
         // Don't set the last buffer id if we're not repeating,
         // we'll be holding on to the last buffer for nothing.
-        if (mFrameRepeatIntervalUs > 0ll) {
+        if (mFrameRepeatIntervalUs > 0LL) {
             setLatestBuffer_l(item);
         }
         ALOGV("buffer submitted [slot=%d, useCount=%ld] acquired=%d",
@@ -755,7 +755,7 @@
             && (mFps > 2 * mCaptureFps
             || mCaptureFps > 2 * mFps)) {
         // Time lapse or slow motion mode
-        if (mPrevCaptureUs < 0ll) {
+        if (mPrevCaptureUs < 0LL) {
             // first capture
             mPrevCaptureUs = mBaseCaptureUs = timeUs;
             // adjust the first sample timestamp.
@@ -1123,19 +1123,19 @@
         mSuspended = false;
         mEndOfStream = false;
         mEndOfStreamSent = false;
-        mSkipFramesBeforeNs = -1ll;
+        mSkipFramesBeforeNs = -1LL;
         mFrameDropper.clear();
-        mFrameRepeatIntervalUs = -1ll;
+        mFrameRepeatIntervalUs = -1LL;
         mRepeatLastFrameGeneration = 0;
         mOutstandingFrameRepeatCount = 0;
         mLatestBuffer.mBuffer.reset();
         mFrameRepeatBlockedOnCodecBuffer = false;
         mFps = -1.0;
         mCaptureFps = -1.0;
-        mBaseCaptureUs = -1ll;
-        mBaseFrameUs = -1ll;
-        mPrevCaptureUs = -1ll;
-        mPrevFrameUs = -1ll;
+        mBaseCaptureUs = -1LL;
+        mBaseFrameUs = -1LL;
+        mPrevCaptureUs = -1LL;
+        mPrevFrameUs = -1LL;
         mFrameCount = 0;
         mInputBufferTimeOffsetUs = 0;
         mStopTimeUs = -1;
@@ -1201,7 +1201,7 @@
 
     Mutex::Autolock autoLock(mMutex);
 
-    if (mExecuting || repeatAfterUs <= 0ll) {
+    if (mExecuting || repeatAfterUs <= 0LL) {
         return INVALID_OPERATION;
     }
 
@@ -1213,7 +1213,7 @@
     Mutex::Autolock autoLock(mMutex);
 
     // timeOffsetUs must be negative for adjustment.
-    if (timeOffsetUs >= 0ll) {
+    if (timeOffsetUs >= 0LL) {
         return INVALID_OPERATION;
     }
 
@@ -1247,7 +1247,7 @@
 
     mSkipFramesBeforeNs =
             (skipFramesBeforeUs > 0 && skipFramesBeforeUs <= INT64_MAX / 1000) ?
-            (skipFramesBeforeUs * 1000) : -1ll;
+            (skipFramesBeforeUs * 1000) : -1LL;
 
     return OK;
 }
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index d393c7a..41bc16c 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -738,7 +738,7 @@
                 } else {
                     int64_t currentTime = mBufferTimestamps.top();
                     currentTime += mStreamInfo->aacSamplesPerFrame *
-                            1000000ll / mStreamInfo->aacSampleRate;
+                            1000000LL / mStreamInfo->aacSampleRate;
                     mBufferTimestamps.add(currentTime);
                 }
             } else {
@@ -989,7 +989,7 @@
                         // adjust/interpolate next time stamp
                         *currentBufLeft -= decodedSize;
                         *nextTimeStamp += mStreamInfo->aacSamplesPerFrame *
-                                1000000ll / mStreamInfo->aacSampleRate;
+                                1000000LL / mStreamInfo->aacSampleRate;
                         ALOGV("adjusted nextTimeStamp/size to %lld/%d",
                                 (long long) *nextTimeStamp, *currentBufLeft);
                     } else {
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
index 96e668e..6e437cf 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -63,7 +63,7 @@
       mInputSize(0),
       mInputFrame(NULL),
       mAllocatedFrameSize(0),
-      mInputTimeUs(-1ll),
+      mInputTimeUs(-1LL),
       mSawInputEOS(false),
       mSignalledError(false) {
     initPorts();
@@ -587,7 +587,7 @@
             // "Time" on the input buffer has in effect advanced by the
             // number of audio frames we just advanced nOffset by.
             inHeader->nTimeStamp +=
-                (copy * 1000000ll / mSampleRate)
+                (copy * 1000000LL / mSampleRate)
                     / (mNumChannels * sizeof(int16_t));
 
             if (inHeader->nFilledLen == 0) {
@@ -725,7 +725,7 @@
     mAllocatedFrameSize = 0;
 
     mSentCodecSpecificData = false;
-    mInputTimeUs = -1ll;
+    mInputTimeUs = -1LL;
     mSawInputEOS = false;
     mSignalledError = false;
 }
diff --git a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
index b7e84ec..34dd011 100644
--- a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
@@ -505,7 +505,7 @@
 
             outHeader->nTimeStamp =
                 mAnchorTimeUs
-                    + (mNumSamplesOutput * 1000000ll) / kSampleRateNB;
+                    + (mNumSamplesOutput * 1000000LL) / kSampleRateNB;
 
             mNumSamplesOutput += kNumSamplesPerFrameNB;
         } else {
@@ -513,7 +513,7 @@
 
             outHeader->nTimeStamp =
                 mAnchorTimeUs
-                    + (mNumSamplesOutput * 1000000ll) / kSampleRateWB;
+                    + (mNumSamplesOutput * 1000000LL) / kSampleRateWB;
 
             mNumSamplesOutput += kNumSamplesPerFrameWB;
         }
diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
index f97c44f..85ab64e 100644
--- a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
@@ -49,7 +49,7 @@
       mBitRate(0),
       mMode(MR475),
       mInputSize(0),
-      mInputTimeUs(-1ll),
+      mInputTimeUs(-1LL),
       mSawInputEOS(false),
       mSignalledError(false) {
     initPorts();
@@ -340,7 +340,7 @@
             // "Time" on the input buffer has in effect advanced by the
             // number of audio frames we just advanced nOffset by.
             inHeader->nTimeStamp +=
-                (copy * 1000000ll / kSampleRate) / sizeof(int16_t);
+                (copy * 1000000LL / kSampleRate) / sizeof(int16_t);
 
             if (inHeader->nFilledLen == 0) {
                 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
index a644b66..7fb8a4c 100644
--- a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
+++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
@@ -50,7 +50,7 @@
       mBitRate(0),
       mMode(VOAMRWB_MD66),
       mInputSize(0),
-      mInputTimeUs(-1ll),
+      mInputTimeUs(-1LL),
       mSawInputEOS(false),
       mSignalledError(false) {
     initPorts();
@@ -387,7 +387,7 @@
             // "Time" on the input buffer has in effect advanced by the
             // number of audio frames we just advanced nOffset by.
             inHeader->nTimeStamp +=
-                (copy * 1000000ll / kSampleRate) / sizeof(int16_t);
+                (copy * 1000000LL / kSampleRate) / sizeof(int16_t);
 
             if (inHeader->nFilledLen == 0) {
                 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
index 3924fc2..bf5e243 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
@@ -607,7 +607,7 @@
             timeTaken = mTimeEnd - mTimeStart;
 
             ALOGV("timeTaken=%6lldus delay=%6lldus numBytes=%6d",
-                    (long long) (timeTaken / 1000ll), (long long) (timeDelay / 1000ll),
+                    (long long) (timeTaken / 1000LL), (long long) (timeDelay / 1000LL),
                    s_dec_op.u4_num_bytes_consumed);
             if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
                 mFlushNeeded = true;
diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
index 4db0060..842a7ce 100644
--- a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
@@ -89,12 +89,12 @@
     def.eDir = OMX_DirOutput;
     def.nBufferCountMin = kNumOutputBuffers;
     def.nBufferCountActual = def.nBufferCountMin;
-    def.nBufferSize = 4096 * FLACDecoder::kMaxChannels;
+    def.nBufferSize = kNumSamplesPerFrame * FLACDecoder::kMaxChannels * sizeof(float);
     def.bEnabled = OMX_TRUE;
     def.bPopulated = OMX_FALSE;
     def.eDomain = OMX_PortDomainAudio;
     def.bBuffersContiguous = OMX_FALSE;
-    def.nBufferAlignment = 2;
+    def.nBufferAlignment = sizeof(float);
 
     def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
     def.format.audio.pNativeRender = NULL;
@@ -173,7 +173,7 @@
                 flacParams->nChannels = mStreamInfo.channels;
                 flacParams->nSampleRate = mStreamInfo.sample_rate;
             } else {
-                flacParams->nChannels = 1;
+                flacParams->nChannels = 2;
                 flacParams->nSampleRate = 44100;
             }
 
@@ -195,10 +195,10 @@
                 return OMX_ErrorBadPortIndex;
             }
 
-            pcmParams->eNumData = OMX_NumericalDataSigned;
+            pcmParams->eNumData = mNumericalData;
             pcmParams->eEndian = OMX_EndianBig;
             pcmParams->bInterleaved = OMX_TRUE;
-            pcmParams->nBitPerSample = 16;
+            pcmParams->nBitPerSample = mBitsPerSample;
             pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
             pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
             pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
@@ -211,7 +211,7 @@
                 pcmParams->nChannels = mStreamInfo.channels;
                 pcmParams->nSamplingRate = mStreamInfo.sample_rate;
             } else {
-                pcmParams->nChannels = 1;
+                pcmParams->nChannels = 2;
                 pcmParams->nSamplingRate = 44100;
             }
 
@@ -281,6 +281,19 @@
                 return OMX_ErrorBadPortIndex;
             }
 
+            if (pcmParams->eNumData == OMX_NumericalDataFloat && pcmParams->nBitPerSample == 32) {
+                mNumericalData = OMX_NumericalDataFloat;
+                mBitsPerSample = 32;
+            } else if (pcmParams->eNumData == OMX_NumericalDataSigned
+                     && pcmParams->nBitPerSample == 16) {
+                mNumericalData = OMX_NumericalDataSigned;
+                mBitsPerSample = 16;
+            } else {
+                ALOGE("Invalid eNumData %d, nBitsPerSample %d",
+                        pcmParams->eNumData, pcmParams->nBitPerSample);
+                return OMX_ErrorUndefined;
+            }
+
             return OMX_ErrorNone;
         }
 
@@ -301,11 +314,13 @@
     List<BufferInfo *> &inQueue = getPortQueue(0);
     List<BufferInfo *> &outQueue = getPortQueue(1);
 
+    const bool outputFloat = mNumericalData == OMX_NumericalDataFloat;
+
     ALOGV("onQueueFilled %d/%d:", inQueue.empty(), outQueue.empty());
     while ((!inQueue.empty() || mSawInputEOS) && !outQueue.empty() && !mFinishedDecoder) {
         BufferInfo *outInfo = *outQueue.begin();
         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
-        int16_t *outBuffer = reinterpret_cast<int16_t *>(outHeader->pBuffer + outHeader->nOffset);
+        void *outBuffer = reinterpret_cast<void *>(outHeader->pBuffer + outHeader->nOffset);
         size_t outBufferSize = outHeader->nAllocLen - outHeader->nOffset;
         int64_t timeStamp = 0;
 
@@ -374,7 +389,7 @@
             }
 
             status_t decoderErr = mFLACDecoder->decodeOneFrame(
-                    inBuffer, inBufferLength, outBuffer, &outBufferSize);
+                    inBuffer, inBufferLength, outBuffer, &outBufferSize, outputFloat);
             if (decoderErr != OK) {
                 ALOGE("onQueueFilled: FLACDecoder decodeOneFrame returns error %d", decoderErr);
                 mSignalledError = true;
@@ -393,7 +408,9 @@
                 continue;
             }
         } else if (mSawInputEOS) {
-            status_t decoderErr = mFLACDecoder->decodeOneFrame(NULL, 0, outBuffer, &outBufferSize);
+            status_t decoderErr = mFLACDecoder->decodeOneFrame(
+                    nullptr /* inBuffer */, 0 /* inBufferLen */,
+                    outBuffer, &outBufferSize, outputFloat);
             mFinishedDecoder = true;
             if (decoderErr != OK) {
                 ALOGE("onQueueFilled: FLACDecoder finish returns error %d", decoderErr);
@@ -456,7 +473,8 @@
             mOutputPortSettingsChange = AWAITING_ENABLED;
             PortInfo *info = editPortInfo(1 /* portIndex */);
             if (!info->mDef.bEnabled) {
-                info->mDef.nBufferSize = mStreamInfo.max_blocksize * mStreamInfo.channels * 2;
+                info->mDef.nBufferSize =
+                        mStreamInfo.max_blocksize * mStreamInfo.channels * sizeof(float);
             }
             break;
         }
diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
index b63f7ad..ba02074 100644
--- a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
@@ -45,10 +45,14 @@
     virtual void onReset() override;
 
 private:
+    static constexpr unsigned int kNumSamplesPerFrame = 2048; // adjusted based on stream.
+
     enum {
         kNumInputBuffers   = 4,
         kNumOutputBuffers  = 4,
     };
+    OMX_NUMERICALDATATYPE mNumericalData = OMX_NumericalDataSigned;
+    OMX_U32 mBitsPerSample = 16;
 
     FLACDecoder *mFLACDecoder;
     FLAC__StreamMetadata_StreamInfo mStreamInfo;
diff --git a/media/libstagefright/codecs/flac/enc/Android.bp b/media/libstagefright/codecs/flac/enc/Android.bp
index 9b696da..b32ab08 100644
--- a/media/libstagefright/codecs/flac/enc/Android.bp
+++ b/media/libstagefright/codecs/flac/enc/Android.bp
@@ -28,7 +28,10 @@
     ],
 
     header_libs: ["libbase_headers"],
-    static_libs: ["libFLAC"],
+    static_libs: [
+        "libaudioutils",
+        "libFLAC",
+    ],
 
     name: "libstagefright_soft_flacenc",
     vendor_available: true,
diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
index 955f211..3add006 100644
--- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
+++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
@@ -20,7 +20,7 @@
 #include <utils/Log.h>
 
 #include "SoftFlacEncoder.h"
-
+#include <audio_utils/primitives.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 
@@ -75,7 +75,9 @@
     }
 
     if (!mSignalledError) { // no use allocating input buffer if we had an error above
-        mInputBufferPcm32 = (FLAC__int32*) malloc(sizeof(FLAC__int32) * 2 * kMaxNumSamplesPerFrame);
+        // 2x the pcm16 samples can exist with the same size as pcmFloat samples.
+        mInputBufferPcm32 = (FLAC__int32*) malloc(
+                sizeof(FLAC__int32) * kNumSamplesPerFrame * kMaxChannels * 2);
         if (mInputBufferPcm32 == NULL) {
             ALOGE("SoftFlacEncoder::SoftFlacEncoder(name=%s) error allocating internal input buffer", name);
             mSignalledError = true;
@@ -115,14 +117,14 @@
     // configure input port of the encoder
     def.nPortIndex = 0;
     def.eDir = OMX_DirInput;
-    def.nBufferCountMin = kNumBuffers;// TODO verify that 1 is enough
+    def.nBufferCountMin = kNumBuffers;
     def.nBufferCountActual = def.nBufferCountMin;
     def.nBufferSize = kMaxInputBufferSize;
     def.bEnabled = OMX_TRUE;
     def.bPopulated = OMX_FALSE;
     def.eDomain = OMX_PortDomainAudio;
     def.bBuffersContiguous = OMX_FALSE;
-    def.nBufferAlignment = 2;
+    def.nBufferAlignment = sizeof(float);
 
     def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
     def.format.audio.pNativeRender = NULL;
@@ -134,7 +136,7 @@
     // configure output port of the encoder
     def.nPortIndex = 1;
     def.eDir = OMX_DirOutput;
-    def.nBufferCountMin = kNumBuffers;// TODO verify that 1 is enough
+    def.nBufferCountMin = kNumBuffers;
     def.nBufferCountActual = def.nBufferCountMin;
     def.nBufferSize = kMaxOutputBufferSize;
     def.bEnabled = OMX_TRUE;
@@ -193,10 +195,10 @@
                 return OMX_ErrorUndefined;
             }
 
-            pcmParams->eNumData = OMX_NumericalDataSigned;
+            pcmParams->eNumData = mNumericalData;
             pcmParams->eEndian = OMX_EndianBig;
             pcmParams->bInterleaved = OMX_TRUE;
-            pcmParams->nBitPerSample = 16;
+            pcmParams->nBitPerSample = mBitsPerSample;
             pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
             pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
             pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
@@ -270,12 +272,26 @@
                 return OMX_ErrorUndefined;
             }
 
-            if (pcmParams->nChannels < 1 || pcmParams->nChannels > 2) {
+            if (pcmParams->nChannels < 1 || pcmParams->nChannels > kMaxChannels) {
                 return OMX_ErrorUndefined;
             }
 
             mNumChannels = pcmParams->nChannels;
             mSampleRate = pcmParams->nSamplingRate;
+
+            if (pcmParams->eNumData == OMX_NumericalDataFloat && pcmParams->nBitPerSample == 32) {
+                mNumericalData = OMX_NumericalDataFloat;
+                mBitsPerSample = 32;
+            } else if (pcmParams->eNumData == OMX_NumericalDataSigned
+                     && pcmParams->nBitPerSample == 16) {
+                mNumericalData = OMX_NumericalDataSigned;
+                mBitsPerSample = 16;
+            } else {
+                ALOGE("%s: invalid eNumData %d, nBitsPerSample %d",
+                        __func__, pcmParams->eNumData, pcmParams->nBitPerSample);
+                return OMX_ErrorUndefined;
+            }
+
             ALOGV("will encode %d channels at %dHz", mNumChannels, mSampleRate);
 
             return configureEncoder();
@@ -356,6 +372,10 @@
     List<BufferInfo *> &inQueue = getPortQueue(0);
     List<BufferInfo *> &outQueue = getPortQueue(1);
 
+    const bool inputFloat = mNumericalData == OMX_NumericalDataFloat;
+    const size_t sampleSize = inputFloat ? sizeof(float) : sizeof(int16_t);
+    const size_t frameSize = sampleSize * mNumChannels;
+
     FLAC__bool ok = true;
 
     while ((!inQueue.empty() || mSawInputEOS) && !outQueue.empty() && !mSentOutputEOS) {
@@ -381,13 +401,21 @@
             mEncoderReturnedNbBytes = 0;
             mCurrentInputTimeStamp = inHeader->nTimeStamp;
 
-            const unsigned nbInputFrames = inHeader->nFilledLen / (2 * mNumChannels);
-            const unsigned nbInputSamples = inHeader->nFilledLen / 2;
-            const OMX_S16 * const pcm16 = reinterpret_cast<OMX_S16 *>(inHeader->pBuffer);
+            const unsigned nbInputFrames = inHeader->nFilledLen / frameSize;
+            const unsigned nbInputSamples = inHeader->nFilledLen / sampleSize;
 
-            CHECK_LE(nbInputSamples, 2 * kMaxNumSamplesPerFrame);
-            for (unsigned i=0 ; i < nbInputSamples ; i++) {
-                mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
+            if (inputFloat) {
+                CHECK_LE(nbInputSamples, kNumSamplesPerFrame * kMaxChannels);
+                const float * const pcmFloat = reinterpret_cast<float *>(inHeader->pBuffer);
+                 memcpy_to_q8_23_from_float_with_clamp(
+                         mInputBufferPcm32, pcmFloat, nbInputSamples);
+            } else {
+                // note nbInputSamples may be 2x as large for pcm16 data.
+                CHECK_LE(nbInputSamples, kNumSamplesPerFrame * kMaxChannels * 2);
+                const int16_t * const pcm16 = reinterpret_cast<int16_t *>(inHeader->pBuffer);
+                for (unsigned i = 0; i < nbInputSamples; ++i) {
+                    mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
+                }
             }
             ALOGV(" about to encode %u samples per channel", nbInputFrames);
             ok = FLAC__stream_encoder_process_interleaved(
@@ -526,10 +554,12 @@
         return OMX_ErrorInvalidState;
     }
 
+    const bool inputFloat = mNumericalData == OMX_NumericalDataFloat;
+    const int codecBitsPerSample = inputFloat ? 24 : 16;
     FLAC__bool ok = true;
     ok = ok && FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mNumChannels);
     ok = ok && FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, mSampleRate);
-    ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, 16);
+    ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, codecBitsPerSample);
     ok = ok && FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder,
             (unsigned)mCompressionLevel);
     ok = ok && FLAC__stream_encoder_set_verify(mFlacStreamEncoder, false);
diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h
index 64a6b1e..722fc13 100644
--- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h
+++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h
@@ -45,8 +45,10 @@
 
 private:
     const unsigned int kNumBuffers = 2;
-    const unsigned int kMaxNumSamplesPerFrame = 1152;
-    const unsigned int kMaxInputBufferSize = kMaxNumSamplesPerFrame * sizeof(int16_t) * 2;
+    static constexpr unsigned int kMaxChannels = 2;
+    static constexpr unsigned int kNumSamplesPerFrame = 1152;
+    static constexpr unsigned int kMaxInputBufferSize =
+            kNumSamplesPerFrame * kMaxChannels * sizeof(float);
     const unsigned int kMaxOutputBufferSize = 65536;    //TODO check if this can be reduced
 
     bool mSignalledError;
@@ -54,6 +56,8 @@
     OMX_U32 mNumChannels;
     OMX_U32 mSampleRate;
     OMX_U32 mCompressionLevel;
+    OMX_NUMERICALDATATYPE mNumericalData = OMX_NumericalDataSigned;
+    OMX_U32 mBitsPerSample = 16;
 
     // should the data received by the callback be written to the output port
     bool        mEncoderWriteData;
diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
index 7a4cca9..c14983a 100644
--- a/media/libstagefright/codecs/g711/dec/SoftG711.cpp
+++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
@@ -372,7 +372,7 @@
 
         int32_t step = 4 << segment;
 
-        int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33;
+        int32_t abs = (0x80L << exponent) + step * mantissa + step / 2 - 4 * 33;
 
         *out++ = (x < 0x80) ? -abs : abs;
     }
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index fda7028..a8fcdd1 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -382,6 +382,7 @@
     if (portIndex == 0 && mInitialized) {
         CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE);
     }
+    mFramesConfigured = false;
 }
 
 void SoftMPEG4::onReset() {
diff --git a/media/libstagefright/codecs/m4v_h263/enc/src/rate_control.cpp b/media/libstagefright/codecs/m4v_h263/enc/src/rate_control.cpp
index 53149c1..ecc3217 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/src/rate_control.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/src/rate_control.cpp
@@ -377,15 +377,15 @@
 /*  In/out   : Nr, B, Rr                                                    */
 /*  Return   : Void                                                         */
 /*  Modified :                                                              */
+/* Input argument "video" is guaranteed non-null by caller                  */
 /* ======================================================================== */
 
-
 PV_STATUS RC_UpdateBuffer(VideoEncData *video, Int currLayer, Int num_skip)
 {
     rateControl *rc  = video->rc[currLayer];
     MultiPass   *pMP = video->pMP[currLayer];
 
-    if (video == NULL || rc == NULL || pMP == NULL)
+    if (rc == NULL || pMP == NULL)
         return PV_FAIL;
 
     rc->VBV_fullness   -= (Int)(rc->bitrate / rc->framerate * num_skip); //rc[currLayer]->Rp;
@@ -524,6 +524,7 @@
 /*  In/out   : rc->T                                                                */
 /*  Return   : Void                                                                 */
 /*  Modified :                                                                      */
+/* Input argument "input" is guaranteed non-null by caller                          */
 /* ================================================================================ */
 
 void targetBitCalculation(void *input)
@@ -537,7 +538,7 @@
     Int diff_counter_BTsrc, diff_counter_BTdst, prev_counter_diff, curr_counter_diff, bound;
     /* BT = Bit Transfer, for pMP->counter_BTsrc, pMP->counter_BTdst */
 
-    if (video == NULL || currVol == NULL || pMP == NULL || rc == NULL)
+    if (currVol == NULL || pMP == NULL || rc == NULL)
         return;
 
     /* some stuff about frame dropping remained here to be done because pMP cannot be inserted into updateRateControl()*/
@@ -693,6 +694,7 @@
 /*  In/out   : rc->T and rc->Qc                                                     */
 /*  Return   : Void                                                                 */
 /*  Modified :                                                                      */
+/*  Input argument "input" is guaranteed non-null by caller                         */
 /* ================================================================================ */
 
 /* Mad based variable bit allocation + QP calculation with a new quadratic method */
@@ -708,7 +710,7 @@
     float curr_mad, prev_mad, curr_RD, prev_RD, average_mad, aver_QP;
 
 
-    if (video == NULL || currVol == NULL || pMP == NULL || rc == NULL)
+    if (currVol == NULL || pMP == NULL || rc == NULL)
         return;
 
     /* Mad based variable bit allocation */
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index cd984f0..80083f7 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -407,7 +407,7 @@
         }
 
         outHeader->nTimeStamp =
-            mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mSamplingRate;
+            mAnchorTimeUs + (mNumFramesOutput * 1000000LL) / mSamplingRate;
 
         if (inHeader) {
             CHECK_GE((int32_t)inHeader->nFilledLen, mConfig->inputBufferUsedLength);
diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
index 942f850..4f61aa8 100644
--- a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
+++ b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
@@ -430,6 +430,15 @@
                 return;
             }
 
+            if (size < sizeof(int64_t)) {
+                // The 2nd and 3rd input buffer are expected to contain
+                //  an int64_t (see below), so make sure we get at least
+                //  that much. The first input buffer must contain 19 bytes,
+                //  but that is checked already.
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
+            }
+
             if (mInputBufferCount == 0) {
                 delete mHeader;
                 mHeader = new OpusHeader();
@@ -573,7 +582,7 @@
         outHeader->nFilledLen = numFrames * sizeof(int16_t) * mHeader->channels;
 
         outHeader->nTimeStamp = mAnchorTimeUs +
-                                (mNumFramesOutput * 1000000ll) /
+                                (mNumFramesOutput * 1000000LL) /
                                 kRate;
 
         mNumFramesOutput += numFrames;
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index ce8d458..76a400c 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -554,7 +554,7 @@
 
         outHeader->nTimeStamp =
             mAnchorTimeUs
-                + (mNumFramesOutput * 1000000ll) / mVi->rate;
+                + (mNumFramesOutput * 1000000LL) / mVi->rate;
 
         mNumFramesOutput += numFrames;
 
diff --git a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
index f352fba..8a86a0d 100644
--- a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
+++ b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
@@ -110,15 +110,22 @@
 
 {
     initPorts();
-    CHECK_EQ(initDecoder(), (status_t)OK);
+    mMemoryVec.clear();
+    mDrcMemoryVec.clear();
+
+    CHECK_EQ(initDecoder(), IA_NO_ERROR);
 }
 
 SoftXAAC::~SoftXAAC() {
-    int errCode = deInitXAACDecoder();
-    if (0 != errCode) {
-        ALOGE("deInitXAACDecoder() failed %d", errCode);
+    IA_ERRORCODE err_code = deInitXAACDecoder();
+    if (IA_NO_ERROR != err_code) {
+        ALOGE("deInitXAACDecoder() failed %d", err_code);
     }
 
+    err_code = deInitMPEGDDDrc();
+    if (IA_NO_ERROR != err_code) {
+        ALOGE("deInitMPEGDDDrc() failed %d", err_code);
+    }
     mIsCodecInitialized = false;
     mIsCodecConfigFlushRequired = false;
 }
@@ -164,36 +171,16 @@
     addPort(def);
 }
 
-status_t SoftXAAC::initDecoder() {
-    status_t status = UNKNOWN_ERROR;
-
+IA_ERRORCODE SoftXAAC::initDecoder() {
     int ui_drc_val;
     IA_ERRORCODE err_code = IA_NO_ERROR;
     int loop = 0;
 
     err_code = initXAACDecoder();
     if (err_code != IA_NO_ERROR) {
-        if (NULL == mXheaacCodecHandle) {
-            ALOGE("AAC decoder handle is null");
-        }
-        if (NULL == mMpegDDrcHandle) {
-            ALOGE("MPEG-D DRC decoder handle is null");
-        }
-        for (loop = 1; loop < mMallocCount; loop++) {
-            if (mMemoryArray[loop] == NULL) {
-                ALOGE(" memory allocation error %d\n", loop);
-                break;
-            }
-        }
-        ALOGE("initXAACDecoder Failed");
-
-        for (loop = 0; loop < mMallocCount; loop++) {
-            if (mMemoryArray[loop]) free(mMemoryArray[loop]);
-        }
-        mMallocCount = 0;
-        return status;
-    } else {
-        status = OK;
+        ALOGE("initXAACDecoder failed with error %d", err_code);
+        deInitXAACDecoder();
+        return err_code;
     }
 
     mEndOfInput = false;
@@ -274,7 +261,7 @@
     RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_DRC_EFFECT_TYPE");
 
 #endif
-    return status;
+    return IA_NO_ERROR;
 }
 
 OMX_ERRORTYPE SoftXAAC::internalGetParameter(OMX_INDEXTYPE index, OMX_PTR params) {
@@ -547,9 +534,6 @@
     /* sample currently                                                  */
     if (mIsCodecInitialized) {
         numOutBytes = mOutputFrameLength * (mPcmWdSz / 8) * mNumChannels;
-        if ((mPcmWdSz / 8) != 2) {
-            ALOGE("XAAC assumes 2 bytes per sample! mPcmWdSz %d", mPcmWdSz);
-        }
     }
 
     while ((!inQueue.empty() || mEndOfInput) && !outQueue.empty()) {
@@ -569,8 +553,8 @@
                 inBufferLength = inHeader->nFilledLen;
 
                 /* GA header configuration sent to Decoder! */
-                int err_code = configXAACDecoder(inBuffer, inBufferLength);
-                if (0 != err_code) {
+                IA_ERRORCODE err_code = configXAACDecoder(inBuffer, inBufferLength);
+                if (IA_NO_ERROR != err_code) {
                     ALOGW("configXAACDecoder err_code = %d", err_code);
                     mSignalledError = true;
                     notify(OMX_EventError, OMX_ErrorUndefined, err_code, NULL);
@@ -665,7 +649,7 @@
                     mCurrentTimestamp = inHeader->nTimeStamp;
                     mLastInHeader = inHeader;
                 } else {
-                    mCurrentTimestamp = mPrevTimestamp + mOutputFrameLength * 1000000ll / mSampFreq;
+                    mCurrentTimestamp = mPrevTimestamp + mOutputFrameLength * 1000000LL / mSampFreq;
                 }
             } else {
                 inBuffer = inHeader->pBuffer + inHeader->nOffset;
@@ -682,8 +666,8 @@
             /* which should initialize the codec. Once this state is reached, call the  */
             /* decodeXAACStream API with same frame to decode!                        */
             if (!mIsCodecInitialized) {
-                int err_code = configXAACDecoder(inBuffer, inBufferLength);
-                if (0 != err_code) {
+                IA_ERRORCODE err_code = configXAACDecoder(inBuffer, inBufferLength);
+                if (IA_NO_ERROR != err_code) {
                     ALOGW("configXAACDecoder Failed 2 err_code = %d", err_code);
                     mSignalledError = true;
                     notify(OMX_EventError, OMX_ErrorUndefined, err_code, NULL);
@@ -845,7 +829,7 @@
     }
 }
 
-int SoftXAAC::configflushDecode() {
+IA_ERRORCODE SoftXAAC::configflushDecode() {
     IA_ERRORCODE err_code;
     UWORD32 ui_init_done;
     uint32_t inBufferLength = 8203;
@@ -871,16 +855,13 @@
             "Found Codec with below config---\nsampFreq %d\nnumChannels %d\npcmWdSz "
             "%d\nchannelMask %d\noutputFrameLength %d",
             mSampFreq, mNumChannels, mPcmWdSz, mChannelMask, mOutputFrameLength);
-        if (mNumChannels > MAX_CHANNEL_COUNT) {
-            ALOGE(" No of channels are more than max channels\n");
-            mIsCodecInitialized = false;
-        } else
-            mIsCodecInitialized = true;
+
+        mIsCodecInitialized = true;
     }
-    return err_code;
+    return IA_NO_ERROR;
 }
-int SoftXAAC::drainDecoder() {
-    return 0;
+IA_ERRORCODE SoftXAAC::drainDecoder() {
+    return IA_NO_ERROR;
 }
 
 void SoftXAAC::onReset() {
@@ -921,7 +902,7 @@
     }
 }
 
-int SoftXAAC::initXAACDecoder() {
+IA_ERRORCODE SoftXAAC::initXAACDecoder() {
     LOOPIDX i;
 
     /* Error code */
@@ -939,11 +920,11 @@
     UWORD32 ui_proc_mem_tabs_size;
     /* API size */
     UWORD32 pui_api_size;
+    pVOID pv_alloc_ptr;
 
     mInputBufferSize = 0;
     mInputBuffer = 0;
     mOutputBuffer = 0;
-    mMallocCount = 0;
 
     /* Process struct initing end */
     /* ******************************************************************/
@@ -954,20 +935,13 @@
     err_code = ixheaacd_dec_api(NULL, IA_API_CMD_GET_API_SIZE, 0, &pui_api_size);
     RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_API_SIZE");
 
-    if (mMallocCount == MAX_MEM_ALLOCS) {
-        ALOGE("mMemoryArray is full");
-        return IA_FATAL_ERROR;
-    }
-
     /* Allocate memory for API */
-    mMemoryArray[mMallocCount] = memalign(4, pui_api_size);
-    if (mMemoryArray[mMallocCount] == NULL) {
+    mXheaacCodecHandle = memalign(4, pui_api_size);
+    if (mXheaacCodecHandle == NULL) {
         ALOGE("malloc for pui_api_size + 4 >> %d Failed", pui_api_size + 4);
         return IA_FATAL_ERROR;
     }
-    /* Set API object with the memory allocated */
-    mXheaacCodecHandle = (pVOID)((WORD8*)mMemoryArray[mMallocCount]);
-    mMallocCount++;
+    mMemoryVec.push(mXheaacCodecHandle);
 
     /* Set the config params to default values */
     err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT,
@@ -979,23 +953,16 @@
 
     RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_API_SIZE");
 
-    if (mMallocCount == MAX_MEM_ALLOCS) {
-        ALOGE("mMemoryArray is full");
-        return IA_FATAL_ERROR;
-    }
-
     /* Allocate memory for API */
-    mMemoryArray[mMallocCount] = memalign(4, pui_api_size);
+    mMpegDDrcHandle = memalign(4, pui_api_size);
 
-    if (mMemoryArray[mMallocCount] == NULL) {
+    if (mMpegDDrcHandle == NULL) {
         ALOGE("malloc for drc api structure Failed");
         return IA_FATAL_ERROR;
     }
-    memset(mMemoryArray[mMallocCount], 0, pui_api_size);
+    mMemoryVec.push(mMpegDDrcHandle);
 
-    /* Set API object with the memory allocated */
-    mMpegDDrcHandle = (pVOID)((WORD8*)mMemoryArray[mMallocCount]);
-    mMallocCount++;
+    memset(mMpegDDrcHandle, 0, pui_api_size);
 
     /* Set the config params to default values */
     err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
@@ -1021,23 +988,17 @@
                                 &ui_proc_mem_tabs_size);
     RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEMTABS_SIZE");
 
-    if (mMallocCount == MAX_MEM_ALLOCS) {
-        ALOGE("mMemoryArray is full");
-        return IA_FATAL_ERROR;
-    }
-
-    mMemoryArray[mMallocCount] = memalign(4, ui_proc_mem_tabs_size);
-    if (mMemoryArray[mMallocCount] == NULL) {
+    pv_alloc_ptr = memalign(4, ui_proc_mem_tabs_size);
+    if (pv_alloc_ptr == NULL) {
         ALOGE("Malloc for size (ui_proc_mem_tabs_size + 4) = %d failed!",
               ui_proc_mem_tabs_size + 4);
         return IA_FATAL_ERROR;
     }
-    mMallocCount++;
-    /* Set pointer for process memory tables    */
-    err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_MEMTABS_PTR, 0,
-                                (pVOID)((WORD8*)mMemoryArray[mMallocCount - 1]));
-    RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEMTABS_PTR");
+    mMemoryVec.push(pv_alloc_ptr);
 
+    /* Set pointer for process memory tables    */
+    err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_MEMTABS_PTR, 0, pv_alloc_ptr);
+    RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEMTABS_PTR");
 
     /* initialize the API, post config, fill memory tables  */
     err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT,
@@ -1066,17 +1027,12 @@
         err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_MEM_INFO_TYPE, i, &ui_type);
         RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_TYPE");
 
-        if (mMallocCount == MAX_MEM_ALLOCS) {
-            ALOGE("mMemoryArray is full");
-            return IA_FATAL_ERROR;
-        }
-        mMemoryArray[mMallocCount] = memalign(ui_alignment, ui_size);
-        if (mMemoryArray[mMallocCount] == NULL) {
+        pv_alloc_ptr = memalign(ui_alignment, ui_size);
+        if (pv_alloc_ptr == NULL) {
             ALOGE("Malloc for size (ui_size + ui_alignment) = %d failed!", ui_size + ui_alignment);
             return IA_FATAL_ERROR;
         }
-        pv_alloc_ptr = (pVOID)((WORD8*)mMemoryArray[mMallocCount]);
-        mMallocCount++;
+        mMemoryVec.push(pv_alloc_ptr);
 
         /* Set the buffer pointer */
         err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_MEM_PTR, i, pv_alloc_ptr);
@@ -1095,7 +1051,7 @@
     return IA_NO_ERROR;
 }
 
-int SoftXAAC::configXAACDecoder(uint8_t* inBuffer, uint32_t inBufferLength) {
+IA_ERRORCODE SoftXAAC::configXAACDecoder(uint8_t* inBuffer, uint32_t inBufferLength) {
     UWORD32 ui_init_done;
     int32_t i_bytes_consumed;
 
@@ -1154,13 +1110,73 @@
 
     return IA_NO_ERROR;
 }
-int SoftXAAC::configMPEGDDrc() {
+IA_ERRORCODE SoftXAAC::initMPEGDDDrc() {
+    IA_ERRORCODE err_code = IA_NO_ERROR;
+    int i;
+
+    for (i = 0; i < (WORD32)2; i++) {
+        WORD32 ui_size, ui_alignment, ui_type;
+        pVOID pv_alloc_ptr;
+
+        /* Get memory size */
+        err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEM_INFO_SIZE, i, &ui_size);
+
+        RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_SIZE");
+
+        /* Get memory alignment */
+        err_code =
+            ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEM_INFO_ALIGNMENT, i, &ui_alignment);
+
+        RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_ALIGNMENT");
+
+        /* Get memory type */
+        err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEM_INFO_TYPE, i, &ui_type);
+        RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_TYPE");
+
+        pv_alloc_ptr = memalign(4, ui_size);
+        if (pv_alloc_ptr == NULL) {
+            ALOGE(" Cannot create requested memory  %d", ui_size);
+            return IA_FATAL_ERROR;
+        }
+        mDrcMemoryVec.push(pv_alloc_ptr);
+
+        /* Set the buffer pointer */
+        err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEM_PTR, i, pv_alloc_ptr);
+
+        RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR");
+    }
+
+    WORD32 ui_size;
+    ui_size = 8192 * 2;
+
+    mDrcInBuf = (int8_t*)memalign(4, ui_size);
+    if (mDrcInBuf == NULL) {
+        ALOGE(" Cannot create requested memory  %d", ui_size);
+        return IA_FATAL_ERROR;
+    }
+    mDrcMemoryVec.push(mDrcInBuf);
+
+    err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEM_PTR, 2, mDrcInBuf);
+    RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR");
+
+    mDrcOutBuf = (int8_t*)memalign(4, ui_size);
+    if (mDrcOutBuf == NULL) {
+        ALOGE(" Cannot create requested memory  %d", ui_size);
+        return IA_FATAL_ERROR;
+    }
+    mDrcMemoryVec.push(mDrcOutBuf);
+
+    err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEM_PTR, 3, mDrcOutBuf);
+    RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR");
+
+    return IA_NO_ERROR;
+}
+IA_ERRORCODE SoftXAAC::configMPEGDDrc() {
     IA_ERRORCODE err_code = IA_NO_ERROR;
     int i_effect_type;
     int i_loud_norm;
     int i_target_loudness;
     unsigned int i_sbr_mode;
-    int n_mems;
     int i;
 
 #ifdef ENABLE_MPEG_D_DRC
@@ -1217,78 +1233,16 @@
 
         RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS");
 
-        for (i = 0; i < (WORD32)2; i++) {
-            WORD32 ui_size, ui_alignment, ui_type;
-            pVOID pv_alloc_ptr;
+        /* Free any memory that is allocated for MPEG D Drc so far */
+        deInitMPEGDDDrc();
 
-            /* Get memory size */
-            err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEM_INFO_SIZE, i, &ui_size);
-
-            RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_SIZE");
-
-            /* Get memory alignment */
-            err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEM_INFO_ALIGNMENT, i,
-                                      &ui_alignment);
-
-            RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_ALIGNMENT");
-
-            /* Get memory type */
-            err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEM_INFO_TYPE, i, &ui_type);
-            RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_TYPE");
-            if (mMallocCount == MAX_MEM_ALLOCS) {
-                ALOGE("mMemoryArray is full");
-                return IA_FATAL_ERROR;
-            }
-
-            mMemoryArray[mMallocCount] = memalign(4, ui_size);
-            if (mMemoryArray[mMallocCount] == NULL) {
-                ALOGE(" Cannot create requested memory  %d", ui_size);
-                return IA_FATAL_ERROR;
-            }
-            pv_alloc_ptr = (pVOID)((WORD8*)mMemoryArray[mMallocCount]);
-            mMallocCount++;
-
-            /* Set the buffer pointer */
-            err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEM_PTR, i, pv_alloc_ptr);
-
-            RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR");
+        err_code = initMPEGDDDrc();
+        if (err_code != IA_NO_ERROR) {
+            ALOGE("initMPEGDDDrc failed with error %d", err_code);
+            deInitMPEGDDDrc();
+            return err_code;
         }
-        {
-            WORD32 ui_size;
-            ui_size = 8192 * 2;
-            if (mMallocCount == MAX_MEM_ALLOCS) {
-                ALOGE("mMemoryArray is full");
-                return IA_FATAL_ERROR;
-            }
 
-            mMemoryArray[mMallocCount] = memalign(4, ui_size);
-            if (mMemoryArray[mMallocCount] == NULL) {
-                ALOGE(" Cannot create requested memory  %d", ui_size);
-                return IA_FATAL_ERROR;
-            }
-
-            mDrcInBuf = (int8_t*)mMemoryArray[mMallocCount];
-            mMallocCount++;
-            err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEM_PTR, 2,
-                                      /*mOutputBuffer*/ mDrcInBuf);
-            RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR");
-
-            if (mMallocCount == MAX_MEM_ALLOCS) {
-                ALOGE("mMemoryArray is full");
-                return IA_FATAL_ERROR;
-            }
-            mMemoryArray[mMallocCount] = memalign(4, ui_size);
-            if (mMemoryArray[mMallocCount] == NULL) {
-                ALOGE(" Cannot create requested memory  %d", ui_size);
-                return IA_FATAL_ERROR;
-            }
-
-            mDrcOutBuf = (int8_t*)mMemoryArray[mMallocCount];
-            mMallocCount++;
-            err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEM_PTR, 3,
-                                      /*mOutputBuffer*/ mDrcOutBuf);
-            RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR");
-        }
         /* DRC buffers
             buf[0] - contains extension element pay load loudness related
             buf[1] - contains extension element pay load*/
@@ -1423,10 +1377,10 @@
     }
 #endif
 
-    return err_code;
+    return IA_NO_ERROR;
 }
-int SoftXAAC::decodeXAACStream(uint8_t* inBuffer, uint32_t inBufferLength, int32_t* bytesConsumed,
-                               int32_t* outBytes) {
+IA_ERRORCODE SoftXAAC::decodeXAACStream(uint8_t* inBuffer, uint32_t inBufferLength,
+                                        int32_t* bytesConsumed, int32_t* outBytes) {
     if (mInputBufferSize < inBufferLength) {
         ALOGE("Cannot config AAC, input buffer size %d < inBufferLength %d", mInputBufferSize,
               inBufferLength);
@@ -1516,24 +1470,33 @@
         memcpy(mOutputBuffer, mDrcOutBuf, *outBytes);
     }
 #endif
-    return err_code;
+    return IA_NO_ERROR;
 }
 
-int SoftXAAC::deInitXAACDecoder() {
+IA_ERRORCODE SoftXAAC::deInitXAACDecoder() {
     ALOGI("deInitXAACDecoder");
 
     /* Tell that the input is over in this buffer */
     IA_ERRORCODE err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INPUT_OVER, 0, NULL);
-    RETURN_IF_FATAL(err_code, "IA_API_CMD_INPUT_OVER");
 
-    for (int i = 0; i < mMallocCount; i++) {
-        if (mMemoryArray[i]) free(mMemoryArray[i]);
+    /* Irrespective of error returned in IA_API_CMD_INPUT_OVER, free allocated memory */
+    for (void* buf : mMemoryVec) {
+        free(buf);
     }
-    mMallocCount = 0;
-
+    mMemoryVec.clear();
     return err_code;
 }
 
+IA_ERRORCODE SoftXAAC::deInitMPEGDDDrc() {
+    ALOGI("deInitMPEGDDDrc");
+
+    for (void* buf : mDrcMemoryVec) {
+        free(buf);
+    }
+    mDrcMemoryVec.clear();
+    return IA_NO_ERROR;
+}
+
 IA_ERRORCODE SoftXAAC::getXAACStreamInfo() {
     IA_ERRORCODE err_code = IA_NO_ERROR;
 
@@ -1546,11 +1509,19 @@
     err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
                                 IA_ENHAACPLUS_DEC_CONFIG_PARAM_NUM_CHANNELS, &mNumChannels);
     RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_NUM_CHANNELS");
+    if (mNumChannels > MAX_CHANNEL_COUNT) {
+        ALOGE(" No of channels are more than max channels\n");
+        return IA_FATAL_ERROR;
+    }
 
     /* PCM word size */
     err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
                                 IA_ENHAACPLUS_DEC_CONFIG_PARAM_PCM_WDSZ, &mPcmWdSz);
     RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_PCM_WDSZ");
+    if ((mPcmWdSz / 8) != 2) {
+        ALOGE("Invalid Number of bytes per sample: %d, Expected is 2", mPcmWdSz);
+        return IA_FATAL_ERROR;
+    }
 
     /* channel mask to tell the arrangement of channels in bit stream */
     err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
diff --git a/media/libstagefright/codecs/xaacdec/SoftXAAC.h b/media/libstagefright/codecs/xaacdec/SoftXAAC.h
index 6176082..a62a797 100644
--- a/media/libstagefright/codecs/xaacdec/SoftXAAC.h
+++ b/media/libstagefright/codecs/xaacdec/SoftXAAC.h
@@ -33,8 +33,6 @@
 #include "impd_apicmd_standards.h"
 #include "impd_drc_config_params.h"
 
-#define MAX_MEM_ALLOCS 100
-
 extern "C" IA_ERRORCODE ixheaacd_dec_api(pVOID p_ia_module_obj, WORD32 i_cmd, WORD32 i_idx,
                                          pVOID pv_value);
 extern "C" IA_ERRORCODE ia_drc_dec_api(pVOID p_ia_module_obj, WORD32 i_cmd, WORD32 i_idx,
@@ -80,18 +78,19 @@
     enum { NONE, AWAITING_DISABLED, AWAITING_ENABLED } mOutputPortSettingsChange;
 
     void initPorts();
-    status_t initDecoder();
+    IA_ERRORCODE initDecoder();
     bool isConfigured() const;
-    int drainDecoder();
-    int initXAACDecoder();
-    int deInitXAACDecoder();
+    IA_ERRORCODE drainDecoder();
+    IA_ERRORCODE initXAACDecoder();
+    IA_ERRORCODE deInitXAACDecoder();
+    IA_ERRORCODE initMPEGDDDrc();
+    IA_ERRORCODE deInitMPEGDDDrc();
+    IA_ERRORCODE configXAACDecoder(uint8_t* inBuffer, uint32_t inBufferLength);
+    IA_ERRORCODE configMPEGDDrc();
+    IA_ERRORCODE decodeXAACStream(uint8_t* inBuffer, uint32_t inBufferLength,
+                                  int32_t* bytesConsumed, int32_t* outBytes);
 
-    int configXAACDecoder(uint8_t* inBuffer, uint32_t inBufferLength);
-    int configMPEGDDrc();
-    int decodeXAACStream(uint8_t* inBuffer, uint32_t inBufferLength, int32_t* bytesConsumed,
-                         int32_t* outBytes);
-
-    int configflushDecode();
+    IA_ERRORCODE configflushDecode();
     IA_ERRORCODE getXAACStreamInfo();
     IA_ERRORCODE setXAACDRCInfo(int32_t drcCut, int32_t drcBoost, int32_t drcRefLevel,
                                 int32_t drcHeavyCompression
@@ -120,9 +119,8 @@
     int8_t* mDrcOutBuf;
     int32_t mMpegDDRCPresent;
     int32_t mDRCFlag;
-
-    void* mMemoryArray[MAX_MEM_ALLOCS];
-    int32_t mMallocCount;
+    Vector<void*> mMemoryVec;
+    Vector<void*> mDrcMemoryVec;
 
     DISALLOW_EVIL_CONSTRUCTORS(SoftXAAC);
 };
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 86bd9d6..d136d9e 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -27,6 +27,7 @@
 
 #include "libyuv/convert_from.h"
 #include "libyuv/convert_argb.h"
+#include "libyuv/planar_functions.h"
 #include "libyuv/video_common.h"
 #include <functional>
 #include <sys/time.h>
@@ -91,10 +92,17 @@
 
         case OMX_COLOR_FormatCbYCrY:
         case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
-        case OMX_COLOR_FormatYUV420SemiPlanar:
         case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
             return mDstFormat == OMX_COLOR_Format16bitRGB565;
 
+        case OMX_COLOR_FormatYUV420SemiPlanar:
+#ifdef USE_LIBYUV
+            return mDstFormat == OMX_COLOR_Format16bitRGB565
+                    || mDstFormat == OMX_COLOR_Format32BitRGBA8888;
+#else
+            return mDstFormat == OMX_COLOR_Format16bitRGB565;
+#endif
+
         default:
             return false;
     }
@@ -236,7 +244,11 @@
             break;
 
         case OMX_COLOR_FormatYUV420SemiPlanar:
+#ifdef USE_LIBYUV
+            err = convertYUV420SemiPlanarUseLibYUV(src, dst);
+#else
             err = convertYUV420SemiPlanar(src, dst);
+#endif
             break;
 
         case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
@@ -365,6 +377,36 @@
     return OK;
 }
 
+status_t ColorConverter::convertYUV420SemiPlanarUseLibYUV(
+        const BitmapParams &src, const BitmapParams &dst) {
+    uint8_t *dst_ptr = (uint8_t *)dst.mBits
+        + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
+
+    const uint8_t *src_y =
+        (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft;
+
+    const uint8_t *src_u =
+        (const uint8_t *)src.mBits + src.mStride * src.mHeight
+        + (src.mCropTop / 2) * src.mStride + src.mCropLeft;
+
+    switch (mDstFormat) {
+    case OMX_COLOR_Format16bitRGB565:
+        libyuv::NV12ToRGB565(src_y, src.mStride, src_u, src.mStride, (uint8 *)dst_ptr,
+                dst.mStride, src.cropWidth(), src.cropHeight());
+        break;
+
+    case OMX_COLOR_Format32BitRGBA8888:
+        libyuv::NV12ToARGB(src_y, src.mStride, src_u, src.mStride, (uint8 *)dst_ptr,
+                dst.mStride, src.cropWidth(), src.cropHeight());
+        break;
+
+    default:
+        return ERROR_UNSUPPORTED;
+   }
+
+   return OK;
+}
+
 std::function<void (void *, void *, void *, size_t,
                     signed *, signed *, signed *, signed *)>
 getReadFromSrc(OMX_COLOR_FORMATTYPE srcFormat) {
@@ -852,7 +894,7 @@
 
     const uint8_t *src_u =
         (const uint8_t *)src.mBits + src.mHeight * src.mStride +
-        src.mCropTop * src.mStride / 2 + src.mCropLeft;
+        (src.mCropTop / 2) * src.mStride + src.mCropLeft;
 
     for (size_t y = 0; y < src.cropHeight(); ++y) {
         for (size_t x = 0; x < src.cropWidth(); x += 2) {
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
index 751b053..307c9b0 100644
--- a/media/libstagefright/flac/dec/Android.bp
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -27,11 +27,17 @@
     },
 
     static: {
-        whole_static_libs: ["libFLAC"],
+        whole_static_libs: [
+            "libFLAC",
+            "libaudioutils",
+        ],
     },
 
     shared: {
-        static_libs: ["libFLAC"],
+        static_libs: [
+            "libFLAC",
+            "libaudioutils",
+        ],
     },
 
     shared_libs: [
diff --git a/media/libstagefright/flac/dec/FLACDecoder.cpp b/media/libstagefright/flac/dec/FLACDecoder.cpp
index dfdc41c..cef0bc6 100644
--- a/media/libstagefright/flac/dec/FLACDecoder.cpp
+++ b/media/libstagefright/flac/dec/FLACDecoder.cpp
@@ -20,6 +20,7 @@
 
 #include "FLACDecoder.h"
 
+#include <audio_utils/primitives.h> // float_from_i32
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaDefs.h>
@@ -117,104 +118,43 @@
     mErrorStatus = status;
 }
 
-// Copy samples from FLAC native 32-bit non-interleaved to 16-bit interleaved.
+// Copy samples from FLAC native 32-bit non-interleaved to 16-bit signed
+// or 32-bit float interleaved.
+// TODO: Consider moving to audio_utils.  See similar code at FLACExtractor.cpp
 // These are candidates for optimization if needed.
-static void copyMono8(
-        int16_t *dst,
-        const int * src[FLACDecoder::kMaxChannels],
+static void copyTo16Signed(
+        short *dst,
+        const int *const *src,
         unsigned nSamples,
-        unsigned /* nChannels */) {
-    for (unsigned i = 0; i < nSamples; ++i) {
-        *dst++ = src[0][i] << 8;
-    }
-}
-
-static void copyStereo8(
-        int16_t *dst,
-        const int * src[FLACDecoder::kMaxChannels],
-        unsigned nSamples,
-        unsigned /* nChannels */) {
-    for (unsigned i = 0; i < nSamples; ++i) {
-        *dst++ = src[0][i] << 8;
-        *dst++ = src[1][i] << 8;
-    }
-}
-
-static void copyMultiCh8(
-        int16_t *dst,
-        const int * src[FLACDecoder::kMaxChannels],
-        unsigned nSamples,
-        unsigned nChannels) {
-    for (unsigned i = 0; i < nSamples; ++i) {
-        for (unsigned c = 0; c < nChannels; ++c) {
-            *dst++ = src[c][i] << 8;
+        unsigned nChannels,
+        unsigned bitsPerSample) {
+    const int leftShift = 16 - (int)bitsPerSample; // cast to int to prevent unsigned overflow.
+    if (leftShift >= 0) {
+        for (unsigned i = 0; i < nSamples; ++i) {
+            for (unsigned c = 0; c < nChannels; ++c) {
+                *dst++ = src[c][i] << leftShift;
+            }
+        }
+    } else {
+        const int rightShift = -leftShift;
+        for (unsigned i = 0; i < nSamples; ++i) {
+            for (unsigned c = 0; c < nChannels; ++c) {
+                *dst++ = src[c][i] >> rightShift;
+            }
         }
     }
 }
 
-static void copyMono16(
-        int16_t *dst,
-        const int * src[FLACDecoder::kMaxChannels],
+static void copyToFloat(
+        float *dst,
+        const int *const *src,
         unsigned nSamples,
-        unsigned /* nChannels */) {
-    for (unsigned i = 0; i < nSamples; ++i) {
-        *dst++ = src[0][i];
-    }
-}
-
-static void copyStereo16(
-        int16_t *dst,
-        const int * src[FLACDecoder::kMaxChannels],
-        unsigned nSamples,
-        unsigned /* nChannels */) {
-    for (unsigned i = 0; i < nSamples; ++i) {
-        *dst++ = src[0][i];
-        *dst++ = src[1][i];
-    }
-}
-
-static void copyMultiCh16(
-        int16_t *dst,
-        const int * src[FLACDecoder::kMaxChannels],
-        unsigned nSamples,
-        unsigned nChannels) {
+        unsigned nChannels,
+        unsigned bitsPerSample) {
+    const unsigned leftShift = 32 - bitsPerSample;
     for (unsigned i = 0; i < nSamples; ++i) {
         for (unsigned c = 0; c < nChannels; ++c) {
-            *dst++ = src[c][i];
-        }
-    }
-}
-
-// TODO: 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
-static void copyMono24(
-        int16_t *dst,
-        const int * src[FLACDecoder::kMaxChannels],
-        unsigned nSamples,
-        unsigned /* nChannels */) {
-    for (unsigned i = 0; i < nSamples; ++i) {
-        *dst++ = src[0][i] >> 8;
-    }
-}
-
-static void copyStereo24(
-        int16_t *dst,
-        const int * src[FLACDecoder::kMaxChannels],
-        unsigned nSamples,
-        unsigned /* nChannels */) {
-    for (unsigned i = 0; i < nSamples; ++i) {
-        *dst++ = src[0][i] >> 8;
-        *dst++ = src[1][i] >> 8;
-    }
-}
-
-static void copyMultiCh24(
-        int16_t *dst,
-        const int * src[FLACDecoder::kMaxChannels],
-        unsigned nSamples,
-        unsigned nChannels) {
-    for (unsigned i = 0; i < nSamples; ++i) {
-        for (unsigned c = 0; c < nChannels; ++c) {
-            *dst++ = src[c][i] >> 8;
+            *dst++ = float_from_i32(src[c][i] << leftShift);
         }
     }
 }
@@ -238,8 +178,7 @@
       mStreamInfoValid(false),
       mWriteRequested(false),
       mWriteCompleted(false),
-      mErrorStatus((FLAC__StreamDecoderErrorStatus) -1),
-      mCopy(nullptr) {
+      mErrorStatus((FLAC__StreamDecoderErrorStatus) -1) {
     ALOGV("ctor:");
     memset(&mStreamInfo, 0, sizeof(mStreamInfo));
     memset(&mWriteHeader, 0, sizeof(mWriteHeader));
@@ -379,6 +318,7 @@
         case 8:
         case 16:
         case 24:
+        case 32: // generally rare, but is supported in the framework
             break;
 
         default:
@@ -387,31 +327,6 @@
             return ERROR_MALFORMED;
     }
 
-    // configure the appropriate copy function, defaulting to trespass
-    static const struct {
-        unsigned mChannels;
-        unsigned mBitsPerSample;
-        void (*mCopy)(int16_t *dst, const int * src[kMaxChannels],
-                unsigned nSamples, unsigned nChannels);
-    } table[] = {
-        { 1,  8, copyMono8     },
-        { 2,  8, copyStereo8   },
-        { 8,  8, copyMultiCh8  },
-        { 1, 16, copyMono16    },
-        { 2, 16, copyStereo16  },
-        { 8, 16, copyMultiCh16 },
-        { 1, 24, copyMono24    },
-        { 2, 24, copyStereo24  },
-        { 8, 24, copyMultiCh24 },
-    };
-    for (const auto &entry : table) {
-        if (entry.mChannels >= getChannels() &&
-                entry.mBitsPerSample == getBitsPerSample()) {
-            mCopy = entry.mCopy;
-            break;
-        }
-    }
-
     // Now we have all metadata blocks.
     mBufferPos = 0;
     mBufferDataSize = 0;
@@ -420,7 +335,7 @@
 }
 
 status_t FLACDecoder::decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen,
-        int16_t *outBuffer, size_t *outBufferLen) {
+        void *outBuffer, size_t *outBufferLen, bool outputFloat) {
     ALOGV("decodeOneFrame: input size(%zu)", inBufferLen);
 
     if (!mStreamInfoValid) {
@@ -469,21 +384,33 @@
         return ERROR_MALFORMED;
     }
 
-    size_t bufferSize = blocksize * getChannels() * sizeof(int16_t);
+    const unsigned channels = getChannels();
+    const size_t sampleSize = outputFloat ? sizeof(float) : sizeof(int16_t);
+    const size_t frameSize = channels * sampleSize;
+    size_t bufferSize = blocksize * frameSize;
     if (bufferSize > *outBufferLen) {
         ALOGW("decodeOneFrame: output buffer holds only partial frame %zu:%zu",
                 *outBufferLen, bufferSize);
-        blocksize = *outBufferLen / (getChannels() * sizeof(int16_t));
-        bufferSize = blocksize * getChannels() * sizeof(int16_t);
+        blocksize = *outBufferLen / frameSize;
+        bufferSize = blocksize * frameSize;
     }
 
-    if (mCopy == nullptr) {
-        ALOGE("decodeOneFrame: format is not supported: channels(%d), BitsPerSample(%d)",
-                getChannels(), getBitsPerSample());
-        return ERROR_UNSUPPORTED;
-    }
     // copy PCM from FLAC write buffer to output buffer, with interleaving
-    (*mCopy)(outBuffer, mWriteBuffer, blocksize, getChannels());
+
+    const unsigned bitsPerSample = getBitsPerSample();
+    if (outputFloat) {
+        copyToFloat(reinterpret_cast<float*>(outBuffer),
+                    mWriteBuffer,
+                    blocksize,
+                    channels,
+                    bitsPerSample);
+    } else {
+        copyTo16Signed(reinterpret_cast<short*>(outBuffer),
+                       mWriteBuffer,
+                       blocksize,
+                       channels,
+                       bitsPerSample);
+    }
     *outBufferLen = bufferSize;
     return OK;
 }
diff --git a/media/libstagefright/flac/dec/FLACDecoder.h b/media/libstagefright/flac/dec/FLACDecoder.h
index af419a2..694fccb 100644
--- a/media/libstagefright/flac/dec/FLACDecoder.h
+++ b/media/libstagefright/flac/dec/FLACDecoder.h
@@ -41,7 +41,7 @@
 
     status_t parseMetadata(const uint8_t *inBuffer, size_t inBufferLen);
     status_t decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen,
-            int16_t *outBuffer, size_t *outBufferLen);
+            void *outBuffer, size_t *outBufferLen, bool outputFloat = false);
     void flush();
     virtual ~FLACDecoder();
 
@@ -89,8 +89,6 @@
     // most recent error reported by libFLAC decoder
     FLAC__StreamDecoderErrorStatus mErrorStatus;
 
-    void (*mCopy)(int16_t *dst, const int *src[kMaxChannels], unsigned nSamples, unsigned nChannels);
-
     status_t init();
 
     // FLAC stream decoder callbacks as C++ instance methods
diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp
index 768cbd6..a276722 100644
--- a/media/libstagefright/foundation/ALooper.cpp
+++ b/media/libstagefright/foundation/ALooper.cpp
@@ -66,7 +66,7 @@
 
 // static
 int64_t ALooper::GetNowUs() {
-    return systemTime(SYSTEM_TIME_MONOTONIC) / 1000ll;
+    return systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
 }
 
 ALooper::ALooper()
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index dcf1ab8..dd1d904 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -4,8 +4,8 @@
     vendor_available: true,
 }
 
-cc_library {
-    name: "libstagefright_foundation",
+cc_defaults {
+    name: "libstagefright_foundation_defaults",
     vendor_available: true,
     vndk: {
         enabled: true,
@@ -25,6 +25,7 @@
     header_libs: [
         "libhardware_headers",
         "libstagefright_foundation_headers",
+        "media_ndk_headers",
         "media_plugin_headers",
     ],
 
@@ -64,8 +65,13 @@
         "AudioPresentationInfo.cpp",
         "ByteUtils.cpp",
         "ColorUtils.cpp",
+        "MediaBuffer.cpp",
+        "MediaBufferBase.cpp",
+        "MediaBufferGroup.cpp",
         "MediaDefs.cpp",
         "MediaKeys.cpp",
+        "MetaData.cpp",
+        "MetaDataBase.cpp",
         "avc_utils.cpp",
         "base64.cpp",
         "hexdump.cpp",
@@ -81,3 +87,20 @@
         cfi: true,
     },
 }
+
+cc_library {
+    name: "libstagefright_foundation",
+    defaults: ["libstagefright_foundation_defaults"],
+}
+
+cc_library_static {
+    name: "libstagefright_foundation_without_imemory",
+    defaults: ["libstagefright_foundation_defaults"],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wall",
+        "-DNO_IMEMORY",
+    ],
+}
diff --git a/media/libmediaextractor/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
similarity index 93%
rename from media/libmediaextractor/MediaBuffer.cpp
rename to media/libstagefright/foundation/MediaBuffer.cpp
index bab3a03..9beac05 100644
--- a/media/libmediaextractor/MediaBuffer.cpp
+++ b/media/libstagefright/foundation/MediaBuffer.cpp
@@ -59,9 +59,11 @@
 #ifndef NO_IMEMORY
     } else {
         ALOGV("creating memoryDealer");
-        sp<MemoryDealer> memoryDealer =
-                new MemoryDealer(size + sizeof(SharedControl), "MediaBuffer");
-        mMemory = memoryDealer->allocate(size + sizeof(SharedControl));
+        size_t newSize = 0;
+        if (!__builtin_add_overflow(size, sizeof(SharedControl), &newSize)) {
+            sp<MemoryDealer> memoryDealer = new MemoryDealer(newSize, "MediaBuffer");
+            mMemory = memoryDealer->allocate(newSize);
+        }
         if (mMemory == NULL) {
             ALOGW("Failed to allocate shared memory, trying regular allocation!");
             mData = malloc(size);
diff --git a/media/libmediaextractor/MediaBufferBase.cpp b/media/libstagefright/foundation/MediaBufferBase.cpp
similarity index 100%
rename from media/libmediaextractor/MediaBufferBase.cpp
rename to media/libstagefright/foundation/MediaBufferBase.cpp
diff --git a/media/libmediaextractor/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
similarity index 100%
rename from media/libmediaextractor/MediaBufferGroup.cpp
rename to media/libstagefright/foundation/MediaBufferGroup.cpp
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index aba44bb..9d1ec1f 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -23,6 +23,7 @@
 
 const char *MEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
 const char *MEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
+const char *MEDIA_MIMETYPE_VIDEO_AV1 = "video/av01";
 const char *MEDIA_MIMETYPE_VIDEO_AVC = "video/avc";
 const char *MEDIA_MIMETYPE_VIDEO_HEVC = "video/hevc";
 const char *MEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
diff --git a/media/libmediaextractor/MetaData.cpp b/media/libstagefright/foundation/MetaData.cpp
similarity index 100%
rename from media/libmediaextractor/MetaData.cpp
rename to media/libstagefright/foundation/MetaData.cpp
diff --git a/media/libmediaextractor/MetaDataBase.cpp b/media/libstagefright/foundation/MetaDataBase.cpp
similarity index 100%
rename from media/libmediaextractor/MetaDataBase.cpp
rename to media/libstagefright/foundation/MetaDataBase.cpp
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index 8edddcc..e68852d 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -25,6 +25,7 @@
 
 extern const char *MEDIA_MIMETYPE_VIDEO_VP8;
 extern const char *MEDIA_MIMETYPE_VIDEO_VP9;
+extern const char *MEDIA_MIMETYPE_VIDEO_AV1;
 extern const char *MEDIA_MIMETYPE_VIDEO_AVC;
 extern const char *MEDIA_MIMETYPE_VIDEO_HEVC;
 extern const char *MEDIA_MIMETYPE_VIDEO_MPEG4;
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index c4a072b..c0ee14e 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -32,7 +32,6 @@
         "libcrypto",
         "libcutils",
         "libmedia",
-        "libmediaextractor",
         "libmediandk",
         "libstagefright",
         "libstagefright_foundation",
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 86872c5..2ecfa43 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -44,10 +44,10 @@
 
 // static
 // Bandwidth Switch Mark Defaults
-const int64_t LiveSession::kUpSwitchMarkUs = 15000000ll;
-const int64_t LiveSession::kDownSwitchMarkUs = 20000000ll;
-const int64_t LiveSession::kUpSwitchMarginUs = 5000000ll;
-const int64_t LiveSession::kResumeThresholdUs = 100000ll;
+const int64_t LiveSession::kUpSwitchMarkUs = 15000000LL;
+const int64_t LiveSession::kDownSwitchMarkUs = 20000000LL;
+const int64_t LiveSession::kUpSwitchMarginUs = 5000000LL;
+const int64_t LiveSession::kResumeThresholdUs = 100000LL;
 
 //TODO: redefine this mark to a fair value
 // default buffer underflow mark
@@ -66,9 +66,9 @@
     // Bandwidth estimation parameters
     static const int32_t kShortTermBandwidthItems = 3;
     static const int32_t kMinBandwidthHistoryItems = 20;
-    static const int64_t kMinBandwidthHistoryWindowUs = 5000000ll; // 5 sec
-    static const int64_t kMaxBandwidthHistoryWindowUs = 30000000ll; // 30 sec
-    static const int64_t kMaxBandwidthHistoryAgeUs = 60000000ll; // 60 sec
+    static const int64_t kMinBandwidthHistoryWindowUs = 5000000LL; // 5 sec
+    static const int64_t kMaxBandwidthHistoryWindowUs = 30000000LL; // 30 sec
+    static const int64_t kMaxBandwidthHistoryAgeUs = 60000000LL; // 60 sec
 
     struct BandwidthEntry {
         int64_t mTimestampUs;
@@ -284,7 +284,7 @@
       mPrevBufferPercentage(-1),
       mCurBandwidthIndex(-1),
       mOrigBandwidthIndex(-1),
-      mLastBandwidthBps(-1ll),
+      mLastBandwidthBps(-1LL),
       mLastBandwidthStable(false),
       mBandwidthEstimator(new BandwidthEstimator()),
       mMaxWidth(720),
@@ -294,8 +294,8 @@
       mSwapMask(0),
       mSwitchGeneration(0),
       mSubtitleGeneration(0),
-      mLastDequeuedTimeUs(0ll),
-      mRealTimeBaseUs(0ll),
+      mLastDequeuedTimeUs(0LL),
+      mRealTimeBaseUs(0LL),
       mReconfigurationInProgress(false),
       mSwitchInProgress(false),
       mUpSwitchMark(kUpSwitchMarkUs),
@@ -844,7 +844,7 @@
                     // (If we don't have that cushion we'd rather cancel and try again.)
                     int64_t delayUs =
                         switchUp ?
-                            (kUnderflowMarkMs * 1000ll + 1000000ll)
+                            (kUnderflowMarkMs * 1000LL + 1000000LL)
                             : 0;
                     bool needResumeUntil = false;
                     sp<AMessage> stopParams = msg;
@@ -954,7 +954,7 @@
 
 // static
 bool LiveSession::isBandwidthValid(const BandwidthItem &item) {
-    static const int64_t kBlacklistWindowUs = 300 * 1000000ll;
+    static const int64_t kBlacklistWindowUs = 300 * 1000000LL;
     return item.mLastFailureUs < 0
             || ALooper::GetNowUs() - item.mLastFailureUs > kBlacklistWindowUs;
 }
@@ -1060,7 +1060,7 @@
             BandwidthItem item;
 
             item.mPlaylistIndex = i;
-            item.mLastFailureUs = -1ll;
+            item.mLastFailureUs = -1LL;
 
             sp<AMessage> meta;
             AString uri;
@@ -1114,7 +1114,7 @@
 
     mPlaylist->pickRandomMediaItems();
     changeConfiguration(
-            0ll /* timeUs */, initialBandwidthIndex, false /* pickTrack */);
+            0LL /* timeUs */, initialBandwidthIndex, false /* pickTrack */);
 }
 
 void LiveSession::finishDisconnect() {
@@ -1175,7 +1175,7 @@
     FetcherInfo info;
     info.mFetcher = new PlaylistFetcher(
             notify, this, uri, mCurBandwidthIndex, mSubtitleGeneration);
-    info.mDurationUs = -1ll;
+    info.mDurationUs = -1LL;
     info.mToBeRemoved = false;
     info.mToBeResumed = false;
     mFetcherLooper->registerHandler(info.mFetcher);
@@ -1466,7 +1466,7 @@
 }
 
 status_t LiveSession::getDuration(int64_t *durationUs) const {
-    int64_t maxDurationUs = -1ll;
+    int64_t maxDurationUs = -1LL;
     for (size_t i = 0; i < mFetcherInfos.size(); ++i) {
         int64_t fetcherDurationUs = mFetcherInfos.valueAt(i).mDurationUs;
 
@@ -1592,7 +1592,7 @@
         // Delay fetcher removal if not picking tracks, AND old fetcher
         // has stream mask that overlaps new variant. (Okay to discard
         // old fetcher now, if completely no overlap.)
-        if (discardFetcher && timeUs < 0ll && !pickTrack
+        if (discardFetcher && timeUs < 0LL && !pickTrack
                 && (fetcher->getStreamTypeMask() & streamMask)) {
             discardFetcher = false;
             delayRemoval = true;
@@ -1604,7 +1604,7 @@
         } else {
             float threshold = 0.0f; // default to pause after current block (47Kbytes)
             bool disconnect = false;
-            if (timeUs >= 0ll) {
+            if (timeUs >= 0LL) {
                 // seeking, no need to finish fetching
                 disconnect = true;
             } else if (delayRemoval) {
@@ -1620,7 +1620,7 @@
     }
 
     sp<AMessage> msg;
-    if (timeUs < 0ll) {
+    if (timeUs < 0LL) {
         // skip onChangeConfiguration2 (decoder destruction) if not seeking.
         msg = new AMessage(kWhatChangeConfiguration3, this);
     } else {
@@ -1654,9 +1654,9 @@
     if (!mReconfigurationInProgress) {
         int32_t pickTrack = 0;
         msg->findInt32("pickTrack", &pickTrack);
-        changeConfiguration(-1ll /* timeUs */, -1, pickTrack);
+        changeConfiguration(-1LL /* timeUs */, -1, pickTrack);
     } else {
-        msg->post(1000000ll); // retry in 1 sec
+        msg->post(1000000LL); // retry in 1 sec
     }
 }
 
@@ -1788,7 +1788,7 @@
     CHECK(msg->findInt64("timeUs", &timeUs));
     CHECK(msg->findInt32("pickTrack", &pickTrack));
 
-    if (timeUs < 0ll) {
+    if (timeUs < 0LL) {
         if (!pickTrack) {
             // mSwapMask contains streams that are in both old and new variant,
             // (in mNewStreamMask & mStreamMask) but with different URIs
@@ -2062,7 +2062,7 @@
 void LiveSession::schedulePollBuffering() {
     sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
     msg->setInt32("generation", mPollBufferingGeneration);
-    msg->post(1000000ll);
+    msg->post(1000000LL);
 }
 
 void LiveSession::cancelPollBuffering() {
@@ -2208,13 +2208,13 @@
         int64_t readyMarkUs =
             (mInPreparationPhase ?
                 mBufferingSettings.mInitialMarkMs :
-                mBufferingSettings.mResumePlaybackMarkMs) * 1000ll;
+                mBufferingSettings.mResumePlaybackMarkMs) * 1000LL;
         if (bufferedDurationUs > readyMarkUs
                 || mPacketSources[i]->isFinished(0)) {
             ++readyCount;
         }
         if (!mPacketSources[i]->isFinished(0)) {
-            if (bufferedDurationUs < kUnderflowMarkMs * 1000ll) {
+            if (bufferedDurationUs < kUnderflowMarkMs * 1000LL) {
                 ++underflowCount;
             }
             if (bufferedDurationUs > mUpSwitchMark) {
@@ -2300,7 +2300,7 @@
         ssize_t lowestValid = getLowestValidBandwidthIndex();
         if (mCurBandwidthIndex > lowestValid) {
             cancelBandwidthSwitch();
-            changeConfiguration(-1ll, lowestValid);
+            changeConfiguration(-1LL, lowestValid);
             return true;
         }
     }
@@ -2370,7 +2370,7 @@
             // if not yet prepared, just restart again with new bw index.
             // this is faster and playback experience is cleaner.
             changeConfiguration(
-                    mInPreparationPhase ? 0 : -1ll, bandwidthIndex);
+                    mInPreparationPhase ? 0 : -1LL, bandwidthIndex);
             return true;
         }
     }
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index d06d9f2..16179d3 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -258,7 +258,7 @@
       mIsEvent(false),
       mFirstSeqNumber(-1),
       mLastSeqNumber(-1),
-      mTargetDurationUs(-1ll),
+      mTargetDurationUs(-1LL),
       mDiscontinuitySeq(0),
       mDiscontinuityCount(0),
       mSelectedIndex(-1) {
@@ -716,7 +716,7 @@
             ALOGE("Media playlist missing #EXT-X-TARGETDURATION");
             return ERROR_MALFORMED;
         }
-        mTargetDurationUs = targetDurationSecs * 1000000ll;
+        mTargetDurationUs = targetDurationSecs * 1000000LL;
 
         mFirstSeqNumber = 0;
         if (mMeta != NULL) {
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 823f90e..562c625 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -50,8 +50,8 @@
 namespace android {
 
 // static
-const int64_t PlaylistFetcher::kMinBufferedDurationUs = 30000000ll;
-const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll;
+const int64_t PlaylistFetcher::kMinBufferedDurationUs = 30000000LL;
+const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000LL;
 // LCM of 188 (size of a TS packet) & 1k works well
 const int32_t PlaylistFetcher::kDownloadBlockSize = 47 * 1024;
 
@@ -152,25 +152,25 @@
       mURI(uri),
       mFetcherID(id),
       mStreamTypeMask(0),
-      mStartTimeUs(-1ll),
-      mSegmentStartTimeUs(-1ll),
-      mDiscontinuitySeq(-1ll),
+      mStartTimeUs(-1LL),
+      mSegmentStartTimeUs(-1LL),
+      mDiscontinuitySeq(-1LL),
       mStartTimeUsRelative(false),
-      mLastPlaylistFetchTimeUs(-1ll),
-      mPlaylistTimeUs(-1ll),
+      mLastPlaylistFetchTimeUs(-1LL),
+      mPlaylistTimeUs(-1LL),
       mSeqNumber(-1),
       mNumRetries(0),
       mStartup(true),
       mIDRFound(false),
       mSeekMode(LiveSession::kSeekModeExactPosition),
       mTimeChangeSignaled(false),
-      mNextPTSTimeUs(-1ll),
+      mNextPTSTimeUs(-1LL),
       mMonitorQueueGeneration(0),
       mSubtitleGeneration(subtitleGeneration),
-      mLastDiscontinuitySeq(-1ll),
+      mLastDiscontinuitySeq(-1LL),
       mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY),
       mFirstPTSValid(false),
-      mFirstTimeUs(-1ll),
+      mFirstTimeUs(-1LL),
       mVideoBuffer(new AnotherPacketSource(NULL)),
       mSampleAesKeyItemChanged(false),
       mThresholdRatio(-1.0f),
@@ -200,7 +200,7 @@
     CHECK_GE(seqNumber, firstSeqNumberInPlaylist);
     CHECK_LE(seqNumber, lastSeqNumberInPlaylist);
 
-    int64_t segmentStartUs = 0ll;
+    int64_t segmentStartUs = 0LL;
     for (int32_t index = 0;
             index < seqNumber - firstSeqNumberInPlaylist; ++index) {
         sp<AMessage> itemMeta;
@@ -240,13 +240,13 @@
 int64_t PlaylistFetcher::delayUsToRefreshPlaylist() const {
     int64_t nowUs = ALooper::GetNowUs();
 
-    if (mPlaylist == NULL || mLastPlaylistFetchTimeUs < 0ll) {
+    if (mPlaylist == NULL || mLastPlaylistFetchTimeUs < 0LL) {
         CHECK_EQ((int)mRefreshState, (int)INITIAL_MINIMUM_RELOAD_DELAY);
-        return 0ll;
+        return 0LL;
     }
 
     if (mPlaylist->isComplete()) {
-        return (~0llu >> 1);
+        return (~0LLU >> 1);
     }
 
     int64_t targetDurationUs = mPlaylist->getTargetDuration();
@@ -295,7 +295,7 @@
     }
 
     int64_t delayUs = mLastPlaylistFetchTimeUs + minPlaylistAgeUs - nowUs;
-    return delayUs > 0ll ? delayUs : 0ll;
+    return delayUs > 0LL ? delayUs : 0LL;
 }
 
 status_t PlaylistFetcher::decryptBuffer(
@@ -857,7 +857,7 @@
         targetDurationUs = mPlaylist->getTargetDuration();
     }
 
-    int64_t bufferedDurationUs = 0ll;
+    int64_t bufferedDurationUs = 0LL;
     status_t finalResult = OK;
     if (mStreamTypeMask == LiveSession::STREAMTYPE_SUBTITLES) {
         sp<AnotherPacketSource> packetSource =
@@ -870,7 +870,7 @@
         // enqueued to prevent us from waiting on a non-existent stream;
         // when we cannot make out from the manifest what streams are included in
         // a playlist we might assume extra streams.
-        bufferedDurationUs = -1ll;
+        bufferedDurationUs = -1LL;
         for (size_t i = 0; i < mPacketSources.size(); ++i) {
             if ((mStreamTypeMask & mPacketSources.keyAt(i)) == 0
                     || mPacketSources[i]->getLatestEnqueuedMeta() == NULL) {
@@ -882,13 +882,13 @@
 
             FSLOGV(mPacketSources.keyAt(i), "buffered %lld", (long long)bufferedStreamDurationUs);
 
-            if (bufferedDurationUs == -1ll
+            if (bufferedDurationUs == -1LL
                  || bufferedStreamDurationUs < bufferedDurationUs) {
                 bufferedDurationUs = bufferedStreamDurationUs;
             }
         }
-        if (bufferedDurationUs == -1ll) {
-            bufferedDurationUs = 0ll;
+        if (bufferedDurationUs == -1LL) {
+            bufferedDurationUs = 0LL;
         }
     }
 
@@ -901,12 +901,12 @@
         // onDownloadNext();
         sp<AMessage> msg = new AMessage(kWhatDownloadNext, this);
         msg->setInt32("generation", mMonitorQueueGeneration);
-        msg->post(1000l);
+        msg->post(1000L);
     } else {
         // We'd like to maintain buffering above durationToBufferUs, so try
         // again when buffer just about to go below durationToBufferUs
         // (or after targetDurationUs / 2, whichever is smaller).
-        int64_t delayUs = bufferedDurationUs - kMinBufferedDurationUs + 1000000ll;
+        int64_t delayUs = bufferedDurationUs - kMinBufferedDurationUs + 1000000LL;
         if (delayUs > targetDurationUs / 2) {
             delayUs = targetDurationUs / 2;
         }
@@ -1073,10 +1073,10 @@
         }
     }
 
-    mSegmentFirstPTS = -1ll;
+    mSegmentFirstPTS = -1LL;
 
     if (mPlaylist != NULL && mSeqNumber < 0) {
-        CHECK_GE(mStartTimeUs, 0ll);
+        CHECK_GE(mStartTimeUs, 0LL);
 
         if (mSegmentStartTimeUs < 0) {
             if (!mPlaylist->isComplete() && !mPlaylist->isEvent()) {
@@ -1379,7 +1379,7 @@
                         & (LiveSession::STREAMTYPE_AUDIO
                         | LiveSession::STREAMTYPE_VIDEO))) {
             mSession->addBandwidthMeasurement(bytesRead, delayUs);
-            if (delayUs > 2000000ll) {
+            if (delayUs > 2000000LL) {
                 FLOGV("bytesRead %zd took %.2f seconds - abnormal bandwidth dip",
                         bytesRead, (double)delayUs / 1.0e6);
             }
@@ -1553,7 +1553,7 @@
         // if the previous fetcher paused in the middle of a segment, we
         // want to start at a segment that overlaps the last sample
         minDiffUs = -mPlaylist->getTargetDuration();
-        maxDiffUs = 0ll;
+        maxDiffUs = 0LL;
     } else {
         // if the previous fetcher paused at the end of a segment, ideally
         // we want to start at the segment that's roughly aligned with its
@@ -1704,7 +1704,7 @@
         mTSParser = new ATSParser(ATSParser::TS_TIMESTAMPS_ARE_ABSOLUTE);
     }
 
-    if (mNextPTSTimeUs >= 0ll) {
+    if (mNextPTSTimeUs >= 0LL) {
         sp<AMessage> extra = new AMessage;
         // Since we are using absolute timestamps, signal an offset of 0 to prevent
         // ATSParser from skewing the timestamps of access units.
@@ -1719,7 +1719,7 @@
         mTSParser->signalDiscontinuity(
                 ATSParser::DISCONTINUITY_TIME, extra);
 
-        mNextPTSTimeUs = -1ll;
+        mNextPTSTimeUs = -1LL;
     }
 
     if (mSampleAesKeyItemChanged) {
@@ -1740,7 +1740,7 @@
     // setRange to indicate consumed bytes.
     buffer->setRange(buffer->offset() + offset, buffer->size() - offset);
 
-    if (mSegmentFirstPTS < 0ll) {
+    if (mSegmentFirstPTS < 0LL) {
         // get the smallest first PTS from all streams present in this parser
         for (size_t i = mPacketSources.size(); i > 0;) {
             i--;
@@ -1764,12 +1764,12 @@
             if (meta != NULL) {
                 int64_t timeUs;
                 CHECK(meta->findInt64("timeUs", &timeUs));
-                if (mSegmentFirstPTS < 0ll || timeUs < mSegmentFirstPTS) {
+                if (mSegmentFirstPTS < 0LL || timeUs < mSegmentFirstPTS) {
                     mSegmentFirstPTS = timeUs;
                 }
             }
         }
-        if (mSegmentFirstPTS < 0ll) {
+        if (mSegmentFirstPTS < 0LL) {
             // didn't find any TS packet, can return early
             return OK;
         }
@@ -1988,8 +1988,8 @@
         return OK;
     }
 
-    if (mNextPTSTimeUs >= 0ll) {
-        mNextPTSTimeUs = -1ll;
+    if (mNextPTSTimeUs >= 0LL) {
+        mNextPTSTimeUs = -1LL;
     }
 
     // This better be an ISO 13818-7 (AAC) or ISO 13818-1 (MPEG) audio
@@ -2088,17 +2088,17 @@
         packetSource->setFormat(meta);
     }
 
-    int64_t numSamples = 0ll;
+    int64_t numSamples = 0LL;
     int32_t sampleRate;
     CHECK(packetSource->getFormat()->findInt32(kKeySampleRate, &sampleRate));
 
-    int64_t timeUs = (PTS * 100ll) / 9ll;
+    int64_t timeUs = (PTS * 100LL) / 9LL;
     if (mStartup && !mFirstPTSValid) {
         mFirstPTSValid = true;
         mFirstTimeUs = timeUs;
     }
 
-    if (mSegmentFirstPTS < 0ll) {
+    if (mSegmentFirstPTS < 0LL) {
         mSegmentFirstPTS = timeUs;
         if (!mStartTimeUsRelative) {
             // Duplicated logic from how we handle .ts playlists.
@@ -2148,7 +2148,7 @@
 
         CHECK_LE(offset + aac_frame_length, buffer->size());
 
-        int64_t unitTimeUs = timeUs + numSamples * 1000000ll / sampleRate;
+        int64_t unitTimeUs = timeUs + numSamples * 1000000LL / sampleRate;
         offset += aac_frame_length;
 
         // Each AAC frame encodes 1024 samples.
@@ -2209,7 +2209,7 @@
 }
 
 void PlaylistFetcher::updateDuration() {
-    int64_t durationUs = 0ll;
+    int64_t durationUs = 0LL;
     for (size_t index = 0; index < mPlaylist->size(); ++index) {
         sp<AMessage> itemMeta;
         CHECK(mPlaylist->itemAt(
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index b489183..792a68a 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -43,7 +43,7 @@
     }
 
     virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
-        off64_t available = (offset >= (off64_t)mSize) ? 0ll : mSize - offset;
+        off64_t available = (offset >= (off64_t)mSize) ? 0LL : mSize - offset;
 
         size_t copy = (available > (off64_t)size) ? size : available;
         memcpy(data, mData + offset, copy);
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 9b2853e..9d46d2d 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -488,7 +488,8 @@
     status_t setupG711Codec(bool encoder, int32_t sampleRate, int32_t numChannels);
 
     status_t setupFlacCodec(
-            bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel);
+            bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel,
+            AudioEncoding encoding);
 
     status_t setupRawAudioFormat(
             OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels,
diff --git a/media/libstagefright/include/media/stagefright/ColorConverter.h b/media/libstagefright/include/media/stagefright/ColorConverter.h
index 6d4c1bf..75b0d8e 100644
--- a/media/libstagefright/include/media/stagefright/ColorConverter.h
+++ b/media/libstagefright/include/media/stagefright/ColorConverter.h
@@ -90,6 +90,9 @@
     status_t convertYUV420PlanarUseLibYUV(
             const BitmapParams &src, const BitmapParams &dst);
 
+    status_t convertYUV420SemiPlanarUseLibYUV(
+            const BitmapParams &src, const BitmapParams &dst);
+
     status_t convertYUV420Planar16(
             const BitmapParams &src, const BitmapParams &dst);
 
diff --git a/media/libmediaextractor/include/media/DataSource.h b/media/libstagefright/include/media/stagefright/DataSource.h
similarity index 100%
rename from media/libmediaextractor/include/media/DataSource.h
rename to media/libstagefright/include/media/stagefright/DataSource.h
diff --git a/media/libmediaextractor/include/media/DataSourceBase.h b/media/libstagefright/include/media/stagefright/DataSourceBase.h
similarity index 100%
rename from media/libmediaextractor/include/media/DataSourceBase.h
rename to media/libstagefright/include/media/stagefright/DataSourceBase.h
diff --git a/media/libstagefright/include/media/stagefright/MediaBuffer.h b/media/libstagefright/include/media/stagefright/MediaBuffer.h
deleted file mode 120000
index 1d49c1a..0000000
--- a/media/libstagefright/include/media/stagefright/MediaBuffer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../libmediaextractor/include/media/stagefright/MediaBuffer.h
\ No newline at end of file
diff --git a/media/libmediaextractor/include/media/stagefright/MediaBuffer.h b/media/libstagefright/include/media/stagefright/MediaBuffer.h
similarity index 100%
rename from media/libmediaextractor/include/media/stagefright/MediaBuffer.h
rename to media/libstagefright/include/media/stagefright/MediaBuffer.h
diff --git a/media/libstagefright/include/media/stagefright/MediaBufferBase.h b/media/libstagefright/include/media/stagefright/MediaBufferBase.h
deleted file mode 120000
index 80e49b0..0000000
--- a/media/libstagefright/include/media/stagefright/MediaBufferBase.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../libmediaextractor/include/media/stagefright/MediaBufferBase.h
\ No newline at end of file
diff --git a/media/libmediaextractor/include/media/stagefright/MediaBufferBase.h b/media/libstagefright/include/media/stagefright/MediaBufferBase.h
similarity index 100%
rename from media/libmediaextractor/include/media/stagefright/MediaBufferBase.h
rename to media/libstagefright/include/media/stagefright/MediaBufferBase.h
diff --git a/media/libstagefright/include/media/stagefright/MediaBufferGroup.h b/media/libstagefright/include/media/stagefright/MediaBufferGroup.h
deleted file mode 120000
index 009b3d9..0000000
--- a/media/libstagefright/include/media/stagefright/MediaBufferGroup.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../libmediaextractor/include/media/stagefright/MediaBufferGroup.h
\ No newline at end of file
diff --git a/media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h b/media/libstagefright/include/media/stagefright/MediaBufferGroup.h
similarity index 100%
rename from media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h
rename to media/libstagefright/include/media/stagefright/MediaBufferGroup.h
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 704bfdd..c06c288 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -31,6 +31,21 @@
 constexpr int32_t AVCProfileConstrainedBaseline = 0x10000;
 constexpr int32_t AVCProfileConstrainedHigh     = 0x80000;
 
+inline static const char *asString_AVCProfile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case AVCProfileBaseline:            return "Baseline";
+        case AVCProfileMain:                return "Main";
+        case AVCProfileExtended:            return "Extended";
+        case AVCProfileHigh:                return "High";
+        case AVCProfileHigh10:              return "High10";
+        case AVCProfileHigh422:             return "High422";
+        case AVCProfileHigh444:             return "High444";
+        case AVCProfileConstrainedBaseline: return "ConstrainedBaseline";
+        case AVCProfileConstrainedHigh:     return "ConstrainedHigh";
+        default:                            return def;
+    }
+}
+
 constexpr int32_t AVCLevel1       = 0x01;
 constexpr int32_t AVCLevel1b      = 0x02;
 constexpr int32_t AVCLevel11      = 0x04;
@@ -48,6 +63,35 @@
 constexpr int32_t AVCLevel5       = 0x4000;
 constexpr int32_t AVCLevel51      = 0x8000;
 constexpr int32_t AVCLevel52      = 0x10000;
+constexpr int32_t AVCLevel6       = 0x20000;
+constexpr int32_t AVCLevel61      = 0x40000;
+constexpr int32_t AVCLevel62      = 0x80000;
+
+inline static const char *asString_AVCLevel(int32_t i, const char *def = "??") {
+    switch (i) {
+        case AVCLevel1:     return "1";
+        case AVCLevel1b:    return "1b";
+        case AVCLevel11:    return "1.1";
+        case AVCLevel12:    return "1.2";
+        case AVCLevel13:    return "1.3";
+        case AVCLevel2:     return "2";
+        case AVCLevel21:    return "2.1";
+        case AVCLevel22:    return "2.2";
+        case AVCLevel3:     return "3";
+        case AVCLevel31:    return "3.1";
+        case AVCLevel32:    return "3.2";
+        case AVCLevel4:     return "4";
+        case AVCLevel41:    return "4.1";
+        case AVCLevel42:    return "4.2";
+        case AVCLevel5:     return "5";
+        case AVCLevel51:    return "5.1";
+        case AVCLevel52:    return "5.2";
+        case AVCLevel6:     return "6";
+        case AVCLevel61:    return "6.1";
+        case AVCLevel62:    return "6.2";
+        default:            return def;
+    }
+}
 
 constexpr int32_t H263ProfileBaseline             = 0x01;
 constexpr int32_t H263ProfileH320Coding           = 0x02;
@@ -59,6 +103,21 @@
 constexpr int32_t H263ProfileInterlace            = 0x80;
 constexpr int32_t H263ProfileHighLatency          = 0x100;
 
+inline static const char *asString_H263Profile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case H263ProfileBaseline:           return "Baseline";
+        case H263ProfileH320Coding:         return "H320Coding";
+        case H263ProfileBackwardCompatible: return "BackwardCompatible";
+        case H263ProfileISWV2:              return "ISWV2";
+        case H263ProfileISWV3:              return "ISWV3";
+        case H263ProfileHighCompression:    return "HighCompression";
+        case H263ProfileInternet:           return "Internet";
+        case H263ProfileInterlace:          return "Interlace";
+        case H263ProfileHighLatency:        return "HighLatency";
+        default:                            return def;
+    }
+}
+
 constexpr int32_t H263Level10      = 0x01;
 constexpr int32_t H263Level20      = 0x02;
 constexpr int32_t H263Level30      = 0x04;
@@ -68,6 +127,20 @@
 constexpr int32_t H263Level60      = 0x40;
 constexpr int32_t H263Level70      = 0x80;
 
+inline static const char *asString_H263Level(int32_t i, const char *def = "??") {
+    switch (i) {
+        case H263Level10:   return "10";
+        case H263Level20:   return "20";
+        case H263Level30:   return "30";
+        case H263Level40:   return "40";
+        case H263Level45:   return "45";
+        case H263Level50:   return "50";
+        case H263Level60:   return "60";
+        case H263Level70:   return "70";
+        default:            return def;
+    }
+}
+
 constexpr int32_t MPEG4ProfileSimple              = 0x01;
 constexpr int32_t MPEG4ProfileSimpleScalable      = 0x02;
 constexpr int32_t MPEG4ProfileCore                = 0x04;
@@ -85,6 +158,28 @@
 constexpr int32_t MPEG4ProfileAdvancedScalable    = 0x4000;
 constexpr int32_t MPEG4ProfileAdvancedSimple      = 0x8000;
 
+inline static const char *asString_MPEG4Profile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case MPEG4ProfileSimple:            return "Simple";
+        case MPEG4ProfileSimpleScalable:    return "SimpleScalable";
+        case MPEG4ProfileCore:              return "Core";
+        case MPEG4ProfileMain:              return "Main";
+        case MPEG4ProfileNbit:              return "Nbit";
+        case MPEG4ProfileScalableTexture:   return "ScalableTexture";
+        case MPEG4ProfileSimpleFace:        return "SimpleFace";
+        case MPEG4ProfileSimpleFBA:         return "SimpleFBA";
+        case MPEG4ProfileBasicAnimated:     return "BasicAnimated";
+        case MPEG4ProfileHybrid:            return "Hybrid";
+        case MPEG4ProfileAdvancedRealTime:  return "AdvancedRealTime";
+        case MPEG4ProfileCoreScalable:      return "CoreScalable";
+        case MPEG4ProfileAdvancedCoding:    return "AdvancedCoding";
+        case MPEG4ProfileAdvancedCore:      return "AdvancedCore";
+        case MPEG4ProfileAdvancedScalable:  return "AdvancedScalable";
+        case MPEG4ProfileAdvancedSimple:    return "AdvancedSimple";
+        default:                            return def;
+    }
+}
+
 constexpr int32_t MPEG4Level0      = 0x01;
 constexpr int32_t MPEG4Level0b     = 0x02;
 constexpr int32_t MPEG4Level1      = 0x04;
@@ -96,6 +191,22 @@
 constexpr int32_t MPEG4Level5      = 0x80;
 constexpr int32_t MPEG4Level6      = 0x100;
 
+inline static const char *asString_MPEG4Level(int32_t i, const char *def = "??") {
+    switch (i) {
+        case MPEG4Level0:   return "0";
+        case MPEG4Level0b:  return "0b";
+        case MPEG4Level1:   return "1";
+        case MPEG4Level2:   return "2";
+        case MPEG4Level3:   return "3";
+        case MPEG4Level3b:  return "3b";
+        case MPEG4Level4:   return "4";
+        case MPEG4Level4a:  return "4a";
+        case MPEG4Level5:   return "5";
+        case MPEG4Level6:   return "6";
+        default:            return def;
+    }
+}
+
 constexpr int32_t MPEG2ProfileSimple              = 0x00;
 constexpr int32_t MPEG2ProfileMain                = 0x01;
 constexpr int32_t MPEG2Profile422                 = 0x02;
@@ -103,12 +214,35 @@
 constexpr int32_t MPEG2ProfileSpatial             = 0x04;
 constexpr int32_t MPEG2ProfileHigh                = 0x05;
 
+inline static const char *asString_MPEG2Profile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case MPEG2ProfileSimple:    return "Simple";
+        case MPEG2ProfileMain:      return "Main";
+        case MPEG2Profile422:       return "422";
+        case MPEG2ProfileSNR:       return "SNR";
+        case MPEG2ProfileSpatial:   return "Spatial";
+        case MPEG2ProfileHigh:      return "High";
+        default:                    return def;
+    }
+}
+
 constexpr int32_t MPEG2LevelLL     = 0x00;
 constexpr int32_t MPEG2LevelML     = 0x01;
 constexpr int32_t MPEG2LevelH14    = 0x02;
 constexpr int32_t MPEG2LevelHL     = 0x03;
 constexpr int32_t MPEG2LevelHP     = 0x04;
 
+inline static const char *asString_MPEG2Level(int32_t i, const char *def = "??") {
+    switch (i) {
+        case MPEG2LevelLL:  return "LL";
+        case MPEG2LevelML:  return "ML";
+        case MPEG2LevelH14: return "H14";
+        case MPEG2LevelHL:  return "HL";
+        case MPEG2LevelHP:  return "HP";
+        default:            return def;
+    }
+}
+
 constexpr int32_t AACObjectMain       = 1;
 constexpr int32_t AACObjectLC         = 2;
 constexpr int32_t AACObjectSSR        = 3;
@@ -122,13 +256,48 @@
 constexpr int32_t AACObjectELD        = 39;
 constexpr int32_t AACObjectXHE        = 42;
 
+inline static const char *asString_AACObject(int32_t i, const char *def = "??") {
+    switch (i) {
+        case AACObjectMain:         return "Main";
+        case AACObjectLC:           return "LC";
+        case AACObjectSSR:          return "SSR";
+        case AACObjectLTP:          return "LTP";
+        case AACObjectHE:           return "HE";
+        case AACObjectScalable:     return "Scalable";
+        case AACObjectERLC:         return "ERLC";
+        case AACObjectERScalable:   return "ERScalable";
+        case AACObjectLD:           return "LD";
+        case AACObjectHE_PS:        return "HE_PS";
+        case AACObjectELD:          return "ELD";
+        case AACObjectXHE:          return "XHE";
+        default:                    return def;
+    }
+}
+
 constexpr int32_t VP8Level_Version0 = 0x01;
 constexpr int32_t VP8Level_Version1 = 0x02;
 constexpr int32_t VP8Level_Version2 = 0x04;
 constexpr int32_t VP8Level_Version3 = 0x08;
 
+inline static const char *asString_VP8Level(int32_t i, const char *def = "??") {
+    switch (i) {
+        case VP8Level_Version0: return "V0";
+        case VP8Level_Version1: return "V1";
+        case VP8Level_Version2: return "V2";
+        case VP8Level_Version3: return "V3";
+        default:                return def;
+    }
+}
+
 constexpr int32_t VP8ProfileMain = 0x01;
 
+inline static const char *asString_VP8Profile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case VP8ProfileMain:    return "Main";
+        default:                return def;
+    }
+}
+
 constexpr int32_t VP9Profile0 = 0x01;
 constexpr int32_t VP9Profile1 = 0x02;
 constexpr int32_t VP9Profile2 = 0x04;
@@ -138,6 +307,20 @@
 constexpr int32_t VP9Profile2HDR10Plus = 0x4000;
 constexpr int32_t VP9Profile3HDR10Plus = 0x8000;
 
+inline static const char *asString_VP9Profile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case VP9Profile0:           return "0";
+        case VP9Profile1:           return "1";
+        case VP9Profile2:           return "2";
+        case VP9Profile3:           return "3";
+        case VP9Profile2HDR:        return "2HDR";
+        case VP9Profile3HDR:        return "3HDR";
+        case VP9Profile2HDR10Plus:  return "2HDRPlus";
+        case VP9Profile3HDR10Plus:  return "3HDRPlus";
+        default:                    return def;
+    }
+}
+
 constexpr int32_t VP9Level1  = 0x1;
 constexpr int32_t VP9Level11 = 0x2;
 constexpr int32_t VP9Level2  = 0x4;
@@ -153,12 +336,111 @@
 constexpr int32_t VP9Level61 = 0x1000;
 constexpr int32_t VP9Level62 = 0x2000;
 
+inline static const char *asString_VP9Level(int32_t i, const char *def = "??") {
+    switch (i) {
+        case VP9Level1:     return "1";
+        case VP9Level11:    return "1.1";
+        case VP9Level2:     return "2";
+        case VP9Level21:    return "2.1";
+        case VP9Level3:     return "3";
+        case VP9Level31:    return "3.1";
+        case VP9Level4:     return "4";
+        case VP9Level41:    return "4.1";
+        case VP9Level5:     return "5";
+        case VP9Level51:    return "5.1";
+        case VP9Level52:    return "5.2";
+        case VP9Level6:     return "6";
+        case VP9Level61:    return "6.1";
+        case VP9Level62:    return "6.2";
+        default:            return def;
+    }
+}
+
+constexpr int32_t AV1Profile0 = 0x01;
+constexpr int32_t AV1Profile1 = 0x02;
+constexpr int32_t AV1Profile2 = 0x04;
+
+inline static const char *asString_AV1Profile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case AV1Profile0:       return "0";
+        case AV1Profile1:       return "1";
+        case AV1Profile2:       return "2";
+        default:                return def;
+    }
+}
+
+constexpr int32_t AV1Level2  = 0x1;
+constexpr int32_t AV1Level21 = 0x2;
+constexpr int32_t AV1Level22 = 0x4;
+constexpr int32_t AV1Level23 = 0x8;
+constexpr int32_t AV1Level3  = 0x10;
+constexpr int32_t AV1Level31 = 0x20;
+constexpr int32_t AV1Level32 = 0x40;
+constexpr int32_t AV1Level33 = 0x80;
+constexpr int32_t AV1Level4  = 0x100;
+constexpr int32_t AV1Level41 = 0x200;
+constexpr int32_t AV1Level42 = 0x400;
+constexpr int32_t AV1Level43 = 0x800;
+constexpr int32_t AV1Level5  = 0x1000;
+constexpr int32_t AV1Level51 = 0x2000;
+constexpr int32_t AV1Level52 = 0x4000;
+constexpr int32_t AV1Level53 = 0x8000;
+constexpr int32_t AV1Level6  = 0x10000;
+constexpr int32_t AV1Level61 = 0x20000;
+constexpr int32_t AV1Level62 = 0x40000;
+constexpr int32_t AV1Level63 = 0x80000;
+constexpr int32_t AV1Level7  = 0x100000;
+constexpr int32_t AV1Level71 = 0x200000;
+constexpr int32_t AV1Level72 = 0x400000;
+constexpr int32_t AV1Level73 = 0x800000;
+
+inline static const char *asString_AV1Level(int32_t i, const char *def = "??") {
+    switch (i) {
+        case AV1Level2:     return "2";
+        case AV1Level21:    return "2.1";
+        case AV1Level22:    return "2.2";
+        case AV1Level23:    return "2.3";
+        case AV1Level3:     return "3";
+        case AV1Level31:    return "3.1";
+        case AV1Level32:    return "3.2";
+        case AV1Level33:    return "3.3";
+        case AV1Level4:     return "4";
+        case AV1Level41:    return "4.1";
+        case AV1Level42:    return "4.2";
+        case AV1Level43:    return "4.3";
+        case AV1Level5:     return "5";
+        case AV1Level51:    return "5.1";
+        case AV1Level52:    return "5.2";
+        case AV1Level53:    return "5.3";
+        case AV1Level6:     return "6";
+        case AV1Level61:    return "6.1";
+        case AV1Level62:    return "6.2";
+        case AV1Level63:    return "6.3";
+        case AV1Level7:     return "7";
+        case AV1Level71:    return "7.1";
+        case AV1Level72:    return "7.2";
+        case AV1Level73:    return "7.3";
+        default:            return def;
+    }
+}
+
 constexpr int32_t HEVCProfileMain        = 0x01;
 constexpr int32_t HEVCProfileMain10      = 0x02;
 constexpr int32_t HEVCProfileMainStill   = 0x04;
 constexpr int32_t HEVCProfileMain10HDR10 = 0x1000;
 constexpr int32_t HEVCProfileMain10HDR10Plus = 0x2000;
 
+inline static const char *asString_HEVCProfile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case HEVCProfileMain:               return "Main";
+        case HEVCProfileMain10:             return "Main10";
+        case HEVCProfileMainStill:          return "MainStill";
+        case HEVCProfileMain10HDR10:        return "Main10HDR10";
+        case HEVCProfileMain10HDR10Plus:    return "Main10HDR10Plus";
+        default:                            return def;
+    }
+}
+
 constexpr int32_t HEVCMainTierLevel1  = 0x1;
 constexpr int32_t HEVCHighTierLevel1  = 0x2;
 constexpr int32_t HEVCMainTierLevel2  = 0x4;
@@ -186,6 +468,38 @@
 constexpr int32_t HEVCMainTierLevel62 = 0x1000000;
 constexpr int32_t HEVCHighTierLevel62 = 0x2000000;
 
+inline static const char *asString_HEVCTierLevel(int32_t i, const char *def = "??") {
+    switch (i) {
+        case HEVCMainTierLevel1:    return "Main 1";
+        case HEVCHighTierLevel1:    return "High 1";
+        case HEVCMainTierLevel2:    return "Main 2";
+        case HEVCHighTierLevel2:    return "High 2";
+        case HEVCMainTierLevel21:   return "Main 2.1";
+        case HEVCHighTierLevel21:   return "High 2.1";
+        case HEVCMainTierLevel3:    return "Main 3";
+        case HEVCHighTierLevel3:    return "High 3";
+        case HEVCMainTierLevel31:   return "Main 3.1";
+        case HEVCHighTierLevel31:   return "High 3.1";
+        case HEVCMainTierLevel4:    return "Main 4";
+        case HEVCHighTierLevel4:    return "High 4";
+        case HEVCMainTierLevel41:   return "Main 4.1";
+        case HEVCHighTierLevel41:   return "High 4.1";
+        case HEVCMainTierLevel5:    return "Main 5";
+        case HEVCHighTierLevel5:    return "High 5";
+        case HEVCMainTierLevel51:   return "Main 5.1";
+        case HEVCHighTierLevel51:   return "High 5.1";
+        case HEVCMainTierLevel52:   return "Main 5.2";
+        case HEVCHighTierLevel52:   return "High 5.2";
+        case HEVCMainTierLevel6:    return "Main 6";
+        case HEVCHighTierLevel6:    return "High 6";
+        case HEVCMainTierLevel61:   return "Main 6.1";
+        case HEVCHighTierLevel61:   return "High 6.1";
+        case HEVCMainTierLevel62:   return "Main 6.2";
+        case HEVCHighTierLevel62:   return "High 6.2";
+        default:                    return def;
+    }
+}
+
 constexpr int32_t DolbyVisionProfileDvavPer = 0x1;
 constexpr int32_t DolbyVisionProfileDvavPen = 0x2;
 constexpr int32_t DolbyVisionProfileDvheDer = 0x4;
@@ -197,6 +511,22 @@
 constexpr int32_t DolbyVisionProfileDvheSt = 0x100;
 constexpr int32_t DolbyVisionProfileDvavSe = 0x200;
 
+inline static const char *asString_DolbyVisionProfile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case DolbyVisionProfileDvavPer: return "DvavPer";
+        case DolbyVisionProfileDvavPen: return "DvavPen";
+        case DolbyVisionProfileDvheDer: return "DvheDer";
+        case DolbyVisionProfileDvheDen: return "DvheDen";
+        case DolbyVisionProfileDvheDtr: return "DvheDtr";
+        case DolbyVisionProfileDvheStn: return "DvheStn";
+        case DolbyVisionProfileDvheDth: return "DvheDth";
+        case DolbyVisionProfileDvheDtb: return "DvheDtb";
+        case DolbyVisionProfileDvheSt:  return "DvheSt";
+        case DolbyVisionProfileDvavSe:  return "DvavSe";
+        default:                        return def;
+    }
+}
+
 constexpr int32_t DolbyVisionLevelHd24    = 0x1;
 constexpr int32_t DolbyVisionLevelHd30    = 0x2;
 constexpr int32_t DolbyVisionLevelFhd24   = 0x4;
@@ -207,10 +537,34 @@
 constexpr int32_t DolbyVisionLevelUhd48   = 0x80;
 constexpr int32_t DolbyVisionLevelUhd60   = 0x100;
 
+inline static const char *asString_DolbyVisionLevel(int32_t i, const char *def = "??") {
+    switch (i) {
+        case DolbyVisionLevelHd24:  return "Hd24";
+        case DolbyVisionLevelHd30:  return "Hd30";
+        case DolbyVisionLevelFhd24: return "Fhd24";
+        case DolbyVisionLevelFhd30: return "Fhd30";
+        case DolbyVisionLevelFhd60: return "Fhd60";
+        case DolbyVisionLevelUhd24: return "Uhd24";
+        case DolbyVisionLevelUhd30: return "Uhd30";
+        case DolbyVisionLevelUhd48: return "Uhd48";
+        case DolbyVisionLevelUhd60: return "Uhd60";
+        default:                    return def;
+    }
+}
+
 constexpr int32_t BITRATE_MODE_CBR = 2;
 constexpr int32_t BITRATE_MODE_CQ = 0;
 constexpr int32_t BITRATE_MODE_VBR = 1;
 
+inline static const char *asString_BitrateMode(int32_t i, const char *def = "??") {
+    switch (i) {
+        case BITRATE_MODE_CBR:  return "CBR";
+        case BITRATE_MODE_CQ:   return "CQ";
+        case BITRATE_MODE_VBR:  return "VBR";
+        default:                return def;
+    }
+}
+
 constexpr int32_t COLOR_Format12bitRGB444             = 3;
 constexpr int32_t COLOR_Format16bitARGB1555           = 5;
 constexpr int32_t COLOR_Format16bitARGB4444           = 4;
@@ -264,6 +618,64 @@
 constexpr int32_t COLOR_QCOM_FormatYUV420SemiPlanar   = 0x7fa30c00;
 constexpr int32_t COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
 
+inline static const char *asString_ColorFormat(int32_t i, const char *def = "??") {
+    switch (i) {
+        case COLOR_Format12bitRGB444:               return "12bitRGB444";
+        case COLOR_Format16bitARGB1555:             return "16bitARGB1555";
+        case COLOR_Format16bitARGB4444:             return "16bitARGB4444";
+        case COLOR_Format16bitBGR565:               return "16bitBGR565";
+        case COLOR_Format16bitRGB565:               return "16bitRGB565";
+        case COLOR_Format18bitARGB1665:             return "18bitARGB1665";
+        case COLOR_Format18BitBGR666:               return "18BitBGR666";
+        case COLOR_Format18bitRGB666:               return "18bitRGB666";
+        case COLOR_Format19bitARGB1666:             return "19bitARGB1666";
+        case COLOR_Format24BitABGR6666:             return "24BitABGR6666";
+        case COLOR_Format24bitARGB1887:             return "24bitARGB1887";
+        case COLOR_Format24BitARGB6666:             return "24BitARGB6666";
+        case COLOR_Format24bitBGR888:               return "24bitBGR888";
+        case COLOR_Format24bitRGB888:               return "24bitRGB888";
+        case COLOR_Format25bitARGB1888:             return "25bitARGB1888";
+        case COLOR_Format32bitABGR8888:             return "32bitABGR8888";
+        case COLOR_Format32bitARGB8888:             return "32bitARGB8888";
+        case COLOR_Format32bitBGRA8888:             return "32bitBGRA8888";
+        case COLOR_Format8bitRGB332:                return "8bitRGB332";
+        case COLOR_FormatCbYCrY:                    return "CbYCrY";
+        case COLOR_FormatCrYCbY:                    return "CrYCbY";
+        case COLOR_FormatL16:                       return "L16";
+        case COLOR_FormatL2:                        return "L2";
+        case COLOR_FormatL24:                       return "L24";
+        case COLOR_FormatL32:                       return "L32";
+        case COLOR_FormatL4:                        return "L4";
+        case COLOR_FormatL8:                        return "L8";
+        case COLOR_FormatMonochrome:                return "Monochrome";
+        case COLOR_FormatRawBayer10bit:             return "RawBayer10bit";
+        case COLOR_FormatRawBayer8bit:              return "RawBayer8bit";
+        case COLOR_FormatRawBayer8bitcompressed:    return "RawBayer8bitcompressed";
+        case COLOR_FormatRGBAFlexible:              return "RGBAFlexible";
+        case COLOR_FormatRGBFlexible:               return "RGBFlexible";
+        case COLOR_FormatSurface:                   return "Surface";
+        case COLOR_FormatYCbYCr:                    return "YCbYCr";
+        case COLOR_FormatYCrYCb:                    return "YCrYCb";
+        case COLOR_FormatYUV411PackedPlanar:        return "YUV411PackedPlanar";
+        case COLOR_FormatYUV411Planar:              return "YUV411Planar";
+        case COLOR_FormatYUV420Flexible:            return "YUV420Flexible";
+        case COLOR_FormatYUV420PackedPlanar:        return "YUV420PackedPlanar";
+        case COLOR_FormatYUV420PackedSemiPlanar:    return "YUV420PackedSemiPlanar";
+        case COLOR_FormatYUV420Planar:              return "YUV420Planar";
+        case COLOR_FormatYUV420SemiPlanar:          return "YUV420SemiPlanar";
+        case COLOR_FormatYUV422Flexible:            return "YUV422Flexible";
+        case COLOR_FormatYUV422PackedPlanar:        return "YUV422PackedPlanar";
+        case COLOR_FormatYUV422PackedSemiPlanar:    return "YUV422PackedSemiPlanar";
+        case COLOR_FormatYUV422Planar:              return "YUV422Planar";
+        case COLOR_FormatYUV422SemiPlanar:          return "YUV422SemiPlanar";
+        case COLOR_FormatYUV444Flexible:            return "YUV444Flexible";
+        case COLOR_FormatYUV444Interleaved:         return "YUV444Interleaved";
+        case COLOR_QCOM_FormatYUV420SemiPlanar:     return "QCOM_YUV420SemiPlanar";
+        case COLOR_TI_FormatYUV420PackedSemiPlanar: return "TI_YUV420PackedSemiPlanar";
+        default:                                    return def;
+    }
+}
+
 constexpr char FEATURE_AdaptivePlayback[]       = "adaptive-playback";
 constexpr char FEATURE_IntraRefresh[] = "intra-refresh";
 constexpr char FEATURE_PartialFrame[] = "partial-frame";
@@ -273,6 +685,7 @@
 // from MediaFormat.java
 constexpr char MIMETYPE_VIDEO_VP8[] = "video/x-vnd.on2.vp8";
 constexpr char MIMETYPE_VIDEO_VP9[] = "video/x-vnd.on2.vp9";
+constexpr char MIMETYPE_VIDEO_AV1[] = "video/av01";
 constexpr char MIMETYPE_VIDEO_AVC[] = "video/avc";
 constexpr char MIMETYPE_VIDEO_HEVC[] = "video/hevc";
 constexpr char MIMETYPE_VIDEO_MPEG4[] = "video/mp4v-es";
diff --git a/media/libstagefright/include/media/stagefright/MediaErrors.h b/media/libstagefright/include/media/stagefright/MediaErrors.h
index 6a5c6b6..09639e2 100644
--- a/media/libstagefright/include/media/stagefright/MediaErrors.h
+++ b/media/libstagefright/include/media/stagefright/MediaErrors.h
@@ -70,7 +70,12 @@
     ERROR_DRM_DEVICE_REVOKED                 = DRM_ERROR_BASE - 9,
     ERROR_DRM_RESOURCE_BUSY                  = DRM_ERROR_BASE - 10,
     ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION = DRM_ERROR_BASE - 11,
-    ERROR_DRM_LAST_USED_ERRORCODE            = DRM_ERROR_BASE - 11,
+    ERROR_DRM_INSUFFICIENT_SECURITY          = DRM_ERROR_BASE - 12,
+    ERROR_DRM_FRAME_TOO_LARGE                = DRM_ERROR_BASE - 13,
+    ERROR_DRM_RESOURCE_CONTENTION            = DRM_ERROR_BASE - 14,
+    ERROR_DRM_SESSION_LOST_STATE             = DRM_ERROR_BASE - 15,
+    ERROR_DRM_INVALID_STATE                  = DRM_ERROR_BASE - 16,
+    ERROR_DRM_LAST_USED_ERRORCODE            = DRM_ERROR_BASE - 16,
 
     ERROR_DRM_VENDOR_MAX                     = DRM_ERROR_BASE - 500,
     ERROR_DRM_VENDOR_MIN                     = DRM_ERROR_BASE - 999,
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
index 84e01f3..ba6631c 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -19,6 +19,7 @@
 #define MEDIA_EXTRACTOR_FACTORY_H_
 
 #include <stdio.h>
+#include <unordered_set>
 
 #include <media/IMediaExtractor.h>
 
@@ -35,6 +36,7 @@
             const sp<DataSource> &source, const char *mime = NULL);
     static void LoadPlugins(const ::std::string& apkPath);
     static status_t dump(int fd, const Vector<String16>& args);
+    static std::unordered_set<std::string> getSupportedTypes();
     static void SetLinkedLibraries(const std::string& linkedLibraries);
 
 private:
diff --git a/media/libmediaextractor/include/media/MediaSource.h b/media/libstagefright/include/media/stagefright/MediaSource.h
similarity index 100%
rename from media/libmediaextractor/include/media/MediaSource.h
rename to media/libstagefright/include/media/stagefright/MediaSource.h
diff --git a/media/libstagefright/include/media/stagefright/MetaData.h b/media/libstagefright/include/media/stagefright/MetaData.h
deleted file mode 120000
index 160f8d3..0000000
--- a/media/libstagefright/include/media/stagefright/MetaData.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../libmediaextractor/include/media/stagefright/MetaData.h
\ No newline at end of file
diff --git a/media/libmediaextractor/include/media/stagefright/MetaData.h b/media/libstagefright/include/media/stagefright/MetaData.h
similarity index 100%
rename from media/libmediaextractor/include/media/stagefright/MetaData.h
rename to media/libstagefright/include/media/stagefright/MetaData.h
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
deleted file mode 120000
index 1e12193..0000000
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../libmediaextractor/include/media/stagefright/MetaDataBase.h
\ No newline at end of file
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
similarity index 100%
rename from media/libmediaextractor/include/media/stagefright/MetaDataBase.h
rename to media/libstagefright/include/media/stagefright/MetaDataBase.h
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 8dc8d38..f34f9b6 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -96,8 +96,7 @@
 
     bool getCachedDuration(int64_t *durationUs, bool *eos) const;
 
-    status_t getAudioPresentations(size_t trackIdx,
-            AudioPresentationCollection *presentations) const;
+    status_t getAudioPresentations(size_t trackIdx, AudioPresentationCollection *presentations);
 
 protected:
     virtual ~NuMediaExtractor();
diff --git a/media/libstagefright/include/media/stagefright/VideoFrameScheduler2.h b/media/libstagefright/include/media/stagefright/VideoFrameScheduler2.h
index be911cc..891b9a0 100644
--- a/media/libstagefright/include/media/stagefright/VideoFrameScheduler2.h
+++ b/media/libstagefright/include/media/stagefright/VideoFrameScheduler2.h
@@ -34,8 +34,8 @@
 private:
     void updateVsync() override;
 
-    long mAppVsyncOffset;
-    long mSfVsyncOffset;
+    nsecs_t mAppVsyncOffset;
+    nsecs_t mSfVsyncOffset;
     sp<VsyncTracker> mVsyncTracker;
     sp<ChoreographerThread> mChoreographerThread;
     Mutex mLock;
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index e9baa1a..1482072 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -217,6 +217,9 @@
     sp<IDescrambler> mDescrambler;
     AudioPresentationCollection mAudioPresentations;
 
+    // Send audio presentations along with access units.
+    void addAudioPresentations(const sp<ABuffer> &buffer);
+
     // Flush accumulated payload if necessary --- i.e. at EOS or at the start of
     // another payload. event is set if the flushed payload is PES with a sync
     // frame.
@@ -758,21 +761,21 @@
     // reasonable amount of time. To handle the wrap-around, use fancy math
     // to get an extended PTS that is within [-0xffffffff, 0xffffffff]
     // of the latest recovered PTS.
-    if (mLastRecoveredPTS < 0ll) {
+    if (mLastRecoveredPTS < 0LL) {
         // Use the original 33bit number for 1st frame, the reason is that
         // if 1st frame wraps to negative that's far away from 0, we could
         // never start. Only start wrapping around from 2nd frame.
         mLastRecoveredPTS = static_cast<int64_t>(PTS_33bit);
     } else {
         mLastRecoveredPTS = static_cast<int64_t>(
-                ((mLastRecoveredPTS - static_cast<int64_t>(PTS_33bit) + 0x100000000ll)
+                ((mLastRecoveredPTS - static_cast<int64_t>(PTS_33bit) + 0x100000000LL)
                 & 0xfffffffe00000000ull) | PTS_33bit);
         // We start from 0, but recovered PTS could be slightly below 0.
         // Clamp it to 0 as rest of the pipeline doesn't take negative pts.
         // (eg. video is read first and starts at 0, but audio starts at 0xfffffff0)
-        if (mLastRecoveredPTS < 0ll) {
+        if (mLastRecoveredPTS < 0LL) {
             ALOGI("Clamping negative recovered PTS (%" PRId64 ") to 0", mLastRecoveredPTS);
-            mLastRecoveredPTS = 0ll;
+            mLastRecoveredPTS = 0LL;
         }
     }
 
@@ -822,7 +825,7 @@
 
     int64_t timeUs = (PTS * 100) / 9;
 
-    if (mParser->mAbsoluteTimeAnchorUs >= 0ll) {
+    if (mParser->mAbsoluteTimeAnchorUs >= 0LL) {
         timeUs += mParser->mAbsoluteTimeAnchorUs;
     }
 
@@ -1610,9 +1613,9 @@
                     detailedError = _detailedError;
                 });
 
-        if (!returnVoid.isOk()) {
-            ALOGE("[stream %d] descramble failed, trans=%s",
-                    mElementaryPID, returnVoid.description().c_str());
+        if (!returnVoid.isOk() || status != Status::OK) {
+            ALOGE("[stream %d] descramble failed, trans=%s, status=%d",
+                    mElementaryPID, returnVoid.description().c_str(), status);
             return UNKNOWN_ERROR;
         }
 
@@ -1708,6 +1711,13 @@
     return err;
 }
 
+void ATSParser::Stream::addAudioPresentations(const sp<ABuffer> &buffer) {
+    std::ostringstream outStream(std::ios::out);
+    serializeAudioPresentations(mAudioPresentations, &outStream);
+    sp<ABuffer> ap = ABuffer::CreateAsCopy(outStream.str().data(), outStream.str().size());
+    buffer->meta()->setBuffer("audio-presentation-info", ap);
+}
+
 void ATSParser::Stream::onPayloadData(
         unsigned PTS_DTS_flags, uint64_t PTS, uint64_t /* DTS */,
         unsigned PES_scrambling_control,
@@ -1723,7 +1733,7 @@
 
     ALOGV("onPayloadData mStreamType=0x%02x size: %zu", mStreamType, size);
 
-    int64_t timeUs = 0ll;  // no presentation timestamp available.
+    int64_t timeUs = 0LL;  // no presentation timestamp available.
     if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) {
         timeUs = mProgram->convertPTSToTimestamp(PTS);
     }
@@ -1758,8 +1768,10 @@
                     }
                 }
                 mSource = new AnotherPacketSource(meta);
+                if (mAudioPresentations.size() > 0) {
+                    addAudioPresentations(accessUnit);
+                }
                 mSource->queueAccessUnit(accessUnit);
-                mSource->convertAudioPresentationInfoToMetadata(mAudioPresentations);
                 ALOGV("onPayloadData: created AnotherPacketSource PID 0x%08x of type 0x%02x",
                         mElementaryPID, mStreamType);
             }
@@ -1771,8 +1783,10 @@
             if (mSource->getFormat() == NULL) {
                 mSource->setFormat(mQueue->getFormat());
             }
+            if (mAudioPresentations.size() > 0) {
+                addAudioPresentations(accessUnit);
+            }
             mSource->queueAccessUnit(accessUnit);
-            mSource->convertAudioPresentationInfoToMetadata(mAudioPresentations);
         }
 
         // Every access unit has a pesStartOffset queued in |mPesStartOffsets|.
@@ -1855,10 +1869,10 @@
 
 ATSParser::ATSParser(uint32_t flags)
     : mFlags(flags),
-      mAbsoluteTimeAnchorUs(-1ll),
+      mAbsoluteTimeAnchorUs(-1LL),
       mTimeOffsetValid(false),
-      mTimeOffsetUs(0ll),
-      mLastRecoveredPTS(-1ll),
+      mTimeOffsetUs(0LL),
+      mLastRecoveredPTS(-1LL),
       mNumTSPacketsParsed(0),
       mNumPCRs(0) {
     mPSISections.add(0 /* PID */, new PSISection);
@@ -1900,7 +1914,7 @@
         if ((mFlags & TS_TIMESTAMPS_ARE_ABSOLUTE)
                 && extra->findInt64(
                     kATSParserKeyRecentMediaTimeUs, &mediaTimeUs)) {
-            if (mAbsoluteTimeAnchorUs >= 0ll) {
+            if (mAbsoluteTimeAnchorUs >= 0LL) {
                 mediaTimeUs -= mAbsoluteTimeAnchorUs;
             }
             if (mTimeOffsetValid) {
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index e2c5031..62e3a4b 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -35,7 +35,7 @@
 
 namespace android {
 
-const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs
+const int64_t kNearEOSMarkUs = 2000000LL; // 2 secs
 
 AnotherPacketSource::AnotherPacketSource(const sp<MetaData> &meta)
     : mIsAudio(false),
@@ -223,6 +223,12 @@
                     kKeyMpegUserData, 0, mpegUserData->data(), mpegUserData->size());
         }
 
+        sp<ABuffer> ap;
+        if (buffer->meta()->findBuffer("audio-presentation-info", &ap) && ap != NULL) {
+            bufmeta.setData(
+                    kKeyAudioPresentationInfo, 0, ap->data(), ap->size());
+        }
+
         int32_t cryptoMode;
         if (buffer->meta()->findInt32("cryptoMode", &cryptoMode)) {
             int32_t cryptoKey;
@@ -293,7 +299,7 @@
     if (buffer->meta()->findInt32("discontinuity", &discontinuity)){
         ALOGV("queueing a discontinuity with queueAccessUnit");
 
-        mLastQueuedTimeUs = 0ll;
+        mLastQueuedTimeUs = 0LL;
         mEOSResult = OK;
         mLatestEnqueuedMeta = NULL;
 
@@ -697,23 +703,4 @@
     return firstMeta;
 }
 
-void AnotherPacketSource::convertAudioPresentationInfoToMetadata(
-        const AudioPresentationCollection& presentations) {
-    sp<MetaData> meta = getFormat();
-    if (meta == NULL) {
-        return;
-    }
-    if (presentations.empty()) {
-        // Clear audio presentation info in metadata.
-        Mutex::Autolock autoLock(mLock);
-        meta->remove(kKeyAudioPresentationInfo);
-    } else {
-        std::ostringstream outStream(std::ios::out);
-        serializeAudioPresentations(presentations, &outStream);
-        Mutex::Autolock autoLock(mLock);
-        meta->setData(kKeyAudioPresentationInfo, MetaData::TYPE_NONE,
-                outStream.str().data(), outStream.str().size());
-    }
-}
-
 }  // namespace android
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index 57a6c33..f4a6acb 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -85,8 +85,6 @@
     void trimBuffersAfterMeta(const sp<AMessage> &meta);
     sp<AMessage> trimBuffersBeforeMeta(const sp<AMessage> &meta);
 
-    void convertAudioPresentationInfoToMetadata(const AudioPresentationCollection &presentations);
-
 protected:
     virtual ~AnotherPacketSource();
 
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index fb8b9fd..b91edcd 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -1111,7 +1111,7 @@
     memcpy(accessUnit->data(), mBuffer->data() + 4, payloadSize);
 
     int64_t timeUs = fetchTimestamp(payloadSize + 4);
-    if (timeUs < 0ll) {
+    if (timeUs < 0LL) {
         ALOGE("Negative timeUs");
         return NULL;
     }
@@ -1147,7 +1147,7 @@
         return NULL;
     }
 
-    if (info.mTimestampUs < 0ll) {
+    if (info.mTimestampUs < 0LL) {
         ALOGE("Negative info.mTimestampUs");
         return NULL;
     }
@@ -1317,7 +1317,7 @@
 
     }
 
-    if (timeUs == 0ll) {
+    if (timeUs == 0LL) {
         ALOGV("Returning 0 timestamp");
     }
 
@@ -1460,7 +1460,7 @@
             mBuffer->setRange(0, mBuffer->size() - nextScan);
 
             int64_t timeUs = fetchTimestamp(nextScan);
-            if (timeUs < 0ll) {
+            if (timeUs < 0LL) {
                 ALOGE("Negative timeUs");
                 return NULL;
             }
@@ -1545,7 +1545,7 @@
     mBuffer->setRange(0, mBuffer->size() - frameSize);
 
     int64_t timeUs = fetchTimestamp(frameSize);
-    if (timeUs < 0ll) {
+    if (timeUs < 0LL) {
         ALOGE("Negative timeUs");
         return NULL;
     }
@@ -1732,7 +1732,7 @@
                 mBuffer->setRange(0, mBuffer->size() - offset);
 
                 int64_t timeUs = fetchTimestamp(offset);
-                if (timeUs < 0ll) {
+                if (timeUs < 0LL) {
                     ALOGE("Negative timeUs");
                     return NULL;
                 }
@@ -1929,7 +1929,7 @@
                     mBuffer->setRange(0, size);
 
                     int64_t timeUs = fetchTimestamp(offset);
-                    if (timeUs < 0ll) {
+                    if (timeUs < 0LL) {
                         ALOGE("Negative timeus");
                         return NULL;
                     }
diff --git a/media/libstagefright/omx/1.0/Omx.cpp b/media/libstagefright/omx/1.0/Omx.cpp
index 4e2d398..121bb1a 100644
--- a/media/libstagefright/omx/1.0/Omx.cpp
+++ b/media/libstagefright/omx/1.0/Omx.cpp
@@ -124,11 +124,11 @@
         } else {
             uint32_t quirks = 0;
             for (const auto& quirk : codec->second.quirkSet) {
-                if (quirk == "requires-allocate-on-input-ports") {
+                if (quirk == "quirk::requires-allocate-on-input-ports") {
                     quirks |= OMXNodeInstance::
                             kRequiresAllocateBufferOnInputPorts;
                 }
-                if (quirk == "requires-allocate-on-output-ports") {
+                if (quirk == "quirk::requires-allocate-on-output-ports") {
                     quirks |= OMXNodeInstance::
                             kRequiresAllocateBufferOnOutputPorts;
                 }
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 68b375a..d7aacff 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -355,9 +355,9 @@
       mQuirks(0),
       mBufferIDCount(0),
       mRestorePtsFailed(false),
-      mMaxTimestampGapUs(0ll),
-      mPrevOriginalTimeUs(-1ll),
-      mPrevModifiedTimeUs(-1ll)
+      mMaxTimestampGapUs(0LL),
+      mPrevOriginalTimeUs(-1LL),
+      mPrevModifiedTimeUs(-1LL)
 {
     mName = ADebug::GetDebugName(name);
     DEBUG = ADebug::GetDebugLevelFromProperty(name, "debug.stagefright.omx-debug");
@@ -1948,7 +1948,7 @@
 int64_t OMXNodeInstance::getCodecTimestamp(OMX_TICKS timestamp) {
     int64_t originalTimeUs = timestamp;
 
-    if (mMaxTimestampGapUs > 0ll) {
+    if (mMaxTimestampGapUs > 0LL) {
         /* Cap timestamp gap between adjacent frames to specified max
          *
          * In the scenario of cast mirroring, encoding could be suspended for
@@ -1956,7 +1956,7 @@
          * where encoder's rate control logic produces huge frames after a
          * long period of suspension.
          */
-        if (mPrevOriginalTimeUs >= 0ll) {
+        if (mPrevOriginalTimeUs >= 0LL) {
             int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
             timestamp = (timestampGapUs < mMaxTimestampGapUs ?
                 timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
@@ -1964,7 +1964,7 @@
         ALOGV("IN  timestamp: %lld -> %lld",
             static_cast<long long>(originalTimeUs),
             static_cast<long long>(timestamp));
-    } else if (mMaxTimestampGapUs < 0ll) {
+    } else if (mMaxTimestampGapUs < 0LL) {
         /*
          * Apply a fixed timestamp gap between adjacent frames.
          *
@@ -1972,7 +1972,7 @@
          * on frames could go forward or backward. Some encoders may silently
          * drop frames when it goes backward (or even stay unchanged).
          */
-        if (mPrevOriginalTimeUs >= 0ll) {
+        if (mPrevOriginalTimeUs >= 0LL) {
             timestamp = mPrevModifiedTimeUs - mMaxTimestampGapUs;
         }
         ALOGV("IN  timestamp: %lld -> %lld",
@@ -1983,7 +1983,7 @@
     mPrevOriginalTimeUs = originalTimeUs;
     mPrevModifiedTimeUs = timestamp;
 
-    if (mMaxTimestampGapUs != 0ll && !mRestorePtsFailed) {
+    if (mMaxTimestampGapUs != 0LL && !mRestorePtsFailed) {
         mOriginalTimeUs.add(timestamp, originalTimeUs);
     }
 
@@ -2016,7 +2016,7 @@
 void OMXNodeInstance::codecBufferFilled(omx_message &msg) {
     Mutex::Autolock autoLock(mLock);
 
-    if (mMaxTimestampGapUs == 0ll || mRestorePtsFailed) {
+    if (mMaxTimestampGapUs == 0LL || mRestorePtsFailed) {
         return;
     }
 
diff --git a/media/libstagefright/omx/OMXUtils.cpp b/media/libstagefright/omx/OMXUtils.cpp
index b187035..1b8493a 100644
--- a/media/libstagefright/omx/OMXUtils.cpp
+++ b/media/libstagefright/omx/OMXUtils.cpp
@@ -150,6 +150,8 @@
             "video_decoder.vp8", "video_encoder.vp8" },
         { MEDIA_MIMETYPE_VIDEO_VP9,
             "video_decoder.vp9", "video_encoder.vp9" },
+        { MEDIA_MIMETYPE_VIDEO_AV1,
+            "video_decoder.av1", "video_encoder.av1" },
         { MEDIA_MIMETYPE_AUDIO_RAW,
             "audio_decoder.raw", "audio_encoder.raw" },
         { MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
diff --git a/media/libstagefright/omx/tests/Android.bp b/media/libstagefright/omx/tests/Android.bp
index 31bc837..fb03229 100644
--- a/media/libstagefright/omx/tests/Android.bp
+++ b/media/libstagefright/omx/tests/Android.bp
@@ -9,7 +9,6 @@
         "libbinder",
         "libmedia",
         "libmedia_omx",
-        "libmediaextractor",
         "libutils",
         "liblog",
         "libstagefright_foundation",
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 201a5df..b964bc0 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -417,7 +417,7 @@
     if (sessionDesc->getDurationUs(&durationUs)) {
         mFormat->setInt64(kKeyDuration, durationUs);
     } else {
-        mFormat->setInt64(kKeyDuration, -1ll);
+        mFormat->setInt64(kKeyDuration, -1LL);
     }
 
     mInitCheck = OK;
diff --git a/media/libstagefright/rtsp/ARTPAssembler.cpp b/media/libstagefright/rtsp/ARTPAssembler.cpp
index c7a65c2..befc226 100644
--- a/media/libstagefright/rtsp/ARTPAssembler.cpp
+++ b/media/libstagefright/rtsp/ARTPAssembler.cpp
@@ -36,7 +36,7 @@
 
         if (status == WRONG_SEQUENCE_NUMBER) {
             if (mFirstFailureTimeUs >= 0) {
-                if (ALooper::GetNowUs() - mFirstFailureTimeUs > 10000ll) {
+                if (ALooper::GetNowUs() - mFirstFailureTimeUs > 10000LL) {
                     mFirstFailureTimeUs = -1;
 
                     // LOG(VERBOSE) << "waited too long for packet.";
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index a86ab74..6a4706d 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -50,7 +50,7 @@
 }
 
 // static
-const int64_t ARTPConnection::kSelectTimeoutUs = 1000ll;
+const int64_t ARTPConnection::kSelectTimeoutUs = 1000LL;
 
 struct ARTPConnection::StreamInfo {
     int mRTPSocket;
@@ -118,7 +118,7 @@
     bumpSocketBufferSize(*rtcpSocket);
 
     /* rand() * 1000 may overflow int type, use long long */
-    unsigned start = (unsigned)((rand()* 1000ll)/RAND_MAX) + 15550;
+    unsigned start = (unsigned)((rand()* 1000LL)/RAND_MAX) + 15550;
     start &= ~1;
 
     for (unsigned port = start; port < 65536; port += 2) {
@@ -307,7 +307,7 @@
 
     int64_t nowUs = ALooper::GetNowUs();
     if (mLastReceiverReportTimeUs <= 0
-            || mLastReceiverReportTimeUs + 5000000ll <= nowUs) {
+            || mLastReceiverReportTimeUs + 5000000LL <= nowUs) {
         sp<ABuffer> buffer = new ABuffer(kMaxUDPSize);
         List<StreamInfo>::iterator it = mStreams.begin();
         while (it != mStreams.end()) {
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index 4827cd2..4afa6f4 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -180,7 +180,7 @@
     }
 
     int64_t nowUs = ALooper::GetNowUs();
-    if (mLastFIRRequestUs >= 0 && mLastFIRRequestUs + 5000000ll > nowUs) {
+    if (mLastFIRRequestUs >= 0 && mLastFIRRequestUs + 5000000LL > nowUs) {
         // Send FIR requests at most every 5 secs.
         return;
     }
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 49e01c0..4f86773 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -420,10 +420,10 @@
 uint64_t ARTPWriter::GetNowNTP() {
     uint64_t nowUs = ALooper::GetNowUs();
 
-    nowUs += ((70ll * 365 + 17) * 24) * 60 * 60 * 1000000ll;
+    nowUs += ((70LL * 365 + 17) * 24) * 60 * 60 * 1000000LL;
 
-    uint64_t hi = nowUs / 1000000ll;
-    uint64_t lo = ((1ll << 32) * (nowUs % 1000000ll)) / 1000000ll;
+    uint64_t hi = nowUs / 1000000LL;
+    uint64_t lo = ((1LL << 32) * (nowUs % 1000000LL)) / 1000000LL;
 
     return (hi << 32) | lo;
 }
@@ -576,7 +576,7 @@
     int64_t timeUs;
     CHECK(mediaBuf->meta_data().findInt64(kKeyTime, &timeUs));
 
-    uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100ll);
+    uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100LL);
 
     const uint8_t *mediaData =
         (const uint8_t *)mediaBuf->data() + mediaBuf->range_offset();
@@ -671,7 +671,7 @@
     int64_t timeUs;
     CHECK(mediaBuf->meta_data().findInt64(kKeyTime, &timeUs));
 
-    uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100ll);
+    uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100LL);
 
     const uint8_t *mediaData =
         (const uint8_t *)mediaBuf->data() + mediaBuf->range_offset();
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 33c1c18..20cb415 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -39,7 +39,7 @@
 namespace android {
 
 // static
-const int64_t ARTSPConnection::kSelectTimeoutUs = 1000ll;
+const int64_t ARTSPConnection::kSelectTimeoutUs = 1000LL;
 
 // static
 const AString ARTSPConnection::sUserAgent =
diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp
index 23269af..4b6f928 100644
--- a/media/libstagefright/webm/WebmFrameThread.cpp
+++ b/media/libstagefright/webm/WebmFrameThread.cpp
@@ -364,14 +364,14 @@
         // adjust time-stamps after pause/resume
         if (mResumed) {
             int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
-            CHECK_GE(durExcludingEarlierPausesUs, 0ll);
+            CHECK_GE(durExcludingEarlierPausesUs, 0LL);
             int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
             CHECK_GE(pausedDurationUs, lastDurationUs);
             previousPausedDurationUs += pausedDurationUs - lastDurationUs;
             mResumed = false;
         }
         timestampUs -= previousPausedDurationUs;
-        CHECK_GE(timestampUs, 0ll);
+        CHECK_GE(timestampUs, 0LL);
 
         int32_t isSync = false;
         md.findInt32(kKeyIsSyncFrame, &isSync);
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 2dec9fa..6e541ba 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -26,8 +26,9 @@
 #include <sys/stat.h>
 #include <expat.h>
 
-#include <cctype>
 #include <algorithm>
+#include <cctype>
+#include <string>
 
 namespace android {
 
@@ -326,8 +327,8 @@
         case SECTION_DECODER:
         case SECTION_ENCODER:
         {
-            if (strEq(name, "Quirk")) {
-                (void)addQuirk(attrs);
+            if (strEq(name, "Quirk") || strEq(name, "Attribute")) {
+                (void)addQuirk(attrs, name);
             } else if (strEq(name, "Type")) {
                 (void)addTypeFromAttributes(attrs,
                         (mCurrentSection == SECTION_ENCODER));
@@ -348,6 +349,8 @@
             if (outside &&
                     (strEq(name, "Limit") || strEq(name, "Feature"))) {
                 ALOGW("ignoring %s specified outside of a Type", name);
+            } else if (strEq(name, "Alias")) {
+                (void)addAlias(attrs);
             } else if (strEq(name, "Limit")) {
                 (void)addLimit(attrs);
             } else if (strEq(name, "Feature")) {
@@ -579,7 +582,7 @@
     return OK;
 }
 
-status_t MediaCodecsXmlParser::addQuirk(const char **attrs) {
+status_t MediaCodecsXmlParser::addQuirk(const char **attrs, const char *tag) {
     if (mCurrentCodec == mCodecMap.end()) {
         return BAD_VALUE;
     }
@@ -606,7 +609,12 @@
         return BAD_VALUE;
     }
 
-    mCurrentCodec->second.quirkSet.emplace(name);
+    std::string tagString = tag;
+    std::transform(tagString.begin(), tagString.end(), tagString.begin(), ::tolower);
+    tagString.append("::");
+    tagString.append(name);
+    mCurrentCodec->second.quirkSet.emplace(tagString.c_str());
+    ALOGI("adding %s to %s", tagString.c_str(), mCurrentCodec->first.c_str());
     return OK;
 }
 
@@ -760,6 +768,7 @@
             strEq(a_name, "quality") ||
             strEq(a_name, "size") ||
             strEq(a_name, "measured-blocks-per-second") ||
+            strHasPrefix(a_name, "performance-point-") ||
             strHasPrefix(a_name, "measured-frame-rate-")) {
         // "range" is specified in exactly one of the following forms:
         // 1) min-max
@@ -964,6 +973,34 @@
     return OK;
 }
 
+status_t MediaCodecsXmlParser::addAlias(const char **attrs) {
+    size_t i = 0;
+    const char *name = nullptr;
+
+    while (attrs[i] != nullptr) {
+        if (strEq(attrs[i], "name")) {
+            if (attrs[++i] == nullptr) {
+                ALOGE("addAlias: name is null");
+                return BAD_VALUE;
+            }
+            name = attrs[i];
+        } else {
+            ALOGE("addAlias: unrecognized attribute: %s", attrs[i]);
+            return BAD_VALUE;
+        }
+        ++i;
+    }
+
+    // Every feature must have a name.
+    if (name == nullptr) {
+        ALOGE("alias with no 'name' attribute");
+        return BAD_VALUE;
+    }
+
+    mCurrentCodec->second.aliases.emplace_back(name);
+    return OK;
+}
+
 const MediaCodecsXmlParser::AttributeMap&
         MediaCodecsXmlParser::getServiceAttributeMap() const {
     return mServiceAttributeMap;
@@ -1041,11 +1078,18 @@
 
             NodeInfo nodeInfo;
             nodeInfo.name = codecName;
+            // NOTE: no aliases are exposed in role info
+            // attribute quirks are exposed as node attributes
             nodeInfo.attributeList.reserve(typeAttributeMap.size());
             for (const auto& attribute : typeAttributeMap) {
                 nodeInfo.attributeList.push_back(
                         Attribute{attribute.first, attribute.second});
             }
+            for (const std::string &quirk : codec.second.quirkSet) {
+                if (strHasPrefix(quirk.c_str(), "attribute::")) {
+                    nodeInfo.attributeList.push_back(Attribute{quirk, "present"});
+                }
+            }
             nodeList->insert(std::make_pair(
                     std::move(order), std::move(nodeInfo)));
         }
diff --git a/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h b/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
index cc69e52..fd949da 100644
--- a/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
+++ b/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
@@ -65,6 +65,7 @@
         size_t order;      ///< Order of appearance in the file (starting from 0)
         QuirkSet quirkSet; ///< Set of quirks requested by this codec
         TypeMap typeMap;   ///< Map of types supported by this codec
+        std::vector<std::string> aliases; ///< Name aliases for this codec
     };
 
     typedef std::pair<std::string, CodecProperties> Codec;
@@ -76,6 +77,7 @@
     struct NodeInfo {
         std::string name;
         std::vector<Attribute> attributeList;
+        // note: aliases are not exposed here as they are not part of the role map
     };
 
     /**
@@ -171,8 +173,9 @@
     void addMediaCodec(bool encoder, const char *name,
             const char *type = nullptr);
 
-    status_t addQuirk(const char **attrs);
+    status_t addQuirk(const char **attrs, const char *tag);
     status_t addTypeFromAttributes(const char **attrs, bool encoder);
+    status_t addAlias(const char **attrs);
     status_t addLimit(const char **attrs);
     status_t addFeature(const char **attrs);
     void addType(const char *name);
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index f7597db..1fbb85e 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -20,7 +20,7 @@
         libmediaplayerservice \
         libutils \
         libbinder \
-        libicuuc \
+        libandroidicu \
         android.hardware.media.omx@1.0 \
 
 LOCAL_STATIC_LIBRARIES := \
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 73bd2ca..74754ea 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -78,7 +78,6 @@
         "libmedia_omx",
         "libmedia_jni",
         "libmediadrm",
-        "libmediaextractor",
         "libstagefright",
         "libstagefright_foundation",
         "libstagefright_bufferqueue_helper",
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index b86ab42..1a0c3b1 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -357,8 +357,10 @@
               it != mAcquiredImages.end(); it++) {
         AImage* image = *it;
         Mutex::Autolock _l(image->mLock);
-        releaseImageLocked(image, /*releaseFenceFd*/-1);
+        // Do not alter mAcquiredImages while we are iterating on it
+        releaseImageLocked(image, /*releaseFenceFd*/-1, /*clearCache*/false);
     }
+    mAcquiredImages.clear();
 
     // Delete Buffer Items
     for (auto it = mBuffers.begin();
@@ -497,7 +499,7 @@
 }
 
 void
-AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd) {
+AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd, bool clearCache) {
     BufferItem* buffer = image->mBuffer;
     if (buffer == nullptr) {
         // This should not happen, but is not fatal
@@ -521,6 +523,10 @@
     image->mLockedBuffer = nullptr;
     image->mIsClosed = true;
 
+    if (!clearCache) {
+        return;
+    }
+
     bool found = false;
     // cleanup acquired image list
     for (auto it = mAcquiredImages.begin();
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index 78152d2..e328cb1 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -88,7 +88,7 @@
     media_status_t acquireImageLocked(/*out*/AImage** image, /*out*/int* fenceFd);
 
     // Called by AImage/~AImageReader to close image. Caller is responsible to grab AImage::mLock
-    void releaseImageLocked(AImage* image, int releaseFenceFd);
+    void releaseImageLocked(AImage* image, int releaseFenceFd, bool clearCache = true);
 
     static int getBufferWidth(BufferItem* buffer);
     static int getBufferHeight(BufferItem* buffer);
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index f697bd1..8296598 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -448,6 +448,16 @@
         meta->setBuffer(AMEDIAFORMAT_KEY_MPEG_USER_DATA, mpegUserData);
     }
 
+    const void *audioPresentationsPointer;
+    size_t audioPresentationsLength;
+    if (sampleMeta->findData(
+            kKeyAudioPresentationInfo, &dataType,
+            &audioPresentationsPointer, &audioPresentationsLength)) {
+        sp<ABuffer> audioPresentationsData = ABuffer::CreateAsCopy(
+                audioPresentationsPointer, audioPresentationsLength);
+        meta->setBuffer(AMEDIAFORMAT_KEY_AUDIO_PRESENTATION_INFO, audioPresentationsData);
+    }
+
     return AMEDIA_OK;
 }
 
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 92d3aef..fcb706d 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -298,7 +298,7 @@
 EXPORT const char* AMEDIAFORMAT_KEY_CRYPTO_IV = "crypto-iv";
 EXPORT const char* AMEDIAFORMAT_KEY_CRYPTO_KEY = "crypto-key";
 EXPORT const char* AMEDIAFORMAT_KEY_CRYPTO_MODE = "crypto-mode";
-EXPORT const char* AMEDIAFORMAT_KEY_CRYPTO_PLAIN_SIZES = "crypto-encrypted-sizes";
+EXPORT const char* AMEDIAFORMAT_KEY_CRYPTO_PLAIN_SIZES = "crypto-plain-sizes";
 EXPORT const char* AMEDIAFORMAT_KEY_CRYPTO_SKIP_BYTE_BLOCK = "crypto-skip-byte-block";
 EXPORT const char* AMEDIAFORMAT_KEY_CSD = "csd";
 EXPORT const char* AMEDIAFORMAT_KEY_CSD_0 = "csd-0";
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISessionController.aidl b/packages/MediaComponents/apex/java/android/media/session/ISessionController.aidl
index 74897f7..433b12f 100644
--- a/packages/MediaComponents/apex/java/android/media/session/ISessionController.aidl
+++ b/packages/MediaComponents/apex/java/android/media/session/ISessionController.aidl
@@ -48,9 +48,9 @@
     PendingIntent getLaunchPendingIntent();
     long getFlags();
     ParcelableVolumeInfo getVolumeAttributes();
-    void adjustVolume(String packageName, ISessionControllerCallback caller,
+    void adjustVolume(String packageName, String opPackageName, ISessionControllerCallback caller,
             boolean asSystemService, int direction, int flags);
-    void setVolumeTo(String packageName, ISessionControllerCallback caller,
+    void setVolumeTo(String packageName, String opPackageName, ISessionControllerCallback caller,
             int value, int flags);
 
     // These commands are for the TransportControls
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISessionManager.aidl b/packages/MediaComponents/apex/java/android/media/session/ISessionManager.aidl
index 3578c16..d6c226f 100644
--- a/packages/MediaComponents/apex/java/android/media/session/ISessionManager.aidl
+++ b/packages/MediaComponents/apex/java/android/media/session/ISessionManager.aidl
@@ -17,7 +17,6 @@
 
 import android.content.ComponentName;
 import android.media.IRemoteVolumeController;
-import android.media.ISessionTokensListener;
 import android.media.session.IActiveSessionsListener;
 import android.media.session.ICallback;
 import android.media.session.IOnMediaKeyListener;
@@ -36,9 +35,10 @@
     List<IBinder> getSessions(in ComponentName compName, int userId);
     void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
             boolean needWakeLock);
-    void dispatchVolumeKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
-            int stream, boolean musicOnly);
-    void dispatchAdjustVolume(String packageName, int suggestedStream, int delta, int flags);
+    void dispatchVolumeKeyEvent(String packageName, String opPackageName, boolean asSystemService,
+            in KeyEvent keyEvent, int stream, boolean musicOnly);
+    void dispatchAdjustVolume(String packageName, String opPackageName, int suggestedStream,
+            int delta, int flags);
     void addSessionsListener(in IActiveSessionsListener listener, in ComponentName compName,
             int userId);
     void removeSessionsListener(in IActiveSessionsListener listener);
@@ -55,12 +55,4 @@
 
     // MediaSession2
     boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid);
-    boolean createSession2(in Bundle sessionToken);
-    void destroySession2(in Bundle sessionToken);
-    List<Bundle> getSessionTokens(boolean activeSessionOnly, boolean sessionServiceOnly,
-            String packageName);
-
-    void addSessionTokensListener(in ISessionTokensListener listener, int userId,
-            String packageName);
-    void removeSessionTokensListener(in ISessionTokensListener listener, String packageName);
 }
diff --git a/packages/MediaComponents/apex/java/android/media/session/MediaController.java b/packages/MediaComponents/apex/java/android/media/session/MediaController.java
index c060aaf..65682a8 100644
--- a/packages/MediaComponents/apex/java/android/media/session/MediaController.java
+++ b/packages/MediaComponents/apex/java/android/media/session/MediaController.java
@@ -153,7 +153,7 @@
             return false;
         }
         try {
-            return mSessionBinder.sendMediaButton(mContext.getOpPackageName(), mCbStub,
+            return mSessionBinder.sendMediaButton(mContext.getPackageName(), mCbStub,
                     asSystemService, keyEvent);
         } catch (RemoteException e) {
             // System is dead. =(
@@ -186,8 +186,9 @@
                         break;
                 }
                 try {
-                    mSessionBinder.adjustVolume(mContext.getOpPackageName(), mCbStub, true,
-                            direction, AudioManager.FLAG_SHOW_UI);
+                    mSessionBinder.adjustVolume(mContext.getPackageName(),
+                            mContext.getOpPackageName(), mCbStub, true, direction,
+                            AudioManager.FLAG_SHOW_UI);
                 } catch (RemoteException e) {
                     Log.wtf(TAG, "Error calling adjustVolumeBy", e);
                 }
@@ -197,8 +198,8 @@
                 final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
                         | AudioManager.FLAG_FROM_KEY;
                 try {
-                    mSessionBinder.adjustVolume(mContext.getOpPackageName(), mCbStub, true, 0,
-                            flags);
+                    mSessionBinder.adjustVolume(mContext.getPackageName(),
+                            mContext.getOpPackageName(), mCbStub, true, 0, flags);
                 } catch (RemoteException e) {
                     Log.wtf(TAG, "Error calling adjustVolumeBy", e);
                 }
@@ -367,7 +368,8 @@
      */
     public void setVolumeTo(int value, int flags) {
         try {
-            mSessionBinder.setVolumeTo(mContext.getOpPackageName(), mCbStub, value, flags);
+            mSessionBinder.setVolumeTo(mContext.getPackageName(), mContext.getOpPackageName(),
+                    mCbStub, value, flags);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Error calling setVolumeTo.", e);
         }
@@ -388,8 +390,8 @@
      */
     public void adjustVolume(int direction, int flags) {
         try {
-            mSessionBinder.adjustVolume(mContext.getOpPackageName(), mCbStub, false, direction,
-                    flags);
+            mSessionBinder.adjustVolume(mContext.getPackageName(), mContext.getOpPackageName(),
+                    mCbStub, false, direction, flags);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
         }
@@ -455,7 +457,7 @@
             throw new IllegalArgumentException("command cannot be null or empty");
         }
         try {
-            mSessionBinder.sendCommand(mContext.getOpPackageName(), mCbStub, command, args, cb);
+            mSessionBinder.sendCommand(mContext.getPackageName(), mCbStub, command, args, cb);
         } catch (RemoteException e) {
             Log.d(TAG, "Dead object in sendCommand.", e);
         }
@@ -521,7 +523,7 @@
 
         if (!mCbRegistered) {
             try {
-                mSessionBinder.registerCallbackListener(mContext.getOpPackageName(), mCbStub);
+                mSessionBinder.registerCallbackListener(mContext.getPackageName(), mCbStub);
                 mCbRegistered = true;
             } catch (RemoteException e) {
                 Log.e(TAG, "Dead object in registerCallback", e);
@@ -668,7 +670,7 @@
          */
         public void prepare() {
             try {
-                mSessionBinder.prepare(mContext.getOpPackageName(), mCbStub);
+                mSessionBinder.prepare(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling prepare.", e);
             }
@@ -692,7 +694,7 @@
                         "You must specify a non-empty String for prepareFromMediaId.");
             }
             try {
-                mSessionBinder.prepareFromMediaId(mContext.getOpPackageName(), mCbStub, mediaId,
+                mSessionBinder.prepareFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
                         extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e);
@@ -719,7 +721,7 @@
                 query = "";
             }
             try {
-                mSessionBinder.prepareFromSearch(mContext.getOpPackageName(), mCbStub, query,
+                mSessionBinder.prepareFromSearch(mContext.getPackageName(), mCbStub, query,
                         extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
@@ -744,7 +746,7 @@
                         "You must specify a non-empty Uri for prepareFromUri.");
             }
             try {
-                mSessionBinder.prepareFromUri(mContext.getOpPackageName(), mCbStub, uri, extras);
+                mSessionBinder.prepareFromUri(mContext.getPackageName(), mCbStub, uri, extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
             }
@@ -755,7 +757,7 @@
          */
         public void play() {
             try {
-                mSessionBinder.play(mContext.getOpPackageName(), mCbStub);
+                mSessionBinder.play(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling play.", e);
             }
@@ -774,7 +776,7 @@
                         "You must specify a non-empty String for playFromMediaId.");
             }
             try {
-                mSessionBinder.playFromMediaId(mContext.getOpPackageName(), mCbStub, mediaId,
+                mSessionBinder.playFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
                         extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling play(" + mediaId + ").", e);
@@ -797,7 +799,7 @@
                 query = "";
             }
             try {
-                mSessionBinder.playFromSearch(mContext.getOpPackageName(), mCbStub, query, extras);
+                mSessionBinder.playFromSearch(mContext.getPackageName(), mCbStub, query, extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling play(" + query + ").", e);
             }
@@ -816,7 +818,7 @@
                         "You must specify a non-empty Uri for playFromUri.");
             }
             try {
-                mSessionBinder.playFromUri(mContext.getOpPackageName(), mCbStub, uri, extras);
+                mSessionBinder.playFromUri(mContext.getPackageName(), mCbStub, uri, extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling play(" + uri + ").", e);
             }
@@ -828,7 +830,7 @@
          */
         public void skipToQueueItem(long id) {
             try {
-                mSessionBinder.skipToQueueItem(mContext.getOpPackageName(), mCbStub, id);
+                mSessionBinder.skipToQueueItem(mContext.getPackageName(), mCbStub, id);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
             }
@@ -840,7 +842,7 @@
          */
         public void pause() {
             try {
-                mSessionBinder.pause(mContext.getOpPackageName(), mCbStub);
+                mSessionBinder.pause(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling pause.", e);
             }
@@ -852,7 +854,7 @@
          */
         public void stop() {
             try {
-                mSessionBinder.stop(mContext.getOpPackageName(), mCbStub);
+                mSessionBinder.stop(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling stop.", e);
             }
@@ -865,7 +867,7 @@
          */
         public void seekTo(long pos) {
             try {
-                mSessionBinder.seekTo(mContext.getOpPackageName(), mCbStub, pos);
+                mSessionBinder.seekTo(mContext.getPackageName(), mCbStub, pos);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling seekTo.", e);
             }
@@ -877,7 +879,7 @@
          */
         public void fastForward() {
             try {
-                mSessionBinder.fastForward(mContext.getOpPackageName(), mCbStub);
+                mSessionBinder.fastForward(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling fastForward.", e);
             }
@@ -888,7 +890,7 @@
          */
         public void skipToNext() {
             try {
-                mSessionBinder.next(mContext.getOpPackageName(), mCbStub);
+                mSessionBinder.next(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling next.", e);
             }
@@ -900,7 +902,7 @@
          */
         public void rewind() {
             try {
-                mSessionBinder.rewind(mContext.getOpPackageName(), mCbStub);
+                mSessionBinder.rewind(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling rewind.", e);
             }
@@ -911,7 +913,7 @@
          */
         public void skipToPrevious() {
             try {
-                mSessionBinder.previous(mContext.getOpPackageName(), mCbStub);
+                mSessionBinder.previous(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling previous.", e);
             }
@@ -926,7 +928,7 @@
          */
         public void setRating(Rating rating) {
             try {
-                mSessionBinder.rate(mContext.getOpPackageName(), mCbStub, rating);
+                mSessionBinder.rate(mContext.getPackageName(), mCbStub, rating);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling rate.", e);
             }
@@ -961,7 +963,7 @@
                 throw new IllegalArgumentException("CustomAction cannot be null.");
             }
             try {
-                mSessionBinder.sendCustomAction(mContext.getOpPackageName(), mCbStub, action, args);
+                mSessionBinder.sendCustomAction(mContext.getPackageName(), mCbStub, action, args);
             } catch (RemoteException e) {
                 Log.d(TAG, "Dead object in sendCustomAction.", e);
             }
@@ -1140,8 +1142,7 @@
         private boolean mRegistered = false;
 
         public MessageHandler(Looper looper, MediaController.Callback cb) {
-            //TODO:(b/119539849) Uncomment below line and resolve the error.
-            // super(looper, null, true);
+            super(looper);
             mCallback = cb;
         }
 
@@ -1180,6 +1181,7 @@
 
         public void post(int what, Object obj, Bundle data) {
             Message msg = obtainMessage(what, obj);
+            msg.setAsynchronous(true);
             msg.setData(data);
             msg.sendToTarget();
         }
diff --git a/packages/MediaComponents/apex/java/android/media/session/MediaSession.java b/packages/MediaComponents/apex/java/android/media/session/MediaSession.java
index 943843d..73e16a6 100644
--- a/packages/MediaComponents/apex/java/android/media/session/MediaSession.java
+++ b/packages/MediaComponents/apex/java/android/media/session/MediaSession.java
@@ -1458,8 +1458,7 @@
         private RemoteUserInfo mCurrentControllerInfo;
 
         public CallbackMessageHandler(Looper looper, MediaSession.Callback callback) {
-            //TODO:(b/119539849) Uncomment below line and resolve the error.
-            //super(looper, null, true);
+            super(looper);
             mCallback = callback;
             mCallback.mHandler = this;
         }
@@ -1467,6 +1466,7 @@
         public void post(RemoteUserInfo caller, int what, Object obj, Bundle data, long delayMs) {
             Pair<RemoteUserInfo, Object> objWithCaller = Pair.create(caller, obj);
             Message msg = obtainMessage(what, objWithCaller);
+            msg.setAsynchronous(true);
             msg.setData(data);
             if (delayMs > 0) {
                 sendMessageDelayed(msg, delayMs);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 26f76c0..0d6ef46 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2379,7 +2379,8 @@
         return BAD_VALUE;
     }
 
-    sp<ThreadBase> thread = openInput_l(module, input, config, *devices, address, source, flags);
+    sp<ThreadBase> thread = openInput_l(
+            module, input, config, *devices, address, source, flags, AUDIO_DEVICE_NONE, String8{});
 
     if (thread != 0) {
         // notify client processes of the new input creation
@@ -2395,7 +2396,9 @@
                                                          audio_devices_t devices,
                                                          const String8& address,
                                                          audio_source_t source,
-                                                         audio_input_flags_t flags)
+                                                         audio_input_flags_t flags,
+                                                         audio_devices_t outputDevice,
+                                                         const String8& outputDeviceAddress)
 {
     AudioHwDevice *inHwDev = findSuitableHwDev_l(module, devices);
     if (inHwDev == NULL) {
@@ -2424,7 +2427,8 @@
     sp<DeviceHalInterface> inHwHal = inHwDev->hwDevice();
     sp<StreamInHalInterface> inStream;
     status_t status = inHwHal->openInputStream(
-            *input, devices, &halconfig, flags, address.string(), source, &inStream);
+            *input, devices, &halconfig, flags, address.string(), source,
+            outputDevice, outputDeviceAddress, &inStream);
     ALOGV("openInput_l() openInputStream returned input %p, devices %#x, SamplingRate %d"
            ", Format %#x, Channels %#x, flags %#x, status %d addr %s",
             inStream.get(),
@@ -2447,7 +2451,8 @@
         ALOGV("openInput_l() reopening with proposed sampling rate and channel mask");
         inStream.clear();
         status = inHwHal->openInputStream(
-                *input, devices, &halconfig, flags, address.string(), source, &inStream);
+                *input, devices, &halconfig, flags, address.string(), source,
+                outputDevice, outputDeviceAddress, &inStream);
         // FIXME log this new status; HAL should not propose any further changes
     }
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 6c698f6..c1169d2 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -579,6 +579,10 @@
         virtual binder::Status   stop();
         virtual binder::Status   getActiveMicrophones(
                 std::vector<media::MicrophoneInfo>* activeMicrophones);
+        virtual binder::Status   setMicrophoneDirection(
+                int /*audio_microphone_direction_t*/ direction);
+        virtual binder::Status   setMicrophoneFieldDimension(float zoom);
+
     private:
         const sp<RecordThread::RecordTrack> mRecordTrack;
 
@@ -620,7 +624,9 @@
                                            audio_devices_t device,
                                            const String8& address,
                                            audio_source_t source,
-                                           audio_input_flags_t flags);
+                                           audio_input_flags_t flags,
+                                           audio_devices_t outputDevice,
+                                           const String8& outputDeviceAddress);
               sp<ThreadBase> openOutput_l(audio_module_handle_t module,
                                               audio_io_handle_t *output,
                                               audio_config_t *config,
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 538a0eb..3381e4d 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -211,6 +211,8 @@
                 ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
                  ((patch->sinks[0].ext.device.hw_module != srcModule) ||
                   !audioHwDevice->supportsAudioPatches()))) {
+                audio_devices_t outputDevice = AUDIO_DEVICE_NONE;
+                String8 outputDeviceAddress;
                 if (patch->num_sources == 2) {
                     if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
                             (patch->num_sinks != 0 && patch->sinks[0].ext.device.hw_module !=
@@ -261,6 +263,8 @@
                         goto exit;
                     }
                     newPatch.mPlayback.setThread(reinterpret_cast<PlaybackThread*>(thread.get()));
+                    outputDevice = device;
+                    outputDeviceAddress = address;
                 }
                 audio_devices_t device = patch->sources[0].ext.device.type;
                 String8 address = String8(patch->sources[0].ext.device.address);
@@ -293,7 +297,9 @@
                                                                     device,
                                                                     address,
                                                                     AUDIO_SOURCE_MIC,
-                                                                    flags);
+                                                                    flags,
+                                                                    outputDevice,
+                                                                    outputDeviceAddress);
                 ALOGV("mAudioFlinger.openInput_l() returned %p inChannelMask %08x",
                       thread.get(), config.channel_mask);
                 if (thread == 0) {
@@ -322,6 +328,13 @@
                         }
                     }
                     status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
+                    // remove stale audio patch with same input as sink if any
+                    for (auto& iter : mPatches) {
+                        if (iter.second.mAudioPatch.sinks[0].ext.mix.handle == thread->id()) {
+                            mPatches.erase(iter.first);
+                            break;
+                        }
+                    }
                 } else {
                     sp<DeviceHalInterface> hwDevice = audioHwDevice->hwDevice();
                     status = hwDevice->createAudioPatch(patch->num_sources,
@@ -376,6 +389,14 @@
             }
 
             status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
+
+            // remove stale audio patch with same output as source if any
+            for (auto& iter : mPatches) {
+                if (iter.second.mAudioPatch.sources[0].ext.mix.handle == thread->id()) {
+                    mPatches.erase(iter.first);
+                    break;
+                }
+            }
         } break;
         default:
             status = BAD_VALUE;
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 85f5456..32af7d5 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -71,6 +71,9 @@
 
             status_t    getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
 
+            status_t    setMicrophoneDirection(audio_microphone_direction_t direction);
+            status_t    setMicrophoneFieldDimension(float zoom);
+
     static  bool        checkServerLatencySupported(
                                 audio_format_t format, audio_input_flags_t flags) {
                             return audio_is_linear_pcm(format)
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index c6941c0..31a8c7d 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -494,6 +494,8 @@
     case AUDIO_SOURCE_VOICE_COMMUNICATION:  return "voice communication";
     case AUDIO_SOURCE_REMOTE_SUBMIX:        return "remote submix";
     case AUDIO_SOURCE_UNPROCESSED:          return "unprocessed";
+    case AUDIO_SOURCE_VOICE_PERFORMANCE:    return "voice performance";
+    case AUDIO_SOURCE_ECHO_REFERENCE:       return "echo reference";
     case AUDIO_SOURCE_FM_TUNER:             return "FM tuner";
     case AUDIO_SOURCE_HOTWORD:              return "hotword";
     default:                                return "unknown";
@@ -3850,6 +3852,7 @@
         type |= patch->sinks[i].ext.device.type;
     }
 
+    audio_port_handle_t sinkPortId = patch->sinks[0].id;
 #ifdef ADD_BATTERY_DATA
     // when changing the audio output device, call addBatteryData to notify
     // the change
@@ -3879,7 +3882,7 @@
 
     // mPrevOutDevice is the latest device set by createAudioPatch_l(). It is not set when
     // the thread is created so that the first patch creation triggers an ioConfigChanged callback
-    bool configChanged = mPrevOutDevice != type;
+    bool configChanged = (mPrevOutDevice != type) || (mDeviceId != sinkPortId);
     mOutDevice = type;
     mPatch = *patch;
 
@@ -3908,6 +3911,7 @@
     }
     if (configChanged) {
         mPrevOutDevice = type;
+        mDeviceId = sinkPortId;
         sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
     }
     return status;
@@ -7578,6 +7582,20 @@
     return status;
 }
 
+status_t AudioFlinger::RecordThread::setMicrophoneDirection(audio_microphone_direction_t direction)
+{
+    ALOGV("RecordThread::setMicrophoneDirection");
+    AutoMutex _l(mLock);
+    return mInput->stream->setMicrophoneDirection(direction);
+}
+
+status_t AudioFlinger::RecordThread::setMicrophoneFieldDimension(float zoom)
+{
+    ALOGV("RecordThread::setMicrophoneFieldDimension");
+    AutoMutex _l(mLock);
+    return mInput->stream->setMicrophoneFieldDimension(zoom);
+}
+
 void AudioFlinger::RecordThread::updateMetadata_l()
 {
     if (mInput == nullptr || mInput->stream == nullptr ||
@@ -8145,6 +8163,7 @@
 
     // store new device and send to effects
     mInDevice = patch->sources[0].ext.device.type;
+    audio_port_handle_t deviceId = patch->sources[0].id;
     mPatch = *patch;
     for (size_t i = 0; i < mEffectChains.size(); i++) {
         mEffectChains[i]->setDevice_l(mInDevice);
@@ -8186,9 +8205,10 @@
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
 
-    if (mInDevice != mPrevInDevice) {
+    if ((mInDevice != mPrevInDevice) || (mDeviceId != deviceId)) {
         sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
         mPrevInDevice = mInDevice;
+        mDeviceId = deviceId;
     }
 
     return status;
@@ -8285,7 +8305,7 @@
         audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
     : ThreadBase(audioFlinger, id, outDevice, inDevice, MMAP, systemReady),
       mSessionId(AUDIO_SESSION_NONE),
-      mDeviceId(AUDIO_PORT_HANDLE_NONE), mPortId(AUDIO_PORT_HANDLE_NONE),
+      mPortId(AUDIO_PORT_HANDLE_NONE),
       mHalStream(stream), mHalDevice(hwDev->hwDevice()), mAudioHwDev(hwDev),
       mActiveTracks(&this->mLocalLog),
       mHalVolFloat(-1.0f), // Initialize to illegal value so it always gets set properly later.
@@ -8769,7 +8789,7 @@
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
 
-    if (isOutput() && mPrevOutDevice != mOutDevice) {
+    if (isOutput() && (mPrevOutDevice != mOutDevice || mDeviceId != deviceId)) {
         mPrevOutDevice = type;
         sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
         sp<MmapStreamCallback> callback = mCallback.promote();
@@ -8780,7 +8800,7 @@
         }
         mDeviceId = deviceId;
     }
-    if (!isOutput() && mPrevInDevice != mInDevice) {
+    if (!isOutput() && (mPrevInDevice != mInDevice || mDeviceId != deviceId)) {
         mPrevInDevice = type;
         sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
         sp<MmapStreamCallback> callback = mCallback.promote();
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index e8b2158..aab7601 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -485,6 +485,10 @@
                 audio_devices_t         mPrevOutDevice;   // previous output device
                 audio_devices_t         mPrevInDevice;    // previous input device
                 struct audio_patch      mPatch;
+                /**
+                 * @brief mDeviceId  current device port unique identifier
+                 */
+                audio_port_handle_t     mDeviceId = AUDIO_PORT_HANDLE_NONE;
                 audio_source_t          mAudioSource;
 
                 const audio_io_handle_t mId;
@@ -1541,6 +1545,9 @@
 
             status_t    getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
 
+            status_t    setMicrophoneDirection(audio_microphone_direction_t direction);
+            status_t    setMicrophoneFieldDimension(float zoom);
+
             void        updateMetadata_l() override;
 
             bool        fastTrackAvailable() const { return mFastTrackAvail; }
@@ -1704,7 +1711,6 @@
 
                 audio_attributes_t      mAttr;
                 audio_session_t         mSessionId;
-                audio_port_handle_t     mDeviceId;
                 audio_port_handle_t     mPortId;
 
                 wp<MmapStreamCallback>  mCallback;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 9a7f1f1..d23d19d 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1710,6 +1710,18 @@
             mRecordTrack->getActiveMicrophones(activeMicrophones));
 }
 
+binder::Status AudioFlinger::RecordHandle::setMicrophoneDirection(
+        int /*audio_microphone_direction_t*/ direction) {
+    ALOGV("%s()", __func__);
+    return binder::Status::fromStatusT(mRecordTrack->setMicrophoneDirection(
+            static_cast<audio_microphone_direction_t>(direction)));
+}
+
+binder::Status AudioFlinger::RecordHandle::setMicrophoneFieldDimension(float zoom) {
+    ALOGV("%s()", __func__);
+    return binder::Status::fromStatusT(mRecordTrack->setMicrophoneFieldDimension(zoom));
+}
+
 // ----------------------------------------------------------------------------
 #undef LOG_TAG
 #define LOG_TAG "AF::RecordTrack"
@@ -2004,6 +2016,27 @@
     }
 }
 
+status_t AudioFlinger::RecordThread::RecordTrack::setMicrophoneDirection(
+        audio_microphone_direction_t direction) {
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread != 0) {
+        RecordThread *recordThread = (RecordThread *)thread.get();
+        return recordThread->setMicrophoneDirection(direction);
+    } else {
+        return BAD_VALUE;
+    }
+}
+
+status_t AudioFlinger::RecordThread::RecordTrack::setMicrophoneFieldDimension(float zoom) {
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread != 0) {
+        RecordThread *recordThread = (RecordThread *)thread.get();
+        return recordThread->setMicrophoneFieldDimension(zoom);
+    } else {
+        return BAD_VALUE;
+    }
+}
+
 // ----------------------------------------------------------------------------
 #undef LOG_TAG
 #define LOG_TAG "AF::PatchRecord"
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index bfa1b5e..ebb4f3b 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -51,6 +51,7 @@
     libcutils \
     libutils \
     liblog \
+    libaudioclient \
     libsoundtrigger
 
 ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1)
@@ -85,7 +86,7 @@
 LOCAL_SHARED_LIBRARIES += libmedia_helper
 LOCAL_SHARED_LIBRARIES += libmediametrics
 
-LOCAL_SHARED_LIBRARIES += libhidlbase libicuuc libxml2
+LOCAL_SHARED_LIBRARIES += libhidlbase libxml2
 
 ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
 LOCAL_CFLAGS += -DUSE_XML_AUDIO_POLICY_CONF
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index ad12a90..1c2b9d7 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -210,6 +210,10 @@
     virtual status_t registerPolicyMixes(const Vector<AudioMix>& mixes) = 0;
     virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes) = 0;
 
+    virtual status_t setUidDeviceAffinities(uid_t uid, const Vector<AudioDeviceTypeAddr>& devices)
+            = 0;
+    virtual status_t removeUidDeviceAffinities(uid_t uid) = 0;
+
     virtual status_t startAudioSource(const struct audio_port_config *source,
                                       const audio_attributes_t *attributes,
                                       audio_port_handle_t *portId,
diff --git a/services/audiopolicy/TEST_MAPPING b/services/audiopolicy/TEST_MAPPING
new file mode 100644
index 0000000..a94fd87
--- /dev/null
+++ b/services/audiopolicy/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+  "presubmit": [
+    {
+       "name": "audiopolicy_tests"
+    },
+    {
+       "name": "systemaudio_tests"
+    }
+  ]
+}
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 30b0044..46a2a40 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -83,7 +83,10 @@
  * @param[in] inputSource to consider. Valid sources are:
  * - AUDIO_SOURCE_VOICE_COMMUNICATION
  * - AUDIO_SOURCE_CAMCORDER
+ * - AUDIO_SOURCE_VOICE_PERFORMANCE
+ * - AUDIO_SOURCE_UNPROCESSED
  * - AUDIO_SOURCE_MIC
+ * - AUDIO_SOURCE_ECHO_REFERENCE
  * - AUDIO_SOURCE_FM_TUNER
  * - AUDIO_SOURCE_VOICE_RECOGNITION
  * - AUDIO_SOURCE_HOTWORD
@@ -96,10 +99,16 @@
 {
     switch (inputSource) {
     case AUDIO_SOURCE_VOICE_COMMUNICATION:
-        return 6;
+        return 9;
     case AUDIO_SOURCE_CAMCORDER:
-        return 5;
+        return 8;
+    case AUDIO_SOURCE_VOICE_PERFORMANCE:
+        return 7;
+    case AUDIO_SOURCE_UNPROCESSED:
+        return 6;
     case AUDIO_SOURCE_MIC:
+        return 5;
+    case AUDIO_SOURCE_ECHO_REFERENCE:
         return 4;
     case AUDIO_SOURCE_FM_TUNER:
         return 3;
diff --git a/services/audiopolicy/common/managerdefinitions/Android.bp b/services/audiopolicy/common/managerdefinitions/Android.bp
index d0b4973..e5ebab7 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.bp
+++ b/services/audiopolicy/common/managerdefinitions/Android.bp
@@ -24,7 +24,6 @@
     shared_libs: [
         "libcutils",
         "libhidlbase",
-        "libicuuc",
         "liblog",
         "libmedia",
         "libutils",
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index fa9ba0b..d4cfd1e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -23,11 +23,12 @@
 #include "AudioIODescriptorInterface.h"
 #include "AudioPort.h"
 #include "ClientDescriptor.h"
+#include "DeviceDescriptor.h"
 #include "EffectDescriptor.h"
+#include "IOProfile.h"
 
 namespace android {
 
-class IOProfile;
 class AudioMix;
 class AudioPolicyClientInterface;
 
@@ -42,10 +43,16 @@
     audio_port_handle_t getId() const;
     audio_module_handle_t getModuleHandle() const;
 
+    audio_devices_t getDeviceType() const { return (mDevice != nullptr) ?
+                    mDevice->type() : AUDIO_DEVICE_NONE; }
+    sp<DeviceDescriptor> getDevice() const { return mDevice; }
+    void setDevice(const sp<DeviceDescriptor> &device) { mDevice = device; }
+    DeviceVector supportedDevices() const  {
+        return mProfile != nullptr ? mProfile->getSupportedDevices() :  DeviceVector(); }
+
     void dump(String8 *dst) const override;
 
     audio_io_handle_t   mIoHandle = AUDIO_IO_HANDLE_NONE; // input handle
-    audio_devices_t     mDevice = AUDIO_DEVICE_NONE;  // current device this input is routed to
     AudioMix            *mPolicyMix = nullptr;        // non NULL when used by a dynamic policy
     const sp<IOProfile> mProfile;                     // I/O profile this output derives from
 
@@ -61,6 +68,7 @@
     bool isSourceActive(audio_source_t source) const;
     audio_source_t source() const;
     bool isSoundTrigger() const;
+    audio_attributes_t getHighestPriorityAttributes() const;
     void setClientActive(const sp<RecordClientDescriptor>& client, bool active);
     int32_t activeCount() { return mGlobalActiveCount; }
     void trackEffectEnabled(const sp<EffectDescriptor> &effect, bool enabled);
@@ -71,8 +79,7 @@
     void setPatchHandle(audio_patch_handle_t handle) override;
 
     status_t open(const audio_config_t *config,
-                  audio_devices_t device,
-                  const String8& address,
+                  const sp<DeviceDescriptor> &device,
                   audio_source_t source,
                   audio_input_flags_t flags,
                   audio_io_handle_t *input);
@@ -99,6 +106,8 @@
 
     audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
     audio_port_handle_t  mId = AUDIO_PORT_HANDLE_NONE;
+    sp<DeviceDescriptor> mDevice = nullptr; /**< current device this input is routed to */
+
     // Because a preemptible capture session can preempt another one, we end up in an endless loop
     // situation were each session is allowed to restart after being preempted,
     // thus preempting the other one which restarts and so on.
@@ -120,8 +129,8 @@
     sp<AudioInputDescriptor> getInputFromId(audio_port_handle_t id) const;
 
     // count active capture sessions using one of the specified devices.
-    // ignore devices if AUDIO_DEVICE_IN_DEFAULT is passed
-    uint32_t activeInputsCountOnDevices(audio_devices_t devices = AUDIO_DEVICE_IN_DEFAULT) const;
+    // ignore devices if empty vector is passed
+    uint32_t activeInputsCountOnDevices(const DeviceVector &devices) const;
 
     /**
      * return io handle of active input or 0 if no input is active
@@ -130,8 +139,6 @@
      */
     Vector<sp <AudioInputDescriptor> > getActiveInputs();
 
-    audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
-
     sp<AudioInputDescriptor> getInputForClient(audio_port_handle_t portId);
 
     void trackEffectEnabled(const sp<EffectDescriptor> &effect, bool enabled);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index ed995e0..14b995b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -26,13 +26,14 @@
 #include "AudioIODescriptorInterface.h"
 #include "AudioPort.h"
 #include "ClientDescriptor.h"
+#include "DeviceDescriptor.h"
+#include <map>
 
 namespace android {
 
 class IOProfile;
 class AudioMix;
 class AudioPolicyClientInterface;
-class DeviceDescriptor;
 
 // descriptor for audio outputs. Used to maintain current configuration of each opened audio output
 // and keep track of the usage of this output by each audio stream type.
@@ -48,14 +49,12 @@
     void        log(const char* indent);
 
     audio_port_handle_t getId() const;
-    virtual audio_devices_t device() const;
-    virtual bool sharesHwModuleWith(const sp<AudioOutputDescriptor>& outputDesc);
-    virtual audio_devices_t supportedDevices();
+    virtual DeviceVector devices() const { return mDevices; }
+    bool sharesHwModuleWith(const sp<AudioOutputDescriptor>& outputDesc);
+    virtual DeviceVector supportedDevices() const  { return mDevices; }
     virtual bool isDuplicated() const { return false; }
     virtual uint32_t latency() { return 0; }
     virtual bool isFixedVolume(audio_devices_t device);
-    virtual sp<AudioOutputDescriptor> subOutput1() { return 0; }
-    virtual sp<AudioOutputDescriptor> subOutput2() { return 0; }
     virtual bool setVolume(float volume,
                            audio_stream_type_t stream,
                            audio_devices_t device,
@@ -119,7 +118,7 @@
         return mActiveClients;
     }
 
-    audio_devices_t mDevice = AUDIO_DEVICE_NONE; // current device this output is routed to
+    DeviceVector mDevices; /**< current devices this output is routed to */
     nsecs_t mStopTime[AUDIO_STREAM_CNT];
     int mMuteCount[AUDIO_STREAM_CNT];            // mute request counter
     bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
@@ -151,14 +150,15 @@
     virtual ~SwAudioOutputDescriptor() {}
 
             void dump(String8 *dst) const override;
-    virtual audio_devices_t device() const;
-    virtual bool sharesHwModuleWith(const sp<AudioOutputDescriptor>& outputDesc);
-    virtual audio_devices_t supportedDevices();
+    virtual DeviceVector devices() const;
+    void setDevices(const DeviceVector &devices) { mDevices = devices; }
+    bool sharesHwModuleWith(const sp<SwAudioOutputDescriptor>& outputDesc);
+    virtual DeviceVector supportedDevices() const;
     virtual uint32_t latency();
     virtual bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
     virtual bool isFixedVolume(audio_devices_t device);
-    virtual sp<AudioOutputDescriptor> subOutput1() { return mOutput1; }
-    virtual sp<AudioOutputDescriptor> subOutput2() { return mOutput2; }
+    sp<SwAudioOutputDescriptor> subOutput1() { return mOutput1; }
+    sp<SwAudioOutputDescriptor> subOutput2() { return mOutput2; }
             void changeStreamActiveCount(
                     const sp<TrackClientDescriptor>& client, int delta) override;
     virtual bool setVolume(float volume,
@@ -171,22 +171,49 @@
                            const struct audio_port_config *srcConfig = NULL) const;
     virtual void toAudioPort(struct audio_port *port) const;
 
-            status_t open(const audio_config_t *config,
-                          audio_devices_t device,
-                          const String8& address,
-                          audio_stream_type_t stream,
-                          audio_output_flags_t flags,
-                          audio_io_handle_t *output);
-            // Called when a stream is about to be started
-            // Note: called before setClientActive(true);
-            status_t start();
-            // Called after a stream is stopped.
-            // Note: called after setClientActive(false);
-            void stop();
-            void close();
-            status_t openDuplicating(const sp<SwAudioOutputDescriptor>& output1,
-                                     const sp<SwAudioOutputDescriptor>& output2,
-                                     audio_io_handle_t *ioHandle);
+        status_t open(const audio_config_t *config,
+                      const DeviceVector &devices,
+                      audio_stream_type_t stream,
+                      audio_output_flags_t flags,
+                      audio_io_handle_t *output);
+
+        // Called when a stream is about to be started
+        // Note: called before setClientActive(true);
+        status_t start();
+        // Called after a stream is stopped.
+        // Note: called after setClientActive(false);
+        void stop();
+        void close();
+        status_t openDuplicating(const sp<SwAudioOutputDescriptor>& output1,
+                                 const sp<SwAudioOutputDescriptor>& output2,
+                                 audio_io_handle_t *ioHandle);
+
+    /**
+     * @brief supportsDevice
+     * @param device to be checked against
+     * @return true if the device is supported by type (for non bus / remote submix devices),
+     *         true if the device is supported (both type and address) for bus / remote submix
+     *         false otherwise
+     */
+    bool supportsDevice(const sp<DeviceDescriptor> &device) const;
+
+    /**
+     * @brief supportsAllDevices
+     * @param devices to be checked against
+     * @return true if the device is weakly supported by type (e.g. for non bus / rsubmix devices),
+     *         true if the device is supported (both type and address) for bus / remote submix
+     *         false otherwise
+     */
+    bool supportsAllDevices(const DeviceVector &devices) const;
+
+    /**
+     * @brief filterSupportedDevices takes a vector of devices and filters them according to the
+     * device supported by this output (the profile from which this output derives from)
+     * @param devices reference device vector to be filtered
+     * @return vector of devices filtered from the supported devices of this output (weakly or not
+     * depending on the device type)
+     */
+    DeviceVector filterSupportedDevices(const DeviceVector &devices) const;
 
     const sp<IOProfile> mProfile;          // I/O profile this output derives from
     audio_io_handle_t mIoHandle;           // output handle
@@ -208,7 +235,6 @@
 
             void dump(String8 *dst) const override;
 
-    virtual audio_devices_t supportedDevices();
     virtual bool setVolume(float volume,
                            audio_stream_type_t stream,
                            audio_devices_t device,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 5099ebb..d52eb3d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -133,18 +133,14 @@
         mDefaultOutputDevice->attach(module);
         defaultInputDevice->attach(module);
 
-        sp<OutputProfile> outProfile;
-        outProfile = new OutputProfile(String8("primary"));
-        outProfile->attach(module);
+        sp<OutputProfile> outProfile = new OutputProfile(String8("primary"));
         outProfile->addAudioProfile(
                 new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
         outProfile->addSupportedDevice(mDefaultOutputDevice);
         outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
         module->addOutputProfile(outProfile);
 
-        sp<InputProfile> inProfile;
-        inProfile = new InputProfile(String8("primary"));
-        inProfile->attach(module);
+        sp<InputProfile> inProfile = new InputProfile(String8("primary"));
         inProfile->addAudioProfile(micProfile);
         inProfile->addSupportedDevice(defaultInputDevice);
         module->addInputProfile(inProfile);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 96c00ea..e6a62d9 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include "DeviceDescriptor.h"
 #include <utils/RefBase.h>
 #include <media/AudioPolicy.h>
 #include <utils/KeyedVector.h>
@@ -74,12 +75,16 @@
     status_t getOutputForAttr(audio_attributes_t attributes, uid_t uid,
             sp<SwAudioOutputDescriptor> &desc);
 
-    audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource,
-                                                  audio_devices_t availableDeviceTypes,
-                                                  AudioMix **policyMix);
+    sp<DeviceDescriptor> getDeviceAndMixForInputSource(audio_source_t inputSource,
+                                                       const DeviceVector &availableDeviceTypes,
+                                                       AudioMix **policyMix);
 
     status_t getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix);
 
+    status_t setUidDeviceAffinities(uid_t uid, const Vector<AudioDeviceTypeAddr>& devices);
+    status_t removeUidDeviceAffinities(uid_t uid);
+    status_t getDevicesForUid(uid_t uid, Vector<AudioDeviceTypeAddr>& devices) const;
+
     void dump(String8 *dst) const;
 };
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index bb9cad8..1b5a2d6 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -65,6 +65,7 @@
     uint32_t getFlags() const { return mFlags; }
 
     virtual void attach(const sp<HwModule>& module);
+    virtual void detach();
     bool isAttached() { return mModule != 0; }
 
     // Audio port IDs are in a different namespace than AudioFlinger unique IDs
@@ -161,7 +162,7 @@
                                    const struct audio_port_config *srcConfig = NULL) const = 0;
     virtual sp<AudioPort> getAudioPort() const = 0;
     virtual bool hasSameHwModuleAs(const sp<AudioPortConfig>& other) const {
-        return (other != 0) &&
+        return (other != 0) && (other->getAudioPort() != 0) && (getAudioPort() != 0) &&
                 (other->getAudioPort()->getModuleHandle() == getAudioPort()->getModuleHandle());
     }
     unsigned int mSamplingRate = 0u;
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index d02123c..b581665 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -53,6 +53,8 @@
 
     // AudioPort
     virtual void attach(const sp<HwModule>& module);
+    virtual void detach();
+
     virtual void toAudioPort(struct audio_port *port) const;
     virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
 
@@ -164,6 +166,23 @@
         return !operator==(right);
     }
 
+    /**
+     * @brief getFirstValidAddress
+     * @return the first valid address of a list of device, "" if no device with valid address
+     * found.
+     * This helper function helps maintaining compatibility with legacy where we used to have a
+     * devices mask and an address.
+     */
+    String8 getFirstValidAddress() const
+    {
+        for (const auto &device : *this) {
+            if (device->address() != "") {
+                return device->address();
+            }
+        }
+        return String8("");
+    }
+
     std::string toString() const;
 
     void dump(String8 *dst, const String8 &tag, int spaces = 0, bool verbose = true) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index 2b57fa9..d7dc4b0 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -46,6 +46,22 @@
 
     const DeviceVector &getDeclaredDevices() const { return mDeclaredDevices; }
     void setDeclaredDevices(const DeviceVector &devices);
+    DeviceVector getAllDevices() const
+    {
+        DeviceVector devices = mDeclaredDevices;
+        devices.merge(mDynamicDevices);
+        return devices;
+    }
+    void addDynamicDevice(const sp<DeviceDescriptor> &device)
+    {
+        mDynamicDevices.add(device);
+    }
+
+    bool removeDynamicDevice(const sp<DeviceDescriptor> &device)
+    {
+        return mDynamicDevices.remove(device) >= 0;
+    }
+    DeviceVector getDynamicDevices() const { return mDynamicDevices; }
 
     const InputProfileCollection &getInputProfiles() const { return mInputProfiles; }
     const OutputProfileCollection &getOutputProfiles() const { return mOutputProfiles; }
@@ -104,6 +120,7 @@
     InputProfileCollection mInputProfiles;  // input profiles exposed by this module
     uint32_t mHalVersion; // audio HAL API version
     DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
+    DeviceVector mDynamicDevices; /**< devices that can be added/removed at runtime (e.g. rsbumix)*/
     AudioRouteVector mRoutes;
     AudioPortVector mPorts;
 };
@@ -113,13 +130,58 @@
 public:
     sp<HwModule> getModuleFromName(const char *name) const;
 
-    sp<HwModule> getModuleForDevice(audio_devices_t device) const;
+    sp<HwModule> getModuleForDeviceTypes(audio_devices_t device) const;
 
-    sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
-                                             const char *device_address,
-                                             const char *device_name,
+    sp<HwModule> getModuleForDevice(const sp<DeviceDescriptor> &device) const;
+
+    DeviceVector getAvailableDevicesFromModuleName(const char *name,
+                                                   const DeviceVector &availableDevices) const;
+
+    /**
+     * @brief getDeviceDescriptor returns a device descriptor associated to the device type and
+     * device address (if matchAddress is true).
+     * It may loop twice on all modules to check if allowToCreate is true
+     *      -first loop will check if the device is found on a module since declared in the list
+     * of device port in configuration file
+     *      -(allowToCreate is true)second loop will check if the device is weakly supported by one
+     * or more profiles on a given module and will add as a supported device for this module.
+     *       The device will also be added to the dynamic list of device of this module
+     * @param type of the device requested
+     * @param address of the device requested
+     * @param name of the device that requested
+     * @param matchAddress true if a strong match is required
+     * @param allowToCreate true if allowed to create dynamic device (e.g. hdmi, usb...)
+     * @return device descriptor associated to the type (and address if matchAddress is true)
+     */
+    sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t type,
+                                             const char *address,
+                                             const char *name,
+                                             bool allowToCreate = false,
                                              bool matchAddress = true) const;
 
+    /**
+     * @brief createDevice creates a new device from the type and address given. It checks that
+     * according to the device type, a module is supporting this device (weak check).
+     * This concerns only dynamic device, aka device with a specific address and not
+     * already supported by module/underlying profiles.
+     * @param type of the device to be created
+     * @param address of the device to be created
+     * @param name of the device to be created
+     * @return device descriptor if a module is supporting this type, nullptr otherwise.
+     */
+    sp<DeviceDescriptor> createDevice(const audio_devices_t type,
+                                      const char *address,
+                                      const char *name) const;
+
+    /**
+     * @brief cleanUpForDevice: loop on all profiles of all modules to remove device from
+     * the list of supported device. If this device is a dynamic device (aka a device not in the
+     * xml file with a runtime address), it is also removed from the module collection of dynamic
+     * devices.
+     * @param device that has been disconnected
+     */
+    void cleanUpForDevice(const sp<DeviceDescriptor> &device);
+
     void dump(String8 *dst) const;
 };
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index ca6ca56..d0c05a5 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -57,12 +57,25 @@
         }
     }
 
-    // This method is used for input and direct output, and is not used for other output.
-    // If parameter updatedSamplingRate is non-NULL, it is assigned the actual sample rate.
-    // For input, flags is interpreted as audio_input_flags_t.
-    // TODO: merge audio_output_flags_t and audio_input_flags_t.
-    bool isCompatibleProfile(audio_devices_t device,
-                             const String8& address,
+    /**
+     * @brief isCompatibleProfile: This method is used for input and direct output,
+     * and is not used for other output.
+     * Checks if the IO profile is compatible with specified parameters.
+     * For input, flags is interpreted as audio_input_flags_t.
+     * TODO: merge audio_output_flags_t and audio_input_flags_t.
+     *
+     * @param devices vector of devices to be checked for compatibility
+     * @param samplingRate to be checked for compatibility. Must be specified
+     * @param updatedSamplingRate if non-NULL, it is assigned the actual sample rate.
+     * @param format to be checked for compatibility. Must be specified
+     * @param updatedFormat if non-NULL, it is assigned the actual format
+     * @param channelMask to be checked for compatibility. Must be specified
+     * @param updatedChannelMask if non-NULL, it is assigned the actual channel mask
+     * @param flags to be checked for compatibility
+     * @param exactMatchRequiredForInputFlags true if exact match is required on flags
+     * @return true if the profile is compatible, false otherwise.
+     */
+    bool isCompatibleProfile(const DeviceVector &devices,
                              uint32_t samplingRate,
                              uint32_t *updatedSamplingRate,
                              audio_format_t format,
@@ -78,7 +91,7 @@
 
     bool hasSupportedDevices() const { return !mSupportedDevices.isEmpty(); }
 
-    bool supportDevice(audio_devices_t device) const
+    bool supportsDeviceTypes(audio_devices_t device) const
     {
         if (audio_is_output_devices(device)) {
             return mSupportedDevices.types() & device;
@@ -86,41 +99,37 @@
         return mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN);
     }
 
-    bool supportDeviceAddress(const String8 &address) const
+    /**
+     * @brief supportsDevice
+     * @param device to be checked against
+     *        forceCheckOnAddress if true, check on type and address whatever the type, otherwise
+     *        the address enforcement is limited to "offical devices" that distinguishe on address
+     * @return true if the device is supported by type (for non bus / remote submix devices),
+     *         true if the device is supported (both type and address) for bus / remote submix
+     *         false otherwise
+     */
+    bool supportsDevice(const sp<DeviceDescriptor> &device, bool forceCheckOnAddress = false) const
     {
-        return mSupportedDevices[0]->address() == address;
-    }
-
-    // chose first device present in mSupportedDevices also part of deviceType
-    audio_devices_t getSupportedDeviceForType(audio_devices_t deviceType) const
-    {
-        for (size_t k = 0; k  < mSupportedDevices.size(); k++) {
-            audio_devices_t profileType = mSupportedDevices[k]->type();
-            if (profileType & deviceType) {
-                return profileType;
-            }
+        if (!device_distinguishes_on_address(device->type()) && !forceCheckOnAddress) {
+            return supportsDeviceTypes(device->type());
         }
-        return AUDIO_DEVICE_NONE;
+        return mSupportedDevices.contains(device);
     }
 
-    audio_devices_t getSupportedDevicesType() const { return mSupportedDevices.types(); }
-
     void clearSupportedDevices() { mSupportedDevices.clear(); }
     void addSupportedDevice(const sp<DeviceDescriptor> &device)
     {
         mSupportedDevices.add(device);
     }
-
+    void removeSupportedDevice(const sp<DeviceDescriptor> &device)
+    {
+        mSupportedDevices.remove(device);
+    }
     void setSupportedDevices(const DeviceVector &devices)
     {
         mSupportedDevices = devices;
     }
 
-    sp<DeviceDescriptor> getSupportedDeviceByAddress(audio_devices_t type, String8 address) const
-    {
-        return mSupportedDevices.getDevice(type, address);
-    }
-
     const DeviceVector &getSupportedDevices() const { return mSupportedDevices; }
 
     bool canOpenNewIo() {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 0bc88a5..55d4db4 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -21,7 +21,6 @@
 #include <policy.h>
 #include <AudioPolicyInterface.h>
 #include "AudioInputDescriptor.h"
-#include "IOProfile.h"
 #include "AudioGain.h"
 #include "HwModule.h"
 
@@ -55,30 +54,7 @@
 
 audio_source_t AudioInputDescriptor::source() const
 {
-    audio_source_t source = AUDIO_SOURCE_DEFAULT;
-
-    for (bool activeOnly : { true, false }) {
-        int32_t topPriority = -1;
-        app_state_t topState = APP_STATE_IDLE;
-        for (const auto &client : getClientIterable()) {
-            if (activeOnly && !client->active()) {
-                continue;
-            }
-            app_state_t curState = client->appState();
-            if (curState >= topState) {
-                int32_t curPriority = source_priority(client->source());
-                if (curPriority > topPriority) {
-                    source = client->source();
-                    topPriority = curPriority;
-                }
-                topState = curState;
-            }
-        }
-        if (source != AUDIO_SOURCE_DEFAULT) {
-            break;
-        }
-    }
-    return source;
+    return getHighestPriorityAttributes().source;
 }
 
 void AudioInputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
@@ -148,6 +124,34 @@
     return false;
 }
 
+audio_attributes_t AudioInputDescriptor::getHighestPriorityAttributes() const
+{
+    audio_attributes_t attributes = { .source = AUDIO_SOURCE_DEFAULT };
+
+    for (bool activeOnly : { true, false }) {
+        int32_t topPriority = -1;
+        app_state_t topState = APP_STATE_IDLE;
+        for (const auto &client : getClientIterable()) {
+            if (activeOnly && !client->active()) {
+              continue;
+            }
+            app_state_t curState = client->appState();
+            if (curState >= topState) {
+                int32_t curPriority = source_priority(client->source());
+                if (curPriority > topPriority) {
+                    attributes = client->attributes();
+                    topPriority = curPriority;
+                }
+                topState = curState;
+            }
+        }
+        if (attributes.source != AUDIO_SOURCE_DEFAULT) {
+            break;
+        }
+    }
+    return attributes;
+}
+
 bool AudioInputDescriptor::isSoundTrigger() const {
     // sound trigger and non sound trigger clients are not mixed on a given input
     // so check only first client
@@ -180,8 +184,7 @@
 }
 
 status_t AudioInputDescriptor::open(const audio_config_t *config,
-                                       audio_devices_t device,
-                                       const String8& address,
+                                       const sp<DeviceDescriptor> &device,
                                        audio_source_t source,
                                        audio_input_flags_t flags,
                                        audio_io_handle_t *input)
@@ -198,24 +201,26 @@
 
     mDevice = device;
 
-    ALOGV("opening input for device %08x address %s profile %p name %s",
-          mDevice, address.string(), mProfile.get(), mProfile->getName().string());
+    ALOGV("opening input for device %s profile %p name %s",
+          mDevice->toString().c_str(), mProfile.get(), mProfile->getName().string());
+
+    audio_devices_t deviceType = mDevice->type();
 
     status_t status = mClientInterface->openInput(mProfile->getModuleHandle(),
                                                   input,
                                                   &lConfig,
-                                                  &mDevice,
-                                                  address,
+                                                  &deviceType,
+                                                  mDevice->address(),
                                                   source,
                                                   flags);
-    LOG_ALWAYS_FATAL_IF(mDevice != device,
+    LOG_ALWAYS_FATAL_IF(mDevice->type() != deviceType,
                         "%s openInput returned device %08x when given device %08x",
-                        __FUNCTION__, mDevice, device);
+                        __FUNCTION__, mDevice->type(), deviceType);
 
     if (status == NO_ERROR) {
         LOG_ALWAYS_FATAL_IF(*input == AUDIO_IO_HANDLE_NONE,
-                            "%s openInput returned input handle %d for device %08x",
-                            __FUNCTION__, *input, device);
+                            "%s openInput returned input handle %d for device %s",
+                            __FUNCTION__, *input, mDevice->toString().c_str());
         mSamplingRate = lConfig.sample_rate;
         mChannelMask = lConfig.channel_mask;
         mFormat = lConfig.format;
@@ -423,7 +428,7 @@
     dst->appendFormat(" Sampling rate: %d\n", mSamplingRate);
     dst->appendFormat(" Format: %d\n", mFormat);
     dst->appendFormat(" Channels: %08x\n", mChannelMask);
-    dst->appendFormat(" Devices %08x\n", mDevice);
+    dst->appendFormat(" Devices %s\n", mDevice->toString().c_str());
     getEnabledEffects().dump(dst, 1 /*spaces*/, false /*verbose*/);
     dst->append(" AudioRecord Clients:\n");
     ClientMapHandler<RecordClientDescriptor>::dump(dst);
@@ -452,14 +457,13 @@
     return NULL;
 }
 
-uint32_t AudioInputCollection::activeInputsCountOnDevices(audio_devices_t devices) const
+uint32_t AudioInputCollection::activeInputsCountOnDevices(const DeviceVector &devices) const
 {
     uint32_t count = 0;
     for (size_t i = 0; i < size(); i++) {
         const sp<AudioInputDescriptor>  inputDescriptor = valueAt(i);
         if (inputDescriptor->isActive() &&
-                ((devices == AUDIO_DEVICE_IN_DEFAULT) ||
-                 ((inputDescriptor->mDevice & devices & ~AUDIO_DEVICE_BIT_IN) != 0))) {
+                (devices.isEmpty() || devices.contains(inputDescriptor->getDevice()))) {
             count++;
         }
     }
@@ -479,13 +483,6 @@
     return activeInputs;
 }
 
-audio_devices_t AudioInputCollection::getSupportedDevices(audio_io_handle_t handle) const
-{
-    sp<AudioInputDescriptor> inputDesc = valueFor(handle);
-    audio_devices_t devices = inputDesc->mProfile->getSupportedDevicesType();
-    return devices;
-}
-
 sp<AudioInputDescriptor> AudioInputCollection::getInputForClient(audio_port_handle_t portId)
 {
     for (size_t i = 0; i < size(); i++) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 97504ab..643cbd1 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -82,25 +82,10 @@
     return mId;
 }
 
-audio_devices_t AudioOutputDescriptor::device() const
-{
-    return mDevice;
-}
-
-audio_devices_t AudioOutputDescriptor::supportedDevices()
-{
-    return mDevice;
-}
-
 bool AudioOutputDescriptor::sharesHwModuleWith(
         const sp<AudioOutputDescriptor>& outputDesc)
 {
-    if (outputDesc->isDuplicated()) {
-        return sharesHwModuleWith(outputDesc->subOutput1()) ||
-                    sharesHwModuleWith(outputDesc->subOutput2());
-    } else {
-        return hasSameHwModuleAs(outputDesc);
-    }
+    return hasSameHwModuleAs(outputDesc);
 }
 
 void AudioOutputDescriptor::changeStreamActiveCount(const sp<TrackClientDescriptor>& client,
@@ -282,7 +267,7 @@
     dst->appendFormat(" Sampling rate: %d\n", mSamplingRate);
     dst->appendFormat(" Format: %08x\n", mFormat);
     dst->appendFormat(" Channels: %08x\n", mChannelMask);
-    dst->appendFormat(" Devices: %08x\n", device());
+    dst->appendFormat(" Devices: %s\n", devices().toString().c_str());
     dst->appendFormat(" Global active count: %u\n", mGlobalActiveCount);
     dst->append(" Stream volume activeCount muteCount\n");
     for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
@@ -330,17 +315,18 @@
     AudioOutputDescriptor::dump(dst);
 }
 
-audio_devices_t SwAudioOutputDescriptor::device() const
+DeviceVector SwAudioOutputDescriptor::devices() const
 {
     if (isDuplicated()) {
-        return (audio_devices_t)(mOutput1->mDevice | mOutput2->mDevice);
-    } else {
-        return mDevice;
+        DeviceVector devices = mOutput1->devices();
+        devices.merge(mOutput2->devices());
+        return devices;
     }
+    return mDevices;
 }
 
 bool SwAudioOutputDescriptor::sharesHwModuleWith(
-        const sp<AudioOutputDescriptor>& outputDesc)
+        const sp<SwAudioOutputDescriptor>& outputDesc)
 {
     if (isDuplicated()) {
         return mOutput1->sharesHwModuleWith(outputDesc) || mOutput2->sharesHwModuleWith(outputDesc);
@@ -352,13 +338,30 @@
     }
 }
 
-audio_devices_t SwAudioOutputDescriptor::supportedDevices()
+DeviceVector SwAudioOutputDescriptor::supportedDevices() const
 {
     if (isDuplicated()) {
-        return (audio_devices_t)(mOutput1->supportedDevices() | mOutput2->supportedDevices());
-    } else {
-        return mProfile->getSupportedDevicesType();
+        DeviceVector supportedDevices = mOutput1->supportedDevices();
+        supportedDevices.merge(mOutput2->supportedDevices());
+        return supportedDevices;
     }
+    return mProfile->getSupportedDevices();
+}
+
+bool SwAudioOutputDescriptor::supportsDevice(const sp<DeviceDescriptor> &device) const
+{
+    return supportedDevices().contains(device);
+}
+
+bool SwAudioOutputDescriptor::supportsAllDevices(const DeviceVector &devices) const
+{
+    return supportedDevices().containsAllDevices(devices);
+}
+
+DeviceVector SwAudioOutputDescriptor::filterSupportedDevices(const DeviceVector &devices) const
+{
+    DeviceVector filteredDevices = supportedDevices();
+    return filteredDevices.filter(devices);
 }
 
 uint32_t SwAudioOutputDescriptor::latency()
@@ -443,12 +446,15 @@
 }
 
 status_t SwAudioOutputDescriptor::open(const audio_config_t *config,
-                                       audio_devices_t device,
-                                       const String8& address,
+                                       const DeviceVector &devices,
                                        audio_stream_type_t stream,
                                        audio_output_flags_t flags,
                                        audio_io_handle_t *output)
 {
+    mDevices = devices;
+    const String8& address = devices.getFirstValidAddress();
+    audio_devices_t device = devices.types();
+
     audio_config_t lConfig;
     if (config == nullptr) {
         lConfig = AUDIO_CONFIG_INITIALIZER;
@@ -459,7 +465,6 @@
         lConfig = *config;
     }
 
-    mDevice = device;
     // if the selected profile is offloaded and no offload info was specified,
     // create a default one
     if ((mProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
@@ -477,19 +482,19 @@
 
     mFlags = (audio_output_flags_t)(mFlags | flags);
 
-    ALOGV("opening output for device %08x address %s profile %p name %s",
-          mDevice, address.string(), mProfile.get(), mProfile->getName().string());
+    ALOGV("opening output for device %s profile %p name %s",
+          mDevices.toString().c_str(), mProfile.get(), mProfile->getName().string());
 
     status_t status = mClientInterface->openOutput(mProfile->getModuleHandle(),
                                                    output,
                                                    &lConfig,
-                                                   &mDevice,
+                                                   &device,
                                                    address,
                                                    &mLatency,
                                                    mFlags);
-    LOG_ALWAYS_FATAL_IF(mDevice != device,
+    LOG_ALWAYS_FATAL_IF(mDevices.types() != device,
                         "%s openOutput returned device %08x when given device %08x",
-                        __FUNCTION__, mDevice, device);
+                        __FUNCTION__, mDevices.types(), device);
 
     if (status == NO_ERROR) {
         LOG_ALWAYS_FATAL_IF(*output == AUDIO_IO_HANDLE_NONE,
@@ -605,11 +610,6 @@
     mSource->dump(dst, 0, 0);
 }
 
-audio_devices_t HwAudioOutputDescriptor::supportedDevices()
-{
-    return mDevice;
-}
-
 void HwAudioOutputDescriptor::toAudioPortConfig(
                                                  struct audio_port_config *dstConfig,
                                                  const struct audio_port_config *srcConfig) const
@@ -657,7 +657,7 @@
     for (size_t i = 0; i < this->size(); i++) {
         const sp<SwAudioOutputDescriptor> outputDesc = this->valueAt(i);
         if (outputDesc->isStreamActive(stream, inPastMs, sysTime)
-                && ((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) == 0)) {
+                && ((outputDesc->devices().types() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) == 0)) {
             return true;
         }
     }
@@ -670,7 +670,7 @@
     nsecs_t sysTime = systemTime();
     for (size_t i = 0; i < size(); i++) {
         const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
-        if (((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
+        if (((outputDesc->devices().types() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
                 outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
             // do not consider re routing (when the output is going to a dynamic policy)
             // as "remote playback"
@@ -686,7 +686,8 @@
 {
     for (size_t i = 0; i < size(); i++) {
         sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
-        if (!outputDesc->isDuplicated() && outputDesc->device() & AUDIO_DEVICE_OUT_ALL_A2DP) {
+        if (!outputDesc->isDuplicated() &&
+                outputDesc->devices().types() & AUDIO_DEVICE_OUT_ALL_A2DP) {
             return this->keyAt(i);
         }
     }
@@ -700,10 +701,9 @@
     if ((primaryOutput != NULL) && (primaryOutput->mProfile != NULL)
         && (primaryOutput->mProfile->getModule() != NULL)) {
         sp<HwModule> primaryHwModule = primaryOutput->mProfile->getModule();
-        Vector <sp<IOProfile>> primaryHwModuleOutputProfiles =
-                                   primaryHwModule->getOutputProfiles();
-        for (size_t i = 0; i < primaryHwModuleOutputProfiles.size(); i++) {
-            if (primaryHwModuleOutputProfiles[i]->supportDevice(AUDIO_DEVICE_OUT_ALL_A2DP)) {
+
+        for (const auto &outputProfile : primaryHwModule->getOutputProfiles()) {
+            if (outputProfile->supportsDeviceTypes(AUDIO_DEVICE_OUT_ALL_A2DP)) {
                 return true;
             }
         }
@@ -754,13 +754,6 @@
     return false;
 }
 
-audio_devices_t SwAudioOutputCollection::getSupportedDevices(audio_io_handle_t handle) const
-{
-    sp<SwAudioOutputDescriptor> outputDesc = valueFor(handle);
-    audio_devices_t devices = outputDesc->mProfile->getSupportedDevicesType();
-    return devices;
-}
-
 sp<SwAudioOutputDescriptor> SwAudioOutputCollection::getOutputForClient(audio_port_handle_t portId)
 {
     for (size_t i = 0; i < size(); i++) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 3cf8014..d18091c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -280,13 +280,11 @@
     return BAD_VALUE;
 }
 
-audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_source_t inputSource,
-                                                                        audio_devices_t availDevices,
-                                                                        AudioMix **policyMix)
+sp<DeviceDescriptor> AudioPolicyMixCollection::getDeviceAndMixForInputSource(
+        audio_source_t inputSource, const DeviceVector &availDevices, AudioMix **policyMix)
 {
     for (size_t i = 0; i < size(); i++) {
         AudioMix *mix = valueAt(i)->getMix();
-
         if (mix->mMixType != MIX_TYPE_RECORDERS) {
             continue;
         }
@@ -295,17 +293,21 @@
                     mix->mCriteria[j].mValue.mSource == inputSource) ||
                (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule &&
                     mix->mCriteria[j].mValue.mSource != inputSource)) {
-                if (availDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+                // assuming PolicyMix only for remote submix for input
+                // so mix->mDeviceType can only be AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+                audio_devices_t device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+                auto mixDevice = availDevices.getDevice(device, mix->mDeviceAddress);
+                if (mixDevice != nullptr) {
                     if (policyMix != NULL) {
                         *policyMix = mix;
                     }
-                    return AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+                    return mixDevice;
                 }
                 break;
             }
         }
     }
-    return AUDIO_DEVICE_NONE;
+    return nullptr;
 }
 
 status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix)
@@ -340,6 +342,89 @@
     return NO_ERROR;
 }
 
+status_t AudioPolicyMixCollection::setUidDeviceAffinities(uid_t uid,
+        const Vector<AudioDeviceTypeAddr>& devices) {
+    // remove existing rules for this uid
+    removeUidDeviceAffinities(uid);
+
+    // 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();
+        if (mix->mMixType != MIX_TYPE_PLAYERS) {
+            continue;
+        }
+        // check if this mix goes to a device in the list of devices
+        bool deviceMatch = false;
+        for (size_t j = 0; j < devices.size(); j++) {
+            if (devices[j].mType == mix->mDeviceType
+                    && devices[j].mAddress == mix->mDeviceAddress) {
+                deviceMatch = true;
+                break;
+            }
+        }
+        if (deviceMatch) {
+            mix->setMatchUid(uid);
+        } else {
+            // this mix doesn't go to one of the listed devices for the given uid,
+            // modify its rules to exclude the uid
+            mix->setExcludeUid(uid);
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t AudioPolicyMixCollection::removeUidDeviceAffinities(uid_t uid) {
+    // for each player mix: remove existing rules that match or exclude this uid
+    for (size_t i = 0; i < size(); i++) {
+        bool foundUidRule = false;
+        AudioMix *mix = valueAt(i)->getMix();
+        if (mix->mMixType != MIX_TYPE_PLAYERS) {
+            continue;
+        }
+        std::vector<size_t> criteriaToRemove;
+        for (size_t j = 0; j < mix->mCriteria.size(); j++) {
+            const uint32_t rule = mix->mCriteria[j].mRule;
+            // is this rule affecting the uid?
+            if ((rule == RULE_EXCLUDE_UID || rule == RULE_MATCH_UID)
+                    && uid == mix->mCriteria[j].mValue.mUid) {
+                foundUidRule = true;
+                criteriaToRemove.push_back(j);
+            }
+        }
+        if (foundUidRule) {
+            for (size_t j = criteriaToRemove.size() - 1; j >= 0; j--) {
+                mix->mCriteria.removeAt(criteriaToRemove[j]);
+            }
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t AudioPolicyMixCollection::getDevicesForUid(uid_t uid,
+        Vector<AudioDeviceTypeAddr>& devices) const {
+    // 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;
+        AudioMix *mix = valueAt(i)->getMix();
+        if (mix->mMixType != MIX_TYPE_PLAYERS) {
+            continue;
+        }
+        for (size_t j = 0; j < mix->mCriteria.size(); j++) {
+            const uint32_t rule = mix->mCriteria[j].mRule;
+            if (rule == RULE_EXCLUDE_UID
+                    && uid == mix->mCriteria[j].mValue.mUid) {
+                ruleAllowsUid = false;
+                break;
+            }
+        }
+        if (ruleAllowsUid) {
+            devices.add(AudioDeviceTypeAddr(mix->mDeviceType, mix->mDeviceAddress));
+        }
+    }
+    return NO_ERROR;
+}
+
 void AudioPolicyMixCollection::dump(String8 *dst) const
 {
     dst->append("\nAudio Policy Mix:\n");
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 19dde6a..9fcf5e7 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -31,9 +31,15 @@
 // --- AudioPort class implementation
 void AudioPort::attach(const sp<HwModule>& module)
 {
+    ALOGV("%s: attaching module %s to port %s", __FUNCTION__, getModuleName(), mName.string());
     mModule = module;
 }
 
+void AudioPort::detach()
+{
+    mModule = nullptr;
+}
+
 // Note that is a different namespace than AudioFlinger unique IDs
 audio_port_handle_t AudioPort::getNextUniqueId()
 {
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 04cbcd1..01111c5 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -58,6 +58,12 @@
     mId = getNextUniqueId();
 }
 
+void DeviceDescriptor::detach()
+{
+    mId = AUDIO_PORT_HANDLE_NONE;
+    AudioPort::detach();
+}
+
 bool DeviceDescriptor::equals(const sp<DeviceDescriptor>& other) const
 {
     // Devices are considered equal if they:
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 80af88d..7d2d094 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -52,6 +52,9 @@
 
     sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
     devDesc->setAddress(address);
+    addDynamicDevice(devDesc);
+    // Reciprocally attach the device to the module
+    devDesc->attach(this);
     profile->addSupportedDevice(devDesc);
 
     return addOutputProfile(profile);
@@ -97,6 +100,9 @@
 {
     for (size_t i = 0; i < mOutputProfiles.size(); i++) {
         if (mOutputProfiles[i]->getName() == name) {
+            for (const auto &device : mOutputProfiles[i]->getSupportedDevices()) {
+                removeDynamicDevice(device);
+            }
             mOutputProfiles.removeAt(i);
             break;
         }
@@ -114,6 +120,9 @@
 
     sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
     devDesc->setAddress(address);
+    addDynamicDevice(devDesc);
+    // Reciprocally attach the device to the module
+    devDesc->attach(this);
     profile->addSupportedDevice(devDesc);
 
     ALOGV("addInputProfile() name %s rate %d mask 0x%08x",
@@ -126,6 +135,9 @@
 {
     for (size_t i = 0; i < mInputProfiles.size(); i++) {
         if (mInputProfiles[i]->getName() == name) {
+            for (const auto &device : mInputProfiles[i]->getSupportedDevices()) {
+                removeDynamicDevice(device);
+            }
             mInputProfiles.removeAt(i);
             break;
         }
@@ -247,6 +259,7 @@
         }
     }
     mDeclaredDevices.dump(dst, String8("Declared"), 2, true);
+    mDynamicDevices.dump(dst, String8("Dynamic"),  2, true);
     mRoutes.dump(dst, 2);
 }
 
@@ -260,13 +273,13 @@
     return nullptr;
 }
 
-sp <HwModule> HwModuleCollection::getModuleForDevice(audio_devices_t device) const
+sp <HwModule> HwModuleCollection::getModuleForDeviceTypes(audio_devices_t device) const
 {
     for (const auto& module : *this) {
         const auto& profiles = audio_is_output_device(device) ?
                 module->getOutputProfiles() : module->getInputProfiles();
         for (const auto& profile : profiles) {
-            if (profile->supportDevice(device)) {
+            if (profile->supportsDeviceTypes(device)) {
                 return module;
             }
         }
@@ -274,30 +287,127 @@
     return nullptr;
 }
 
-sp<DeviceDescriptor> HwModuleCollection::getDeviceDescriptor(const audio_devices_t device,
-                                                             const char *device_address,
-                                                             const char *device_name,
+sp <HwModule> HwModuleCollection::getModuleForDevice(const sp<DeviceDescriptor> &device) const
+{
+    for (const auto& module : *this) {
+        const auto& profiles = audio_is_output_device(device->type()) ?
+                module->getOutputProfiles() : module->getInputProfiles();
+        for (const auto& profile : profiles) {
+            if (profile->supportsDevice(device)) {
+                return module;
+            }
+        }
+    }
+    return nullptr;
+}
+
+DeviceVector HwModuleCollection::getAvailableDevicesFromModuleName(
+        const char *name, const DeviceVector &availableDevices) const
+{
+    sp<HwModule> module = getModuleFromName(name);
+    if (module == nullptr) {
+        return DeviceVector();
+    }
+    return availableDevices.getDevicesFromHwModule(module->getHandle());
+}
+
+sp<DeviceDescriptor> HwModuleCollection::getDeviceDescriptor(const audio_devices_t deviceType,
+                                                             const char *address,
+                                                             const char *name,
+                                                             bool allowToCreate,
                                                              bool matchAddress) const
 {
-    String8 address = (device_address == nullptr || !matchAddress) ?
-            String8("") : String8(device_address);
+    String8 devAddress = (address == nullptr || !matchAddress) ? String8("") : String8(address);
     // handle legacy remote submix case where the address was not always specified
-    if (device_distinguishes_on_address(device) && (address.length() == 0)) {
-        address = String8("0");
+    if (device_distinguishes_on_address(deviceType) && (devAddress.length() == 0)) {
+        devAddress = String8("0");
     }
 
     for (const auto& hwModule : *this) {
-        DeviceVector declaredDevices = hwModule->getDeclaredDevices();
-        sp<DeviceDescriptor> deviceDesc = declaredDevices.getDevice(device, address);
-        if (deviceDesc) {
-            return deviceDesc;
+        DeviceVector moduleDevices = hwModule->getAllDevices();
+        auto moduleDevice = moduleDevices.getDevice(deviceType, devAddress);
+        if (moduleDevice) {
+            if (allowToCreate) {
+                moduleDevice->attach(hwModule);
+            }
+            return moduleDevice;
         }
     }
+    if (!allowToCreate) {
+        ALOGE("%s: could not find HW module for device %s %04x address %s", __FUNCTION__,
+              name, deviceType, address);
+        return nullptr;
+    }
+    return createDevice(deviceType, address, name);
+}
 
-    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
-    devDesc->setName(String8(device_name));
-    devDesc->setAddress(address);
-    return devDesc;
+sp<DeviceDescriptor> HwModuleCollection::createDevice(const audio_devices_t type,
+                                                      const char *address,
+                                                      const char *name) const
+{
+    sp<HwModule> hwModule = getModuleForDeviceTypes(type);
+    if (hwModule == 0) {
+        ALOGE("%s: could not find HW module for device %04x address %s", __FUNCTION__, type,
+              address);
+        return nullptr;
+    }
+    sp<DeviceDescriptor> device = new DeviceDescriptor(type, String8(name));
+    device->setName(String8(name));
+    device->setAddress(String8(address));
+
+    // Add the device to the list of dynamic devices
+    hwModule->addDynamicDevice(device);
+    // Reciprocally attach the device to the module
+    device->attach(hwModule);
+    ALOGD("%s: adding dynamic device %s to module %s", __FUNCTION__,
+          device->toString().c_str(), hwModule->getName());
+
+    const auto &profiles = (audio_is_output_device(type) ? hwModule->getOutputProfiles() :
+                                                             hwModule->getInputProfiles());
+    for (const auto &profile : profiles) {
+        // Add the device as supported to all profile supporting "weakly" or not the device
+        // according to its type
+        if (profile->supportsDevice(device, false /*matchAdress*/)) {
+
+            // @todo quid of audio profile? import the profile from device of the same type?
+            const auto &isoTypeDeviceForProfile = profile->getSupportedDevices().getDevice(type);
+            device->importAudioPort(isoTypeDeviceForProfile, true /* force */);
+
+            ALOGV("%s: adding device %s to profile %s", __FUNCTION__,
+                  device->toString().c_str(), profile->getTagName().c_str());
+            profile->addSupportedDevice(device);
+        }
+    }
+    return device;
+}
+
+void HwModuleCollection::cleanUpForDevice(const sp<DeviceDescriptor> &device)
+{
+    for (const auto& hwModule : *this) {
+        DeviceVector moduleDevices = hwModule->getAllDevices();
+        if (!moduleDevices.contains(device)) {
+            continue;
+        }
+        device->detach();
+        // Only remove from dynamic list, not from declared list!!!
+        if (!hwModule->getDynamicDevices().contains(device)) {
+            return;
+        }
+        hwModule->removeDynamicDevice(device);
+        ALOGV("%s: removed dynamic device %s from module %s", __FUNCTION__,
+              device->toString().c_str(), hwModule->getName());
+
+        const IOProfileCollection &profiles = audio_is_output_device(device->type()) ?
+                    hwModule->getOutputProfiles() : hwModule->getInputProfiles();
+        for (const auto &profile : profiles) {
+            // For cleanup, strong match is required
+            if (profile->supportsDevice(device, true /*matchAdress*/)) {
+                ALOGV("%s: removing device %s from profile %s", __FUNCTION__,
+                      device->toString().c_str(), profile->getTagName().c_str());
+                profile->removeSupportedDevice(device);
+            }
+        }
+    }
 }
 
 void HwModuleCollection::dump(String8 *dst) const
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index 3788244..fe2eaee 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -25,11 +25,7 @@
 
 namespace android {
 
-// checks if the IO profile is compatible with specified parameters.
-// Sampling rate, format and channel mask must be specified in order to
-// get a valid a match
-bool IOProfile::isCompatibleProfile(audio_devices_t device,
-                                    const String8& address,
+bool IOProfile::isCompatibleProfile(const DeviceVector &devices,
                                     uint32_t samplingRate,
                                     uint32_t *updatedSamplingRate,
                                     audio_format_t format,
@@ -46,14 +42,8 @@
             getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SINK;
     ALOG_ASSERT(isPlaybackThread != isRecordThread);
 
-
-    if (device != AUDIO_DEVICE_NONE) {
-        // just check types if multiple devices are selected
-        if (popcount(device & ~AUDIO_DEVICE_BIT_IN) > 1) {
-            if ((mSupportedDevices.types() & device) != device) {
-                return false;
-            }
-        } else if (mSupportedDevices.getDevice(device, address) == 0) {
+    if (!devices.isEmpty()) {
+        if (!mSupportedDevices.containsAllDevices(devices)) {
             return false;
         }
     }
diff --git a/services/audiopolicy/engineconfigurable/include/AudioPolicyEngineInstance.h b/services/audiopolicy/engineconfigurable/include/AudioPolicyEngineInstance.h
index a597e87..efc69da 100644
--- a/services/audiopolicy/engineconfigurable/include/AudioPolicyEngineInstance.h
+++ b/services/audiopolicy/engineconfigurable/include/AudioPolicyEngineInstance.h
@@ -19,10 +19,8 @@
 class AudioPolicyManagerInterface;
 class AudioPolicyPluginInterface;
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
 
 class Engine;
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
index baaefd2..7631976 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
@@ -7,15 +7,19 @@
 #
 ################################################################################################
 
-ifeq (1, 0)
-
 LOCAL_PATH := $(call my-dir)
 
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), 1)
+
 PFW_CORE := external/parameter-framework
-BUILD_PFW_SETTINGS := $(PFW_CORE)/support/android/build_pfw_settings.mk
+#@TODO: upstream new domain generator
+#BUILD_PFW_SETTINGS := $(PFW_CORE)/support/android/build_pfw_settings.mk
 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
 ##################################################################
@@ -25,7 +29,8 @@
 LOCAL_MODULE := ParameterFrameworkConfigurationPolicy.xml
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/parameter-framework
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/parameter-framework
 LOCAL_SRC_FILES := $(LOCAL_MODULE).in
 
 AUDIO_PATTERN = @TUNING_ALLOWED@
@@ -46,7 +51,8 @@
 LOCAL_MODULE := PolicyClass.xml
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/parameter-framework/Structure/Policy
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/Structure/Policy
 LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
 
@@ -54,12 +60,12 @@
 LOCAL_MODULE := PolicySubsystem.xml
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
 LOCAL_REQUIRED_MODULES := \
     PolicySubsystem-CommonTypes.xml \
-    PolicySubsystem-Volume.xml \
-    libpolicy-subsystem \
+    libpolicy-subsystem
 
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/parameter-framework/Structure/Policy
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/Structure/Policy
 LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
 
@@ -67,7 +73,8 @@
 LOCAL_MODULE := PolicySubsystem-CommonTypes.xml
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/parameter-framework/Structure/Policy
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/Structure/Policy
 LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
 
@@ -76,15 +83,16 @@
 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
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-        PolicyClass.xml \
-        PolicySubsystem.xml \
-        ParameterFrameworkConfigurationPolicy.xml
+LOCAL_REQUIRED_MODULES := \
+    policy_criteria.xml \
+    policy_criterion_types.xml \
+    PolicySubsystem.xml \
+    PolicyClass.xml \
+    ParameterFrameworkConfigurationPolicy.xml
 
 ifeq ($(pfw_rebuild_settings),true)
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_CRITERIA_FILE := $(LOCAL_PATH)/policy_criteria.txt
 PFW_EDD_FILES := \
         $(LOCAL_PATH)/Settings/device_for_strategy_media.pfw \
         $(LOCAL_PATH)/Settings/device_for_strategy_phone.pfw \
@@ -100,6 +108,17 @@
         $(LOCAL_PATH)/Settings/device_for_input_source.pfw \
         $(LOCAL_PATH)/Settings/volumes.pfw
 
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+    $(PFW_EDD_FILES)
+
+
+PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/policy_criterion_types.xml
+PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/policy_criteria.xml
+
+PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
+
+PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
+
 include $(BUILD_PFW_SETTINGS)
 else
 # Use the existing file
@@ -107,19 +126,27 @@
 include $(BUILD_PREBUILT)
 endif # pfw_rebuild_settings
 
+endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), 0)
+
 ######### Policy PFW Settings - No Output #########
+ifeq (0, 1)
+
 include $(CLEAR_VARS)
 LOCAL_MODULE := parameter-framework.policy.no-output
 LOCAL_MODULE_STEM := PolicyConfigurableDomains-NoOutputDevice.xml
 LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-        PolicyClass.xml \
-        PolicySubsystem.xml \
-        ParameterFrameworkConfigurationPolicy.xml
+LOCAL_REQUIRED_MODULES := \
+    policy_criteria.xml \
+    policy_criterion_types.xml \
+    PolicySubsystem.xml \
+    PolicyClass.xml \
+    ParameterFrameworkConfigurationPolicy.xml
 
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_CRITERIA_FILE := $(LOCAL_PATH)/policy_criteria.txt
+PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
+PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/policy_criterion_types.xml
+PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/policy_criteria.xml
 PFW_EDD_FILES := \
         $(LOCAL_PATH)/SettingsNoOutput/device_for_strategies.pfw \
         $(LOCAL_PATH)/Settings/strategy_for_stream.pfw \
@@ -128,20 +155,26 @@
         $(LOCAL_PATH)/Settings/volumes.pfw
 
 include $(BUILD_PFW_SETTINGS)
-
+endif # ifeq (0, 1)
 ######### Policy PFW Settings - No Input #########
+ifeq (0, 1)
+
 include $(CLEAR_VARS)
 LOCAL_MODULE := parameter-framework.policy.no-input
 LOCAL_MODULE_STEM := PolicyConfigurableDomains-NoInputDevice.xml
 LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-        PolicyClass.xml \
-        PolicySubsystem.xml \
-        ParameterFrameworkConfigurationPolicy.xml
+LOCAL_REQUIRED_MODULES := \
+    policy_criteria.xml \
+    policy_criterion_types.xml \
+    PolicySubsystem.xml \
+    PolicyClass.xml \
+    ParameterFrameworkConfigurationPolicy.xml
 
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_CRITERIA_FILE := $(LOCAL_PATH)/policy_criteria.txt
+PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
+PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/policy_criterion_types.xml
+PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/policy_criteria.xml
 PFW_EDD_FILES := \
         $(LOCAL_PATH)/Settings/device_for_strategy_media.pfw \
         $(LOCAL_PATH)/Settings/device_for_strategy_phone.pfw \
@@ -160,3 +193,9 @@
 include $(BUILD_PFW_SETTINGS)
 
 endif # ifeq (1, 0)
+
+#######################################################################
+# Recursive call sub-folder Android.mk
+#######################################################################
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in
index f5615cd..f80a07f 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <ParameterFrameworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    SystemClassName="Policy" ServerPort="5019" TuningAllowed="@TUNING_ALLOWED@">
+    SystemClassName="Policy" ServerPort="/dev/socket/audioserver/policy_debug"
+    TuningAllowed="@TUNING_ALLOWED@">
 
     <SubsystemPlugins>
         <Location Folder="">
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/PolicyConfigurableDomains.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/PolicyConfigurableDomains.xml
index b43f83b..0710441 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/PolicyConfigurableDomains.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/PolicyConfigurableDomains.xml
@@ -8472,7 +8472,7 @@
     <Configurations>
       <Configuration Name="Sonification">
         <CompoundRule Type="All">
-          <SelectionCriterionRule SelectionCriterion="TelephonyMode" MatchesWhen="Is" Value="RingTone"/>
+          <SelectionCriterionRule SelectionCriterion="TelephonyMode" MatchesWhen="Is" Value="Ringtone"/>
         </CompoundRule>
       </Configuration>
       <Configuration Name="Phone">
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/strategy_for_usage.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/strategy_for_usage.pfw
index b3115e7..fbea9e2 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/strategy_for_usage.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/strategy_for_usage.pfw
@@ -24,7 +24,7 @@
 			# In case of Ring or Alarm stream type active, switching to sonification
 			# @todo: handle this dynamic case. As a WA, using Ringtone mode...
 			#
-			TelephonyMode Is RingTone
+			TelephonyMode Is Ringtone
 
 			/Policy/policy/usages/assistance_accessibility/applicable_strategy/strategy = sonification
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/device_for_strategies.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/device_for_strategies.pfw
index 917d4a7..f923610 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/device_for_strategies.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/device_for_strategies.pfw
@@ -9,7 +9,7 @@
 				bluetooth_sco = 0
 				bluetooth_sco_headset = 0
 				bluetooth_sco_carkit = 0
-				bluetooth_a2dp = 0>
+				bluetooth_a2dp = 0
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
@@ -37,7 +37,7 @@
 				bluetooth_sco = 0
 				bluetooth_sco_headset = 0
 				bluetooth_sco_carkit = 0
-				bluetooth_a2dp = 0>
+				bluetooth_a2dp = 0
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
@@ -65,7 +65,7 @@
 				bluetooth_sco = 0
 				bluetooth_sco_headset = 0
 				bluetooth_sco_carkit = 0
-				bluetooth_a2dp = 0>
+				bluetooth_a2dp = 0
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
@@ -93,7 +93,7 @@
 				bluetooth_sco = 0
 				bluetooth_sco_headset = 0
 				bluetooth_sco_carkit = 0
-				bluetooth_a2dp = 0>
+				bluetooth_a2dp = 0
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
@@ -121,7 +121,7 @@
 				bluetooth_sco = 0
 				bluetooth_sco_headset = 0
 				bluetooth_sco_carkit = 0
-				bluetooth_a2dp = 0>
+				bluetooth_a2dp = 0
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
@@ -149,7 +149,7 @@
 				bluetooth_sco = 0
 				bluetooth_sco_headset = 0
 				bluetooth_sco_carkit = 0
-				bluetooth_a2dp = 0>
+				bluetooth_a2dp = 0
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
@@ -177,7 +177,7 @@
 				bluetooth_sco = 0
 				bluetooth_sco_headset = 0
 				bluetooth_sco_carkit = 0
-				bluetooth_a2dp = 0>
+				bluetooth_a2dp = 0
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
@@ -205,7 +205,7 @@
 				bluetooth_sco = 0
 				bluetooth_sco_headset = 0
 				bluetooth_sco_carkit = 0
-				bluetooth_a2dp = 0>
+				bluetooth_a2dp = 0
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
@@ -233,7 +233,7 @@
 				bluetooth_sco = 0
 				bluetooth_sco_headset = 0
 				bluetooth_sco_carkit = 0
-				bluetooth_a2dp = 0>
+				bluetooth_a2dp = 0
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem-CommonTypes.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem-CommonTypes.xml
index 461e44a..daa7f68 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem-CommonTypes.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem-CommonTypes.xml
@@ -37,6 +37,10 @@
             <BitParameter Name="speaker_safe" Size="1" Pos="22"/>
             <BitParameter Name="ip" Size="1" Pos="23"/>
             <BitParameter Name="bus" Size="1" Pos="24"/>
+            <BitParameter Name="proxy" Size="1" Pos="25"/>
+            <BitParameter Name="usb_headset" Size="1" Pos="26"/>
+            <BitParameter Name="hearing_aid" Size="1" Pos="27"/>
+            <BitParameter Name="echo_canceller" Size="1" Pos="28"/>
             <BitParameter Name="stub" Size="1" Pos="30"/>
         </BitParameterBlock>
     </ComponentType>
@@ -67,6 +71,9 @@
             <BitParameter Name="loopback" Size="1" Pos="18"/>
             <BitParameter Name="ip" Size="1" Pos="19"/>
             <BitParameter Name="bus" Size="1" Pos="20"/>
+            <BitParameter Name="proxy" Size="1" Pos="21"/>
+            <BitParameter Name="usb_headset" Size="1" Pos="22"/>
+            <BitParameter Name="bluetooth_ble" Size="1" Pos="23"/>
             <BitParameter Name="stub" Size="1" Pos="30"/>
         </BitParameterBlock>
     </ComponentType>
@@ -144,7 +151,7 @@
 
     <!--#################### STRATEGY COMMON TYPES BEGIN ####################-->
 
-    <ComponentType Name="StrategyConfig" Mapping="Strategy:'%1'">
+    <ComponentType Name="StrategyConfig" Mapping="Strategy">
         <Component Name="selected_output_devices" Type="OutputDevicesMask"/>
     </ComponentType>
 
@@ -170,7 +177,7 @@
         </EnumParameter>
     </ComponentType>
 
-    <ComponentType Name="Stream">
+    <ComponentType Name="Stream"  Mapping="Stream">
         <Component Name="applicable_strategy" Type="Strategy"/>
         <Component Name="applicable_volume_profile" Type="VolumeProfileType"
                    Description="Volume profile followed by a given stream type."/>
@@ -181,7 +188,7 @@
     <!--#################### USAGE COMMON TYPES BEGIN ####################-->
 
     <ComponentType Name="Usage">
-        <Component Name="applicable_strategy" Type="Strategy" Mapping="Usage:'%1'"/>
+        <Component Name="applicable_strategy" Type="Strategy" Mapping="Usage"/>
     </ComponentType>
 
     <!--#################### USAGE COMMON TYPES END ####################-->
@@ -190,7 +197,7 @@
 
     <ComponentType Name="InputSource">
         <Component Name="applicable_input_device" Type="InputDevicesMask"
-                   Mapping="InputSource:'%1'" Description="Selected Input device"/>
+                   Mapping="InputSource" Description="Selected Input device"/>
     </ComponentType>
 
     <!--#################### INPUT SOURCE COMMON TYPES END ####################-->
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem.xml
index ad9c356..45d1e8a 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem.xml
@@ -13,54 +13,40 @@
 
         <!--#################### STRATEGY BEGIN ####################-->
 
-        <ComponentType Name="Strategies" Description="Identifier must match the enum value to make
-                             the link between the PolicyManager and PFW">
-            <Component Name="media" Type="StrategyConfig" Mapping="Amend1:Media,Identifier:0"/>
-            <Component Name="phone" Type="StrategyConfig" Mapping="Amend1:Phone,Identifier:1"/>
-            <Component Name="sonification" Type="StrategyConfig"
-                                           Mapping="Amend1:Sonification,Identifier:2"/>
-            <Component Name="sonification_respectful" Type="StrategyConfig"
-                       Mapping="Amend1:SonificationRespectful,Identifier:3"/>
-            <Component Name="dtmf" Type="StrategyConfig" Mapping="Amend1:Dtmf,Identifier:4"/>
-            <Component Name="enforced_audible" Type="StrategyConfig"
-                                               Mapping="Amend1:EnforcedAudible,Identifier:5"/>
-            <Component Name="transmitted_through_speaker" Type="StrategyConfig"
-                       Mapping="Amend1:TransmittedThroughSpeaker,Identifier:6"/>
-            <Component Name="accessibility" Type="StrategyConfig"
-                                            Mapping="Amend1:Accessibility,Identifier:7"/>
-            <Component Name="rerouting" Type="StrategyConfig"
-                                        Mapping="Amend1:Rerouting,Identifier:8"/>
+        <ComponentType Name="Strategies">
+            <Component Name="media" Type="StrategyConfig" Mapping="Name:STRATEGY_MEDIA"/>
+            <Component Name="phone" Type="StrategyConfig" Mapping="Name:STRATEGY_PHONE"/>
+            <Component Name="sonification" Type="StrategyConfig" Mapping="Name:STRATEGY_SONIFICATION"/>
+            <Component Name="sonification_respectful" Type="StrategyConfig" Mapping="Name:STRATEGY_SONIFICATION_RESPECTFUL"/>
+            <Component Name="dtmf" Type="StrategyConfig" Mapping="Name:STRATEGY_DTMF"/>
+            <Component Name="enforced_audible" Type="StrategyConfig" Mapping="Name:STRATEGY_ENFORCED_AUDIBLE"/>
+            <Component Name="transmitted_through_speaker" Type="StrategyConfig" Mapping="Name:STRATEGY_TRANSMITTED_THROUGH_SPEAKER"/>
+            <Component Name="accessibility" Type="StrategyConfig" Mapping="Name:STRATEGY_ACCESSIBILITY"/>
+            <Component Name="rerouting" Type="StrategyConfig" Mapping=",Name:STRATEGY_REROUTING"/>
         </ComponentType>
 
         <!--#################### STRATEGY END ####################-->
 
         <!--#################### STREAM BEGIN ####################-->
 
-        <ComponentType Name="Streams" Description="associated to audio_stream_type_t definition,
-                             identifier mapping must match the value of the enum">
-            <Component Name="voice_call" Type="Stream" Mapping="Stream:VoiceCall,Identifier:0"/>
-            <Component Name="system" Type="Stream" Mapping="Stream:System,Identifier:1"/>
-            <Component Name="ring" Type="Stream" Mapping="Stream:Ring,Identifier:2"/>
-            <Component Name="music" Type="Stream" Mapping="Stream:Music,Identifier:3"/>
-            <Component Name="alarm" Type="Stream" Mapping="Stream:Alarm,Identifier:4"/>
-            <Component Name="notification" Type="Stream"
-                                           Mapping="Stream:Notification,Identifier:5"/>
-            <Component Name="bluetooth_sco" Type="Stream"
-                                            Mapping="Stream:BluetoothSco,Identifier:6"/>
-            <Component Name="enforced_audible" Type="Stream"
-                                               Mapping="Stream:EnforceAudible,Identifier:7"
-                       Description="Sounds that cannot be muted by user and must
-                                    be routed to speaker"/>
-            <Component Name="dtmf" Type="Stream" Mapping="Stream:Dtmf,Identifier:8"/>
-            <Component Name="tts" Type="Stream" Mapping="Stream:Tts,Identifier:9"
-                             Description="Transmitted Through Speaker.
-                                          Plays over speaker only, silent on other devices"/>
-            <Component Name="accessibility" Type="Stream"
-                                            Mapping="Stream:Accessibility,Identifier:10"
+        <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="Stream:Rerouting,Identifier:11"
+            <Component Name="rerouting" Type="Stream" Mapping="Name:AUDIO_STREAM_REROUTING"
                              Description="For dynamic policy output mixes"/>
-            <Component Name="patch" Type="Stream" Mapping="Stream:Patch,Identifier:12"
+            <Component Name="patch" Type="Stream" Mapping="Name:AUDIO_STREAM_PATCH"
                              Description="For internal audio flinger tracks. Fixed volume"/>
         </ComponentType>
 
@@ -68,36 +54,34 @@
 
         <!--#################### USAGE BEGIN ####################-->
 
-        <ComponentType Name="Usages" Description="associated to audio_usage_t definition,
-                             identifier mapping must match the value of the enum">
-            <Component Name="unknown" Type="Usage" Mapping="Amend1:Unknown,Identifier:0"/>
-            <Component Name="media" Type="Usage" Mapping="Amend1:Media,Identifier:1"/>
+        <ComponentType Name="Usages" Description="associated to audio_usage_t definition">
+            <Component Name="unknown" Type="Usage" Mapping="Name:AUDIO_USAGE_UNKNOWN"/>
+            <Component Name="media" Type="Usage" Mapping="Name:AUDIO_USAGE_MEDIA"/>
             <Component Name="voice_communication" Type="Usage"
-                                                  Mapping="Amend1:VoiceCommunication,Identifier:2"/>
+                       Mapping="Name:AUDIO_USAGE_VOICE_COMMUNICATION"/>
             <Component Name="voice_communication_signalling" Type="Usage"
-                       Mapping="Amend1:VoiceCommunicationSignalling,Identifier:3"/>
-            <Component Name="alarm" Type="Usage" Mapping="Amend1:Alarm,Identifier:4"/>
-            <Component Name="notification" Type="Usage" Mapping="Amend1:Notification,Identifier:5"/>
+                       Mapping="Name:AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING"/>
+            <Component Name="alarm" Type="Usage" Mapping="Name:AUDIO_USAGE_ALARM"/>
+            <Component Name="notification" Type="Usage" Mapping="Name:AUDIO_USAGE_NOTIFICATION"/>
             <Component Name="notification_telephony_ringtone" Type="Usage"
-                       Mapping="Amend1:NotificationTelephonyRingtone,Identifier:6"/>
+                       Mapping="Name:AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE"/>
             <Component Name="notification_communication_request" Type="Usage"
-                       Mapping="Amend1:NotificationCommunicationRequest,Identifier:7"/>
+                       Mapping="Name:AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/>
             <Component Name="notification_communication_instant" Type="Usage"
-                       Mapping="Amend1:NotificationCommunicationInstant,Identifier:8"/>
+                       Mapping="Name:AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/>
             <Component Name="notification_communication_delayed" Type="Usage"
-                       Mapping="Amend1:NotificationCommunicationDelated,Identifier:9"/>
+                       Mapping="Name:AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED"/>
             <Component Name="notification_event" Type="Usage"
-                                                 Mapping="Amend1:NotificationEvent,Identifier:10"/>
+                       Mapping="Name:AUDIO_USAGE_NOTIFICATION_EVENT"/>
             <Component Name="assistance_accessibility" Type="Usage"
-                       Mapping="Amend1:AssistanceAccessibility,Identifier:11"/>
+                       Mapping="Name:AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY"/>
             <Component Name="assistance_navigation_guidance" Type="Usage"
-                       Mapping="Amend1:AssistanceNavigationGuidance,Identifier:12"/>
+                       Mapping="Name:AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
             <Component Name="assistance_sonification" Type="Usage"
-                       Mapping="Amend1:AssistanceSonification,Identifier:13"/>
-            <Component Name="game" Type="Usage" Mapping="Amend1:BluetoothSco,Identifier:14"/>
-            <Component Name="virtual_source" Type="Usage"
-                                             Mapping="Amend1:VirtualSource,Identifier:15"/>
-            <Component Name="assistant" Type="Usage" Mapping="Amend1:Assistant,Identifier:16"/>
+                       Mapping="Name:AUDIO_USAGE_ASSISTANCE_SONIFICATION"/>
+            <Component Name="game" Type="Usage" Mapping="Name:AUDIO_USAGE_GAME"/>
+            <Component Name="virtual_source" Type="Usage" Mapping="Name:AUDIO_USAGE_VIRTUAL_SOURCE"/>
+            <Component Name="assistant" Type="Usage" Mapping="Name:AUDIO_USAGE_ASSISTANT"/>
         </ComponentType>
 
         <!--#################### USAGE END ####################-->
@@ -106,25 +90,25 @@
 
         <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="Amend1:Default,Identifier:0"/>
-            <Component Name="mic" Type="InputSource" Mapping="Amend1:Mic,Identifier:1"/>
+            <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="Amend1:VoiceUplink,Identifier:2"/>
+                                           Mapping="Name:AUDIO_SOURCE_VOICE_UPLINK"/>
             <Component Name="voice_downlink" Type="InputSource"
-                                             Mapping="Amend1:VoiceDownlink,Identifier:3"/>
+                                             Mapping="Name:AUDIO_SOURCE_VOICE_DOWNLINK"/>
             <Component Name="voice_call" Type="InputSource"
-                                         Mapping="Amend1:VoiceCall,Identifier:4"/>
-            <Component Name="camcorder" Type="InputSource" Mapping="Amend1:Camcorder,Identifier:5"/>
+                                         Mapping="Name:AUDIO_SOURCE_VOICE_CALL"/>
+            <Component Name="camcorder" Type="InputSource" Mapping="Name:AUDIO_SOURCE_CAMCORDER"/>
             <Component Name="voice_recognition" Type="InputSource"
-                                                Mapping="Amend1:VoiceRecognition,Identifier:6"/>
+                                                Mapping="Name:AUDIO_SOURCE_VOICE_RECOGNITION"/>
             <Component Name="voice_communication" Type="InputSource"
-                                                  Mapping="Amend1:VoiceCommunication,Identifier:7"/>
+                                                  Mapping="Name:AUDIO_SOURCE_VOICE_COMMUNICATION"/>
             <Component Name="remote_submix" Type="InputSource"
-                                            Mapping="Amend1:RemoteSubmix,Identifier:8"/>
+                                            Mapping="Name:AUDIO_SOURCE_REMOTE_SUBMIX"/>
             <Component Name="unprocessed" Type="InputSource"
-                                            Mapping="Amend1:Unprocessed,Identifier:9"/>
-            <Component Name="fm_tuner" Type="InputSource" Mapping="Amend1:FmTuner,Identifier:1998"/>
-            <Component Name="hotword" Type="InputSource" Mapping="Amend1:Hotword,Identifier:1999"/>
+                                            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 ####################-->
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/policy_criteria.txt b/services/audiopolicy/engineconfigurable/parameter-framework/examples/policy_criteria.txt
deleted file mode 100644
index 480cbe1..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/policy_criteria.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-ExclusiveCriterion TelephonyMode                :   Normal          RingTone                InCall              InCommunication
-InclusiveCriterion AvailableInputDevices        :   Communication Ambient BuiltinMic BluetoothScoHeadset WiredHeadset Hdmi TelephonyRx BackMic RemoteSubmix AnlgDockHeadset DgtlDockHeadset UsbAccessory UsbDevice FmTuner TvTuner Line Spdif BluetoothA2dp Loopback Ip Bus Stub
-InclusiveCriterion AvailableOutputDevices       :   Earpiece Speaker WiredSpeaker WiredHeadset WiredHeadphone BluetoothSco BluetoothScoHeadset BluetoothScoCarkit BluetoothA2dp BluetoothA2dpHeadphones BluetoothA2dpSpeaker Hdmi AnlgDockHeadset DgtlDockHeadset UsbAccessory UsbDevice RemoteSubmix TelephonyTx Line HdmiArc Spdif Fm AuxLine SpeakerSafe Ip Bus Stub
-ExclusiveCriterion ForceUseForCommunication     :   ForceNone       ForceSpeaker            ForceBtSco
-ExclusiveCriterion ForceUseForMedia             :   ForceNone       ForceSpeaker			ForceHeadphones         ForceBtA2dp         ForceWiredAccessory ForceAnalogDock ForceDigitalDock    ForceNoBtA2dp       ForceSystemEnforced
-ExclusiveCriterion ForceUseForRecord            :   ForceNone       ForceBtSco              ForceWiredAccessory
-ExclusiveCriterion ForceUseForDock              :   ForceNone       ForceWiredAccessory     ForceBtCarDock      ForceBtDeskDock     ForceAnalogDock ForceDigitalDock
-ExclusiveCriterion ForceUseForSystem            :   ForceNone       ForceSystemEnforced
-ExclusiveCriterion ForceUseForHdmiSystemAudio   :   ForceNone       ForceHdmiSystemEnforced
-ExclusiveCriterion ForceUseForEncodedSurround   :   ForceNone       ForceEncodedSurroundNever   ForceEncodedSurroundAlways
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
index 3559cf1..db1f038 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
@@ -28,6 +28,7 @@
 LOCAL_SHARED_LIBRARIES := \
     libaudiopolicyengineconfigurable  \
     libparameter \
+    libmedia_helper \
     liblog \
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
index eac4efe..f91f8d7 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
@@ -17,6 +17,7 @@
 #include "InputSource.h"
 #include "PolicyMappingKeys.h"
 #include "PolicySubsystem.h"
+#include <media/TypeConverter.h>
 
 using std::string;
 
@@ -33,9 +34,13 @@
                            instanceConfigurableElement->getBelongingSubsystem())),
       mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
 {
-    mId = static_cast<audio_source_t>(context.getItemAsInteger(MappingKeyIdentifier));
+    std::string name(context.getItem(MappingKeyName));
+
+    if(not android::SourceTypeConverter::fromString(name, mId)) {
+        LOG_ALWAYS_FATAL("Invalid Input Source name: %s, invalid XML structure file", name.c_str());
+    }
     // Declares the strategy to audio policy engine
-    mPolicyPluginInterface->addInputSource(getFormattedMappingValue(), mId);
+    mPolicyPluginInterface->addInputSource(name, mId);
 }
 
 bool InputSource::sendToHW(string & /*error*/)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
index 98d10a9..7374fc3 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
@@ -65,22 +65,22 @@
     addSubsystemObjectFactory(
         new TSubsystemObjectFactory<Stream>(
             mStreamComponentName,
-            (1 << MappingKeyIdentifier))
+            (1 << MappingKeyName))
         );
     addSubsystemObjectFactory(
         new TSubsystemObjectFactory<Strategy>(
             mStrategyComponentName,
-            (1 << MappingKeyAmend1) | (1 << MappingKeyIdentifier))
+            0)
         );
     addSubsystemObjectFactory(
         new TSubsystemObjectFactory<Usage>(
             mUsageComponentName,
-            (1 << MappingKeyAmend1) | (1 << MappingKeyIdentifier))
+            (1 << MappingKeyName))
         );
     addSubsystemObjectFactory(
         new TSubsystemObjectFactory<InputSource>(
             mInputSourceComponentName,
-            (1 << MappingKeyAmend1) | (1 << MappingKeyIdentifier))
+            (1 << MappingKeyName))
         );
 }
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
index 746c3a8..876bcb0 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
@@ -17,10 +17,38 @@
 #include "Strategy.h"
 #include "PolicyMappingKeys.h"
 #include "PolicySubsystem.h"
+#include <RoutingStrategy.h>
 
 using std::string;
 using android::routing_strategy;
 
+namespace detail {
+
+constexpr std::pair<routing_strategy, const char*> routingStrategyMap[] = {
+    {android::STRATEGY_MEDIA, "STRATEGY_MEDIA"},
+    {android::STRATEGY_PHONE, "STRATEGY_PHONE"},
+    {android::STRATEGY_SONIFICATION, "STRATEGY_SONIFICATION"},
+    {android::STRATEGY_SONIFICATION_RESPECTFUL, "STRATEGY_SONIFICATION_RESPECTFUL"},
+    {android::STRATEGY_DTMF, "STRATEGY_DTMF"},
+    {android::STRATEGY_ENFORCED_AUDIBLE, "STRATEGY_ENFORCED_AUDIBLE"},
+    {android::STRATEGY_TRANSMITTED_THROUGH_SPEAKER, "STRATEGY_TRANSMITTED_THROUGH_SPEAKER"},
+    {android::STRATEGY_ACCESSIBILITY, "STRATEGY_ACCESSIBILITY"},
+    {android::STRATEGY_REROUTING, "STRATEGY_REROUTING"},
+};
+
+bool fromString(const char *literalName, routing_strategy &type)
+{
+    for (auto& pair : routingStrategyMap) {
+        if (strcmp(pair.second, literalName) == 0) {
+            type = pair.first;
+            return true;
+        }
+    }
+    return false;
+}
+
+}
+
 Strategy::Strategy(const string &mappingValue,
                    CInstanceConfigurableElement *instanceConfigurableElement,
                    const CMappingContext &context,
@@ -35,10 +63,12 @@
                            instanceConfigurableElement->getBelongingSubsystem())),
       mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
 {
-    mId = static_cast<routing_strategy>(context.getItemAsInteger(MappingKeyIdentifier));
-
+    std::string name(context.getItem(MappingKeyName));
+    if (not detail::fromString(name.c_str(), mId)) {
+        LOG_ALWAYS_FATAL("Invalid Strategy %s, invalid XML structure file", name.c_str());
+    }
     // Declares the strategy to audio policy engine
-    mPolicyPluginInterface->addStrategy(getFormattedMappingValue(), mId);
+    mPolicyPluginInterface->addStrategy(instanceConfigurableElement->getName(), mId);
 }
 
 bool Strategy::sendToHW(string & /*error*/)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.cpp
index c642a23..46c9e1c 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.cpp
@@ -17,6 +17,7 @@
 #include "Stream.h"
 #include "PolicyMappingKeys.h"
 #include "PolicySubsystem.h"
+#include <media/TypeConverter.h>
 
 using std::string;
 using android::routing_strategy;
@@ -29,10 +30,14 @@
                            instanceConfigurableElement->getBelongingSubsystem())),
       mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
 {
-    mId = static_cast<audio_stream_type_t>(context.getItemAsInteger(MappingKeyIdentifier));
+    std::string name(context.getItem(MappingKeyName));
+
+    if (not android::StreamTypeConverter::fromString(name, mId)) {
+        LOG_ALWAYS_FATAL("Invalid Stream type name: %s, invalid XML structure file", name.c_str());
+    }
 
     // Declares the strategy to audio policy engine
-    mPolicyPluginInterface->addStream(getFormattedMappingValue(), mId);
+    mPolicyPluginInterface->addStream(name, mId);
 }
 
 bool Stream::sendToHW(string & /*error*/)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
index 78199f8..925d631 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
@@ -17,6 +17,7 @@
 #include "Usage.h"
 #include "PolicyMappingKeys.h"
 #include "PolicySubsystem.h"
+#include <media/TypeConverter.h>
 
 using std::string;
 using android::routing_strategy;
@@ -34,10 +35,13 @@
                            instanceConfigurableElement->getBelongingSubsystem())),
       mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
 {
-    mId = static_cast<audio_usage_t>(context.getItemAsInteger(MappingKeyIdentifier));
+    std::string name(context.getItem(MappingKeyName));
 
+    if (not android::UsageTypeConverter::fromString(name, mId)) {
+        LOG_ALWAYS_FATAL("Invalid Usage name: %s, invalid XML structure file", name.c_str());
+    }
     // Declares the strategy to audio policy engine
-    mPolicyPluginInterface->addUsage(getFormattedMappingValue(), mId);
+    mPolicyPluginInterface->addUsage(name, mId);
 }
 
 bool Usage::sendToHW(string & /*error*/)
diff --git a/services/audiopolicy/engineconfigurable/sepolicy/audioserver.te b/services/audiopolicy/engineconfigurable/sepolicy/audioserver.te
new file mode 100644
index 0000000..4d41d42
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/sepolicy/audioserver.te
@@ -0,0 +1,4 @@
+userdebug_or_eng(`
+  allow audioserver audioserver_socket:dir rw_dir_perms;
+  allow audioserver audioserver_socket:sock_file create_file_perms;
+')
diff --git a/services/audiopolicy/engineconfigurable/sepolicy/file.te b/services/audiopolicy/engineconfigurable/sepolicy/file.te
new file mode 100644
index 0000000..7db1937
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/sepolicy/file.te
@@ -0,0 +1,2 @@
+# Policy Engine remote connection for runtime debug of parameter framework
+type audioserver_socket, file_type, coredomain_socket;
diff --git a/services/audiopolicy/engineconfigurable/sepolicy/file_contexts b/services/audiopolicy/engineconfigurable/sepolicy/file_contexts
new file mode 100644
index 0000000..950fcce
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/sepolicy/file_contexts
@@ -0,0 +1 @@
+/dev/socket/audioserver(/.*)?    u:object_r:audioserver_socket:s0
diff --git a/services/audiopolicy/engineconfigurable/src/Collection.h b/services/audiopolicy/engineconfigurable/src/Collection.h
index b72ded8..1f8ed8d 100644
--- a/services/audiopolicy/engineconfigurable/src/Collection.h
+++ b/services/audiopolicy/engineconfigurable/src/Collection.h
@@ -28,10 +28,8 @@
 #include <stdint.h>
 #include <string>
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
 
 /**
  * Collection of policy element as a map indexed with a their UID type.
diff --git a/services/audiopolicy/engineconfigurable/src/Element.h b/services/audiopolicy/engineconfigurable/src/Element.h
index 52e77e5..1b55c8c 100644
--- a/services/audiopolicy/engineconfigurable/src/Element.h
+++ b/services/audiopolicy/engineconfigurable/src/Element.h
@@ -22,10 +22,8 @@
 #include <system/audio.h>
 #include <utils/Log.h>
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
 
 template <typename Key>
 class Element
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 0d18ffa..009cf90 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -35,10 +35,9 @@
 using std::string;
 using std::map;
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
+
 template <>
 StrategyCollection &Engine::getCollection<routing_strategy>()
 {
@@ -220,8 +219,10 @@
 }
 
 status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
-                                          audio_policy_dev_state_t /*state*/)
+                                          audio_policy_dev_state_t state)
 {
+    mPolicyParameterMgr->setDeviceConnectionState(devDesc, state);
+
     if (audio_is_output_device(devDesc->type())) {
         return mPolicyParameterMgr->setAvailableOutputDevices(
                     mApmObserver->getAvailableOutputDevices().types());
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index 328d23d..ba4f889 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -21,12 +21,10 @@
 #include <AudioPolicyPluginInterface.h>
 #include "Collection.h"
 
-namespace android
-{
+namespace android {
 class AudioPolicyManagerObserver;
 
-namespace audio_policy
-{
+namespace audio_policy {
 
 class ParameterManagerWrapper;
 class VolumeProfile;
diff --git a/services/audiopolicy/engineconfigurable/src/EngineInstance.cpp b/services/audiopolicy/engineconfigurable/src/EngineInstance.cpp
index 9aa89b2..2442590 100644
--- a/services/audiopolicy/engineconfigurable/src/EngineInstance.cpp
+++ b/services/audiopolicy/engineconfigurable/src/EngineInstance.cpp
@@ -21,10 +21,8 @@
 
 using std::string;
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
 
 EngineInstance::EngineInstance()
 {
diff --git a/services/audiopolicy/engineconfigurable/src/InputSource.cpp b/services/audiopolicy/engineconfigurable/src/InputSource.cpp
index ae39fef..d252d3f 100644
--- a/services/audiopolicy/engineconfigurable/src/InputSource.cpp
+++ b/services/audiopolicy/engineconfigurable/src/InputSource.cpp
@@ -20,13 +20,13 @@
 
 using std::string;
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
+
 status_t Element<audio_source_t>::setIdentifier(audio_source_t identifier)
 {
-    if (identifier > AUDIO_SOURCE_MAX && identifier != AUDIO_SOURCE_HOTWORD) {
+    if (identifier > AUDIO_SOURCE_MAX && identifier != AUDIO_SOURCE_HOTWORD
+        && identifier != AUDIO_SOURCE_FM_TUNER && identifier != AUDIO_SOURCE_ECHO_REFERENCE) {
         return BAD_VALUE;
     }
     mIdentifier = identifier;
diff --git a/services/audiopolicy/engineconfigurable/src/InputSource.h b/services/audiopolicy/engineconfigurable/src/InputSource.h
index 6c498dc..64b390e 100644
--- a/services/audiopolicy/engineconfigurable/src/InputSource.h
+++ b/services/audiopolicy/engineconfigurable/src/InputSource.h
@@ -18,10 +18,8 @@
 
 #include "Element.h"
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
 
 /**
  * Specialization of policy base class element for audio_source_t
diff --git a/services/audiopolicy/engineconfigurable/src/Strategy.cpp b/services/audiopolicy/engineconfigurable/src/Strategy.cpp
index a539914..310b35e 100644
--- a/services/audiopolicy/engineconfigurable/src/Strategy.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Strategy.cpp
@@ -20,10 +20,8 @@
 
 using std::string;
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
 
 status_t Element<routing_strategy>::setIdentifier(routing_strategy identifier)
 {
diff --git a/services/audiopolicy/engineconfigurable/src/Strategy.h b/services/audiopolicy/engineconfigurable/src/Strategy.h
index 1157d55..f2487fd 100644
--- a/services/audiopolicy/engineconfigurable/src/Strategy.h
+++ b/services/audiopolicy/engineconfigurable/src/Strategy.h
@@ -19,10 +19,8 @@
 #include "Element.h"
 #include <RoutingStrategy.h>
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
 
 /**
  * @tparam audio_devices_t: Applicable output device(s) for this strategy.
diff --git a/services/audiopolicy/engineconfigurable/src/Stream.cpp b/services/audiopolicy/engineconfigurable/src/Stream.cpp
index 0ed364f..73fb94d 100644
--- a/services/audiopolicy/engineconfigurable/src/Stream.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Stream.cpp
@@ -21,10 +21,8 @@
 
 using std::string;
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
 
 status_t Element<audio_stream_type_t>::setIdentifier(audio_stream_type_t identifier)
 {
diff --git a/services/audiopolicy/engineconfigurable/src/Stream.h b/services/audiopolicy/engineconfigurable/src/Stream.h
index 6902003..2bf70b3 100644
--- a/services/audiopolicy/engineconfigurable/src/Stream.h
+++ b/services/audiopolicy/engineconfigurable/src/Stream.h
@@ -21,10 +21,9 @@
 #include <RoutingStrategy.h>
 #include <map>
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
+
 /**
  * @tparam routing_strategy: Applicable strategy for this stream.
  */
diff --git a/services/audiopolicy/engineconfigurable/src/Usage.cpp b/services/audiopolicy/engineconfigurable/src/Usage.cpp
index 5d20828..8c0dfba 100644
--- a/services/audiopolicy/engineconfigurable/src/Usage.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Usage.cpp
@@ -18,10 +18,8 @@
 
 #include "Usage.h"
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
 
 status_t Element<audio_usage_t>::setIdentifier(audio_usage_t identifier)
 {
diff --git a/services/audiopolicy/engineconfigurable/src/Usage.h b/services/audiopolicy/engineconfigurable/src/Usage.h
index d69e0e0..72a452f 100644
--- a/services/audiopolicy/engineconfigurable/src/Usage.h
+++ b/services/audiopolicy/engineconfigurable/src/Usage.h
@@ -19,10 +19,8 @@
 #include "Element.h"
 #include <RoutingStrategy.h>
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
 
 /**
  * @tparam routing_strategy: Applicable strategy for this usage.
diff --git a/services/audiopolicy/engineconfigurable/tools/Android.bp b/services/audiopolicy/engineconfigurable/tools/Android.bp
new file mode 100644
index 0000000..d8f29dc
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/tools/Android.bp
@@ -0,0 +1,31 @@
+// 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.
+
+python_binary_host {
+    name: "buildPolicyCriterionTypes.py",
+    owner: "renault",
+    main: "buildPolicyCriterionTypes.py",
+    srcs: [
+        "buildPolicyCriterionTypes.py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+}
+
diff --git a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
new file mode 100755
index 0000000..0fb70a6
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
@@ -0,0 +1,243 @@
+#!/usr/bin/python
+
+#
+# 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.
+#
+
+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 criterion types file used by
+# the engineconfigurable to start the parameter-framework.
+# It prevents to fill them manually and avoid divergences with android.
+#
+# The Device Types criterion types are fed from audio-base.h file with the option
+#           --androidaudiobaseheader <path/to/android/audio/base/file/audio-base.h>
+#
+# The Device Addresses criterion types are fed from the audio policy configuration file
+# in order to discover all the devices for which the address matter.
+#           --audiopolicyconfigurationfile <path/to/audio_policy_configuration.xml>
+#
+# The reference file of criterion types must also be set as an input of the script:
+#           --criteriontypes <path/to/criterion/file/audio_criterion_types.xml.in>
+#
+# At last, the output of the script shall be set also:
+#           --outputfile <path/to/out/vendor/etc/audio_criterion_types.xml>
+#
+
+def parseArgs():
+    argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
+        audio criterion type file generator.\n\
+        Exit with the number of (recoverable or not) error that occured.")
+    argparser.add_argument('--androidaudiobaseheader',
+            help="Android Audio Base C header file, Mandatory.",
+            metavar="ANDROID_AUDIO_BASE_HEADER",
+            type=argparse.FileType('r'),
+            required=True)
+    argparser.add_argument('--audiopolicyconfigurationfile',
+            help="Android Audio Policy Configuration file, Mandatory.",
+            metavar="(AUDIO_POLICY_CONFIGURATION_FILE)",
+            type=argparse.FileType('r'),
+            required=True)
+    argparser.add_argument('--criteriontypes',
+            help="Criterion types XML base file, in \
+            '<criterion_types> \
+                <criterion_type name="" type=<inclusive|exclusive> values=<value1,value2,...>/>' \
+        format. Mandatory.",
+            metavar="CRITERION_TYPE_FILE",
+            type=argparse.FileType('r'),
+            required=True)
+    argparser.add_argument('--outputfile',
+            help="Criterion types outputfile file. Mandatory.",
+            metavar="CRITERION_TYPE_OUTPUT_FILE",
+            type=argparse.FileType('w'),
+            required=True)
+    argparser.add_argument('--verbose',
+            action='store_true')
+
+    return argparser.parse_args()
+
+
+def generateXmlCriterionTypesFile(criterionTypes, addressCriteria, criterionTypesFile, outputFile):
+
+    logging.info("Importing criterionTypesFile {}".format(criterionTypesFile))
+    criterion_types_in_tree = ET.parse(criterionTypesFile)
+
+    criterion_types_root = criterion_types_in_tree.getroot()
+
+    for criterion_name, values_dict in criterionTypes.items():
+        for criterion_type in criterion_types_root.findall('criterion_type'):
+            if criterion_type.get('name') == criterion_name:
+                values_node = ET.SubElement(criterion_type, "values")
+                ordered_values = OrderedDict(sorted(values_dict.items(), key=lambda x: x[1]))
+                for key, value in ordered_values.items():
+                    value_node = ET.SubElement(values_node, "value")
+                    value_node.set('numerical', str(value))
+                    value_node.set('literal', key)
+
+    if addressCriteria:
+        for criterion_name, values_list in addressCriteria.items():
+            for criterion_type in criterion_types_root.findall('criterion_type'):
+                if criterion_type.get('name') == criterion_name:
+                    values_node = ET.SubElement(criterion_type, "values")
+                    index = 0
+                    for value in values_list:
+                        value_node = ET.SubElement(values_node, "value", literal=value)
+                        value_node.set('numerical', str(1 << index))
+                        index += 1
+
+    xmlstr = ET.tostring(criterion_types_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 parseAndroidAudioPolicyConfigurationFile(audiopolicyconfigurationfile):
+
+    logging.info("Checking Audio Policy Configuration file {}".format(audiopolicyconfigurationfile))
+    #
+    # extract all devices addresses from audio policy configuration file
+    #
+    address_criteria_mapping_table = {
+        'sink' : "OutputDevicesAddressesType",
+        'source' : "InputDevicesAddressesType" }
+
+    address_criteria = {
+        'OutputDevicesAddressesType' : [],
+        'InputDevicesAddressesType' : [] }
+
+    oldWorkingDir = os.getcwd()
+    print "Current working directory %s" % oldWorkingDir
+
+    newDir = os.path.join(oldWorkingDir , audiopolicyconfigurationfile.name)
+
+    policy_in_tree = ET.parse(audiopolicyconfigurationfile)
+    os.chdir(os.path.dirname(os.path.normpath(newDir)))
+
+    print "new working directory %s" % os.getcwd()
+
+    policy_root = policy_in_tree.getroot()
+    EI.include(policy_root)
+
+    os.chdir(oldWorkingDir)
+
+    for device in policy_root.iter('devicePort'):
+        for key in address_criteria_mapping_table.keys():
+            if device.get('role') == key and device.get('address') :
+                logging.info("{}: <{}>".format(key, device.get('address')))
+                address_criteria[address_criteria_mapping_table[key]].append(device.get('address'))
+
+    for criteria in address_criteria:
+        values = ','.join(address_criteria[criteria])
+        logging.info("{}: <{}>".format(criteria, values))
+
+    return address_criteria
+
+#
+# Parse the audio-base.h file and output a dictionary of android dependent criterion types:
+#   -Android Mode
+#   -Output devices type
+#   -Input devices type
+#
+def parseAndroidAudioFile(androidaudiobaseheaderFile):
+    #
+    # Adaptation table between Android Enumeration prefix and Audio PFW Criterion type names
+    #
+    criterion_mapping_table = {
+        'AUDIO_MODE' : "AndroidModeType",
+        'AUDIO_DEVICE_OUT' : "OutputDevicesMaskType",
+        'AUDIO_DEVICE_IN' : "InputDevicesMaskType"}
+
+    all_criteria = {
+        'AndroidModeType' : {},
+        'OutputDevicesMaskType' : {},
+        'InputDevicesMaskType' : {} }
+
+    #
+    # _CNT, _MAX, _ALL and _NONE are prohibited values as ther are just helpers for enum users.
+    #
+    ignored_values = [ 'CNT', 'MAX', 'ALL', 'NONE' ]
+
+    criteria_pattern = re.compile(
+        r"\s*(?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))\_" \
+        r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*=\s*" \
+        r"(?P<values>(?:0[xX])?[0-9a-fA-F]+)")
+
+    logging.info("Checking Android Header file {}".format(androidaudiobaseheaderFile))
+
+    for line_number, line in enumerate(androidaudiobaseheaderFile):
+        match = criteria_pattern.match(line)
+        if match:
+            logging.debug("The following line is VALID: {}:{}\n{}".format(
+                androidaudiobaseheaderFile.name, line_number, line))
+
+            criterion_name = criterion_mapping_table[match.groupdict()['type']]
+            literal = ''.join((w.capitalize() for w in match.groupdict()['literal'].split('_')))
+            numerical_value = match.groupdict()['values']
+
+            # for AUDIO_DEVICE_IN: need to remove sign bit
+            if criterion_name == "InputDevicesMaskType":
+                numerical_value = str(int(numerical_value, 0) & ~2147483648)
+
+            # Remove duplicated numerical values
+            if int(numerical_value, 0) in all_criteria[criterion_name].values():
+                logging.info("criterion {} duplicated values:".format(criterion_name))
+                logging.info("{}:{}".format(numerical_value, literal))
+                logging.info("KEEPING LATEST")
+                for key in all_criteria[criterion_name].keys():
+                    if all_criteria[criterion_name][key] == int(numerical_value, 0):
+                        del all_criteria[criterion_name][key]
+
+            all_criteria[criterion_name][literal] = int(numerical_value, 0)
+
+            logging.debug("type:{},".format(criterion_name))
+            logging.debug("iteral:{},".format(literal))
+            logging.debug("values:{}.".format(numerical_value))
+
+    return all_criteria
+
+
+def main():
+    logging.root.setLevel(logging.INFO)
+    args = parseArgs()
+
+    all_criteria = parseAndroidAudioFile(args.androidaudiobaseheader)
+
+    address_criteria = parseAndroidAudioPolicyConfigurationFile(args.audiopolicyconfigurationfile)
+
+    criterion_types = args.criteriontypes
+
+    generateXmlCriterionTypesFile(all_criteria, address_criteria, criterion_types, args.outputfile)
+
+# If this file is directly executed
+if __name__ == "__main__":
+    exit(main())
diff --git a/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk b/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk
new file mode 100644
index 0000000..2b86469
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk
@@ -0,0 +1,35 @@
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(PFW_CRITERION_TYPES_FILE)
+$(LOCAL_BUILT_MODULE): MY_TOOL := domainGeneratorPolicy.py
+$(LOCAL_BUILT_MODULE): MY_TOPLEVEL_FILE := $(PFW_TOPLEVEL_FILE)
+$(LOCAL_BUILT_MODULE): MY_CRITERIA_FILE := $(PFW_CRITERIA_FILE)
+$(LOCAL_BUILT_MODULE): MY_TUNING_FILE := $(PFW_TUNING_FILE)
+$(LOCAL_BUILT_MODULE): MY_EDD_FILES := $(PFW_EDD_FILES)
+$(LOCAL_BUILT_MODULE): MY_DOMAIN_FILES := $(PFW_DOMAIN_FILES)
+$(LOCAL_BUILT_MODULE): MY_SCHEMAS_DIR := $(PFW_SCHEMAS_DIR)
+$(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(PFW_CRITERION_TYPES_FILE)
+$(LOCAL_BUILT_MODULE): $(LOCAL_REQUIRED_MODULES) $(LOCAL_ADDITIONAL_DEPENDENCIES) domainGeneratorPolicy.py
+
+	"$(MY_TOOL)" --validate \
+		--toplevel-config "$(MY_TOPLEVEL_FILE)" \
+		--criteria "$(MY_CRITERIA_FILE)" \
+		--criteriontypes "$(MY_CRITERION_TYPES_FILE)" \
+		--initial-settings $(MY_TUNING_FILE) \
+		--add-edds $(MY_EDD_FILES) \
+		--add-domains $(MY_DOMAIN_FILES) \
+		--schemas-dir $(MY_SCHEMAS_DIR) > "$@"
+
+
+# Clear variables for further use
+PFW_TOPLEVEL_FILE :=
+PFW_STRUCTURE_FILES :=
+PFW_CRITERIA_FILE :=
+PFW_CRITERION_TYPES_FILE :=
+PFW_TUNING_FILE :=
+PFW_EDD_FILES :=
+PFW_DOMAIN_FILES :=
+PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
diff --git a/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py b/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py
new file mode 100755
index 0000000..7929402
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py
@@ -0,0 +1,268 @@
+#!/usr/bin/python
+
+#
+# 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.
+#
+
+import EddParser
+from PFWScriptGenerator import PfwScriptTranslator
+import hostConfig
+
+import argparse
+import re
+import sys
+import tempfile
+import os
+import logging
+import subprocess
+import xml.etree.ElementTree as ET
+
+#
+# In order to build the XML Settings file at build time, an instance of the parameter-framework
+# shall be started and fed with all the criterion types/criteria that will be used by
+# the engineconfigurable.
+# This scripts allows generates the settings from the same audio_criterion_types.xml /
+# audio_criteria.xml files used at run time by the engineconfigurable
+#
+
+def parseArgs():
+    argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
+        Settings file generator.\n\
+        Exit with the number of (recoverable or not) error that occured.")
+    argparser.add_argument('--toplevel-config',
+            help="Top-level parameter-framework configuration file. Mandatory.",
+            metavar="TOPLEVEL_CONFIG_FILE",
+            required=True)
+    argparser.add_argument('--criteria',
+            help="Criteria file, in XML format: \
+                  in '<criteria> \
+                          <criterion name="" type=""/> \
+                      </criteria>' \
+        format. Mandatory.",
+            metavar="CRITERIA_FILE",
+            type=argparse.FileType('r'),
+            required=True)
+    argparser.add_argument('--criteriontypes',
+            help="Criterion types XML file, in \
+            '<criterion_types> \
+                <criterion_type name="" type=<inclusive|exclusive> values=<value1,value2,...>/> \
+             </criterion_types>' \
+        format. Mandatory.",
+            metavar="CRITERION_TYPE_FILE",
+            type=argparse.FileType('r'),
+            required=False)
+    argparser.add_argument('--initial-settings',
+            help="Initial XML settings file (containing a \
+        <ConfigurableDomains>  tag",
+            nargs='?',
+            default=None,
+            metavar="XML_SETTINGS_FILE")
+    argparser.add_argument('--add-domains',
+            help="List of single domain files (each containing a single \
+        <ConfigurableDomain> tag",
+            metavar="XML_DOMAIN_FILE",
+            nargs='*',
+            dest='xml_domain_files',
+            default=[])
+    argparser.add_argument('--add-edds',
+            help="List of files in EDD syntax (aka \".pfw\" files)",
+            metavar="EDD_FILE",
+            type=argparse.FileType('r'),
+            nargs='*',
+            default=[],
+            dest='edd_files')
+    argparser.add_argument('--schemas-dir',
+            help="Directory of parameter-framework XML Schemas for generation \
+        validation",
+            default=None)
+    argparser.add_argument('--target-schemas-dir',
+            help="Ignored. Kept for retro-compatibility")
+    argparser.add_argument('--validate',
+            help="Validate the settings against XML schemas",
+            action='store_true')
+    argparser.add_argument('--verbose',
+            action='store_true')
+
+    return argparser.parse_args()
+
+#
+# Parses audio_criterion_types.xml / audio_criteria.xml files used at run time by the
+# engineconfigurable and outputs a dictionnary of criteria.
+# For each criteria, the name, type (aka inclusive (bitfield) or exclusive (enum), the values
+# are provided.
+#
+def parseCriteriaAndCriterionTypes(criteriaFile, criterionTypesFile):
+    # Parse criteria and criterion types XML files
+    #
+    criteria_tree = ET.parse(criteriaFile)
+    logging.info("Importing criteriaFile {}".format(criteriaFile))
+    criterion_types_tree = ET.parse(criterionTypesFile)
+    logging.info("Importing criterionTypesFile {}".format(criterionTypesFile))
+
+    criteria_root = criteria_tree.getroot()
+    criterion_types_root = criterion_types_tree.getroot()
+
+    all_criteria = []
+    for criterion in criteria_root.findall('criterion'):
+        criterion_name = criterion.get('name')
+        type_name = criterion.get('type')
+        logging.info("Importing criterion_name {}".format(criterion_name))
+        logging.info("Importing type_name {}".format(type_name))
+
+        for criterion_types in criterion_types_tree.findall('criterion_type'):
+            criterion_type_name = criterion_types.get('name')
+            if criterion_type_name == type_name:
+                criterion_inclusiveness = criterion_types.get('type')
+
+                criterion_values = []
+
+                values_node = criterion_types.find('values')
+                if values_node:
+                    for value in values_node.findall('value'):
+                        criterion_values.append(value.get('literal'))
+
+                if len(criterion_values) == 0:
+                    criterion_values.append('')
+
+                logging.info("Importing criterion_type_name {}".format(criterion_type_name))
+                logging.info("Importing criterion_inclusiveness {}".format(criterion_inclusiveness))
+                logging.info("Importing criterion_values {}".format(criterion_values))
+
+                all_criteria.append({
+                    "name" : criterion_name,
+                    "inclusive" : criterion_inclusiveness,
+                    "values" : criterion_values})
+                break
+
+    return all_criteria
+
+#
+# Parses the Edd files (aka .pfw extension file), which is a simplified language to write the
+# parameter framework settings.
+#
+def parseEdd(EDDFiles):
+    parsed_edds = []
+
+    for edd_file in EDDFiles:
+        try:
+            root = EddParser.Parser().parse(edd_file)
+        except EddParser.MySyntaxError as ex:
+            logging.critical(str(ex))
+            logging.info("EXIT ON FAILURE")
+            exit(2)
+
+        try:
+            root.propagate()
+        except EddParser.MyPropagationError, ex :
+            logging.critical(str(ex))
+            logging.info("EXIT ON FAILURE")
+            exit(1)
+
+        parsed_edds.append((edd_file.name, root))
+    return parsed_edds
+
+#
+# Generates all the required commands to be sent to the instance of parameter-framework launched
+# at runtime to generate the XML Settings file.
+# It takes as input the collection of criteria, the domains and the simplified settings read from
+# pfw.
+#
+def generateDomainCommands(logging, all_criteria, initial_settings, xml_domain_files, parsed_edds):
+        # create and inject all the criteria
+        logging.info("Creating all criteria")
+        for criterion in all_criteria:
+            yield ["createSelectionCriterion", criterion['inclusive'],
+                   criterion['name']] + criterion['values']
+
+        yield ["start"]
+
+        # Import initial settings file
+        if initial_settings:
+            logging.info("Importing initial settings file {}".format(initial_settings))
+            yield ["importDomainsWithSettingsXML", initial_settings]
+
+        # Import each standalone domain files
+        for domain_file in xml_domain_files:
+            logging.info("Importing single domain file {}".format(domain_file))
+            yield ["importDomainWithSettingsXML", domain_file]
+
+        # Generate the script for each EDD file
+        for filename, parsed_edd in parsed_edds:
+            logging.info("Translating and injecting EDD file {}".format(filename))
+            translator = PfwScriptTranslator()
+            parsed_edd.translate(translator)
+            for command in translator.getScript():
+                yield command
+
+#
+# Entry point of the domain generator.
+#       -Parses Criterion types and criteria files
+#       -Parses settings written in simplified pfw language.
+#       -Launches a parameter-framework
+#       -Translates the settings into command that can be interpreted by parameter-framework.
+#       -Use the exports command and output them in XML Settings file.
+#
+def main():
+    logging.root.setLevel(logging.INFO)
+    args = parseArgs()
+
+    all_criteria = parseCriteriaAndCriterionTypes(args.criteria, args.criteriontypes)
+
+    #
+    # EDD files (aka ".pfw" files)
+    #
+    parsed_edds = parseEdd(args.edd_files)
+
+    # We need to modify the toplevel configuration file to account for differences
+    # between development setup and target (installation) setup, in particular, the
+    # TuningMwith ode must be enforced, regardless of what will be allowed on the target
+    fake_toplevel_config = tempfile.NamedTemporaryFile(mode='w', delete=False, suffix=".xml",
+                                                       prefix="TMPdomainGeneratorPFConfig_")
+
+    install_path = os.path.dirname(os.path.realpath(args.toplevel_config))
+    hostConfig.configure(
+            infile=args.toplevel_config,
+            outfile=fake_toplevel_config,
+            structPath=install_path)
+    fake_toplevel_config.close()
+
+    # Create the connector. Pipe its input to us in order to write commands;
+    # connect its output to stdout in order to have it dump the domains
+    # there; connect its error output to stderr.
+    connector = subprocess.Popen(["domainGeneratorConnector",
+                            fake_toplevel_config.name,
+                            'verbose' if args.verbose else 'no-verbose',
+                            'validate' if args.validate else 'no-validate',
+                            args.schemas_dir],
+                           stdout=sys.stdout, stdin=subprocess.PIPE, stderr=sys.stderr)
+
+    initial_settings = None
+    if args.initial_settings:
+        initial_settings = os.path.realpath(args.initial_settings)
+
+    for command in generateDomainCommands(logging, all_criteria, initial_settings,
+                                       args.xml_domain_files, parsed_edds):
+        connector.stdin.write('\0'.join(command))
+        connector.stdin.write("\n")
+
+    # Closing the connector's input triggers the domain generation
+    connector.stdin.close()
+    connector.wait()
+    os.remove(fake_toplevel_config.name)
+    return connector.returncode
+
+# If this file is directly executed
+if __name__ == "__main__":
+    exit(main())
diff --git a/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk b/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk
new file mode 100644
index 0000000..4814376
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk
@@ -0,0 +1,24 @@
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(CRITERION_TYPES_FILE)
+$(LOCAL_BUILT_MODULE): MY_ANDROID_AUDIO_BASE_HEADER_FILE := $(ANDROID_AUDIO_BASE_HEADER_FILE)
+$(LOCAL_BUILT_MODULE): MY_AUDIO_POLICY_CONFIGURATION_FILE := $(AUDIO_POLICY_CONFIGURATION_FILE)
+$(LOCAL_BUILT_MODULE): MY_CRITERION_TOOL := $(HOST_OUT)/bin/buildPolicyCriterionTypes.py
+$(LOCAL_BUILT_MODULE): $(LOCAL_REQUIRED_MODULES) $(LOCAL_ADDITIONAL_DEPENDENCIES) \
+    buildPolicyCriterionTypes.py \
+    $(CRITERION_TYPES_FILE) \
+    $(ANDROID_AUDIO_BASE_HEADER_FILE)
+
+	"$(MY_CRITERION_TOOL)" \
+		--androidaudiobaseheader "$(MY_ANDROID_AUDIO_BASE_HEADER_FILE)" \
+		--audiopolicyconfigurationfile "$(MY_AUDIO_POLICY_CONFIGURATION_FILE)" \
+		--criteriontypes "$(MY_CRITERION_TYPES_FILE)" \
+		--outputfile "$(@)"
+
+# Clear variables for further use
+CRITERION_TYPES_FILE :=
+ANDROID_AUDIO_BASE_HEADER_FILE :=
+AUDIO_POLICY_CONFIGURATION_FILE :=
diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.mk b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
index b128a38..d19a364 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/Android.mk
+++ b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
@@ -1,5 +1,8 @@
 LOCAL_PATH:= $(call my-dir)
 
+TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
+PROVISION_CRITERION_TYPES := $(TOOLS)/provision_criterion_types_from_android_headers.mk
+
 ##################################################################
 # WRAPPER LIBRARY
 ##################################################################
@@ -10,12 +13,22 @@
     $(LOCAL_PATH)/include \
     frameworks/av/services/audiopolicy/engineconfigurable/include \
     frameworks/av/services/audiopolicy/engineconfigurable/interface \
+    frameworks/av/services/audiopolicy/common/include \
+    external/libxml2/include \
+    external/icu/icu4c/source/common
 
-LOCAL_SRC_FILES:= ParameterManagerWrapper.cpp
+LOCAL_SRC_FILES:= \
+    ParameterManagerWrapper.cpp \
+    ParameterManagerWrapperConfig.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libparameter \
-    libmedia_helper
+    libmedia_helper \
+    libicuuc \
+    libxml2
+
+LOCAL_STATIC_LIBRARIES := \
+    libaudiopolicycomponents
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
@@ -31,11 +44,35 @@
 # CONFIGURATION FILE
 ##################################################################
 
-# specific management of audio_policy_criteria.conf
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), 1)
+
 include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_criteria.conf
+LOCAL_MODULE := policy_wrapper_configuration.xml
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
+LOCAL_VENDOR_MODULE := true
 LOCAL_SRC_FILES := config/$(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := policy_criteria.xml
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
+LOCAL_SRC_FILES := config/$(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := policy_criterion_types.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+    $(TARGET_OUT_VENDOR_ETC)/audio_policy_configuration.xml
+
+AUDIO_POLICY_CONFIGURATION_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_configuration.xml
+ANDROID_AUDIO_BASE_HEADER_FILE := system/media/audio/include/system/audio-base.h
+CRITERION_TYPES_FILE := $(LOCAL_PATH)/config/policy_criterion_types.xml.in
+
+include $(PROVISION_CRITERION_TYPES)
+
+endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), 1)
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index 9b0442e..1934fa4 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -18,7 +18,7 @@
 //#define LOG_NDEBUG 0
 
 #include "ParameterManagerWrapper.h"
-#include "audio_policy_criteria_conf.h"
+#include "ParameterManagerWrapperConfig.h"
 #include <ParameterMgrPlatformConnector.h>
 #include <SelectionCriterionTypeInterface.h>
 #include <SelectionCriterionInterface.h>
@@ -38,6 +38,7 @@
 using std::string;
 using std::map;
 using std::vector;
+using CriterionTypes = std::map<std::string, ISelectionCriterionTypeInterface *>;
 
 /// PFW related definitions
 // Logger
@@ -56,16 +57,36 @@
     }
 };
 
-namespace android
-{
+namespace android {
 
 using utilities::convertTo;
 
-namespace audio_policy
-{
+namespace audio_policy {
+
 const char *const ParameterManagerWrapper::mPolicyPfwDefaultConfFileName =
     "/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
 
+static const char *const gInputDeviceCriterionName = "AvailableInputDevices";
+static const char *const gOutputDeviceCriterionName = "AvailableOutputDevices";
+static const char *const gPhoneStateCriterionName = "TelephonyMode";
+static const char *const gOutputDeviceAddressCriterionName = "AvailableOutputDevicesAddresses";
+static const char *const gInputDeviceAddressCriterionName = "AvailableInputDevicesAddresses";
+
+/**
+ * Order MUST be align with defintiion of audio_policy_force_use_t within audio_policy.h
+ */
+static const char *const gForceUseCriterionTag[AUDIO_POLICY_FORCE_USE_CNT] =
+{
+    [AUDIO_POLICY_FORCE_FOR_COMMUNICATION] =        "ForceUseForCommunication",
+    [AUDIO_POLICY_FORCE_FOR_MEDIA] =                "ForceUseForMedia",
+    [AUDIO_POLICY_FORCE_FOR_RECORD] =               "ForceUseForRecord",
+    [AUDIO_POLICY_FORCE_FOR_DOCK] =                 "ForceUseForDock",
+    [AUDIO_POLICY_FORCE_FOR_SYSTEM] =               "ForceUseForSystem",
+    [AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] =    "ForceUseForHdmiSystemAudio",
+    [AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND] =     "ForceUseForEncodedSurround",
+    [AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING] =      "ForceUseForVibrateRinging"
+};
+
 template <>
 struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionInterface> {};
 template <>
@@ -80,15 +101,64 @@
     // Logger
     mPfwConnector->setLogger(mPfwConnectorLogger);
 
-    // Load criteria file
-    if ((loadAudioPolicyCriteriaConfig(gAudioPolicyCriteriaVendorConfFilePath) != NO_ERROR) &&
-        (loadAudioPolicyCriteriaConfig(gAudioPolicyCriteriaConfFilePath) != NO_ERROR)) {
-        ALOGE("%s: Neither vendor conf file (%s) nor system conf file (%s) could be found",
-              __FUNCTION__, gAudioPolicyCriteriaVendorConfFilePath,
-              gAudioPolicyCriteriaConfFilePath);
+    status_t loadResult = loadConfig();
+    if (loadResult < 0) {
+        ALOGE("Policy Wrapper configuration is partially invalid.");
     }
 }
 
+status_t ParameterManagerWrapper::loadConfig()
+{
+    auto result = wrapper_config::parse();
+    if (result.parsedConfig == nullptr) {
+        return -ENOENT;
+    }
+    ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
+
+    CriterionTypes criterionTypes;
+    for (auto criterionType : result.parsedConfig->criterionTypes) {
+        ALOG_ASSERT(criterionTypes.find(criterionType.name) == criterionTypes.end(),
+                          "CriterionType %s already added", criterionType.name.c_str());
+        ALOGV("%s: Adding new criterionType %s", __FUNCTION__, criterionType.name.c_str());
+
+        auto criterionTypePfw =
+                mPfwConnector->createSelectionCriterionType(criterionType.isInclusive);
+
+        for (auto pair : criterionType.valuePairs) {
+            std::string error;
+            ALOGV("%s: Adding pair %d,%s for criterionType %s", __FUNCTION__, pair.first,
+                  pair.second.c_str(), criterionType.name.c_str());
+            criterionTypePfw->addValuePair(pair.first, pair.second, error);
+        }
+        criterionTypes[criterionType.name] = criterionTypePfw;
+    }
+
+    for (auto criterion : result.parsedConfig->criteria) {
+        ALOG_ASSERT(mPolicyCriteria.find(criterion.name) == mPolicyCriteria.end(),
+                    "%s: Criterion %s already added", __FUNCTION__, criterion.name.c_str());
+
+        auto criterionType =
+                getElement<ISelectionCriterionTypeInterface>(criterion.typeName, criterionTypes);
+        ALOG_ASSERT(criterionType != nullptr, "No %s Criterion type found for criterion %s",
+                    criterion.typeName.c_str(), criterion.name.c_str());
+
+        auto criterionPfw = mPfwConnector->createSelectionCriterion(criterion.name, criterionType);
+        mPolicyCriteria[criterion.name] = criterionPfw;
+
+        if (not criterion.defaultLiteralValue.empty()) {
+            int numericalValue = 0;
+            if (not criterionType->getNumericalValue(criterion.defaultLiteralValue.c_str(),
+                                                     numericalValue)) {
+                ALOGE("%s; trying to apply invalid default literal value (%s)", __FUNCTION__,
+                      criterion.defaultLiteralValue.c_str());
+                continue;
+            }
+            criterionPfw->setCriterionState(numericalValue);
+        }
+    }
+    return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
+}
+
 ParameterManagerWrapper::~ParameterManagerWrapper()
 {
     // Unset logger
@@ -112,112 +182,6 @@
     return NO_ERROR;
 }
 
-
-void ParameterManagerWrapper::addCriterionType(const string &typeName, bool isInclusive)
-{
-    ALOG_ASSERT(mPolicyCriterionTypes.find(typeName) == mPolicyCriterionTypes.end(),
-                      "CriterionType %s already added", typeName.c_str());
-    ALOGD("%s: Adding new criterionType %s", __FUNCTION__, typeName.c_str());
-
-    mPolicyCriterionTypes[typeName] = mPfwConnector->createSelectionCriterionType(isInclusive);
-}
-
-void ParameterManagerWrapper::addCriterionTypeValuePair(
-    const string &typeName,
-    uint32_t numericValue,
-    const string &literalValue)
-{
-    ALOG_ASSERT(mPolicyCriterionTypes.find(typeName) != mPolicyCriterionTypes.end(),
-                      "CriterionType %s not found", typeName.c_str());
-    ALOGV("%s: Adding new value pair (%d,%s) for criterionType %s", __FUNCTION__,
-          numericValue, literalValue.c_str(), typeName.c_str());
-    ISelectionCriterionTypeInterface *criterionType = mPolicyCriterionTypes[typeName];
-    std::string error;
-    criterionType->addValuePair(numericValue, literalValue, error);
-}
-
-void ParameterManagerWrapper::loadCriterionType(cnode *root, bool isInclusive)
-{
-    ALOG_ASSERT(root != NULL, "error in parsing file");
-    cnode *node;
-    for (node = root->first_child; node != NULL; node = node->next) {
-
-        ALOG_ASSERT(node != NULL, "error in parsing file");
-        const char *typeName = node->name;
-        char *valueNames = strndup(node->value, strlen(node->value));
-
-        addCriterionType(typeName, isInclusive);
-
-        uint32_t index = 0;
-        char *ctx;
-        char *valueName = strtok_r(valueNames, ",", &ctx);
-        while (valueName != NULL) {
-            if (strlen(valueName) != 0) {
-
-                // Conf file may use or not pair, if no pair, use incremental index, else
-                // use provided index.
-                if (strchr(valueName, ':') != NULL) {
-
-                    char *first = strtok(valueName, ":");
-                    char *second = strtok(NULL, ":");
-                    ALOG_ASSERT((first != NULL) && (strlen(first) != 0) &&
-                                      (second != NULL) && (strlen(second) != 0),
-                                      "invalid value pair");
-
-                    if (!convertTo<string, uint32_t>(first, index)) {
-                        ALOGE("%s: Invalid index(%s) found", __FUNCTION__, first);
-                    }
-                    addCriterionTypeValuePair(typeName, index, second);
-                } else {
-
-                    uint32_t pfwIndex = isInclusive ? 1 << index : index;
-                    addCriterionTypeValuePair(typeName, pfwIndex, valueName);
-                    index += 1;
-                }
-            }
-            valueName = strtok_r(NULL, ",", &ctx);
-        }
-        free(valueNames);
-    }
-}
-
-void ParameterManagerWrapper::loadInclusiveCriterionType(cnode *root)
-{
-    ALOG_ASSERT(root != NULL, "error in parsing file");
-    cnode *node = config_find(root, gInclusiveCriterionTypeTag.c_str());
-    if (node == NULL) {
-        return;
-    }
-    loadCriterionType(node, true);
-}
-
-void ParameterManagerWrapper::loadExclusiveCriterionType(cnode *root)
-{
-    ALOG_ASSERT(root != NULL, "error in parsing file");
-    cnode *node = config_find(root, gExclusiveCriterionTypeTag.c_str());
-    if (node == NULL) {
-        return;
-    }
-    loadCriterionType(node, false);
-}
-
-void ParameterManagerWrapper::parseChildren(cnode *root, string &defaultValue, string &type)
-{
-    ALOG_ASSERT(root != NULL, "error in parsing file");
-    cnode *node;
-    for (node = root->first_child; node != NULL; node = node->next) {
-        ALOG_ASSERT(node != NULL, "error in parsing file");
-
-        if (string(node->name) == gDefaultTag) {
-            defaultValue = node->value;
-        } else if (string(node->name) == gTypeTag) {
-            type = node->value;
-        } else {
-             ALOGE("%s: Unrecognized %s %s node", __FUNCTION__, node->name, node->value);
-        }
-    }
-}
-
 template <typename T>
 T *ParameterManagerWrapper::getElement(const string &name, std::map<string, T *> &elementsMap)
 {
@@ -236,97 +200,6 @@
     return it != elementsMap.end() ? it->second : NULL;
 }
 
-void ParameterManagerWrapper::loadCriteria(cnode *root)
-{
-    ALOG_ASSERT(root != NULL, "error in parsing file");
-    cnode *node = config_find(root, gCriterionTag.c_str());
-
-    if (node == NULL) {
-        ALOGW("%s: no inclusive criteria found", __FUNCTION__);
-        return;
-    }
-    for (node = node->first_child; node != NULL; node = node->next) {
-        loadCriterion(node);
-    }
-}
-
-void ParameterManagerWrapper::addCriterion(const string &name, const string &typeName,
-                              const string &defaultLiteralValue)
-{
-    ALOG_ASSERT(mPolicyCriteria.find(name) == mPolicyCriteria.end(),
-                "Route Criterion %s already added", name.c_str());
-
-    ISelectionCriterionTypeInterface *criterionType =
-            getElement<ISelectionCriterionTypeInterface>(typeName, mPolicyCriterionTypes);
-
-    ISelectionCriterionInterface *criterion =
-            mPfwConnector->createSelectionCriterion(name, criterionType);
-
-    mPolicyCriteria[name] = criterion;
-    int numericalValue = 0;
-    if (!criterionType->getNumericalValue(defaultLiteralValue.c_str(),  numericalValue)) {
-        ALOGE("%s; trying to apply invalid default literal value (%s)", __FUNCTION__,
-              defaultLiteralValue.c_str());
-    }
-    criterion->setCriterionState(numericalValue);
-}
-
-void ParameterManagerWrapper::loadCriterion(cnode *root)
-{
-    ALOG_ASSERT(root != NULL, "error in parsing file");
-    const char *criterionName = root->name;
-
-    ALOG_ASSERT(mPolicyCriteria.find(criterionName) == mPolicyCriteria.end(),
-                      "Criterion %s already added", criterionName);
-
-    string paramKeyName = "";
-    string path = "";
-    string typeName = "";
-    string defaultValue = "";
-
-    parseChildren(root, defaultValue, typeName);
-
-    addCriterion(criterionName, typeName, defaultValue);
-}
-
-void ParameterManagerWrapper::loadConfig(cnode *root)
-{
-    ALOG_ASSERT(root != NULL, "error in parsing file");
-    cnode *node = config_find(root, gPolicyConfTag.c_str());
-    if (node == NULL) {
-        ALOGW("%s: Could not find node for pfw", __FUNCTION__);
-        return;
-    }
-    ALOGD("%s: Loading conf for pfw", __FUNCTION__);
-    loadInclusiveCriterionType(node);
-    loadExclusiveCriterionType(node);
-    loadCriteria(node);
-}
-
-
-status_t ParameterManagerWrapper::loadAudioPolicyCriteriaConfig(const char *path)
-{
-    ALOG_ASSERT(path != NULL, "error in parsing file: empty path");
-    cnode *root;
-    char *data;
-    ALOGD("%s", __FUNCTION__);
-    data = (char *)load_file(path, NULL);
-    if (data == NULL) {
-        return -ENODEV;
-    }
-    root = config_node("", "");
-    ALOG_ASSERT(root != NULL, "Unable to allocate a configuration node");
-    config_load(root, data);
-
-    loadConfig(root);
-
-    config_free(root);
-    free(root);
-    free(data);
-    ALOGD("%s: loaded", __FUNCTION__);
-    return NO_ERROR;
-}
-
 bool ParameterManagerWrapper::isStarted()
 {
     return mPfwConnector && mPfwConnector->isStarted();
@@ -335,9 +208,9 @@
 status_t ParameterManagerWrapper::setPhoneState(audio_mode_t mode)
 {
     ISelectionCriterionInterface *criterion =
-            getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria);
+            getElement<ISelectionCriterionInterface>(gPhoneStateCriterionName, mPolicyCriteria);
     if (criterion == NULL) {
-        ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionTag.c_str());
+        ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionName);
         return BAD_VALUE;
     }
     if (!isValueValidForCriterion(criterion, static_cast<int>(mode))) {
@@ -351,9 +224,9 @@
 audio_mode_t ParameterManagerWrapper::getPhoneState() const
 {
     const ISelectionCriterionInterface *criterion =
-            getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria);
+            getElement<ISelectionCriterionInterface>(gPhoneStateCriterionName, mPolicyCriteria);
     if (criterion == NULL) {
-        ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionTag.c_str());
+        ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionName);
         return AUDIO_MODE_NORMAL;
     }
     return static_cast<audio_mode_t>(criterion->getCriterionState());
@@ -370,7 +243,7 @@
     ISelectionCriterionInterface *criterion =
             getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
     if (criterion == NULL) {
-        ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage].c_str());
+        ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage]);
         return BAD_VALUE;
     }
     if (!isValueValidForCriterion(criterion, static_cast<int>(config))) {
@@ -390,7 +263,7 @@
     const ISelectionCriterionInterface *criterion =
             getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
     if (criterion == NULL) {
-        ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage].c_str());
+        ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage]);
         return AUDIO_POLICY_FORCE_NONE;
     }
     return static_cast<audio_policy_forced_cfg_t>(criterion->getCriterionState());
@@ -404,12 +277,45 @@
     return interface->getLiteralValue(valueToCheck, literalValue);
 }
 
+status_t ParameterManagerWrapper::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+                                                           audio_policy_dev_state_t state)
+{
+    std::string criterionName = audio_is_output_device(devDesc->type()) ?
+                gOutputDeviceAddressCriterionName : gInputDeviceAddressCriterionName;
+
+    ALOGV("%s: device with address %s %s", __FUNCTION__, devDesc->mAddress.string(),
+          state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE? "disconnected" : "connected");
+    ISelectionCriterionInterface *criterion =
+            getElement<ISelectionCriterionInterface>(criterionName, mPolicyCriteria);
+
+    if (criterion == NULL) {
+        ALOGE("%s: no criterion found for %s", __FUNCTION__, criterionName.c_str());
+        return DEAD_OBJECT;
+    }
+
+    auto criterionType = criterion->getCriterionType();
+    int deviceAddressId;
+    if (not criterionType->getNumericalValue(devDesc->address().string(), deviceAddressId)) {
+        ALOGW("%s: unknown device address reported (%s)", __FUNCTION__, devDesc->address().c_str());
+        return BAD_TYPE;
+    }
+    int currentValueMask = criterion->getCriterionState();
+    if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
+        currentValueMask |= deviceAddressId;
+    }
+    else {
+        currentValueMask &= ~deviceAddressId;
+    }
+    criterion->setCriterionState(currentValueMask);
+    return NO_ERROR;
+}
+
 status_t ParameterManagerWrapper::setAvailableInputDevices(audio_devices_t inputDevices)
 {
     ISelectionCriterionInterface *criterion =
-            getElement<ISelectionCriterionInterface>(gInputDeviceCriterionTag, mPolicyCriteria);
+            getElement<ISelectionCriterionInterface>(gInputDeviceCriterionName, mPolicyCriteria);
     if (criterion == NULL) {
-        ALOGE("%s: no criterion found for %s", __FUNCTION__, gInputDeviceCriterionTag.c_str());
+        ALOGE("%s: no criterion found for %s", __FUNCTION__, gInputDeviceCriterionName);
         return DEAD_OBJECT;
     }
     criterion->setCriterionState(inputDevices & ~AUDIO_DEVICE_BIT_IN);
@@ -420,9 +326,9 @@
 status_t ParameterManagerWrapper::setAvailableOutputDevices(audio_devices_t outputDevices)
 {
     ISelectionCriterionInterface *criterion =
-            getElement<ISelectionCriterionInterface>(gOutputDeviceCriterionTag, mPolicyCriteria);
+            getElement<ISelectionCriterionInterface>(gOutputDeviceCriterionName, mPolicyCriteria);
     if (criterion == NULL) {
-        ALOGE("%s: no criterion found for %s", __FUNCTION__, gOutputDeviceCriterionTag.c_str());
+        ALOGE("%s: no criterion found for %s", __FUNCTION__, gOutputDeviceCriterionName);
         return DEAD_OBJECT;
     }
     criterion->setCriterionState(outputDevices);
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapperConfig.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapperConfig.cpp
new file mode 100644
index 0000000..bc6d046
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapperConfig.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::AudioPolicyEngine/PFWWrapperConfig"
+#define LOG_NDEBUG 0
+
+#include "ParameterManagerWrapperConfig.h"
+
+#include <media/convert.h>
+#include <utils/Log.h>
+#include <libxml/parser.h>
+#include <libxml/xinclude.h>
+#include <string>
+#include <vector>
+#include <sstream>
+#include <istream>
+
+
+namespace android {
+
+using utilities::convertTo;
+
+namespace audio_policy {
+namespace wrapper_config {
+namespace detail {
+
+std::string getXmlAttribute(const xmlNode *cur, const char *attribute)
+{
+    xmlChar *xmlValue = xmlGetProp(cur, (const xmlChar *)attribute);
+    if (xmlValue == NULL) {
+        return "";
+    }
+    std::string value((const char *)xmlValue);
+    xmlFree(xmlValue);
+    return value;
+}
+
+template <class Trait>
+static status_t deserializeCollection(_xmlDoc *doc, const _xmlNode *cur,
+                                      typename Trait::Collection &collection,
+                                      size_t &nbSkippedElement)
+{
+    const xmlNode *root = cur->xmlChildrenNode;
+    while (root != NULL) {
+        if (xmlStrcmp(root->name, (const xmlChar *)Trait::collectionTag) &&
+            xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
+            root = root->next;
+            continue;
+        }
+        const xmlNode *child = root;
+        if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {
+            child = child->xmlChildrenNode;
+        }
+        while (child != NULL) {
+            if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
+                status_t status = Trait::deserialize(doc, child, collection);
+                if (status == NO_ERROR) {
+                    nbSkippedElement += 1;
+                }
+            }
+            child = child->next;
+        }
+        if (!xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
+            return NO_ERROR;
+        }
+        root = root->next;
+    }
+    return NO_ERROR;
+}
+
+const char *const ValueTraits::tag = "value";
+const char *const ValueTraits::collectionTag = "values";
+
+const char ValueTraits::Attributes::literal[] = "literal";
+const char ValueTraits::Attributes::numerical[] = "numerical";
+
+status_t ValueTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *child, Collection &values)
+{
+    std::string literal = getXmlAttribute(child, Attributes::literal);
+    if (literal.empty()) {
+        ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::literal);
+        return BAD_VALUE;
+    }
+    uint32_t numerical = 0;
+    std::string numericalTag = getXmlAttribute(child, Attributes::numerical);
+    if (numericalTag.empty()) {
+        ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::literal);
+        return BAD_VALUE;
+    }
+    if (!convertTo(numericalTag, numerical)) {
+        ALOGE("%s: : Invalid value(%s)", __FUNCTION__, numericalTag.c_str());
+        return BAD_VALUE;
+    }
+    values.push_back({numerical, literal});
+    return NO_ERROR;
+}
+
+const char *const CriterionTypeTraits::tag = "criterion_type";
+const char *const CriterionTypeTraits::collectionTag = "criterion_types";
+
+const char CriterionTypeTraits::Attributes::name[] = "name";
+const char CriterionTypeTraits::Attributes::type[] = "type";
+
+status_t CriterionTypeTraits::deserialize(_xmlDoc *doc, const _xmlNode *child,
+                                          Collection &criterionTypes)
+{
+    std::string name = getXmlAttribute(child, Attributes::name);
+    if (name.empty()) {
+        ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::name);
+        return BAD_VALUE;
+    }
+    ALOGV("%s: %s %s = %s", __FUNCTION__, tag, Attributes::name, name.c_str());
+
+    std::string type = getXmlAttribute(child, Attributes::type);
+    if (type.empty()) {
+        ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::type);
+        return BAD_VALUE;
+    }
+    ALOGV("%s: %s %s = %s", __FUNCTION__, tag, Attributes::type, type.c_str());
+    bool isInclusive(type == "inclusive");
+
+    ValuePairs pairs;
+    size_t nbSkippedElements = 0;
+    detail::deserializeCollection<detail::ValueTraits>(doc, child, pairs, nbSkippedElements);
+
+    criterionTypes.push_back({name, isInclusive, pairs});
+    return NO_ERROR;
+}
+
+const char *const CriterionTraits::tag = "criterion";
+const char *const CriterionTraits::collectionTag = "criteria";
+
+const char CriterionTraits::Attributes::name[] = "name";
+const char CriterionTraits::Attributes::type[] = "type";
+const char CriterionTraits::Attributes::defaultVal[] = "default";
+
+status_t CriterionTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *child, Collection &criteria)
+{
+    std::string name = getXmlAttribute(child, Attributes::name);
+    if (name.empty()) {
+        ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::name);
+        return BAD_VALUE;
+    }
+    ALOGV("%s: %s = %s", __FUNCTION__, Attributes::name, name.c_str());
+
+    std::string defaultValue = getXmlAttribute(child, Attributes::defaultVal);
+    if (defaultValue.empty()) {
+        // Not mandatory to provide a default value for a criterion, even it is recommanded...
+        ALOGV("%s: No attribute %s found", __FUNCTION__, Attributes::defaultVal);
+    }
+    ALOGV("%s: %s = %s", __FUNCTION__, Attributes::defaultVal, defaultValue.c_str());
+
+    std::string typeName = getXmlAttribute(child, Attributes::type);
+    if (typeName.empty()) {
+        ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::name);
+        return BAD_VALUE;
+    }
+    ALOGV("%s: %s = %s", __FUNCTION__, Attributes::type, typeName.c_str());
+
+    criteria.push_back({name, typeName, defaultValue});
+    return NO_ERROR;
+}
+} // namespace detail
+
+ParsingResult parse(const char* path) {
+    xmlDocPtr doc;
+    doc = xmlParseFile(path);
+    if (doc == NULL) {
+        ALOGE("%s: Could not parse document %s", __FUNCTION__, path);
+        return {nullptr, 0};
+    }
+    xmlNodePtr cur = xmlDocGetRootElement(doc);
+    if (cur == NULL) {
+        ALOGE("%s: Could not parse: empty document %s", __FUNCTION__, path);
+        xmlFreeDoc(doc);
+        return {nullptr, 0};
+    }
+    if (xmlXIncludeProcess(doc) < 0) {
+        ALOGE("%s: libxml failed to resolve XIncludes on document %s", __FUNCTION__, path);
+        return {nullptr, 0};
+    }
+    size_t nbSkippedElements = 0;
+    auto config = std::make_unique<Config>();
+
+    detail::deserializeCollection<detail::CriterionTraits>(
+                doc, cur, config->criteria, nbSkippedElements);
+    detail::deserializeCollection<detail::CriterionTypeTraits>(
+                doc, cur, config->criterionTypes, nbSkippedElements);
+
+    return {std::move(config), nbSkippedElements};
+}
+
+} // namespace wrapper_config
+} // namespace audio_policy
+} // namespace android
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapperConfig.h b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapperConfig.h
new file mode 100644
index 0000000..467d0e1
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapperConfig.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <utils/Errors.h>
+
+struct _xmlNode;
+struct _xmlDoc;
+
+namespace android {
+namespace audio_policy {
+namespace wrapper_config {
+
+/** Default path of audio policy usages configuration file. */
+constexpr char DEFAULT_PATH[] = "/vendor/etc/policy_wrapper_configuration.xml";
+
+/** Directories where the effect libraries will be search for. */
+constexpr const char* POLICY_USAGE_LIBRARY_PATH[] = {"/odm/etc/", "/vendor/etc/", "/system/etc/"};
+
+using ValuePair = std::pair<uint32_t, std::string>;
+using ValuePairs = std::vector<ValuePair>;
+
+struct CriterionType
+{
+    std::string name;
+    bool isInclusive;
+    ValuePairs valuePairs;
+};
+
+using CriterionTypes = std::vector<CriterionType>;
+
+struct Criterion
+{
+    std::string name;
+    std::string typeName;
+    std::string defaultLiteralValue;
+};
+
+using Criteria = std::vector<Criterion>;
+
+struct Config {
+    float version;
+    Criteria criteria;
+    CriterionTypes criterionTypes;
+};
+
+namespace detail
+{
+struct ValueTraits
+{
+    static const char *const tag;
+    static const char *const collectionTag;
+
+    struct Attributes
+    {
+        static const char literal[];
+        static const char numerical[];
+    };
+
+    typedef ValuePair Element;
+    typedef ValuePair *PtrElement;
+    typedef ValuePairs Collection;
+
+    static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root,
+                                         Collection &collection);
+};
+
+struct CriterionTypeTraits
+{
+    static const char *const tag;
+    static const char *const collectionTag;
+
+    struct Attributes
+    {
+        static const char name[];
+        static const char type[];
+    };
+
+    typedef CriterionType Element;
+    typedef CriterionType *PtrElement;
+    typedef CriterionTypes Collection;
+
+    static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root,
+                                         Collection &collection);
+};
+
+struct CriterionTraits
+{
+    static const char *const tag;
+    static const char *const collectionTag;
+
+    struct Attributes
+    {
+        static const char name[];
+        static const char type[];
+        static const char defaultVal[];
+    };
+
+    typedef Criterion Element;
+    typedef Criterion *PtrElement;
+    typedef Criteria Collection;
+
+    static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root,
+                                         Collection &collection);
+};
+} // namespace detail
+
+/** Result of `parse(const char*)` */
+struct ParsingResult {
+    /** Parsed config, nullptr if the xml lib could not load the file */
+    std::unique_ptr<Config> parsedConfig;
+    size_t nbSkippedElement; //< Number of skipped invalid product strategies
+};
+
+/** Parses the provided audio policy usage configuration.
+ * @return audio policy usage @see Config
+ */
+ParsingResult parse(const char* path = DEFAULT_PATH);
+
+} // namespace wrapper_config
+} // namespace audio_policy
+} // android
diff --git a/services/audiopolicy/engineconfigurable/wrapper/audio_policy_criteria_conf.h b/services/audiopolicy/engineconfigurable/wrapper/audio_policy_criteria_conf.h
deleted file mode 100644
index e4fd176..0000000
--- a/services/audiopolicy/engineconfigurable/wrapper/audio_policy_criteria_conf.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <string>
-#include <system/audio_policy.h>
-
-//////////////////////////////////////////////////////////////////////////////////////////////////
-//      Definitions for audio policy criteria configuration file (audio_policy_criteria.conf)   //
-//                                                                                              //
-//      @TODO: scripted from audio.h & audio_policy,h                                           //
-//////////////////////////////////////////////////////////////////////////////////////////////////
-
-static const char *const gAudioPolicyCriteriaConfFilePath =
-    "/system/etc/audio_policy_criteria.conf";
-static const char *const gAudioPolicyCriteriaVendorConfFilePath =
-    "/vendor/etc/audio_policy_criteria.conf";
-
-/**
- * PFW instances tags
- */
-static const std::string &gPolicyConfTag = "Policy";
-static const std::string &gDefaultTag = "Default";
-static const std::string &gTypeTag = "Type";
-
-/**
- * PFW elements tags
- */
-static const std::string &gInclusiveCriterionTypeTag = "InclusiveCriterionType";
-static const std::string &gExclusiveCriterionTypeTag = "ExclusiveCriterionType";
-static const std::string &gCriterionTag = "Criterion";
-
-/**
- * PFW known criterion tags
- */
-static const std::string &gInputDeviceCriterionTag = "AvailableInputDevices";
-static const std::string &gOutputDeviceCriterionTag = "AvailableOutputDevices";
-static const std::string &gPhoneStateCriterionTag = "TelephonyMode";
-
-/**
- * Order MUST be align with defintiion of audio_policy_force_use_t within audio_policy.h
- */
-static const std::string gForceUseCriterionTag[AUDIO_POLICY_FORCE_USE_CNT] =
-{
-    [AUDIO_POLICY_FORCE_FOR_COMMUNICATION] =        "ForceUseForCommunication",
-    [AUDIO_POLICY_FORCE_FOR_MEDIA] =                "ForceUseForMedia",
-    [AUDIO_POLICY_FORCE_FOR_RECORD] =               "ForceUseForRecord",
-    [AUDIO_POLICY_FORCE_FOR_DOCK] =                 "ForceUseForDock",
-    [AUDIO_POLICY_FORCE_FOR_SYSTEM] =               "ForceUseForSystem",
-    [AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] =    "ForceUseForHdmiSystemAudio",
-    [AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND] =     "ForceUseForEncodedSurround",
-    [AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING] =      "ForceUseForVibrateRinging"
-};
-
-
-
-
-
-
diff --git a/services/audiopolicy/engineconfigurable/wrapper/config/audio_policy_criteria.conf b/services/audiopolicy/engineconfigurable/wrapper/config/audio_policy_criteria.conf
deleted file mode 100644
index 043d5a6..0000000
--- a/services/audiopolicy/engineconfigurable/wrapper/config/audio_policy_criteria.conf
+++ /dev/null
@@ -1,146 +0,0 @@
-################################################################################################
-#
-# @NOTE:
-# Audio Policy Criteria file example for generic device build
-#
-# Any vendor shall have its own configuration within the corresponding device folder
-#
-################################################################################################
-
-#########################################################
-# Criterion type Example:
-# For each criterion, a couple of numerical, literal values must be provided to the PFW.
-# The numerical part is not mandatory. If not filled by the user, a default numerical value will be
-# automatically provided by audio HAL using the following logic:
-#   - Exclusive criterion:
-#          * 0 -> first literal value,
-#          * 1 -> second literal value,
-#               ...
-#          * N -> (N+1)th literal value.
-#   - Inclusive criterion:
-#          * 1 << 0 -> first literal value,
-#          * 1 << 1 -> second literal value,
-#               ...
-#          * 1 << N -> (N+1)th literal value,
-#
-#########################################################
-# Policy {
-#    InclusiveCriterionType|ExclusiveCriterionType {
-#        <Criterion Name>  [numerical value 1:]<literal value 1>,[numerical value 2:]<literal value 2>,<literal value 3>,...
-#    }
-# }
-
-#########################################################
-# Criterion:
-#########################################################
-# Policy {
-#    Criterion {
-#        <Criterion Name> {
-#            Type            <Criterion type name>
-#            Default         <default value of the criterion>
-#        }
-#    }
-# }
-
-Policy {
-    InclusiveCriterionType {
-        #
-        # DO NOT CHANGE ORDER. This definition must be aligned with the definition of
-        # AUDIO_DEVICE_OUT_* within <system/audio.h> file of android.
-        #
-        OutputDevicesMaskType   Earpiece,Speaker,WiredHeadset,WiredHeadphone,BluetoothSco,BluetoothScoHeadset,BluetoothScoCarkit,BluetoothA2dp,BluetoothA2dpHeadphones,BluetoothA2dpSpeaker,Hdmi,AnlgDockHeadset,DgtlDockHeadset,UsbAccessory,UsbDevice,RemoteSubmix,TelephonyTx,Line,HdmiArc,Spdif,Fm,AuxLine,SpeakerSafe
-        #
-        # DO NOT CHANGE ORDER. This definition must be aligned with the definition of
-        # AUDIO_DEVICE_IN_* within <system/audio.h> file of android.
-        # Note also that direction bit will be decimated by AudioHAL in order to allow using a mask
-        # with the cardinality of 1 between a bit and an input device.
-        #
-        InputDevicesMaskType    Communication,Ambient,BuiltinMic,BluetoothScoHeadset,WiredHeadset,Hdmi,TelephonyRx,BackMic,RemoteSubmix,AnlgDockHeadset,DgtlDockHeadset,UsbAccessory,UsbDevice,FmTuner,TvTune,Line,Spdif,BluetoothA2dp,Loopback
-    }
-    ExclusiveCriterionType {
-        #
-        # The values of the mode MUST be aligned with the definition of the audio_mode_t
-        # from system/audio.h
-        #
-        AndroidModeType     0:Normal,1:RingTone,2:InCall,3:InCommunication
-        #
-        # The values of the mode MUST be aligned with the definition of the
-        # audio_policy_forced_config_t from system/audio.h
-        #
-        ForceUseForCommunicationType    0:ForceNone,1:ForceSpeaker,3:ForceBtSco
-        #
-        # The values of the mode MUST be aligned with the definition of the
-        # audio_policy_forced_config_t from system/audio.h
-        #
-        ForceUseForMediaType            0:ForceNone,1:ForceSpeaker,2:ForceHeadphones,4:ForceBtA2dp,5:ForceWiredAccessory,8:ForceAnalogDock,9:ForceDigitalDock,10:ForceNoBtA2dp
-        #
-        # The values of the mode MUST be aligned with the definition of the
-        # audio_policy_forced_config_t from system/audio.h
-        #
-        ForceUseForRecordType           0:ForceNone,3:ForceBtSco,5:ForceWiredAccessory
-        #
-        # The values of the mode MUST be aligned with the definition of the
-        # audio_policy_forced_config_t from system/audio.h
-        #
-        ForceUseForDockType             0:ForceNone,5:ForceWiredAccessory,6:ForceBtCarDock,7:ForceBtDeskDock,8:ForceAnalogDock,9:ForceDigitalDock
-        #
-        # The values of the mode MUST be aligned with the definition of the
-        # audio_policy_forced_config_t from system/audio.h
-        #
-        ForceUseForSystemType           0:ForceNone,11:ForceSystemEnforced
-        #
-        # The values of the mode MUST be aligned with the definition of the
-        # audio_policy_forced_config_t from system/audio.h
-        #
-        ForceUseForHdmiSystemAudioType  0:ForceNone,12:ForceHdmiSystemEnforced
-        #
-        # The values of the mode MUST be aligned with the definition of the
-        # audio_policy_forced_config_t from system/audio_policy.h
-        #
-        ForceUseForEncodedSurroundType  0:ForceNone,13:ForceEncodedSurroundNever,14:ForceEncodedSurroundAlways
-    }
-
-    Criterion {
-        AvailableInputDevices {
-            Type            InputDevicesMaskType
-            Default         none
-        }
-        AvailableOutputDevices {
-            Type            OutputDevicesMaskType
-            Default         none
-        }
-        TelephonyMode {
-            Type            AndroidModeType
-            Default         Normal
-        }
-        ForceUseForCommunication {
-            Type            ForceUseForCommunicationType
-            Default         ForceNone
-        }
-        ForceUseForMedia {
-            Type            ForceUseForMediaType
-            Default         ForceNone
-        }
-        ForceUseForRecord {
-            Type            ForceUseForRecordType
-            Default         ForceNone
-        }
-        ForceUseForDock {
-            Type            ForceUseForDockType
-            Default         ForceNone
-        }
-        ForceUseForSystem {
-            Type            ForceUseForSystemType
-            Default         ForceNone
-        }
-        ForceUseForHdmiSystemAudio {
-            Type            ForceUseForHdmiSystemAudioType
-            Default         ForceNone
-        }
-        ForceUseForEncodedSurround {
-            Type            ForceUseForEncodedSurroundType
-            Default         ForceNone
-        }
-    }
-}
-
diff --git a/services/audiopolicy/engineconfigurable/wrapper/config/policy_criteria.xml b/services/audiopolicy/engineconfigurable/wrapper/config/policy_criteria.xml
new file mode 100644
index 0000000..ec82b2e
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/wrapper/config/policy_criteria.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+<criteria>
+    <criterion name="AvailableInputDevices" type="InputDevicesMaskType" default="none"/>
+    <criterion name="AvailableOutputDevices" type="OutputDevicesMaskType" default="none"/>
+    <criterion name="AvailableOutputDevicesAddresses" type="OutputDevicesAddressesType" default="none"/>
+    <criterion name="AvailableInputDevicesAddresses" type="InputDevicesAddressesType" default="none"/>
+    <criterion name="TelephonyMode" type="AndroidModeType" default="Normal"/>
+    <criterion name="ForceUseForCommunication" type="ForceUseForCommunicationType" default="ForceNone"/>
+    <criterion name="ForceUseForMedia" type="ForceUseForMediaType" default="ForceNone"/>
+    <criterion name="ForceUseForRecord" type="ForceUseForRecordType" default="ForceNone"/>
+    <criterion name="ForceUseForDock" type="ForceUseForDockType" default="ForceNone"/>
+    <criterion name="ForceUseForSystem" type="ForceUseForSystemType" default="ForceNone"/>
+    <criterion name="ForceUseForHdmiSystemAudio" type="ForceUseForHdmiSystemAudioType" default="ForceNone"/>
+    <criterion name="ForceUseForEncodedSurround" type="ForceUseForEncodedSurroundType" default="ForceNone"/>
+    <criterion name="ForceUseForVibrateRinging" type="ForceUseForVibrateRingingType" default="ForceNone"/>
+</criteria>
diff --git a/services/audiopolicy/engineconfigurable/wrapper/config/policy_criterion_types.xml.in b/services/audiopolicy/engineconfigurable/wrapper/config/policy_criterion_types.xml.in
new file mode 100644
index 0000000..6cb799f
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/wrapper/config/policy_criterion_types.xml.in
@@ -0,0 +1,91 @@
+<?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.
+-->
+<criterion_types>
+    <criterion_type name="OutputDevicesMaskType" type="inclusive"/>
+    <criterion_type name="InputDevicesMaskType" type="inclusive"/>
+    <criterion_type name="OutputDevicesAddressesType" type="inclusive"/>
+    <criterion_type name="InputDevicesAddressesType" type="inclusive"/>
+    <criterion_type name="AndroidModeType" type="exclusive"/>
+    <criterion_type name="BooleanType" type="exclusive">
+        <values>
+            <value literal="False" numerical="0"/>
+            <value literal="True" numerical="1"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForCommunicationType" type="exclusive">
+        <values>
+            <value literal="ForceNone" numerical="0"/>
+            <value literal="ForceSpeaker" numerical="1"/>
+            <value literal="ForceBtSco" numerical="3"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForMediaType" type="exclusive">
+        <values>
+            <value literal="ForceNone" numerical="0"/>
+            <value literal="ForceSpeaker" numerical="1"/>
+            <value literal="ForceHeadphones" numerical="2"/>
+            <value literal="ForceBtA2dp" numerical="4"/>
+            <value literal="ForceWiredAccessory" numerical="5"/>
+            <value literal="ForceAnalogDock" numerical="8"/>
+            <value literal="ForceDigitalDock" numerical="9"/>
+            <value literal="ForceNoBtA2dp" numerical="10"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForRecordType" type="exclusive">
+        <values>
+            <value literal="ForceNone" numerical="0"/>
+            <value literal="ForceBtSco" numerical="3"/>
+            <value literal="ForceWiredAccessory" numerical="5"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForDockType" type="exclusive">
+        <values>
+            <value literal="ForceNone" numerical="0"/>
+            <value literal="ForceWiredAccessory" numerical="5"/>
+            <value literal="ForceBtCarDock" numerical="6"/>
+            <value literal="ForceBtDeskDock" numerical="7"/>
+            <value literal="ForceAnalogDock" numerical="8"/>
+            <value literal="ForceDigitalDock" numerical="9"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForSystemType" type="exclusive" >
+        <values>
+            <value literal="ForceNone" numerical="0"/>
+            <value literal="ForceSystemEnforced" numerical="11"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForHdmiSystemAudioType" type="exclusive">
+        <values>
+            <value literal="ForceNone" numerical="0"/>
+            <value literal="ForceHdmiSystemEnforced" numerical="12"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForEncodedSurroundType" type="exclusive">
+        <values>
+            <value literal="ForceNone" numerical="0"/>
+            <value literal="ForceEncodedSurroundNever" numerical="13"/>
+            <value literal="ForceEncodedSurroundAlways" numerical="14"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForVibrateRingingType" type="exclusive">
+        <values>
+            <value literal="ForceNone" numerical="0"/>
+            <value literal="ForceBtSco" numerical="3"/>
+        </values>
+    </criterion_type>
+</criterion_types>
+
+
diff --git a/services/audiopolicy/engineconfigurable/wrapper/config/policy_wrapper_configuration.xml b/services/audiopolicy/engineconfigurable/wrapper/config/policy_wrapper_configuration.xml
new file mode 100644
index 0000000..5d9193b
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/wrapper/config/policy_wrapper_configuration.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- 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.
+-->
+<!--
+    These are the minimum required criteria to be used by Audio HAL to ensure a basic
+    user experience on an Android device
+-->
+<configuration name="audio_policy_wrapper_configuration" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+    <xi:include href="policy_criterion_types.xml"/>
+    <xi:include href="policy_criteria.xml"/>
+
+</configuration>
diff --git a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
index 4c1acfe..1a634a1 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
@@ -16,10 +16,15 @@
 
 #pragma once
 
+#include <AudioGain.h>
+#include <AudioPort.h>
+#include <HwModule.h>
+#include <DeviceDescriptor.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
 #include <utils/Errors.h>
 #include <utils/RWLock.h>
+#include <utils/RefBase.h>
 #include <list>
 #include <map>
 #include <string>
@@ -27,27 +32,17 @@
 
 class CParameterMgrPlatformConnector;
 class ISelectionCriterionInterface;
-class ISelectionCriterionTypeInterface;
 struct cnode;
 
 class ParameterMgrPlatformConnectorLogger;
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
 
 class ParameterManagerWrapper
 {
 private:
-    typedef std::pair<int, const char *> CriterionTypeValuePair;
-
-    typedef std::map<std::string, ISelectionCriterionInterface *> CriterionCollection;
-    typedef std::map<std::string, ISelectionCriterionTypeInterface *> CriterionTypeCollection;
-    typedef CriterionCollection::iterator CriterionMapIterator;
-    typedef CriterionCollection::const_iterator CriterionMapConstIterator;
-    typedef CriterionTypeCollection::iterator CriterionTypeMapIterator;
-    typedef CriterionTypeCollection::const_iterator CriteriaTypeMapConstIterator;
+    using Criteria = std::map<std::string, ISelectionCriterionInterface *>;
 
 public:
     ParameterManagerWrapper();
@@ -120,6 +115,9 @@
      */
     status_t setAvailableOutputDevices(audio_devices_t outputDevices);
 
+    status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+                                      audio_policy_dev_state_t state);
+
 private:
     /**
      * Apply the configuration of the platform on the policy parameter manager.
@@ -136,93 +134,11 @@
     /**
      * Load the criterion configuration file.
      *
-     * @param[in] path Criterion conf file path.
-     *
      * @return NO_ERROR is parsing successful, error code otherwise.
      */
-    status_t loadAudioPolicyCriteriaConfig(const char *path);
+    status_t loadConfig();
 
-    /**
-     * Add a criterion type to AudioPolicyPfw.
-     *
-     * @param[in] typeName of the PFW criterion type.
-     * @param[in] isInclusive attribute of the criterion type.
-     */
-    void addCriterionType(const std::string &typeName, bool isInclusive);
-
-    /**
-     * Add a criterion type value pair to AudioPolicyPfw.
-     *
-     * @param[in] typeName criterion type name to which this value pair is added to.
-     * @param[in] numeric part of the value pair.
-     * @param[in] literal part of the value pair.
-     */
-    void addCriterionTypeValuePair(const std::string &typeName, uint32_t numeric,
-                                   const std::string &literal);
-
-    /**
-     * Add a criterion to AudioPolicyPfw.
-     *
-     * @param[in] name of the PFW criterion.
-     * @param[in] typeName criterion type name to which this criterion is associated to.
-     * @param[in] defaultLiteralValue of the PFW criterion.
-     */
-    void addCriterion(const std::string &name,
-                      const std::string &typeName,
-                      const std::string &defaultLiteralValue);
-    /**
-     * Parse and load the inclusive criterion type from configuration file.
-     *
-     * @param[in] root node of the configuration file.
-     */
-    void loadInclusiveCriterionType(cnode *root);
-
-    /**
-     * Parse and load the exclusive criterion type from configuration file.
-     *
-     * @param[in] root node of the configuration file.
-     */
-    void loadExclusiveCriterionType(cnode *root);
-
-    /**
-     * Parse and load the criteria from configuration file.
-     *
-     * @param[in] root node of the configuration file.
-     */
-    void loadCriteria(cnode *root);
-
-    /**
-     * Parse and load a criterion from configuration file.
-     *
-     * @param[in] root node of the configuration file.
-     */
-    void loadCriterion(cnode *root);
-
-    /**
-     * Parse and load the criterion types from configuration file.
-     *
-     * @param[in] root node of the configuration file
-     * @param[in] isInclusive true if inclusive, false is exclusive.
-     */
-    void loadCriterionType(cnode *root, bool isInclusive);
-
-    /**
-     * Load the configuration file.
-     *
-     * @param[in] root node of the configuration file.
-     */
-    void loadConfig(cnode *root);
-
-    /**
-     * Parse and load the chidren node from a given root node.
-     *
-     * @param[in] root node of the configuration file
-     * @param[out] defaultValue of the parameter manager element to retrieve.
-     * @param[out] type of the parameter manager element to retrieve.
-    */
-    void parseChildren(cnode *root, std::string &defaultValue, std::string &type);
-
-    /**
+     /**
      * Retrieve an element from a map by its name.
      *
      * @tparam T type of element to search.
@@ -266,8 +182,7 @@
 
     bool isValueValidForCriterion(ISelectionCriterionInterface *criterion, int valueToCheck);
 
-    CriterionTypeCollection mPolicyCriterionTypes; /**< Policy Criterion Type map. */
-    CriterionCollection mPolicyCriteria; /**< Policy Criterion Map. */
+    Criteria mPolicyCriteria; /**< Policy Criterion Map. */
 
     CParameterMgrPlatformConnector *mPfwConnector; /**< Policy Parameter Manager connector. */
     ParameterMgrPlatformConnectorLogger *mPfwConnectorLogger; /**< Policy PFW logger. */
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 69395f3..3d68cd8 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -322,7 +322,7 @@
             // a primary device
             // FIXME: this is not the right way of solving this problem
             audio_devices_t availPrimaryOutputDevices =
-                (primaryOutput->supportedDevices() | AUDIO_DEVICE_OUT_HEARING_AID) &
+                (primaryOutput->supportedDevices().types() | AUDIO_DEVICE_OUT_HEARING_AID) &
                 availableOutputDevices.types();
 
             if (((availableInputDevices.types() &
@@ -475,7 +475,7 @@
             // compressed format as they would likely not be mixed and dropped.
             for (size_t i = 0; i < outputs.size(); i++) {
                 sp<AudioOutputDescriptor> desc = outputs.valueAt(i);
-                audio_devices_t devices = desc->device() &
+                audio_devices_t devices = desc->devices().types() &
                     (AUDIO_DEVICE_OUT_HDMI | AUDIO_DEVICE_OUT_SPDIF | AUDIO_DEVICE_OUT_HDMI_ARC);
                 if (desc->isActive() && !audio_is_linear_pcm(desc->mFormat) &&
                         devices != AUDIO_DEVICE_NONE) {
@@ -631,6 +631,7 @@
         case AUDIO_SOURCE_UNPROCESSED:
         case AUDIO_SOURCE_HOTWORD:
         case AUDIO_SOURCE_CAMCORDER:
+        case AUDIO_SOURCE_VOICE_PERFORMANCE:
             inputSource = AUDIO_SOURCE_VOICE_COMMUNICATION;
             break;
         default:
@@ -737,16 +738,32 @@
             device = AUDIO_DEVICE_IN_VOICE_CALL;
         }
         break;
+    case AUDIO_SOURCE_VOICE_PERFORMANCE:
+        if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
+            device = AUDIO_DEVICE_IN_USB_HEADSET;
+        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
+            device = AUDIO_DEVICE_IN_USB_DEVICE;
+        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+        }
+        break;
     case AUDIO_SOURCE_REMOTE_SUBMIX:
         if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
             device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
         }
         break;
-     case AUDIO_SOURCE_FM_TUNER:
+    case AUDIO_SOURCE_FM_TUNER:
         if (availableDeviceTypes & AUDIO_DEVICE_IN_FM_TUNER) {
             device = AUDIO_DEVICE_IN_FM_TUNER;
         }
         break;
+    case AUDIO_SOURCE_ECHO_REFERENCE:
+        if (availableDeviceTypes & AUDIO_DEVICE_IN_ECHO_REFERENCE) {
+            device = AUDIO_DEVICE_IN_ECHO_REFERENCE;
+        }
+        break;
     default:
         ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
         break;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index aa205f0..5c8a799 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -88,36 +88,39 @@
     return status;
 }
 
-void AudioPolicyManager::broadcastDeviceConnectionState(audio_devices_t device,
-                                                        audio_policy_dev_state_t state,
-                                                        const String8 &device_address)
+void AudioPolicyManager::broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
+                                                        audio_policy_dev_state_t state)
 {
-    AudioParameter param(device_address);
+    AudioParameter param(device->address());
     const String8 key(state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE ?
                 AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect);
-    param.addInt(key, device);
+    param.addInt(key, device->type());
     mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString());
 }
 
-status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device,
+status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t deviceType,
                                                          audio_policy_dev_state_t state,
                                                          const char *device_address,
                                                          const char *device_name)
 {
     ALOGV("setDeviceConnectionStateInt() device: 0x%X, state %d, address %s name %s",
-            device, state, device_address, device_name);
+            deviceType, state, device_address, device_name);
 
     // connect/disconnect only 1 device at a time
-    if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
+    if (!audio_is_output_device(deviceType) && !audio_is_input_device(deviceType)) return BAD_VALUE;
 
-    sp<DeviceDescriptor> devDesc =
-            mHwModules.getDeviceDescriptor(device, device_address, device_name);
+    sp<DeviceDescriptor> device =
+            mHwModules.getDeviceDescriptor(deviceType, device_address, device_name,
+                                           state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+    if (device == 0) {
+        return INVALID_OPERATION;
+    }
 
     // handle output devices
-    if (audio_is_output_device(device)) {
+    if (audio_is_output_device(deviceType)) {
         SortedVector <audio_io_handle_t> outputs;
 
-        ssize_t index = mAvailableOutputDevices.indexOf(devDesc);
+        ssize_t index = mAvailableOutputDevices.indexOf(device);
 
         // save a copy of the opened output descriptors before any output is opened or closed
         // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies()
@@ -127,70 +130,60 @@
         // handle output device connection
         case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: {
             if (index >= 0) {
-                ALOGW("setDeviceConnectionState() device already connected: %x", device);
+                ALOGW("%s() device already connected: %s", __func__, device->toString().c_str());
                 return INVALID_OPERATION;
             }
-            ALOGV("setDeviceConnectionState() connecting device %x", device);
+            ALOGV("%s() connecting device %s", __func__, device->toString().c_str());
 
             // register new device as available
-            index = mAvailableOutputDevices.add(devDesc);
-            if (index >= 0) {
-                sp<HwModule> module = mHwModules.getModuleForDevice(device);
-                if (module == 0) {
-                    ALOGD("setDeviceConnectionState() could not find HW module for device %08x",
-                          device);
-                    mAvailableOutputDevices.remove(devDesc);
-                    return INVALID_OPERATION;
-                }
-                mAvailableOutputDevices[index]->attach(module);
-            } else {
+            if (mAvailableOutputDevices.add(device) < 0) {
                 return NO_MEMORY;
             }
 
             // Before checking outputs, broadcast connect event to allow HAL to retrieve dynamic
             // parameters on newly connected devices (instead of opening the outputs...)
-            broadcastDeviceConnectionState(device, state, devDesc->address());
+            broadcastDeviceConnectionState(device, state);
 
-            if (checkOutputsForDevice(devDesc, state, outputs, devDesc->address()) != NO_ERROR) {
-                mAvailableOutputDevices.remove(devDesc);
+            if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) {
+                mAvailableOutputDevices.remove(device);
 
-                broadcastDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
-                                               devDesc->address());
+                mHwModules.cleanUpForDevice(device);
+
+                broadcastDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
                 return INVALID_OPERATION;
             }
             // Propagate device availability to Engine
-            mEngine->setDeviceConnectionState(devDesc, state);
+            mEngine->setDeviceConnectionState(device, state);
 
             // outputs should never be empty here
             ALOG_ASSERT(outputs.size() != 0, "setDeviceConnectionState():"
                     "checkOutputsForDevice() returned no outputs but status OK");
-            ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs",
-                  outputs.size());
+            ALOGV("%s() checkOutputsForDevice() returned %zu outputs", __func__, outputs.size());
 
             } break;
         // handle output device disconnection
         case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: {
             if (index < 0) {
-                ALOGW("setDeviceConnectionState() device not connected: %x", device);
+                ALOGW("%s() device not connected: %s", __func__, device->toString().c_str());
                 return INVALID_OPERATION;
             }
 
-            ALOGV("setDeviceConnectionState() disconnecting output device %x", device);
+            ALOGV("%s() disconnecting output device %s", __func__, device->toString().c_str());
 
             // Send Disconnect to HALs
-            broadcastDeviceConnectionState(device, state, devDesc->address());
+            broadcastDeviceConnectionState(device, state);
 
             // remove device from available output devices
-            mAvailableOutputDevices.remove(devDesc);
+            mAvailableOutputDevices.remove(device);
 
-            checkOutputsForDevice(devDesc, state, outputs, devDesc->address());
+            checkOutputsForDevice(device, state, outputs);
 
             // Propagate device availability to Engine
-            mEngine->setDeviceConnectionState(devDesc, state);
+            mEngine->setDeviceConnectionState(device, state);
             } break;
 
         default:
-            ALOGE("setDeviceConnectionState() invalid state: %x", state);
+            ALOGE("%s() invalid state: %x", __func__, state);
             return BAD_VALUE;
         }
 
@@ -199,8 +192,8 @@
             if (!outputs.isEmpty()) {
                 for (audio_io_handle_t output : outputs) {
                     sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output);
-                    // close unused outputs after device disconnection or direct outputs that have been
-                    // opened by checkOutputsForDevice() to query dynamic parameters
+                    // close unused outputs after device disconnection or direct outputs that have
+                    // been opened by checkOutputsForDevice() to query dynamic parameters
                     if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) ||
                             (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
                              (desc->mDirectOpenCount == 0))) {
@@ -214,29 +207,28 @@
         });
 
         if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
-            audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
-            updateCallRouting(newDevice);
+            DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, false /*fromCache*/);
+            updateCallRouting(newDevices);
         }
-        const audio_devices_t msdOutDevice = getModuleDeviceTypes(
-                mAvailableOutputDevices, AUDIO_HARDWARE_MODULE_ID_MSD);
+        const DeviceVector msdOutDevices = getMsdAudioOutDevices();
         for (size_t i = 0; i < mOutputs.size(); i++) {
             sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
             if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (desc != mPrimaryOutput)) {
-                audio_devices_t newDevice = getNewOutputDevice(desc, true /*fromCache*/);
+                DeviceVector newDevices = getNewOutputDevices(desc, true /*fromCache*/);
                 // do not force device change on duplicated output because if device is 0, it will
                 // also force a device 0 for the two outputs it is duplicated to which may override
                 // a valid device selection on those outputs.
-                bool force = (msdOutDevice == AUDIO_DEVICE_NONE || msdOutDevice != desc->device())
+                bool force = (msdOutDevices.isEmpty() || msdOutDevices != desc->devices())
                         && !desc->isDuplicated()
-                        && (!device_distinguishes_on_address(device)
+                        && (!device_distinguishes_on_address(deviceType)
                                 // always force when disconnecting (a non-duplicated device)
                                 || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
-                setOutputDevice(desc, newDevice, force, 0);
+                setOutputDevices(desc, newDevices, force, 0);
             }
         }
 
         if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
-            cleanUpForDevice(devDesc);
+            cleanUpForDevice(device);
         }
 
         mpClientInterface->onAudioPortListUpdate();
@@ -244,67 +236,59 @@
     }  // end if is output device
 
     // handle input devices
-    if (audio_is_input_device(device)) {
+    if (audio_is_input_device(deviceType)) {
         SortedVector <audio_io_handle_t> inputs;
 
-        ssize_t index = mAvailableInputDevices.indexOf(devDesc);
+        ssize_t index = mAvailableInputDevices.indexOf(device);
         switch (state)
         {
         // handle input device connection
         case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: {
             if (index >= 0) {
-                ALOGW("setDeviceConnectionState() device already connected: %d", device);
+                ALOGW("%s() device already connected: %s", __func__, device->toString().c_str());
                 return INVALID_OPERATION;
             }
-            sp<HwModule> module = mHwModules.getModuleForDevice(device);
-            if (module == NULL) {
-                ALOGW("setDeviceConnectionState(): could not find HW module for device %08x",
-                      device);
-                return INVALID_OPERATION;
-            }
-
             // Before checking intputs, broadcast connect event to allow HAL to retrieve dynamic
             // parameters on newly connected devices (instead of opening the inputs...)
-            broadcastDeviceConnectionState(device, state, devDesc->address());
+            broadcastDeviceConnectionState(device, state);
 
-            if (checkInputsForDevice(devDesc, state, inputs, devDesc->address()) != NO_ERROR) {
-                broadcastDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
-                                               devDesc->address());
+            if (checkInputsForDevice(device, state, inputs) != NO_ERROR) {
+                broadcastDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
+
+                mHwModules.cleanUpForDevice(device);
+
                 return INVALID_OPERATION;
             }
 
-            index = mAvailableInputDevices.add(devDesc);
-            if (index >= 0) {
-                mAvailableInputDevices[index]->attach(module);
-            } else {
+            if (mAvailableInputDevices.add(device) < 0) {
                 return NO_MEMORY;
             }
 
             // Propagate device availability to Engine
-            mEngine->setDeviceConnectionState(devDesc, state);
+            mEngine->setDeviceConnectionState(device, state);
         } break;
 
         // handle input device disconnection
         case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: {
             if (index < 0) {
-                ALOGW("setDeviceConnectionState() device not connected: %d", device);
+                ALOGW("%s() device not connected: %s", __func__, device->toString().c_str());
                 return INVALID_OPERATION;
             }
 
-            ALOGV("setDeviceConnectionState() disconnecting input device %x", device);
+            ALOGV("%s() disconnecting input device %s", __func__, device->toString().c_str());
 
             // Set Disconnect to HALs
-            broadcastDeviceConnectionState(device, state, devDesc->address());
+            broadcastDeviceConnectionState(device, state);
 
-            checkInputsForDevice(devDesc, state, inputs, devDesc->address());
-            mAvailableInputDevices.remove(devDesc);
+            checkInputsForDevice(device, state, inputs);
+            mAvailableInputDevices.remove(device);
 
             // Propagate device availability to Engine
-            mEngine->setDeviceConnectionState(devDesc, state);
+            mEngine->setDeviceConnectionState(device, state);
         } break;
 
         default:
-            ALOGE("setDeviceConnectionState() invalid state: %x", state);
+            ALOGE("%s() invalid state: %x", __func__, state);
             return BAD_VALUE;
         }
 
@@ -314,19 +298,19 @@
         updateDevicesAndOutputs();
 
         if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
-            audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
-            updateCallRouting(newDevice);
+            DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, false /*fromCache*/);
+            updateCallRouting(newDevices);
         }
 
         if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
-            cleanUpForDevice(devDesc);
+            cleanUpForDevice(device);
         }
 
         mpClientInterface->onAudioPortListUpdate();
         return NO_ERROR;
     } // end if is input device
 
-    ALOGW("setDeviceConnectionState() invalid device: %x", device);
+    ALOGW("%s() invalid device: %s", __func__, device->toString().c_str());
     return BAD_VALUE;
 }
 
@@ -334,7 +318,7 @@
                                                                       const char *device_address)
 {
     sp<DeviceDescriptor> devDesc =
-            mHwModules.getDeviceDescriptor(device, device_address, "",
+            mHwModules.getDeviceDescriptor(device, device_address, "", false /* allowToCreate */,
                                            (strlen(device_address) != 0)/*matchAddress*/);
 
     if (devDesc == 0) {
@@ -350,7 +334,7 @@
     } else if (audio_is_input_device(device)) {
         deviceVector = &mAvailableInputDevices;
     } else {
-        ALOGW("getDeviceConnectionState() invalid device type %08x", device);
+        ALOGW("%s() invalid device type %08x", __func__, device);
         return AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
     }
 
@@ -376,8 +360,7 @@
     // Check if the device is currently connected
     sp<DeviceDescriptor> devDesc =
             mHwModules.getDeviceDescriptor(device, device_address, device_name);
-    ssize_t index = mAvailableOutputDevices.indexOf(devDesc);
-    if (index < 0) {
+    if (devDesc == 0 || mAvailableOutputDevices.indexOf(devDesc) < 0) {
         // Nothing to do: device is not connected
         return NO_ERROR;
     }
@@ -425,16 +408,20 @@
     return NO_ERROR;
 }
 
-uint32_t AudioPolicyManager::updateCallRouting(audio_devices_t rxDevice, uint32_t delayMs)
+uint32_t AudioPolicyManager::updateCallRouting(const DeviceVector &rxDevices, uint32_t delayMs)
 {
     bool createTxPatch = false;
     uint32_t muteWaitMs = 0;
 
-    if(!hasPrimaryOutput() || mPrimaryOutput->device() == AUDIO_DEVICE_OUT_STUB) {
+    if(!hasPrimaryOutput() || mPrimaryOutput->devices().types() == AUDIO_DEVICE_OUT_STUB) {
         return muteWaitMs;
     }
-    audio_devices_t txDevice = getDeviceAndMixForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
-    ALOGV("updateCallRouting device rxDevice %08x txDevice %08x", rxDevice, txDevice);
+    ALOG_ASSERT(!rxDevices.isEmpty(), "updateCallRouting() no selected output device");
+
+    audio_attributes_t attr = { .source = AUDIO_SOURCE_VOICE_COMMUNICATION };
+    auto txDevice = getDeviceAndMixForAttributes(attr);
+    ALOGV("updateCallRouting device rxDevice %s txDevice %s", 
+          rxDevices.toString().c_str(), txDevice->toString().c_str());
 
     // release existing RX patch if any
     if (mCallRxPatch != 0) {
@@ -450,16 +437,15 @@
     // If the RX device is on the primary HW module, then use legacy routing method for voice calls
     // via setOutputDevice() on primary output.
     // Otherwise, create two audio patches for TX and RX path.
-    if (availablePrimaryOutputDevices() & rxDevice) {
-        muteWaitMs = setOutputDevice(mPrimaryOutput, rxDevice, true, delayMs);
+    if (availablePrimaryOutputDevices().contains(rxDevices.itemAt(0))) {
+        muteWaitMs = setOutputDevices(mPrimaryOutput, rxDevices, true, delayMs);
         // If the TX device is also on the primary HW module, setOutputDevice() will take care
         // of it due to legacy implementation. If not, create a patch.
-        if ((availablePrimaryInputDevices() & txDevice & ~AUDIO_DEVICE_BIT_IN)
-                == AUDIO_DEVICE_NONE) {
+        if (!availablePrimaryModuleInputDevices().contains(txDevice)) {
             createTxPatch = true;
         }
     } else { // create RX path audio patch
-        mCallRxPatch = createTelephonyPatch(true /*isRx*/, rxDevice, delayMs);
+        mCallRxPatch = createTelephonyPatch(true /*isRx*/, rxDevices.itemAt(0), delayMs);
         createTxPatch = true;
     }
     if (createTxPatch) { // create TX path audio patch
@@ -470,26 +456,31 @@
 }
 
 sp<AudioPatch> AudioPolicyManager::createTelephonyPatch(
-        bool isRx, audio_devices_t device, uint32_t delayMs) {
+        bool isRx, const sp<DeviceDescriptor> &device, uint32_t delayMs) {
     PatchBuilder patchBuilder;
 
-    sp<DeviceDescriptor> txSourceDeviceDesc;
+    if (device == nullptr) {
+        return nullptr;
+    }
     if (isRx) {
-        patchBuilder.addSink(findDevice(mAvailableOutputDevices, device)).
-                addSource(findDevice(mAvailableInputDevices, AUDIO_DEVICE_IN_TELEPHONY_RX));
+        patchBuilder.addSink(device).
+                addSource(mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_TELEPHONY_RX));
     } else {
-        patchBuilder.addSource(txSourceDeviceDesc = findDevice(mAvailableInputDevices, device)).
-                addSink(findDevice(mAvailableOutputDevices, AUDIO_DEVICE_OUT_TELEPHONY_TX));
+        patchBuilder.addSource(device).
+                addSink(mAvailableOutputDevices.getDevice(AUDIO_DEVICE_OUT_TELEPHONY_TX));
     }
 
-    audio_devices_t outputDevice = isRx ? device : AUDIO_DEVICE_OUT_TELEPHONY_TX;
-    SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(outputDevice, mOutputs);
-    audio_io_handle_t output = selectOutput(outputs);
+    // @TODO: still ignoring the address, or not dealing platform with mutliple telephonydevices
+    const sp<DeviceDescriptor> outputDevice = isRx ?
+                device : mAvailableOutputDevices.getDevice(AUDIO_DEVICE_OUT_TELEPHONY_TX);
+    SortedVector<audio_io_handle_t> outputs =
+            getOutputsForDevices(DeviceVector(outputDevice), mOutputs);
+    audio_io_handle_t output = selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
     // request to reuse existing output stream if one is already opened to reach the target device
     if (output != AUDIO_IO_HANDLE_NONE) {
         sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
-        ALOG_ASSERT(!outputDesc->isDuplicated(),
-                "%s() %#x device output %d is duplicated", __func__, outputDevice, output);
+        ALOG_ASSERT(!outputDesc->isDuplicated(), "%s() %s device output %d is duplicated", __func__,
+                    outputDevice->toString().c_str(), output);
         patchBuilder.addSource(outputDesc, { .stream = AUDIO_STREAM_PATCH });
     }
 
@@ -499,7 +490,7 @@
         // call TX device but this information is not in the audio patch and logic here must be
         // symmetric to the one in startInput()
         for (const auto& activeDesc : mInputs.getActiveInputs()) {
-            if (activeDesc->hasSameHwModuleAs(txSourceDeviceDesc)) {
+            if (activeDesc->hasSameHwModuleAs(device)) {
                 closeActiveClients(activeDesc);
             }
         }
@@ -599,17 +590,17 @@
     }
 
     if (hasPrimaryOutput()) {
-        // Note that despite the fact that getNewOutputDevice() is called on the primary output,
+        // Note that despite the fact that getNewOutputDevices() is called on the primary output,
         // the device returned is not necessarily reachable via this output
-        audio_devices_t rxDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
+        DeviceVector rxDevices = getNewOutputDevices(mPrimaryOutput, false /*fromCache*/);
         // force routing command to audio hardware when ending call
         // even if no device change is needed
-        if (isStateInCall(oldState) && rxDevice == AUDIO_DEVICE_NONE) {
-            rxDevice = mPrimaryOutput->device();
+        if (isStateInCall(oldState) && rxDevices.isEmpty()) {
+            rxDevices = mPrimaryOutput->devices();
         }
 
         if (state == AUDIO_MODE_IN_CALL) {
-            updateCallRouting(rxDevice, delayMs);
+            updateCallRouting(rxDevices, delayMs);
         } else if (oldState == AUDIO_MODE_IN_CALL) {
             if (mCallRxPatch != 0) {
                 mpClientInterface->releaseAudioPatch(mCallRxPatch->mAfPatchHandle, 0);
@@ -619,18 +610,18 @@
                 mpClientInterface->releaseAudioPatch(mCallTxPatch->mAfPatchHandle, 0);
                 mCallTxPatch.clear();
             }
-            setOutputDevice(mPrimaryOutput, rxDevice, force, 0);
+            setOutputDevices(mPrimaryOutput, rxDevices, force, 0);
         } else {
-            setOutputDevice(mPrimaryOutput, rxDevice, force, 0);
+            setOutputDevices(mPrimaryOutput, rxDevices, force, 0);
         }
     }
 
     // reevaluate routing on all outputs in case tracks have been started during the call
     for (size_t i = 0; i < mOutputs.size(); i++) {
         sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
-        audio_devices_t newDevice = getNewOutputDevice(desc, true /*fromCache*/);
+        DeviceVector newDevices = getNewOutputDevices(desc, true /*fromCache*/);
         if (state != AUDIO_MODE_IN_CALL || desc != mPrimaryOutput) {
-            setOutputDevice(desc, newDevice, (newDevice != AUDIO_DEVICE_NONE), 0 /*delayMs*/);
+            setOutputDevices(desc, newDevices, !newDevices.isEmpty(), 0 /*delayMs*/);
         }
     }
 
@@ -654,7 +645,7 @@
 }
 
 void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage,
-                                         audio_policy_forced_cfg_t config)
+                                     audio_policy_forced_cfg_t config)
 {
     ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mEngine->getPhoneState());
     if (config == mEngine->getForceUse(usage)) {
@@ -680,26 +671,24 @@
         delayMs = TOUCH_SOUND_FIXED_DELAY_MS;
     }
     if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
-        audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, true /*fromCache*/);
-        waitMs = updateCallRouting(newDevice, delayMs);
+        DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, true /*fromCache*/);
+        waitMs = updateCallRouting(newDevices, delayMs);
     }
     for (size_t i = 0; i < mOutputs.size(); i++) {
         sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
-        audio_devices_t newDevice = getNewOutputDevice(outputDesc, true /*fromCache*/);
+        DeviceVector newDevices = getNewOutputDevices(outputDesc, true /*fromCache*/);
         if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (outputDesc != mPrimaryOutput)) {
-            waitMs = setOutputDevice(outputDesc, newDevice, (newDevice != AUDIO_DEVICE_NONE),
-                                     delayMs);
+            waitMs = setOutputDevices(outputDesc, newDevices, !newDevices.isEmpty(), delayMs);
         }
-        if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
-            applyStreamVolumes(outputDesc, newDevice, waitMs, true);
+        if (forceVolumeReeval && !newDevices.isEmpty()) {
+            applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true);
         }
     }
 
     for (const auto& activeDesc : mInputs.getActiveInputs()) {
-        audio_devices_t newDevice = getNewInputDevice(activeDesc);
+        auto newDevice = getNewInputDevice(activeDesc);
         // Force new input selection if the new device can not be reached via current input
-        if (activeDesc->mProfile->getSupportedDevices().types() &
-                (newDevice & ~AUDIO_DEVICE_BIT_IN)) {
+        if (activeDesc->mProfile->getSupportedDevices().contains(newDevice)) {
             setInputDevice(activeDesc->mIoHandle, newDevice);
         } else {
             closeInput(activeDesc->mIoHandle);
@@ -715,7 +704,7 @@
 // Find an output profile compatible with the parameters passed. When "directOnly" is set, restrict
 // search to profiles for direct outputs.
 sp<IOProfile> AudioPolicyManager::getProfileForOutput(
-                                                   audio_devices_t device,
+                                                   const DeviceVector& devices,
                                                    uint32_t samplingRate,
                                                    audio_format_t format,
                                                    audio_channel_mask_t channelMask,
@@ -736,7 +725,7 @@
 
     for (const auto& hwModule : mHwModules) {
         for (const auto& curProfile : hwModule->getOutputProfiles()) {
-            if (!curProfile->isCompatibleProfile(device, String8(""),
+            if (!curProfile->isCompatibleProfile(devices,
                     samplingRate, NULL /*updatedSamplingRate*/,
                     format, NULL /*updatedFormat*/,
                     channelMask, NULL /*updatedChannelMask*/,
@@ -744,7 +733,7 @@
                 continue;
             }
             // reject profiles not corresponding to a device currently available
-            if ((mAvailableOutputDevices.types() & curProfile->getSupportedDevicesType()) == 0) {
+            if (!mAvailableOutputDevices.containsAtLeastOne(curProfile->getSupportedDevices())) {
                 continue;
             }
             if (!directOnly) return curProfile;
@@ -765,7 +754,7 @@
 audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream)
 {
     routing_strategy strategy = getStrategy(stream);
-    audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
+    DeviceVector devices = getDevicesForStrategy(strategy, false /*fromCache*/);
 
     // Note that related method getOutputForAttr() uses getOutputForDevice() not selectOutput().
     // We use selectOutput() here since we don't have the desired AudioTrack sample rate,
@@ -773,10 +762,11 @@
     // getOutput() solely on audio_stream_type such as AudioSystem::getOutputFrameCount()
     // and AudioSystem::getOutputSamplingRate().
 
-    SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
-    audio_io_handle_t output = selectOutput(outputs);
+    SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
+    audio_io_handle_t output = selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
 
-    ALOGV("getOutput() stream %d selected device %08x, output %d", stream, device, output);
+    ALOGV("getOutput() stream %d selected devices %s, output %d", stream,
+          devices.toString().c_str(), output);
     return output;
 }
 
@@ -813,12 +803,11 @@
                                                  audio_output_flags_t *flags,
                                                  audio_port_handle_t *selectedDeviceId)
 {
-    DeviceVector outputDevices;
+    DeviceVector devices;
     routing_strategy strategy;
-    audio_devices_t device;
-    const audio_port_handle_t requestedDeviceId = *selectedDeviceId;
-    audio_devices_t msdDevice =
-            getModuleDeviceTypes(mAvailableOutputDevices, AUDIO_HARDWARE_MODULE_ID_MSD);
+    audio_devices_t deviceType = AUDIO_DEVICE_NONE;
+    const audio_port_handle_t requestedPortId = *selectedDeviceId;
+    DeviceVector msdDevices = getMsdAudioOutDevices();
 
     status_t status = getAudioAttributes(resultAttr, attr, *stream);
     if (status != NO_ERROR) {
@@ -829,17 +818,16 @@
           " session %d selectedDeviceId %d",
           __func__,
           resultAttr->usage, resultAttr->content_type, resultAttr->tags, resultAttr->flags,
-          session, requestedDeviceId);
+          session, requestedPortId);
 
     *stream = streamTypefromAttributesInt(resultAttr);
 
     strategy = getStrategyForAttr(resultAttr);
 
     // First check for explicit routing (eg. setPreferredDevice)
-    if (requestedDeviceId != AUDIO_PORT_HANDLE_NONE) {
-        sp<DeviceDescriptor> deviceDesc =
-            mAvailableOutputDevices.getDeviceFromId(requestedDeviceId);
-        device = deviceDesc->type();
+    sp<DeviceDescriptor> requestedDevice = mAvailableOutputDevices.getDeviceFromId(requestedPortId);
+    if (requestedDevice != nullptr) {
+        deviceType = requestedDevice->type();
     } else {
         // If no explict route, is there a matching dynamic policy that applies?
         sp<SwAudioOutputDescriptor> desc;
@@ -863,7 +851,7 @@
             ALOGW("%s no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE", __func__);
             return BAD_VALUE;
         }
-        device = getDeviceForStrategy(strategy, false /*fromCache*/);
+        deviceType = getDeviceForStrategy(strategy, false /*fromCache*/);
     }
 
     if ((resultAttr->flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
@@ -875,42 +863,44 @@
     // FIXME: provide a more generic approach which is not device specific and move this back
     // to getOutputForDevice.
     // TODO: Remove check of AUDIO_STREAM_MUSIC once migration is completed on the app side.
-    if (device == AUDIO_DEVICE_OUT_TELEPHONY_TX &&
+    if (deviceType == AUDIO_DEVICE_OUT_TELEPHONY_TX &&
         (*stream == AUDIO_STREAM_MUSIC || resultAttr->usage == AUDIO_USAGE_VOICE_COMMUNICATION) &&
         audio_is_linear_pcm(config->format) &&
         isInCall()) {
-        if (requestedDeviceId != AUDIO_PORT_HANDLE_NONE) {
+        if (requestedPortId != AUDIO_PORT_HANDLE_NONE) {
             *flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
         } else {
             // Get the devce type directly from the engine to bypass preferred route logic
-            device = mEngine->getDeviceForStrategy(strategy);
+            deviceType = mEngine->getDeviceForStrategy(strategy);
         }
     }
 
     ALOGV("%s device 0x%x, sampling rate %d, format %#x, channel mask %#x, "
           "flags %#x",
-          __func__, device, config->sample_rate, config->format, config->channel_mask, *flags);
+          __func__,
+          deviceType, config->sample_rate, config->format, config->channel_mask, *flags);
 
     *output = AUDIO_IO_HANDLE_NONE;
-    if (msdDevice != AUDIO_DEVICE_NONE) {
-        *output = getOutputForDevice(msdDevice, session, *stream, config, flags);
-        if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatch(device) == NO_ERROR) {
-            ALOGV("%s() Using MSD device 0x%x instead of device 0x%x",
-                    __func__, msdDevice, device);
-            device = msdDevice;
+    if (!msdDevices.isEmpty()) {
+        *output = getOutputForDevices(msdDevices, session, *stream, config, flags);
+        sp<DeviceDescriptor> deviceDesc = mAvailableOutputDevices.getDevice(deviceType);
+        if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatch(deviceDesc) == NO_ERROR) {
+            ALOGV("%s() Using MSD devices %s instead of device %s",
+                    __func__, msdDevices.toString().c_str(), deviceDesc->toString().c_str());
+            deviceType = msdDevices.types();
         } else {
             *output = AUDIO_IO_HANDLE_NONE;
         }
     }
+    devices = mAvailableOutputDevices.getDevicesFromTypeMask(deviceType);
     if (*output == AUDIO_IO_HANDLE_NONE) {
-        *output = getOutputForDevice(device, session, *stream, config, flags);
+        *output = getOutputForDevices(devices, session, *stream, config, flags);
     }
     if (*output == AUDIO_IO_HANDLE_NONE) {
         return INVALID_OPERATION;
     }
 
-    outputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(device);
-    *selectedDeviceId = getFirstDeviceId(outputDevices);
+    *selectedDeviceId = getFirstDeviceId(devices);
 
     ALOGV("%s returns output %d selectedDeviceId %d", __func__, *output, *selectedDeviceId);
 
@@ -931,7 +921,7 @@
     if (*portId != AUDIO_PORT_HANDLE_NONE) {
         return INVALID_OPERATION;
     }
-    const audio_port_handle_t requestedDeviceId = *selectedDeviceId;
+    const audio_port_handle_t requestedPortId = *selectedDeviceId;
     audio_attributes_t resultAttr;
     status_t status = getOutputForAttrInt(&resultAttr, output, session, attr, stream, uid,
             config, flags, selectedDeviceId);
@@ -946,20 +936,20 @@
 
     sp<TrackClientDescriptor> clientDesc =
         new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig,
-                                  requestedDeviceId, *stream,
+                                  requestedPortId, *stream,
                                   getStrategyForAttr(&resultAttr),
                                   *flags);
     sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
     outputDesc->addClient(clientDesc);
 
     ALOGV("%s returns output %d selectedDeviceId %d for port ID %d",
-          __func__, *output, requestedDeviceId, *portId);
+          __func__, *output, requestedPortId, *portId);
 
     return NO_ERROR;
 }
 
-audio_io_handle_t AudioPolicyManager::getOutputForDevice(
-        audio_devices_t device,
+audio_io_handle_t AudioPolicyManager::getOutputForDevices(
+        const DeviceVector &devices,
         audio_session_t session,
         audio_stream_type_t stream,
         const audio_config_t *config,
@@ -1017,7 +1007,7 @@
 
     if (((*flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
             !(mEffects.isNonOffloadableEffectEnabled() || mMasterMono)) {
-        profile = getProfileForOutput(device,
+        profile = getProfileForOutput(devices,
                                    config->sample_rate,
                                    config->format,
                                    config->channel_mask,
@@ -1037,7 +1027,7 @@
                     (config->channel_mask == desc->mChannelMask) &&
                     (session == desc->mDirectClientSession)) {
                     desc->mDirectOpenCount++;
-                    ALOGI("getOutputForDevice() reusing direct output %d for session %d",
+                    ALOGI("%s reusing direct output %d for session %d", __func__, 
                         mOutputs.keyAt(i), session);
                     return mOutputs.keyAt(i);
                 }
@@ -1051,8 +1041,7 @@
         sp<SwAudioOutputDescriptor> outputDesc =
                 new SwAudioOutputDescriptor(profile, mpClientInterface);
 
-        DeviceVector outputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(device);
-        String8 address = getFirstDeviceAddress(outputDevices);
+        String8 address = getFirstDeviceAddress(devices);
 
         // MSD patch may be using the only output stream that can service this request. Release
         // MSD patch to prioritize this request over any active output on MSD.
@@ -1062,7 +1051,7 @@
             for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) {
                 const struct audio_port_config *sink = &patch->mPatch.sinks[j];
                 if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
-                        (sink->ext.device.type & device) != AUDIO_DEVICE_NONE &&
+                        (sink->ext.device.type & devices.types()) != AUDIO_DEVICE_NONE &&
                         (address.isEmpty() || strncmp(sink->ext.device.address, address.string(),
                                 AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
                     releaseAudioPatch(patch->mHandle, mUidCached);
@@ -1071,15 +1060,15 @@
             }
         }
 
-        status = outputDesc->open(config, device, address, stream, *flags, &output);
+        status = outputDesc->open(config, devices, stream, *flags, &output);
 
         // only accept an output with the requested parameters
         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)) {
-            ALOGV("getOutputForDevice() failed opening direct output: output %d sample rate %d %d,"
-                    "format %d %d, channel mask %04x %04x", output, config->sample_rate,
+            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);
             if (output != AUDIO_IO_HANDLE_NONE) {
@@ -1097,7 +1086,7 @@
 
         addOutput(output, outputDesc);
         mPreviousOutputs = mOutputs;
-        ALOGV("getOutputForDevice() returns new direct output %d", output);
+        ALOGV("%s returns new direct output %d", __func__, output);
         mpClientInterface->onAudioPortListUpdate();
         return output;
     }
@@ -1118,14 +1107,14 @@
     if (audio_is_linear_pcm(config->format)) {
         // get which output is suitable for the specified stream. The actual
         // routing change will happen when startOutput() will be called
-        SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
+        SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
 
         // 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);
     }
-    ALOGW_IF((output == 0), "getOutputForDevice() could not find output for stream %d, "
+    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);
 
@@ -1133,13 +1122,14 @@
 }
 
 sp<DeviceDescriptor> AudioPolicyManager::getMsdAudioInDevice() const {
-    sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
-    if (msdModule != 0) {
-        DeviceVector msdInputDevices = mAvailableInputDevices.getDevicesFromHwModule(
-                msdModule->getHandle());
-        if (!msdInputDevices.isEmpty()) return msdInputDevices.itemAt(0);
-    }
-    return 0;
+    auto msdInDevices = mHwModules.getAvailableDevicesFromModuleName(AUDIO_HARDWARE_MODULE_ID_MSD,
+                                                                     mAvailableInputDevices);
+    return msdInDevices.isEmpty()? nullptr : msdInDevices.itemAt(0);
+}
+
+DeviceVector AudioPolicyManager::getMsdAudioOutDevices() const {
+    return mHwModules.getAvailableDevicesFromModuleName(AUDIO_HARDWARE_MODULE_ID_MSD,
+                                                        mAvailableOutputDevices);
 }
 
 const AudioPatchCollection AudioPolicyManager::getMsdPatches() const {
@@ -1160,7 +1150,7 @@
     return msdPatches;
 }
 
-status_t AudioPolicyManager::getBestMsdAudioProfileFor(audio_devices_t outputDevice,
+status_t AudioPolicyManager::getBestMsdAudioProfileFor(const sp<DeviceDescriptor> &outputDevice,
         bool hwAvSync, audio_port_config *sourceConfig, audio_port_config *sinkConfig) const
 {
     sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
@@ -1170,7 +1160,7 @@
     }
     sp<HwModule> deviceModule = mHwModules.getModuleForDevice(outputDevice);
     if (deviceModule == nullptr) {
-        ALOGE("%s() unable to get module for %#x", __func__, outputDevice);
+        ALOGE("%s() unable to get module for %s", __func__, outputDevice->toString().c_str());
         return NO_INIT;
     }
     const InputProfileCollection &inputProfiles = msdModule->getInputProfiles();
@@ -1180,7 +1170,7 @@
     }
     const OutputProfileCollection &outputProfiles = deviceModule->getOutputProfiles();
     if (outputProfiles.isEmpty()) {
-        ALOGE("%s() no output profiles for device %#x", __func__, outputDevice);
+        ALOGE("%s() no output profiles for device %s", __func__, outputDevice->toString().c_str());
         return NO_INIT;
     }
     AudioProfileVector msdProfiles;
@@ -1201,8 +1191,8 @@
             compressedFormatsOrder, surroundChannelMasksOrder, true /*preferHigherSamplingRates*/,
             &bestSinkConfig);
     if (result != NO_ERROR) {
-        ALOGD("%s() no matching profiles found for device: %#x, hwAvSync: %d",
-                __func__, outputDevice, hwAvSync);
+        ALOGD("%s() no matching profiles found for device: %s, hwAvSync: %d",
+                __func__, outputDevice->toString().c_str(), hwAvSync);
         return result;
     }
     sinkConfig->sample_rate = bestSinkConfig.sample_rate;
@@ -1231,11 +1221,10 @@
     return NO_ERROR;
 }
 
-PatchBuilder AudioPolicyManager::buildMsdPatch(audio_devices_t outputDevice) const
+PatchBuilder AudioPolicyManager::buildMsdPatch(const sp<DeviceDescriptor> &outputDevice) const
 {
     PatchBuilder patchBuilder;
-    patchBuilder.addSource(getMsdAudioInDevice()).
-            addSink(findDevice(mAvailableOutputDevices, outputDevice));
+    patchBuilder.addSource(getMsdAudioInDevice()).addSink(outputDevice);
     audio_port_config sourceConfig = patchBuilder.patch()->sources[0];
     audio_port_config sinkConfig = patchBuilder.patch()->sinks[0];
     // TODO: Figure out whether MSD module has HW_AV_SYNC flag set in the AP config file.
@@ -1253,15 +1242,18 @@
     return patchBuilder;
 }
 
-status_t AudioPolicyManager::setMsdPatch(audio_devices_t outputDevice) {
-    ALOGV("%s() for outputDevice %#x", __func__, outputDevice);
-    if (outputDevice == AUDIO_DEVICE_NONE) {
+status_t AudioPolicyManager::setMsdPatch(const sp<DeviceDescriptor> &outputDevice) {
+    sp<DeviceDescriptor> device = outputDevice;
+    if (device == nullptr) {
         // Use media strategy for unspecified output device. This should only
         // occur on checkForDeviceAndOutputChanges(). Device connection events may
         // therefore invalidate explicit routing requests.
-        outputDevice = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+        DeviceVector devices = getDevicesForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+        LOG_ALWAYS_FATAL_IF(devices.isEmpty(), "no outpudevice to set Msd Patch");
+        device = devices.itemAt(0);
     }
-    PatchBuilder patchBuilder = buildMsdPatch(outputDevice);
+    ALOGV("%s() for device %s", __func__, device->toString().c_str());
+    PatchBuilder patchBuilder = buildMsdPatch(device);
     const struct audio_patch* patch = patchBuilder.patch();
     const AudioPatchCollection msdPatches = getMsdPatches();
     if (!msdPatches.isEmpty()) {
@@ -1277,8 +1269,9 @@
             patch, 0 /*delayMs*/, mUidCached, nullptr /*patchDescPtr*/);
     ALOGE_IF(status != NO_ERROR, "%s() error %d creating MSD audio patch", __func__, status);
     ALOGI_IF(status == NO_ERROR, "%s() Patch created from MSD_IN to "
-           "device:%#x (format:%#x channels:%#x samplerate:%d)", __func__, outputDevice,
-           patch->sources[0].format, patch->sources[0].channel_mask, patch->sources[0].sample_rate);
+           "device:%s (format:%#x channels:%#x samplerate:%d)", __func__,
+             device->toString().c_str(), patch->sources[0].format,
+             patch->sources[0].channel_mask, patch->sources[0].sample_rate);
     return status;
 }
 
@@ -1289,7 +1282,7 @@
                                                        uint32_t samplingRate)
 {
     // select one output among several that provide a path to a particular device or set of
-    // devices (the list was previously build by getOutputsForDevice()).
+    // devices (the list was previously build by getOutputsForDevices()).
     // The priority is as follows:
     // 1: the output supporting haptic playback when requesting haptic playback
     // 2: the output with the highest number of requested policy flags
@@ -1451,17 +1444,19 @@
     bool force = !outputDesc->isActive() &&
             (outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
 
-    audio_devices_t device = AUDIO_DEVICE_NONE;
+    DeviceVector devices;
     AudioMix *policyMix = NULL;
     const char *address = NULL;
     if (outputDesc->mPolicyMix != NULL) {
         policyMix = outputDesc->mPolicyMix;
+        audio_devices_t newDeviceType;
         address = policyMix->mDeviceAddress.string();
         if ((policyMix->mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
-            device = policyMix->mDeviceType;
+            newDeviceType = policyMix->mDeviceType;
         } else {
-            device = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+            newDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
         }
+        devices.add(mAvailableOutputDevices.getDevice(newDeviceType, String8(address)));
     }
 
     // requiresMuteCheck is false when we can bypass mute strategy.
@@ -1476,8 +1471,8 @@
     outputDesc->setClientActive(client, true);
 
     if (client->hasPreferredDevice(true)) {
-        device = getNewOutputDevice(outputDesc, false /*fromCache*/);
-        if (device != outputDesc->device()) {
+        devices = getNewOutputDevices(outputDesc, false /*fromCache*/);
+        if (devices != outputDesc->devices()) {
             checkStrategyRoute(getStrategy(stream), outputDesc->mIoHandle);
         }
     }
@@ -1486,10 +1481,10 @@
         selectOutputForMusicEffects();
     }
 
-    if (outputDesc->streamActiveCount(stream) == 1 || device != AUDIO_DEVICE_NONE) {
+    if (outputDesc->streamActiveCount(stream) == 1 || !devices.isEmpty()) {
         // starting an output being rerouted?
-        if (device == AUDIO_DEVICE_NONE) {
-            device = getNewOutputDevice(outputDesc, false /*fromCache*/);
+        if (devices.isEmpty()) {
+            devices = getNewOutputDevices(outputDesc, false /*fromCache*/);
         }
 
         routing_strategy strategy = getStrategy(stream);
@@ -1498,13 +1493,13 @@
                             (beaconMuteLatency > 0);
         uint32_t waitMs = beaconMuteLatency;
         for (size_t i = 0; i < mOutputs.size(); i++) {
-            sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
+            sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
             if (desc != outputDesc) {
                 // An output has a shared device if
                 // - managed by the same hw module
                 // - supports the currently selected device
                 const bool sharedDevice = outputDesc->sharesHwModuleWith(desc)
-                        && (desc->supportedDevices() & device) != AUDIO_DEVICE_NONE;
+                        && (!desc->filterSupportedDevices(devices).isEmpty());
 
                 // force a device change if any other output is:
                 // - managed by the same hw module
@@ -1514,7 +1509,7 @@
                 // In this case, the audio HAL must receive the new device selection so that it can
                 // change the device currently selected by the other output.
                 if (sharedDevice &&
-                        desc->device() != device &&
+                        desc->devices() != devices &&
                         desc->getPatchHandle() != AUDIO_PATCH_HANDLE_NONE) {
                     force = true;
                 }
@@ -1537,13 +1532,13 @@
         }
 
         const uint32_t muteWaitMs =
-                setOutputDevice(outputDesc, device, force, 0, NULL, address, requiresMuteCheck);
+                setOutputDevices(outputDesc, devices, force, 0, NULL, requiresMuteCheck);
 
         // apply volume rules for current stream and device if necessary
         checkAndSetVolume(stream,
-                          mVolumeCurves->getVolumeIndex(stream, outputDesc->device()),
+                          mVolumeCurves->getVolumeIndex(stream, outputDesc->devices().types()),
                           outputDesc,
-                          outputDesc->device());
+                          outputDesc->devices().types());
 
         // update the outputs if starting an output with a stream that can affect notification
         // routing
@@ -1574,7 +1569,7 @@
 
     // Automatically enable the remote submix input when output is started on a re routing mix
     // of type MIX_TYPE_RECORDERS
-    if (audio_is_remote_submix_device(device) && policyMix != NULL &&
+    if (audio_is_remote_submix_device(devices.types()) && policyMix != NULL &&
         policyMix->mMixType == MIX_TYPE_RECORDERS) {
         setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
                                     AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
@@ -1619,7 +1614,7 @@
         if (outputDesc->streamActiveCount(stream) == 1) {
             // Automatically disable the remote submix input when output is stopped on a
             // re routing mix of type MIX_TYPE_RECORDERS
-            if (audio_is_remote_submix_device(outputDesc->mDevice) &&
+            if (audio_is_remote_submix_device(outputDesc->devices().types()) &&
                 outputDesc->mPolicyMix != NULL &&
                 outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
                 setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
@@ -1640,33 +1635,31 @@
         // store time at which the stream was stopped - see isStreamActive()
         if (outputDesc->streamActiveCount(stream) == 0 || forceDeviceUpdate) {
             outputDesc->mStopTime[stream] = systemTime();
-            audio_devices_t newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
+            DeviceVector newDevices = getNewOutputDevices(outputDesc, false /*fromCache*/);
             // delay the device switch by twice the latency because stopOutput() is executed when
             // the track stop() command is received and at that time the audio track buffer can
             // still contain data that needs to be drained. The latency only covers the audio HAL
             // and kernel buffers. Also the latency does not always include additional delay in the
             // audio path (audio DSP, CODEC ...)
-            setOutputDevice(outputDesc, newDevice, false, outputDesc->latency()*2);
+            setOutputDevices(outputDesc, newDevices, false, outputDesc->latency()*2);
 
             // force restoring the device selection on other active outputs if it differs from the
             // one being selected for this output
             uint32_t delayMs = outputDesc->latency()*2;
             for (size_t i = 0; i < mOutputs.size(); i++) {
-                sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
+                sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
                 if (desc != outputDesc &&
                         desc->isActive() &&
                         outputDesc->sharesHwModuleWith(desc) &&
-                        (newDevice != desc->device())) {
-                    audio_devices_t newDevice2 = getNewOutputDevice(desc, false /*fromCache*/);
-                    bool force = desc->device() != newDevice2;
+                        (newDevices != desc->devices())) {
+                    DeviceVector newDevices2 = getNewOutputDevices(desc, false /*fromCache*/);
+                    bool force = desc->devices() != newDevices2;
 
-                    setOutputDevice(desc,
-                                    newDevice2,
-                                    force,
-                                    delayMs);
+                    setOutputDevices(desc, newDevices2, force, delayMs);
+
                     // re-apply device specific volume if not done by setOutputDevice()
                     if (!force) {
-                        applyStreamVolumes(desc, newDevice2, delayMs);
+                        applyStreamVolumes(desc, newDevices2.types(), delayMs);
                     }
                 }
             }
@@ -1739,29 +1732,27 @@
           attr->source, config->sample_rate, config->format, config->channel_mask, session, flags);
 
     status_t status = NO_ERROR;
-    // handle legacy remote submix case where the address was not always specified
-    String8 address = String8("");
     audio_source_t halInputSource;
-    audio_source_t inputSource = attr->source;
+    audio_attributes_t attributes = *attr;
     AudioMix *policyMix = NULL;
-    DeviceVector inputDevices;
+    sp<DeviceDescriptor> device;
     sp<AudioInputDescriptor> inputDesc;
     sp<RecordClientDescriptor> clientDesc;
     audio_port_handle_t requestedDeviceId = *selectedDeviceId;
     bool isSoundTrigger;
-    audio_devices_t device;
 
     // The supplied portId must be AUDIO_PORT_HANDLE_NONE
     if (*portId != AUDIO_PORT_HANDLE_NONE) {
         return INVALID_OPERATION;
     }
 
-    if (inputSource == AUDIO_SOURCE_DEFAULT) {
-        inputSource = AUDIO_SOURCE_MIC;
+    if (attr->source == AUDIO_SOURCE_DEFAULT) {
+        attributes.source = AUDIO_SOURCE_MIC;
     }
 
     // Explicit routing?
-    sp<DeviceDescriptor> deviceDesc = mAvailableInputDevices.getDeviceFromId(*selectedDeviceId);
+    sp<DeviceDescriptor> explicitRoutingDevice = 
+            mAvailableInputDevices.getDeviceFromId(*selectedDeviceId);
 
     // special case for mmap capture: if an input IO handle is specified, we reuse this input if
     // possible
@@ -1802,7 +1793,7 @@
             }
         }
         *inputType = API_INPUT_LEGACY;
-        device = inputDesc->mDevice;
+        device = inputDesc->getDevice();
 
         ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
         goto exit;
@@ -1811,44 +1802,38 @@
     *input = AUDIO_IO_HANDLE_NONE;
     *inputType = API_INPUT_INVALID;
 
-    halInputSource = inputSource;
+    halInputSource = attributes.source;
 
-    if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
-            strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
-        status = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
+    if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
+            strncmp(attributes.tags, "addr=", strlen("addr=")) == 0) {
+        status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
         if (status != NO_ERROR) {
             goto error;
         }
         *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
-        device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
-        address = String8(attr->tags + strlen("addr="));
+        device = mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+                                                  String8(attr->tags + strlen("addr=")));
     } else {
-        if (deviceDesc != 0) {
-            device = deviceDesc->type();
+        if (explicitRoutingDevice != nullptr) {
+            device = explicitRoutingDevice;
         } else {
-            device = getDeviceAndMixForInputSource(inputSource, &policyMix);
+            device = getDeviceAndMixForAttributes(attributes, &policyMix);
         }
-        if (device == AUDIO_DEVICE_NONE) {
-            ALOGW("getInputForAttr() could not find device for source %d", inputSource);
+        if (device == nullptr) {
+            ALOGW("getInputForAttr() could not find device for source %d", attributes.source);
             status = BAD_VALUE;
             goto error;
         }
-        if (policyMix != NULL) {
-            address = policyMix->mDeviceAddress;
-            if (policyMix->mMixType == MIX_TYPE_RECORDERS) {
-                // 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
-                // know about it and is therefore considered "legacy"
-                *inputType = API_INPUT_LEGACY;
-            } else {
-                // recording a mix of players defined by an external policy, we're rerouting for
-                // an external policy
-                *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
-            }
-        } else if (audio_is_remote_submix_device(device)) {
-            address = String8("0");
+        if (policyMix != nullptr) {
+            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
+            // know about it and is therefore considered "legacy"
+            *inputType = API_INPUT_LEGACY;
+        } else if (audio_is_remote_submix_device(device->type())) {
+            device = mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX, String8("0"));
             *inputType = API_INPUT_MIX_CAPTURE;
-        } else if (device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
+        } else if (device->type() == AUDIO_DEVICE_IN_TELEPHONY_RX) {
             *inputType = API_INPUT_TELEPHONY_RX;
         } else {
             *inputType = API_INPUT_LEGACY;
@@ -1856,7 +1841,7 @@
 
     }
 
-    *input = getInputForDevice(device, address, session, inputSource,
+    *input = getInputForDevice(device, session, attributes.source,
                                config, flags,
                                policyMix);
     if (*input == AUDIO_IO_HANDLE_NONE) {
@@ -1866,16 +1851,16 @@
 
 exit:
 
-    inputDevices = mAvailableInputDevices.getDevicesFromTypeMask(device);
-    *selectedDeviceId = getFirstDeviceId(inputDevices);
+    *selectedDeviceId = mAvailableInputDevices.contains(device) ? 
+            device->getId() : AUDIO_PORT_HANDLE_NONE;
 
-    isSoundTrigger = inputSource == AUDIO_SOURCE_HOTWORD &&
+    isSoundTrigger = attributes.source == AUDIO_SOURCE_HOTWORD &&
         mSoundTriggerSessions.indexOfKey(session) > 0;
     *portId = AudioPort::getNextUniqueId();
 
-    clientDesc = new RecordClientDescriptor(*portId, uid, session,
-                                  *attr, *config, requestedDeviceId,
-                                  inputSource,flags, isSoundTrigger);
+    clientDesc = new RecordClientDescriptor(*portId, uid, session, *attr, *config,
+                                            requestedDeviceId, attributes.source, flags,
+                                            isSoundTrigger);
     inputDesc = mInputs.valueFor(*input);
     inputDesc->addClient(clientDesc);
 
@@ -1889,8 +1874,7 @@
 }
 
 
-audio_io_handle_t AudioPolicyManager::getInputForDevice(audio_devices_t device,
-                                                        String8 address,
+audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescriptor> &device,
                                                         audio_session_t session,
                                                         audio_source_t inputSource,
                                                         const audio_config_base_t *config,
@@ -1926,8 +1910,7 @@
     audio_input_flags_t profileFlags = flags;
     for (;;) {
         profileFormat = config->format; // reset each time through loop, in case it is updated
-        profile = getInputProfile(device, address,
-                                  profileSamplingRate, profileFormat, profileChannelMask,
+        profile = getInputProfile(device, profileSamplingRate, profileFormat, profileChannelMask,
                                   profileFlags);
         if (profile != 0) {
             break; // success
@@ -1936,9 +1919,9 @@
         } else if (profileFlags != AUDIO_INPUT_FLAG_NONE) {
             profileFlags = AUDIO_INPUT_FLAG_NONE; // retry
         } else { // fail
-            ALOGW("getInputForDevice() could not find profile for device 0x%X, "
-                  "sampling rate %u, format %#x, channel mask 0x%X, flags %#x",
-                    device, config->sample_rate, config->format, config->channel_mask, flags);
+            ALOGW("%s could not find profile for device %s, sampling rate %u, format %#x, "
+                  "channel mask 0x%X, flags %#x", __func__, device->toString().c_str(), 
+                  config->sample_rate, config->format, config->channel_mask, flags);
             return input;
         }
     }
@@ -1995,14 +1978,7 @@
     lConfig.channel_mask = profileChannelMask;
     lConfig.format = profileFormat;
 
-    if (address == "") {
-        DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromTypeMask(device);
-        // the inputs vector must be of size >= 1, but we don't want to crash here
-        address = getFirstDeviceAddress(inputDevices);
-    }
-
-    status_t status = inputDesc->open(&lConfig, device, address,
-            halInputSource, profileFlags, &input);
+    status_t status = inputDesc->open(&lConfig, device, halInputSource, profileFlags, &input);
 
     // only accept input with the exact requested set of parameters
     if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE ||
@@ -2059,7 +2035,7 @@
 
     // indicate active capture to sound trigger service if starting capture from a mic on
     // primary HW module
-    audio_devices_t device = getNewInputDevice(inputDesc);
+    sp<DeviceDescriptor> device = getNewInputDevice(inputDesc);
     setInputDevice(input, device, true /* force */);
 
     if (inputDesc->activeCount()  == 1) {
@@ -2070,8 +2046,8 @@
                     MIX_STATE_MIXING);
         }
 
-        audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
-        if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
+        DeviceVector primaryInputDevices = availablePrimaryModuleInputDevices();
+        if (primaryInputDevices.contains(device) &&
                 mInputs.activeInputsCountOnDevices(primaryInputDevices) == 1) {
             SoundTrigger::setCaptureState(true);
         }
@@ -2079,7 +2055,7 @@
         // automatically enable the remote submix output when input is started if not
         // used by a policy mix of type MIX_TYPE_RECORDERS
         // For remote submix (a virtual device), we open only one input per capture request.
-        if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+        if (audio_is_remote_submix_device(inputDesc->getDeviceType())) {
             String8 address = String8("");
             if (inputDesc->mPolicyMix == NULL) {
                 address = String8("0");
@@ -2130,7 +2106,7 @@
 
         // automatically disable the remote submix output when input is stopped if not
         // used by a policy mix of type MIX_TYPE_RECORDERS
-        if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+        if (audio_is_remote_submix_device(inputDesc->getDeviceType())) {
             String8 address = String8("");
             if (inputDesc->mPolicyMix == NULL) {
                 address = String8("0");
@@ -2143,14 +2119,12 @@
                                          address, "remote-submix");
             }
         }
-
-        audio_devices_t device = inputDesc->mDevice;
         resetInputDevice(input);
 
         // indicate inactive capture to sound trigger service if stopping capture from a mic on
         // primary HW module
-        audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
-        if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
+        DeviceVector primaryInputDevices = availablePrimaryModuleInputDevices();
+        if (primaryInputDevices.contains(inputDesc->getDevice()) &&
                 mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
             SoundTrigger::setCaptureState(false);
         }
@@ -2280,7 +2254,7 @@
     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->device();
+        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;
@@ -2356,8 +2330,8 @@
     // 4: the first output in the list
 
     routing_strategy strategy = getStrategy(AUDIO_STREAM_MUSIC);
-    audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
-    SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
+    DeviceVector devices = getDevicesForStrategy(strategy, false /*fromCache*/);
+    SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
 
     if (outputs.size() == 0) {
         return AUDIO_IO_HANDLE_NONE;
@@ -2674,6 +2648,57 @@
     }
 }
 
+status_t AudioPolicyManager::setUidDeviceAffinities(uid_t uid,
+        const Vector<AudioDeviceTypeAddr>& devices) {
+    ALOGV("%s() uid=%d num devices %zu", __FUNCTION__, uid, devices.size());
+    // uid/device affinity is only for output devices
+    for (size_t i = 0; i < devices.size(); i++) {
+        if (!audio_is_output_device(devices[i].mType)) {
+            ALOGE("setUidDeviceAffinities() device=%08x is NOT an output device",
+                    devices[i].mType);
+            return BAD_VALUE;
+        }
+    }
+    status_t res =  mPolicyMixes.setUidDeviceAffinities(uid, devices);
+    if (res == NO_ERROR) {
+        // reevaluate outputs for all given devices
+        for (size_t i = 0; i < devices.size(); i++) {
+            sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(
+                            devices[i].mType, devices[i].mAddress, String8());
+            SortedVector<audio_io_handle_t> outputs;
+            if (checkOutputsForDevice(devDesc, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+                    outputs) != NO_ERROR) {
+                ALOGE("setUidDeviceAffinities() error in checkOutputsForDevice for device=%08x"
+                        " addr=%s", devices[i].mType, devices[i].mAddress.string());
+                return INVALID_OPERATION;
+            }
+        }
+    }
+    return res;
+}
+
+status_t AudioPolicyManager::removeUidDeviceAffinities(uid_t uid) {
+    ALOGV("%s() uid=%d", __FUNCTION__, uid);
+    Vector<AudioDeviceTypeAddr> devices;
+    status_t res =  mPolicyMixes.getDevicesForUid(uid, devices);
+    if (res == NO_ERROR) {
+        // reevaluate outputs for all found devices
+        for (size_t i = 0; i < devices.size(); i++) {
+            sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(
+                    devices[i].mType, devices[i].mAddress, String8());
+            SortedVector<audio_io_handle_t> outputs;
+            if (checkOutputsForDevice(devDesc, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+                    outputs) != NO_ERROR) {
+                ALOGE("%s() error in checkOutputsForDevice for device=%08x addr=%s",
+                        __FUNCTION__, devices[i].mType, devices[i].mAddress.string());
+                return INVALID_OPERATION;
+            }
+        }
+    }
+
+    return res;
+}
+
 void AudioPolicyManager::dump(String8 *dst) const
 {
     dst->appendFormat("\nAudioPolicyManager Dump: %p\n", this);
@@ -2783,7 +2808,7 @@
 
     // See if there is a profile to support this.
     // AUDIO_DEVICE_NONE
-    sp<IOProfile> profile = getProfileForOutput(AUDIO_DEVICE_NONE /*ignore device */,
+    sp<IOProfile> profile = getProfileForOutput(DeviceVector() /*ignore device */,
                                             offloadInfo.sample_rate,
                                             offloadInfo.format,
                                             offloadInfo.channel_mask,
@@ -2797,7 +2822,7 @@
                                                  const audio_attributes_t& attributes) {
     audio_output_flags_t output_flags = AUDIO_OUTPUT_FLAG_NONE;
     audio_attributes_flags_to_audio_output_flags(attributes.flags, output_flags);
-    sp<IOProfile> profile = getProfileForOutput(AUDIO_DEVICE_NONE /*ignore device */,
+    sp<IOProfile> profile = getProfileForOutput(DeviceVector() /*ignore device */,
                                             config.sample_rate,
                                             config.format,
                                             config.channel_mask,
@@ -2991,8 +3016,7 @@
                 return BAD_VALUE;
             }
 
-            if (!outputDesc->mProfile->isCompatibleProfile(devDesc->type(),
-                                                           devDesc->address(),
+            if (!outputDesc->mProfile->isCompatibleProfile(DeviceVector(devDesc),
                                                            patch->sources[0].sample_rate,
                                                            NULL,  // updatedSamplingRate
                                                            patch->sources[0].format,
@@ -3013,7 +3037,7 @@
         // TODO: reconfigure output format and channels here
         ALOGV("createAudioPatch() setting device %08x on output %d",
               devices.types(), outputDesc->mIoHandle);
-        setOutputDevice(outputDesc, devices.types(), true, 0, handle);
+        setOutputDevices(outputDesc, devices, true, 0, handle);
         index = mAudioPatches.indexOfKey(*handle);
         if (index >= 0) {
             if (patchDesc != 0 && patchDesc != mAudioPatches.valueAt(index)) {
@@ -3042,14 +3066,13 @@
                     return BAD_VALUE;
                 }
             }
-            sp<DeviceDescriptor> devDesc =
+            sp<DeviceDescriptor> device =
                     mAvailableInputDevices.getDeviceFromId(patch->sources[0].id);
-            if (devDesc == 0) {
+            if (device == 0) {
                 return BAD_VALUE;
             }
 
-            if (!inputDesc->mProfile->isCompatibleProfile(devDesc->type(),
-                                                          devDesc->address(),
+            if (!inputDesc->mProfile->isCompatibleProfile(DeviceVector(device),
                                                           patch->sinks[0].sample_rate,
                                                           NULL, /*updatedSampleRate*/
                                                           patch->sinks[0].format,
@@ -3063,9 +3086,9 @@
                 return INVALID_OPERATION;
             }
             // TODO: reconfigure output format and channels here
-            ALOGV("createAudioPatch() setting device %08x on output %d",
-                                                  devDesc->type(), inputDesc->mIoHandle);
-            setInputDevice(inputDesc->mIoHandle, devDesc->type(), true, handle);
+            ALOGV("%s() setting device %s on output %d", __func__,
+                  device->toString().c_str(), inputDesc->mIoHandle);
+            setInputDevice(inputDesc->mIoHandle, device, true, handle);
             index = mAudioPatches.indexOfKey(*handle);
             if (index >= 0) {
                 if (patchDesc != 0 && patchDesc != mAudioPatches.valueAt(index)) {
@@ -3085,16 +3108,16 @@
                     return BAD_VALUE;
                 }
             }
-            sp<DeviceDescriptor> srcDeviceDesc =
+            sp<DeviceDescriptor> srcDevice =
                     mAvailableInputDevices.getDeviceFromId(patch->sources[0].id);
-            if (srcDeviceDesc == 0) {
+            if (srcDevice == 0) {
                 return BAD_VALUE;
             }
 
             //update source and sink with our own data as the data passed in the patch may
             // be incomplete.
             struct audio_patch newPatch = *patch;
-            srcDeviceDesc->toAudioPortConfig(&newPatch.sources[0], &patch->sources[0]);
+            srcDevice->toAudioPortConfig(&newPatch.sources[0], &patch->sources[0]);
 
             for (size_t i = 0; i < patch->num_sinks; i++) {
                 if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
@@ -3102,26 +3125,26 @@
                     return INVALID_OPERATION;
                 }
 
-                sp<DeviceDescriptor> sinkDeviceDesc =
+                sp<DeviceDescriptor> sinkDevice =
                         mAvailableOutputDevices.getDeviceFromId(patch->sinks[i].id);
-                if (sinkDeviceDesc == 0) {
+                if (sinkDevice == 0) {
                     return BAD_VALUE;
                 }
-                sinkDeviceDesc->toAudioPortConfig(&newPatch.sinks[i], &patch->sinks[i]);
+                sinkDevice->toAudioPortConfig(&newPatch.sinks[i], &patch->sinks[i]);
 
                 // create a software bridge in PatchPanel if:
                 // - source and sink devices are on different HW modules OR
                 // - audio HAL version is < 3.0
                 // - audio HAL version is >= 3.0 but no route has been declared between devices
-                if (!srcDeviceDesc->hasSameHwModuleAs(sinkDeviceDesc) ||
-                        (srcDeviceDesc->getModuleVersionMajor() < 3) ||
-                        !srcDeviceDesc->getModule()->supportsPatch(srcDeviceDesc, sinkDeviceDesc)) {
+                if (!srcDevice->hasSameHwModuleAs(sinkDevice) ||
+                        (srcDevice->getModuleVersionMajor() < 3) ||
+                        !srcDevice->getModule()->supportsPatch(srcDevice, sinkDevice)) {
                     // support only one sink device for now to simplify output selection logic
                     if (patch->num_sinks > 1) {
                         return INVALID_OPERATION;
                     }
                     SortedVector<audio_io_handle_t> outputs =
-                                            getOutputsForDevice(sinkDeviceDesc->type(), mOutputs);
+                            getOutputsForDevices(DeviceVector(sinkDevice), mOutputs);
                     // if the sink device is reachable via an opened output stream, request to go via
                     // this output stream by adding a second source to the patch description
                     audio_io_handle_t output = selectOutput(outputs);
@@ -3179,11 +3202,11 @@
             return BAD_VALUE;
         }
 
-        setOutputDevice(outputDesc,
-                        getNewOutputDevice(outputDesc, true /*fromCache*/),
-                       true,
-                       0,
-                       NULL);
+        setOutputDevices(outputDesc,
+                         getNewOutputDevices(outputDesc, true /*fromCache*/),
+                         true,
+                         0,
+                         NULL);
     } else if (patch->sources[0].type == AUDIO_PORT_TYPE_DEVICE) {
         if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
             sp<AudioInputDescriptor> inputDesc = mInputs.getInputFromId(patch->sinks[0].id);
@@ -3306,8 +3329,8 @@
 void AudioPolicyManager::checkStrategyRoute(routing_strategy strategy,
                                             audio_io_handle_t ouptutToSkip)
 {
-    audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
-    SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
+    DeviceVector devices = getDevicesForStrategy(strategy, false /*fromCache*/);
+    SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
     for (size_t j = 0; j < mOutputs.size(); j++) {
         if (mOutputs.keyAt(j) == ouptutToSkip) {
             continue;
@@ -3326,8 +3349,8 @@
                 }
             }
         } else {
-            audio_devices_t newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
-            setOutputDevice(outputDesc, newDevice, false);
+            setOutputDevices(
+                        outputDesc, getNewOutputDevices(outputDesc, false /*fromCache*/), false);
         }
     }
 }
@@ -3390,7 +3413,8 @@
 {
     *session = (audio_session_t)mpClientInterface->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
     *ioHandle = (audio_io_handle_t)mpClientInterface->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_INPUT);
-    *device = getDeviceAndMixForInputSource(AUDIO_SOURCE_HOTWORD);
+    audio_attributes_t attr = { .source = AUDIO_SOURCE_HOTWORD };
+    *device = getDeviceAndMixForAttributes(attr)->type();
 
     return mSoundTriggerSessions.acquireSession(*session, *ioHandle);
 }
@@ -3416,10 +3440,10 @@
         return INVALID_OPERATION;
     }
 
-    sp<DeviceDescriptor> srcDeviceDesc =
+    sp<DeviceDescriptor> srcDevice =
             mAvailableInputDevices.getDevice(source->ext.device.type,
-                                              String8(source->ext.device.address));
-    if (srcDeviceDesc == 0) {
+                                             String8(source->ext.device.address));
+    if (srcDevice == 0) {
         ALOGW("%s source->ext.device.type %08x not found", __FUNCTION__, source->ext.device.type);
         return BAD_VALUE;
     }
@@ -3430,7 +3454,7 @@
     sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
 
     sp<SourceClientDescriptor> sourceDesc =
-        new SourceClientDescriptor(*portId, uid, *attributes, patchDesc, srcDeviceDesc,
+        new SourceClientDescriptor(*portId, uid, *attributes, patchDesc, srcDevice,
                                    streamTypefromAttributesInt(attributes),
                                    getStrategyForAttr(attributes));
 
@@ -3451,18 +3475,20 @@
     audio_attributes_t attributes = sourceDesc->attributes();
     routing_strategy strategy = getStrategyForAttr(&attributes);
     audio_stream_type_t stream = sourceDesc->stream();
-    sp<DeviceDescriptor> srcDeviceDesc = sourceDesc->srcDevice();
+    sp<DeviceDescriptor> srcDevice = sourceDesc->srcDevice();
 
-    audio_devices_t sinkDevice = getDeviceForStrategy(strategy, true);
-    sp<DeviceDescriptor> sinkDeviceDesc =
-            mAvailableOutputDevices.getDevice(sinkDevice, String8(""));
+    DeviceVector sinkDevices = getDevicesForStrategy(strategy, true);
+    ALOG_ASSERT(!sinkDevices.isEmpty(), "connectAudioSource(): no device found for strategy");
+    sp<DeviceDescriptor> sinkDevice = sinkDevices.itemAt(0);
+    ALOG_ASSERT(mAvailableOutputDevices.contains(sinkDevice), "%s: Device %s not available",
+                __FUNCTION__, sinkDevice->toString().c_str());
 
     audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
 
-    if (srcDeviceDesc->hasSameHwModuleAs(sinkDeviceDesc) &&
-            srcDeviceDesc->getModuleVersionMajor() >= 3 &&
-            sinkDeviceDesc->getModule()->supportsPatch(srcDeviceDesc, sinkDeviceDesc) &&
-            srcDeviceDesc->getAudioPort()->mGains.size() > 0) {
+    if (srcDevice->hasSameHwModuleAs(sinkDevice) &&
+            srcDevice->getModuleVersionMajor() >= 3 &&
+            sinkDevice->getModule()->supportsPatch(srcDevice, sinkDevice) &&
+            srcDevice->getAudioPort()->mGains.size() > 0) {
         ALOGV("%s Device to Device route supported by >=3.0 HAL", __FUNCTION__);
         // TODO: may explicitly specify whether we should use HW or SW patch
         //   create patch between src device and output device
@@ -3479,12 +3505,12 @@
         getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE,
                 &attributes, &stream, sourceDesc->uid(), &config, &flags, &selectedDeviceId);
         if (output == AUDIO_IO_HANDLE_NONE) {
-            ALOGV("%s no output for device %08x", __FUNCTION__, sinkDevice);
+            ALOGV("%s no output for device %08x", __FUNCTION__, sinkDevices.types());
             return INVALID_OPERATION;
         }
         sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
         if (outputDesc->isDuplicated()) {
-            ALOGV("%s output for device %08x is duplicated", __FUNCTION__, sinkDevice);
+            ALOGV("%s output for device %08x is duplicated", __FUNCTION__, sinkDevices.types());
             return INVALID_OPERATION;
         }
         status_t status = outputDesc->start();
@@ -3498,7 +3524,7 @@
         // - the sink is defined by whatever output device is currently selected for the output
         // though which this patch is routed.
         PatchBuilder patchBuilder;
-        patchBuilder.addSource(srcDeviceDesc).addSource(outputDesc, { .stream = stream });
+        patchBuilder.addSource(srcDevice).addSource(outputDesc, { .stream = stream });
         status = mpClientInterface->createAudioPatch(patchBuilder.patch(),
                                                               &afPatchHandle,
                                                               0);
@@ -3925,8 +3951,6 @@
 
     // mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices
     // open all output streams needed to access attached devices
-    audio_devices_t outputDeviceTypes = mAvailableOutputDevices.types();
-    audio_devices_t inputDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
     for (const auto& hwModule : mHwModulesAll) {
         hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));
         if (hwModule->getHandle() == AUDIO_MODULE_HANDLE_NONE) {
@@ -3955,51 +3979,49 @@
             if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
                 continue;
             }
-            audio_devices_t profileType = outProfile->getSupportedDevicesType();
-            if ((profileType & mDefaultOutputDevice->type()) != AUDIO_DEVICE_NONE) {
-                profileType = mDefaultOutputDevice->type();
+            const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
+            DeviceVector availProfileDevices = supportedDevices.filter(mAvailableOutputDevices);
+            sp<DeviceDescriptor> supportedDevice = 0;
+            if (supportedDevices.contains(mDefaultOutputDevice)) {
+                supportedDevice = mDefaultOutputDevice;
             } else {
-                // chose first device present in profile's SupportedDevices also part of
-                // outputDeviceTypes
-                profileType = outProfile->getSupportedDeviceForType(outputDeviceTypes);
+                // choose first device present in profile's SupportedDevices also part of
+                // mAvailableOutputDevices.
+                if (availProfileDevices.isEmpty()) {
+                    continue;
+                }
+                supportedDevice = availProfileDevices.itemAt(0);
             }
-            if ((profileType & outputDeviceTypes) == 0) {
+            if (!mAvailableOutputDevices.contains(supportedDevice)) {
                 continue;
             }
             sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
                                                                                  mpClientInterface);
-            const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
-            const DeviceVector &devicesForType = supportedDevices.getDevicesFromTypeMask(
-                    profileType);
-            String8 address = getFirstDeviceAddress(devicesForType);
             audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-            status_t status = outputDesc->open(nullptr, profileType, address,
-                                           AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE, &output);
-
+            status_t status = outputDesc->open(nullptr, DeviceVector(supportedDevice),
+                                               AUDIO_STREAM_DEFAULT,
+                                               AUDIO_OUTPUT_FLAG_NONE, &output);
             if (status != NO_ERROR) {
-                ALOGW("Cannot open output stream for device %08x on hw module %s",
-                      outputDesc->mDevice,
-                      hwModule->getName());
-            } else {
-                for (const auto& dev : supportedDevices) {
-                    ssize_t index = mAvailableOutputDevices.indexOf(dev);
-                    // give a valid ID to an attached device once confirmed it is reachable
-                    if (index >= 0 && !mAvailableOutputDevices[index]->isAttached()) {
-                        mAvailableOutputDevices[index]->attach(hwModule);
-                    }
-                }
-                if (mPrimaryOutput == 0 &&
-                        outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
-                    mPrimaryOutput = outputDesc;
-                }
-                addOutput(output, outputDesc);
-                setOutputDevice(outputDesc,
-                                profileType,
-                                true,
-                                0,
-                                NULL,
-                                address);
+                ALOGW("Cannot open output stream for devices %s on hw module %s",
+                      supportedDevice->toString().c_str(), hwModule->getName());
+                continue;
             }
+            for (const auto &device : availProfileDevices) {
+                // give a valid ID to an attached device once confirmed it is reachable
+                if (!device->isAttached()) {
+                    device->attach(hwModule);
+                }
+            }
+            if (mPrimaryOutput == 0 &&
+                    outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
+                mPrimaryOutput = outputDesc;
+            }
+            addOutput(output, outputDesc);
+            setOutputDevices(outputDesc,
+                             DeviceVector(supportedDevice),
+                             true,
+                             0,
+                             NULL);
         }
         // open input streams needed to access attached devices to validate
         // mAvailableInputDevices list
@@ -4014,84 +4036,68 @@
                 continue;
             }
             // chose first device present in profile's SupportedDevices also part of
-            // inputDeviceTypes
-            audio_devices_t profileType = inProfile->getSupportedDeviceForType(inputDeviceTypes);
-
-            if ((profileType & inputDeviceTypes) == 0) {
+            // available input devices
+            const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
+            DeviceVector availProfileDevices = supportedDevices.filter(mAvailableInputDevices);
+            if (availProfileDevices.isEmpty()) {
+                ALOGE("%s: Input device list is empty!", __FUNCTION__);
                 continue;
             }
             sp<AudioInputDescriptor> inputDesc =
                     new AudioInputDescriptor(inProfile, mpClientInterface);
 
-            DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromTypeMask(profileType);
-            //   the inputs vector must be of size >= 1, but we don't want to crash here
-            String8 address = getFirstDeviceAddress(inputDevices);
-            ALOGV("  for input device 0x%x using address %s", profileType, address.string());
-            ALOGE_IF(inputDevices.size() == 0, "Input device list is empty!");
-
             audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
             status_t status = inputDesc->open(nullptr,
-                                              profileType,
-                                              address,
+                                              availProfileDevices.itemAt(0),
                                               AUDIO_SOURCE_MIC,
                                               AUDIO_INPUT_FLAG_NONE,
                                               &input);
-
-            if (status == NO_ERROR) {
-                for (const auto& dev : inProfile->getSupportedDevices()) {
-                    ssize_t index = mAvailableInputDevices.indexOf(dev);
-                    // give a valid ID to an attached device once confirmed it is reachable
-                    if (index >= 0) {
-                        sp<DeviceDescriptor> devDesc = mAvailableInputDevices[index];
-                        if (!devDesc->isAttached()) {
-                            devDesc->attach(hwModule);
-                            devDesc->importAudioPort(inProfile, true);
-                        }
-                    }
-                }
-                inputDesc->close();
-            } else {
-                ALOGW("Cannot open input stream for device %08x on hw module %s",
-                      profileType,
+            if (status != NO_ERROR) {
+                ALOGW("Cannot open input stream for device %s on hw module %s",
+                      availProfileDevices.toString().c_str(),
                       hwModule->getName());
+                continue;
             }
+            for (const auto &device : availProfileDevices) {
+                // give a valid ID to an attached device once confirmed it is reachable
+                if (!device->isAttached()) {
+                    device->attach(hwModule);
+                    device->importAudioPort(inProfile, true);
+                }
+            }
+            inputDesc->close();
         }
     }
     // make sure all attached devices have been allocated a unique ID
-    for (size_t i = 0; i  < mAvailableOutputDevices.size();) {
-        if (!mAvailableOutputDevices[i]->isAttached()) {
-            ALOGW("Output device %08x unreachable", mAvailableOutputDevices[i]->type());
-            mAvailableOutputDevices.remove(mAvailableOutputDevices[i]);
-            continue;
+    auto checkAndSetAvailable = [this](auto& devices) {
+        for (size_t i = 0; i < devices.size();) {
+            const auto &device = devices[i];
+            if (!device->isAttached()) {
+                ALOGW("device %s is unreachable", device->toString().c_str());
+                devices.remove(device);
+                continue;
+            }
+            // Device is now validated and can be appended to the available devices of the engine
+            mEngine->setDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+            i++;
         }
-        // The device is now validated and can be appended to the available devices of the engine
-        mEngine->setDeviceConnectionState(mAvailableOutputDevices[i],
-                                          AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
-        i++;
-    }
-    for (size_t i = 0; i  < mAvailableInputDevices.size();) {
-        if (!mAvailableInputDevices[i]->isAttached()) {
-            ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->type());
-            mAvailableInputDevices.remove(mAvailableInputDevices[i]);
-            continue;
-        }
-        // The device is now validated and can be appended to the available devices of the engine
-        mEngine->setDeviceConnectionState(mAvailableInputDevices[i],
-                                          AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
-        i++;
-    }
+    };
+    checkAndSetAvailable(mAvailableOutputDevices);
+    checkAndSetAvailable(mAvailableInputDevices);
+
     // make sure default device is reachable
-    if (mDefaultOutputDevice == 0 || mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) {
-        ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->type());
+    if (mDefaultOutputDevice == 0 || !mAvailableOutputDevices.contains(mDefaultOutputDevice)) {
+        ALOGE_IF(mDefaultOutputDevice != 0, "Default device %s is unreachable",
+                 mDefaultOutputDevice->toString().c_str());
         status = NO_INIT;
     }
     // If microphones address is empty, set it according to device type
     for (size_t i = 0; i  < mAvailableInputDevices.size(); i++) {
         if (mAvailableInputDevices[i]->address().isEmpty()) {
             if (mAvailableInputDevices[i]->type() == AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                mAvailableInputDevices[i]->address() = String8(AUDIO_BOTTOM_MICROPHONE_ADDRESS);
+                mAvailableInputDevices[i]->setAddress(String8(AUDIO_BOTTOM_MICROPHONE_ADDRESS));
             } else if (mAvailableInputDevices[i]->type() == AUDIO_DEVICE_IN_BACK_MIC) {
-                mAvailableInputDevices[i]->address() = String8(AUDIO_BACK_MICROPHONE_ADDRESS);
+                mAvailableInputDevices[i]->setAddress(String8(AUDIO_BACK_MICROPHONE_ADDRESS));
             }
         }
     }
@@ -4155,44 +4161,27 @@
     nextAudioPortGeneration();
 }
 
-void AudioPolicyManager::findIoHandlesByAddress(const sp<SwAudioOutputDescriptor>& desc /*in*/,
-        const audio_devices_t device /*in*/,
-        const String8& address /*in*/,
-        SortedVector<audio_io_handle_t>& outputs /*out*/) {
-    sp<DeviceDescriptor> devDesc =
-        desc->mProfile->getSupportedDeviceByAddress(device, address);
-    if (devDesc != 0) {
-        ALOGV("findIoHandlesByAddress(): adding opened output %d on same address %s",
-              desc->mIoHandle, address.string());
-        outputs.add(desc->mIoHandle);
-    }
-}
-
-status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor>& devDesc,
+status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor>& device,
                                                    audio_policy_dev_state_t state,
-                                                   SortedVector<audio_io_handle_t>& outputs,
-                                                   const String8& address)
+                                                   SortedVector<audio_io_handle_t>& outputs)
 {
-    audio_devices_t device = devDesc->type();
+    audio_devices_t deviceType = device->type();
+    const String8 &address = device->address();
     sp<SwAudioOutputDescriptor> desc;
 
-    if (audio_device_is_digital(device)) {
+    if (audio_device_is_digital(deviceType)) {
         // erase all current sample rates, formats and channel masks
-        devDesc->clearAudioProfiles();
+        device->clearAudioProfiles();
     }
 
     if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
         // first list already open outputs that can be routed to this device
         for (size_t i = 0; i < mOutputs.size(); i++) {
             desc = mOutputs.valueAt(i);
-            if (!desc->isDuplicated() && (desc->supportedDevices() & device)) {
-                if (!device_distinguishes_on_address(device)) {
-                    ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i));
-                    outputs.add(mOutputs.keyAt(i));
-                } else {
-                    ALOGV("  checking address match due to device 0x%x", device);
-                    findIoHandlesByAddress(desc, device, address, outputs);
-                }
+            if (!desc->isDuplicated() && desc->supportsDevice(device)) {
+                ALOGV("checkOutputsForDevice(): adding opened output %d on device %s",
+                      mOutputs.keyAt(i), device->toString().c_str());
+                outputs.add(mOutputs.keyAt(i));
             }
         }
         // then look for output profiles that can be routed to this device
@@ -4200,13 +4189,10 @@
         for (const auto& hwModule : mHwModules) {
             for (size_t j = 0; j < hwModule->getOutputProfiles().size(); j++) {
                 sp<IOProfile> profile = hwModule->getOutputProfiles()[j];
-                if (profile->supportDevice(device)) {
-                    if (!device_distinguishes_on_address(device) ||
-                            profile->supportDeviceAddress(address)) {
-                        profiles.add(profile);
-                        ALOGV("checkOutputsForDevice(): adding profile %zu from module %s",
-                                j, hwModule->getName());
-                    }
+                if (profile->supportsDevice(device)) {
+                    profiles.add(profile);
+                    ALOGV("checkOutputsForDevice(): adding profile %zu from module %s",
+                          j, hwModule->getName());
                 }
             }
         }
@@ -4214,7 +4200,7 @@
         ALOGV("  found %zu profiles, %zu outputs", profiles.size(), outputs.size());
 
         if (profiles.isEmpty() && outputs.isEmpty()) {
-            ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
+            ALOGW("checkOutputsForDevice(): No output available for device %04x", deviceType);
             return BAD_VALUE;
         }
 
@@ -4230,8 +4216,8 @@
                 if (!desc->isDuplicated() && desc->mProfile == profile) {
                     // matching profile: save the sample rates, format and channel masks supported
                     // by the profile in our device descriptor
-                    if (audio_device_is_digital(device)) {
-                        devDesc->importAudioPort(profile);
+                    if (audio_device_is_digital(deviceType)) {
+                        device->importAudioPort(profile);
                     }
                     break;
                 }
@@ -4247,20 +4233,20 @@
             }
 
             ALOGV("opening output for device %08x with params %s profile %p name %s",
-                  device, address.string(), profile.get(), profile->getName().string());
+                  deviceType, address.string(), profile.get(), profile->getName().string());
             desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
             audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-            status_t status = desc->open(nullptr, device, address,
+            status_t status = desc->open(nullptr, DeviceVector(device),
                                          AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE, &output);
 
             if (status == NO_ERROR) {
                 // Here is where the out_set_parameters() for card & device gets called
                 if (!address.isEmpty()) {
-                    char *param = audio_device_address_to_parameter(device, address);
+                    char *param = audio_device_address_to_parameter(deviceType, address);
                     mpClientInterface->setParameters(output, String8(param));
                     free(param);
                 }
-                updateAudioProfiles(devDesc, output, profile->getAudioProfiles());
+                updateAudioProfiles(device, output, profile->getAudioProfiles());
                 if (!profile->hasValidAudioProfile()) {
                     ALOGW("checkOutputsForDevice() missing param");
                     desc->close();
@@ -4275,7 +4261,8 @@
                     config.offload_info.channel_mask = config.channel_mask;
                     config.offload_info.format = config.format;
 
-                    status_t status = desc->open(&config, device, address, AUDIO_STREAM_DEFAULT,
+                    status_t status = desc->open(&config, DeviceVector(device),
+                                                 AUDIO_STREAM_DEFAULT,
                                                  AUDIO_OUTPUT_FLAG_NONE, &output);
                     if (status != NO_ERROR) {
                         output = AUDIO_IO_HANDLE_NONE;
@@ -4284,14 +4271,15 @@
 
                 if (output != AUDIO_IO_HANDLE_NONE) {
                     addOutput(output, desc);
-                    if (device_distinguishes_on_address(device) && address != "0") {
+                    if (device_distinguishes_on_address(deviceType) && address != "0") {
                         sp<AudioPolicyMix> policyMix;
-                        if (mPolicyMixes.getAudioPolicyMix(address, policyMix) != NO_ERROR) {
-                            ALOGE("checkOutputsForDevice() cannot find policy for address %s",
+                        if (mPolicyMixes.getAudioPolicyMix(address, policyMix) == NO_ERROR) {
+                            policyMix->setOutput(desc);
+                            desc->mPolicyMix = policyMix->getMix();
+                        } else {
+                            ALOGW("checkOutputsForDevice() cannot find policy for address %s",
                                   address.string());
                         }
-                        policyMix->setOutput(desc);
-                        desc->mPolicyMix = policyMix->getMix();
 
                     } else if (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) &&
                                     hasPrimaryOutput()) {
@@ -4323,28 +4311,28 @@
                 output = AUDIO_IO_HANDLE_NONE;
             }
             if (output == AUDIO_IO_HANDLE_NONE) {
-                ALOGW("checkOutputsForDevice() could not open output for device %x", device);
+                ALOGW("checkOutputsForDevice() could not open output for device %x", deviceType);
                 profiles.removeAt(profile_index);
                 profile_index--;
             } else {
                 outputs.add(output);
                 // Load digital format info only for digital devices
-                if (audio_device_is_digital(device)) {
-                    devDesc->importAudioPort(profile);
+                if (audio_device_is_digital(deviceType)) {
+                    device->importAudioPort(profile);
                 }
 
-                if (device_distinguishes_on_address(device)) {
-                    ALOGV("checkOutputsForDevice(): setOutputDevice(dev=0x%x, addr=%s)",
-                            device, address.string());
-                    setOutputDevice(desc, device, true/*force*/, 0/*delay*/,
-                            NULL/*patch handle*/, address.string());
+                if (device_distinguishes_on_address(deviceType)) {
+                    ALOGV("checkOutputsForDevice(): setOutputDevices %s",
+                            device->toString().c_str());
+                    setOutputDevices(desc, DeviceVector(device), true/*force*/, 0/*delay*/,
+                                     NULL/*patch handle*/);
                 }
                 ALOGV("checkOutputsForDevice(): adding output %d", output);
             }
         }
 
         if (profiles.isEmpty()) {
-            ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
+            ALOGW("checkOutputsForDevice(): No output available for device %04x", deviceType);
             return BAD_VALUE;
         }
     } else { // Disconnect
@@ -4353,10 +4341,9 @@
             desc = mOutputs.valueAt(i);
             if (!desc->isDuplicated()) {
                 // exact match on device
-                if (device_distinguishes_on_address(device) &&
-                        (desc->supportedDevices() == device)) {
-                    findIoHandlesByAddress(desc, device, address, outputs);
-                } else if (!(desc->supportedDevices() & mAvailableOutputDevices.types())) {
+                if (device_distinguishes_on_address(deviceType) && desc->supportsDevice(device)) {
+                    outputs.add(mOutputs.keyAt(i));
+                } else if (!mAvailableOutputDevices.containsAtLeastOne(desc->supportedDevices())) {
                     ALOGV("checkOutputsForDevice(): disconnecting adding output %d",
                             mOutputs.keyAt(i));
                     outputs.add(mOutputs.keyAt(i));
@@ -4367,7 +4354,7 @@
         for (const auto& hwModule : mHwModules) {
             for (size_t j = 0; j < hwModule->getOutputProfiles().size(); j++) {
                 sp<IOProfile> profile = hwModule->getOutputProfiles()[j];
-                if (profile->supportDevice(device)) {
+                if (profile->supportsDevice(device)) {
                     ALOGV("checkOutputsForDevice(): "
                             "clearing direct output profile %zu on module %s",
                             j, hwModule->getName());
@@ -4379,24 +4366,22 @@
     return NO_ERROR;
 }
 
-status_t AudioPolicyManager::checkInputsForDevice(const sp<DeviceDescriptor>& devDesc,
+status_t AudioPolicyManager::checkInputsForDevice(const sp<DeviceDescriptor>& device,
                                                   audio_policy_dev_state_t state,
-                                                  SortedVector<audio_io_handle_t>& inputs,
-                                                  const String8& address)
+                                                  SortedVector<audio_io_handle_t>& inputs)
 {
-    audio_devices_t device = devDesc->type();
     sp<AudioInputDescriptor> desc;
 
-    if (audio_device_is_digital(device)) {
+    if (audio_device_is_digital(device->type())) {
         // erase all current sample rates, formats and channel masks
-        devDesc->clearAudioProfiles();
+        device->clearAudioProfiles();
     }
 
     if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
         // first list already open inputs that can be routed to this device
         for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
             desc = mInputs.valueAt(input_index);
-            if (desc->mProfile->supportDevice(device)) {
+            if (desc->mProfile->supportsDeviceTypes(device->type())) {
                 ALOGV("checkInputsForDevice(): adding opened input %d", mInputs.keyAt(input_index));
                inputs.add(mInputs.keyAt(input_index));
             }
@@ -4410,19 +4395,16 @@
                  profile_index++) {
                 sp<IOProfile> profile = hwModule->getInputProfiles()[profile_index];
 
-                if (profile->supportDevice(device)) {
-                    if (!device_distinguishes_on_address(device) ||
-                            profile->supportDeviceAddress(address)) {
-                        profiles.add(profile);
-                        ALOGV("checkInputsForDevice(): adding profile %zu from module %s",
-                                profile_index, hwModule->getName());
-                    }
+                if (profile->supportsDevice(device)) {
+                    profiles.add(profile);
+                    ALOGV("checkInputsForDevice(): adding profile %zu from module %s",
+                          profile_index, hwModule->getName());
                 }
             }
         }
 
         if (profiles.isEmpty() && inputs.isEmpty()) {
-            ALOGW("checkInputsForDevice(): No input available for device 0x%X", device);
+            ALOGW("%s: No input available for device %s", __func__, device->toString().c_str());
             return BAD_VALUE;
         }
 
@@ -4437,8 +4419,8 @@
             for (input_index = 0; input_index < mInputs.size(); input_index++) {
                 desc = mInputs.valueAt(input_index);
                 if (desc->mProfile == profile) {
-                    if (audio_device_is_digital(device)) {
-                        devDesc->importAudioPort(profile);
+                    if (audio_device_is_digital(device->type())) {
+                        device->importAudioPort(profile);
                     }
                     break;
                 }
@@ -4457,18 +4439,18 @@
             audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
             status_t status = desc->open(nullptr,
                                          device,
-                                         address,
                                          AUDIO_SOURCE_MIC,
                                          AUDIO_INPUT_FLAG_NONE,
                                          &input);
 
             if (status == NO_ERROR) {
+                const String8& address = device->address();
                 if (!address.isEmpty()) {
-                    char *param = audio_device_address_to_parameter(device, address);
+                    char *param = audio_device_address_to_parameter(device->type(), address);
                     mpClientInterface->setParameters(input, String8(param));
                     free(param);
                 }
-                updateAudioProfiles(devDesc, input, profile->getAudioProfiles());
+                updateAudioProfiles(device, input, profile->getAudioProfiles());
                 if (!profile->hasValidAudioProfile()) {
                     ALOGW("checkInputsForDevice() direct input missing param");
                     desc->close();
@@ -4481,20 +4463,21 @@
             } // endif input != 0
 
             if (input == AUDIO_IO_HANDLE_NONE) {
-                ALOGW("checkInputsForDevice() could not open input for device 0x%X", device);
+                ALOGW("%s could not open input for device %s", __func__,  
+                       device->toString().c_str());
                 profiles.removeAt(profile_index);
                 profile_index--;
             } else {
                 inputs.add(input);
-                if (audio_device_is_digital(device)) {
-                    devDesc->importAudioPort(profile);
+                if (audio_device_is_digital(device->type())) {
+                    device->importAudioPort(profile);
                 }
                 ALOGV("checkInputsForDevice(): adding input %d", input);
             }
         } // end scan profiles
 
         if (profiles.isEmpty()) {
-            ALOGW("checkInputsForDevice(): No input available for device 0x%X", device);
+            ALOGW("%s: No input available for device %s", __func__,  device->toString().c_str());
             return BAD_VALUE;
         }
     } else {
@@ -4502,7 +4485,7 @@
         // check if one opened input is not needed any more after disconnecting one device
         for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
             desc = mInputs.valueAt(input_index);
-            if (!(desc->mProfile->supportDevice(mAvailableInputDevices.types()))) {
+            if (!mAvailableInputDevices.containsAtLeastOne(desc->supportedDevices())) {
                 ALOGV("checkInputsForDevice(): disconnecting adding input %d",
                       mInputs.keyAt(input_index));
                 inputs.add(mInputs.keyAt(input_index));
@@ -4514,7 +4497,7 @@
                  profile_index < hwModule->getInputProfiles().size();
                  profile_index++) {
                 sp<IOProfile> profile = hwModule->getInputProfiles()[profile_index];
-                if (profile->supportDevice(device)) {
+                if (profile->supportsDevice(device)) {
                     ALOGV("checkInputsForDevice(): clearing direct input profile %zu on module %s",
                             profile_index, hwModule->getName());
                     profile->clearAudioProfiles();
@@ -4588,7 +4571,7 @@
 
     // MSD patches may have been released to support a non-MSD direct output. Reset MSD patch if
     // no direct outputs are open.
-    if (mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD) != 0) {
+    if (!getMsdAudioOutDevices().isEmpty()) {
         bool directOutputOpen = false;
         for (size_t i = 0; i < mOutputs.size(); i++) {
             if (mOutputs[i]->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
@@ -4615,7 +4598,7 @@
 
     nextAudioPortGeneration();
 
-    audio_devices_t device = inputDesc->mDevice;
+    sp<DeviceDescriptor> device = inputDesc->getDevice();
     ssize_t index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
     if (index >= 0) {
         sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
@@ -4627,26 +4610,26 @@
     inputDesc->close();
     mInputs.removeItem(input);
 
-    audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
-    if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
+    DeviceVector primaryInputDevices = availablePrimaryModuleInputDevices();
+    if (primaryInputDevices.contains(device) &&
             mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
         SoundTrigger::setCaptureState(false);
     }
 }
 
-SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(
-                                                                audio_devices_t device,
-                                                                const SwAudioOutputCollection& openOutputs)
+SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevices(
+            const DeviceVector &devices,
+            const SwAudioOutputCollection& openOutputs)
 {
     SortedVector<audio_io_handle_t> outputs;
 
-    ALOGVV("getOutputsForDevice() device %04x", device);
+    ALOGVV("%s() devices %s", __func__, devices.toString().c_str());
     for (size_t i = 0; i < openOutputs.size(); i++) {
-        ALOGVV("output %zu isDuplicated=%d device=%04x",
+        ALOGVV("output %zu isDuplicated=%d device=%s",
                 i, openOutputs.valueAt(i)->isDuplicated(),
-                openOutputs.valueAt(i)->supportedDevices());
-        if ((device & openOutputs.valueAt(i)->supportedDevices()) == device) {
-            ALOGVV("getOutputsForDevice() found output %d", openOutputs.keyAt(i));
+                openOutputs.valueAt(i)->supportedDevices().toString().c_str());
+        if (openOutputs.valueAt(i)->supportsAllDevices(devices)) {
+            ALOGVV("%s() found output %d", __func__, openOutputs.keyAt(i));
             outputs.add(openOutputs.keyAt(i));
         }
     }
@@ -4668,10 +4651,10 @@
 
 void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy)
 {
-    audio_devices_t oldDevice = getDeviceForStrategy(strategy, true /*fromCache*/);
-    audio_devices_t newDevice = getDeviceForStrategy(strategy, false /*fromCache*/);
-    SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice, mPreviousOutputs);
-    SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(newDevice, mOutputs);
+    DeviceVector oldDevices = getDevicesForStrategy(strategy, true /*fromCache*/);
+    DeviceVector newDevices = getDevicesForStrategy(strategy, false /*fromCache*/);
+    SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevices(oldDevices, mPreviousOutputs);
+    SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevices(newDevices, mOutputs);
 
     // also take into account external policy-related changes: add all outputs which are
     // associated with policies in the "before" and "after" output vectors
@@ -4691,7 +4674,7 @@
         }
     }
 
-    if (srcOutputs != dstOutputs) {
+    if (!dstOutputs.isEmpty() && srcOutputs != dstOutputs) {
         // get maximum latency of all source outputs to determine the minimum mute time guaranteeing
         // audio from invalidated tracks will be rendered when unmuting
         uint32_t maxLatency = 0;
@@ -4701,14 +4684,16 @@
                 maxLatency = desc->latency();
             }
         }
-        ALOGV("checkOutputForStrategy() strategy %d, moving from output %d to output %d",
-              strategy, srcOutputs[0], dstOutputs[0]);
+        ALOGV("%s: strategy %d, moving from output %s to output %s", __func__, strategy,
+              (srcOutputs.isEmpty()? "none" : std::to_string(srcOutputs[0]).c_str()),
+              (dstOutputs.isEmpty()? "none" : std::to_string(dstOutputs[0]).c_str()));
         // mute strategy while moving tracks from one output to another
         for (audio_io_handle_t srcOut : srcOutputs) {
             sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
             if (desc != 0 && isStrategyActive(desc, strategy)) {
                 setStrategyMute(strategy, true, desc);
-                setStrategyMute(strategy, false, desc, maxLatency * LATENCY_MUTE_FACTOR, newDevice);
+                setStrategyMute(strategy, false, desc, maxLatency * LATENCY_MUTE_FACTOR,
+                                newDevices.types());
             }
             sp<SourceClientDescriptor> source =
                     getSourceForStrategyOnOutput(srcOut, strategy);
@@ -4827,26 +4812,28 @@
     return device;
 }
 
-audio_devices_t AudioPolicyManager::getNewOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
-                                                       bool fromCache)
+DeviceVector AudioPolicyManager::getNewOutputDevices(const sp<SwAudioOutputDescriptor>& outputDesc,
+                                                     bool fromCache)
 {
+    DeviceVector devices;
+
     ssize_t index = mAudioPatches.indexOfKey(outputDesc->getPatchHandle());
     if (index >= 0) {
         sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
         if (patchDesc->mUid != mUidCached) {
-            ALOGV("getNewOutputDevice() device %08x forced by patch %d",
-                  outputDesc->device(), outputDesc->getPatchHandle());
-            return outputDesc->device();
+            ALOGV("%s device %s forced by patch %d", __func__,
+                  outputDesc->devices().toString().c_str(), outputDesc->getPatchHandle());
+            return  outputDesc->devices();
         }
     }
 
     // Honor explicit routing requests only if no client using default routing is active on this
     // input: a specific app can not force routing for other apps by setting a preferred device.
     bool active; // unused
-    sp<DeviceDescriptor> deviceDesc =
+    sp<DeviceDescriptor> device =
         findPreferredDevice(outputDesc, STRATEGY_NONE, active, mAvailableOutputDevices);
-    if (deviceDesc != nullptr) {
-        return deviceDesc->type();
+    if (device != nullptr) {
+        return DeviceVector(device);
     }
 
     // check the following by order of priority to request a routing change if necessary:
@@ -4872,66 +4859,65 @@
     // FIXME: extend use of isStrategyActiveOnSameModule() to all strategies
     // with a refined rule considering mutually exclusive devices (using same backend)
     // as opposed to all streams on the same audio HAL module.
-    audio_devices_t device = AUDIO_DEVICE_NONE;
     if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE) &&
         mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
-        device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
+        devices = getDevicesForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
     } else if (isInCall() ||
                isStrategyActiveOnSameModule(outputDesc, STRATEGY_PHONE)) {
-        device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
+        devices = getDevicesForStrategy(STRATEGY_PHONE, fromCache);
     } else if (isStrategyActiveOnSameModule(outputDesc, STRATEGY_SONIFICATION)) {
-        device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
+        devices = getDevicesForStrategy(STRATEGY_SONIFICATION, fromCache);
     } else if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE)) {
-        device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
+        devices = getDevicesForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
     } else if (isStrategyActive(outputDesc, STRATEGY_ACCESSIBILITY)) {
-        device = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, fromCache);
+        devices = getDevicesForStrategy(STRATEGY_ACCESSIBILITY, fromCache);
     } else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION_RESPECTFUL)) {
-        device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache);
+        devices = getDevicesForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache);
     } else if (isStrategyActive(outputDesc, STRATEGY_MEDIA)) {
-        device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
+        devices = getDevicesForStrategy(STRATEGY_MEDIA, fromCache);
     } else if (isStrategyActive(outputDesc, STRATEGY_DTMF)) {
-        device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
+        devices = getDevicesForStrategy(STRATEGY_DTMF, fromCache);
     } else if (isStrategyActive(outputDesc, STRATEGY_TRANSMITTED_THROUGH_SPEAKER)) {
-        device = getDeviceForStrategy(STRATEGY_TRANSMITTED_THROUGH_SPEAKER, fromCache);
+        devices = getDevicesForStrategy(STRATEGY_TRANSMITTED_THROUGH_SPEAKER, fromCache);
     } else if (isStrategyActive(outputDesc, STRATEGY_REROUTING)) {
-        device = getDeviceForStrategy(STRATEGY_REROUTING, fromCache);
+        devices = getDevicesForStrategy(STRATEGY_REROUTING, fromCache);
     }
 
-    ALOGV("getNewOutputDevice() selected device %x", device);
-    return device;
+    ALOGV("getNewOutputDevice() selected devices %s", devices.toString().c_str());
+    return devices;
 }
 
-audio_devices_t AudioPolicyManager::getNewInputDevice(const sp<AudioInputDescriptor>& inputDesc)
+sp<DeviceDescriptor> AudioPolicyManager::getNewInputDevice(
+        const sp<AudioInputDescriptor>& inputDesc)
 {
-    audio_devices_t device = AUDIO_DEVICE_NONE;
+    sp<DeviceDescriptor> device;
 
     ssize_t index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
     if (index >= 0) {
         sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
         if (patchDesc->mUid != mUidCached) {
-            ALOGV("getNewInputDevice() device %08x forced by patch %d",
-                  inputDesc->mDevice, inputDesc->getPatchHandle());
-            return inputDesc->mDevice;
+            ALOGV("getNewInputDevice() device %s forced by patch %d",
+                  inputDesc->getDevice()->toString().c_str(), inputDesc->getPatchHandle());
+            return inputDesc->getDevice();
         }
     }
 
     // Honor explicit routing requests only if no client using default routing is active on this
     // input: a specific app can not force routing for other apps by setting a preferred device.
     bool active;
-    sp<DeviceDescriptor> deviceDesc =
-        findPreferredDevice(inputDesc, AUDIO_SOURCE_DEFAULT, active, mAvailableInputDevices);
-    if (deviceDesc != nullptr) {
-        return deviceDesc->type();
+    device = findPreferredDevice(inputDesc, AUDIO_SOURCE_DEFAULT, active, mAvailableInputDevices);
+    if (device != nullptr) {
+        return device;
     }
 
     // If we are not in call and no client is active on this input, this methods returns
     // AUDIO_DEVICE_NONE, causing the patch on the input stream to be released.
-    audio_source_t source = inputDesc->source();
-    if (source == AUDIO_SOURCE_DEFAULT && isInCall()) {
-        source = AUDIO_SOURCE_VOICE_COMMUNICATION;
+    audio_attributes_t attributes = inputDesc->getHighestPriorityAttributes();
+    if (attributes.source == AUDIO_SOURCE_DEFAULT && isInCall()) {
+        attributes.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
     }
-    if (source != AUDIO_SOURCE_DEFAULT) {
-        device = getDeviceAndMixForInputSource(source);
+    if (attributes.source != AUDIO_SOURCE_DEFAULT) {
+        device = getDeviceAndMixForAttributes(attributes);
     }
 
     return device;
@@ -4953,36 +4939,37 @@
     if (stream < (audio_stream_type_t) 0 || stream >= AUDIO_STREAM_PUBLIC_CNT) {
         return AUDIO_DEVICE_NONE;
     }
-    audio_devices_t activeDevices = AUDIO_DEVICE_NONE;
-    audio_devices_t devices = AUDIO_DEVICE_NONE;
+    DeviceVector activeDevices;
+    DeviceVector devices;
     for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
         if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
             continue;
         }
         routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
-        audio_devices_t curDevices =
-                getDeviceForStrategy((routing_strategy)curStrategy, false /*fromCache*/);
-        devices |= curDevices;
-        for (audio_io_handle_t output : getOutputsForDevice(curDevices, mOutputs)) {
+        DeviceVector curDevices =
+                getDevicesForStrategy((routing_strategy)curStrategy, false /*fromCache*/);
+        devices.merge(curDevices);
+        for (audio_io_handle_t output : getOutputsForDevices(curDevices, mOutputs)) {
             sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
             if (outputDesc->isStreamActive((audio_stream_type_t)curStream)) {
-                activeDevices |= outputDesc->device();
+                activeDevices.merge(outputDesc->devices());
             }
         }
     }
 
     // Favor devices selected on active streams if any to report correct device in case of
     // explicit device selection
-    if (activeDevices != AUDIO_DEVICE_NONE) {
+    if (!activeDevices.isEmpty()) {
         devices = activeDevices;
     }
     /*Filter SPEAKER_SAFE out of results, as AudioService doesn't know about it
       and doesn't really need to.*/
-    if (devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
-        devices |= AUDIO_DEVICE_OUT_SPEAKER;
-        devices &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+    DeviceVector speakerSafeDevices = devices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER_SAFE);
+    if (!speakerSafeDevices.isEmpty()) {
+        devices.merge(mAvailableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER));
+        devices.remove(speakerSafeDevices);
     }
-    return devices;
+    return devices.types();
 }
 
 routing_strategy AudioPolicyManager::getStrategy(audio_stream_type_t stream) const
@@ -5073,34 +5060,33 @@
     return 0;
 }
 
-audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
-                                                         bool fromCache)
+DeviceVector AudioPolicyManager::getDevicesForStrategy(routing_strategy strategy, bool fromCache)
 {
     // Honor explicit routing requests only if all active clients have a preferred route in which
     // case the last active client route is used
-    sp<DeviceDescriptor> deviceDesc = findPreferredDevice(mOutputs, strategy, mAvailableOutputDevices);
-    if (deviceDesc != nullptr) {
-        return deviceDesc->type();
+    sp<DeviceDescriptor> device = findPreferredDevice(mOutputs, strategy, mAvailableOutputDevices);
+    if (device != nullptr) {
+        return DeviceVector(device);
     }
 
     if (fromCache) {
-        ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",
-              strategy, mDeviceForStrategy[strategy]);
-        return mDeviceForStrategy[strategy];
+        ALOGVV("%s from cache strategy %d, device %s", __func__, strategy,
+               mDevicesForStrategy[strategy].toString().c_str());
+        return mDevicesForStrategy[strategy];
     }
-    return mEngine->getDeviceForStrategy(strategy);
+    return mAvailableOutputDevices.getDevicesFromTypeMask(mEngine->getDeviceForStrategy(strategy));
 }
 
 void AudioPolicyManager::updateDevicesAndOutputs()
 {
     for (int i = 0; i < NUM_STRATEGIES; i++) {
-        mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
+        mDevicesForStrategy[i] = getDevicesForStrategy((routing_strategy)i, false /*fromCache*/);
     }
     mPreviousOutputs = mOutputs;
 }
 
 uint32_t AudioPolicyManager::checkDeviceMuteStrategies(const sp<AudioOutputDescriptor>& outputDesc,
-                                                       audio_devices_t prevDevice,
+                                                       audio_devices_t prevDeviceType,
                                                        uint32_t delayMs)
 {
     // mute/unmute strategies using an incompatible device combination
@@ -5111,13 +5097,14 @@
     }
 
     uint32_t muteWaitMs = 0;
-    audio_devices_t device = outputDesc->device();
-    bool shouldMute = outputDesc->isActive() && (popcount(device) >= 2);
+    audio_devices_t deviceType = outputDesc->devices().types();
+    bool shouldMute = outputDesc->isActive() && (popcount(deviceType) >= 2);
 
     for (size_t i = 0; i < NUM_STRATEGIES; i++) {
-        audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
-        curDevice = curDevice & outputDesc->supportedDevices();
-        bool mute = shouldMute && (curDevice & device) && (curDevice != device);
+        audio_devices_t curDeviceType =
+                getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
+        curDeviceType = curDeviceType & outputDesc->supportedDevices().types();
+        bool mute = shouldMute && (curDeviceType & deviceType) && (curDeviceType != deviceType);
         bool doMute = false;
 
         if (mute && !outputDesc->mStrategyMutedByDevice[i]) {
@@ -5131,12 +5118,11 @@
             for (size_t j = 0; j < mOutputs.size(); j++) {
                 sp<AudioOutputDescriptor> desc = mOutputs.valueAt(j);
                 // skip output if it does not share any device with current output
-                if ((desc->supportedDevices() & outputDesc->supportedDevices())
-                        == AUDIO_DEVICE_NONE) {
+                if (!desc->supportedDevices().containsAtLeastOne(outputDesc->supportedDevices())) {
                     continue;
                 }
                 ALOGVV("checkDeviceMuteStrategies() %s strategy %zu (curDevice %04x)",
-                      mute ? "muting" : "unmuting", i, curDevice);
+                      mute ? "muting" : "unmuting", i, curDeviceType);
                 setStrategyMute((routing_strategy)i, mute, desc, mute ? 0 : delayMs);
                 if (isStrategyActive(desc, (routing_strategy)i)) {
                     if (mute) {
@@ -5156,7 +5142,7 @@
 
     // temporary mute output if device selection changes to avoid volume bursts due to
     // different per device volumes
-    if (outputDesc->isActive() && (device != prevDevice)) {
+    if (outputDesc->isActive() && (deviceType != prevDeviceType)) {
         uint32_t tempMuteWaitMs = outputDesc->latency() * 2;
         // temporary mute duration is conservatively set to 4 times the reported latency
         uint32_t tempMuteDurationMs = outputDesc->latency() * 4;
@@ -5170,7 +5156,7 @@
                 // delayed device change
                 setStrategyMute((routing_strategy)i, true, outputDesc, delayMs);
                 setStrategyMute((routing_strategy)i, false, outputDesc,
-                                delayMs + tempMuteDurationMs, device);
+                                delayMs + tempMuteDurationMs, deviceType);
             }
         }
     }
@@ -5184,46 +5170,45 @@
     return 0;
 }
 
-uint32_t AudioPolicyManager::setOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
-                                             audio_devices_t device,
-                                             bool force,
-                                             int delayMs,
-                                             audio_patch_handle_t *patchHandle,
-                                             const char *address,
-                                             bool requiresMuteCheck)
+uint32_t AudioPolicyManager::setOutputDevices(const sp<SwAudioOutputDescriptor>& outputDesc,
+                                              const DeviceVector &devices,
+                                              bool force,
+                                              int delayMs,
+                                              audio_patch_handle_t *patchHandle,
+                                              bool requiresMuteCheck)
 {
-    ALOGV("setOutputDevice() device %04x delayMs %d", device, delayMs);
-    AudioParameter param;
+    ALOGV("%s device %s delayMs %d", __func__, devices.toString().c_str(), delayMs);
     uint32_t muteWaitMs;
 
     if (outputDesc->isDuplicated()) {
-        muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs,
-                nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
-        muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs,
-                nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
+        muteWaitMs = setOutputDevices(outputDesc->subOutput1(), devices, force, delayMs,
+                nullptr /* patchHandle */, requiresMuteCheck);
+        muteWaitMs += setOutputDevices(outputDesc->subOutput2(), devices, force, delayMs,
+                nullptr /* patchHandle */, requiresMuteCheck);
         return muteWaitMs;
     }
-    // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
-    // output profile
-    if ((device != AUDIO_DEVICE_NONE) &&
-            ((device & outputDesc->supportedDevices()) == AUDIO_DEVICE_NONE)) {
-        return 0;
-    }
 
     // filter devices according to output selected
-    device = (audio_devices_t)(device & outputDesc->supportedDevices());
+    DeviceVector filteredDevices = outputDesc->filterSupportedDevices(devices);
 
-    audio_devices_t prevDevice = outputDesc->mDevice;
+    // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
+    // output profile
+    if (!devices.isEmpty() && filteredDevices.isEmpty()) {
+        ALOGV("%s: unsupported device %s for output", __func__, devices.toString().c_str());
+        return 0;
+    }
 
-    ALOGV("setOutputDevice() prevDevice 0x%04x", prevDevice);
+    DeviceVector prevDevices = outputDesc->devices();
 
-    if (device != AUDIO_DEVICE_NONE) {
-        outputDesc->mDevice = device;
+    ALOGV("setOutputDevices() prevDevice %s", prevDevices.toString().c_str());
+
+    if (!filteredDevices.isEmpty()) {
+        outputDesc->setDevices(filteredDevices);
     }
 
     // if the outputs are not materially active, there is no need to mute.
     if (requiresMuteCheck) {
-        muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+        muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevices.types(), delayMs);
     } else {
         ALOGV("%s: suppressing checkDeviceMuteStrategies", __func__);
         muteWaitMs = 0;
@@ -5234,42 +5219,32 @@
     //      OR the requested device is the same as current device
     //  AND force is not specified
     //  AND the output is connected by a valid audio patch.
-    // Doing this check here allows the caller to call setOutputDevice() without conditions
-    if ((device == AUDIO_DEVICE_NONE || device == prevDevice) &&
-        !force &&
-        outputDesc->getPatchHandle() != 0) {
-        ALOGV("setOutputDevice() setting same device 0x%04x or null device", device);
+    // Doing this check here allows the caller to call setOutputDevices() without conditions
+    if ((!filteredDevices.isEmpty() || filteredDevices == prevDevices) &&
+            !force && outputDesc->getPatchHandle() != 0) {
+        ALOGV("%s setting same device %s or null device, force=%d, patch handle=%d", __func__,
+              filteredDevices.toString().c_str(), force, outputDesc->getPatchHandle());
         return muteWaitMs;
     }
 
-    ALOGV("setOutputDevice() changing device");
+    ALOGV("%s changing device to %s", __func__, filteredDevices.toString().c_str());
 
     // do the routing
-    if (device == AUDIO_DEVICE_NONE) {
+    if (filteredDevices.isEmpty()) {
         resetOutputDevice(outputDesc, delayMs, NULL);
     } else {
-        DeviceVector deviceList;
-        if ((address == NULL) || (strlen(address) == 0)) {
-            deviceList = mAvailableOutputDevices.getDevicesFromTypeMask(device);
-        } else {
-            sp<DeviceDescriptor> deviceDesc = mAvailableOutputDevices.getDevice(
-                    device, String8(address));
-            if (deviceDesc) deviceList.add(deviceDesc);
+        PatchBuilder patchBuilder;
+        patchBuilder.addSource(outputDesc);
+        ALOG_ASSERT(filteredDevices.size() <= AUDIO_PATCH_PORTS_MAX, "Too many sink ports");
+        for (const auto &filteredDevice : filteredDevices) {
+            patchBuilder.addSink(filteredDevice);
         }
 
-        if (!deviceList.isEmpty()) {
-            PatchBuilder patchBuilder;
-            patchBuilder.addSource(outputDesc);
-            ALOG_ASSERT(deviceList.size() <= AUDIO_PATCH_PORTS_MAX, "Too many sink ports");
-            for (const auto &device : deviceList) {
-                patchBuilder.addSink(device);
-            }
-            installPatch(__func__, patchHandle, outputDesc.get(), patchBuilder.patch(), delayMs);
-        }
+        installPatch(__func__, patchHandle, outputDesc.get(), patchBuilder.patch(), delayMs);
     }
 
     // update stream volumes according to new device
-    applyStreamVolumes(outputDesc, device, delayMs);
+    applyStreamVolumes(outputDesc, filteredDevices.types(), delayMs);
 
     return muteWaitMs;
 }
@@ -5298,18 +5273,17 @@
 }
 
 status_t AudioPolicyManager::setInputDevice(audio_io_handle_t input,
-                                            audio_devices_t device,
+                                            const sp<DeviceDescriptor> &device,
                                             bool force,
                                             audio_patch_handle_t *patchHandle)
 {
     status_t status = NO_ERROR;
 
     sp<AudioInputDescriptor> inputDesc = mInputs.valueFor(input);
-    if ((device != AUDIO_DEVICE_NONE) && ((device != inputDesc->mDevice) || force)) {
-        inputDesc->mDevice = device;
+    if ((device != nullptr) && ((device != inputDesc->getDevice()) || force)) {
+        inputDesc->setDevice(device);
 
-        DeviceVector deviceList = mAvailableInputDevices.getDevicesFromTypeMask(device);
-        if (!deviceList.isEmpty()) {
+        if (mAvailableInputDevices.contains(device)) {
             PatchBuilder patchBuilder;
             patchBuilder.addSink(inputDesc,
             // AUDIO_SOURCE_HOTWORD is for internal use only:
@@ -5321,7 +5295,7 @@
                         }
                         return result; }).
             //only one input device for now
-                    addSource(deviceList.itemAt(0));
+                    addSource(device);
             status = installPatch(__func__, patchHandle, inputDesc.get(), patchBuilder.patch(), 0);
         }
     }
@@ -5351,8 +5325,7 @@
     return status;
 }
 
-sp<IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
-                                                  const String8& address,
+sp<IOProfile> AudioPolicyManager::getInputProfile(const sp<DeviceDescriptor> &device,
                                                   uint32_t& samplingRate,
                                                   audio_format_t& format,
                                                   audio_channel_mask_t& channelMask,
@@ -5372,7 +5345,7 @@
         for (const auto& profile : hwModule->getInputProfiles()) {
             // profile->log();
             //updatedFormat = format;
-            if (profile->isCompatibleProfile(device, address, samplingRate,
+            if (profile->isCompatibleProfile(DeviceVector(device), samplingRate,
                                              &samplingRate  /*updatedSamplingRate*/,
                                              format,
                                              &format,       /*updatedFormat*/
@@ -5383,7 +5356,7 @@
                                              true /*exactMatchRequiredForInputFlags*/)) {
                 return profile;
             }
-            if (firstInexact == nullptr && profile->isCompatibleProfile(device, address,
+            if (firstInexact == nullptr && profile->isCompatibleProfile(DeviceVector(device),
                                              samplingRate,
                                              &updatedSamplingRate,
                                              format,
@@ -5407,32 +5380,33 @@
     return NULL;
 }
 
-
-audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource,
-                                                                  AudioMix **policyMix)
+sp<DeviceDescriptor> AudioPolicyManager::getDeviceAndMixForAttributes(
+        const audio_attributes_t &attributes, AudioMix **policyMix)
 {
     // Honor explicit routing requests only if all active clients have a preferred route in which
     // case the last active client route is used
-    sp<DeviceDescriptor> deviceDesc =
-        findPreferredDevice(mInputs, inputSource, mAvailableInputDevices);
-    if (deviceDesc != nullptr) {
-        return deviceDesc->type();
+    sp<DeviceDescriptor> device =
+        findPreferredDevice(mInputs, attributes.source, mAvailableInputDevices);
+    if (device != nullptr) {
+        return device;
     }
 
-
-    audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
-    audio_devices_t selectedDeviceFromMix =
-           mPolicyMixes.getDeviceAndMixForInputSource(inputSource, availableDeviceTypes, policyMix);
-
-    if (selectedDeviceFromMix != AUDIO_DEVICE_NONE) {
-        return selectedDeviceFromMix;
-    }
-    return getDeviceForInputSource(inputSource);
+    sp<DeviceDescriptor> selectedDeviceFromMix =
+           mPolicyMixes.getDeviceAndMixForInputSource(attributes.source, mAvailableInputDevices,
+                                                      policyMix);
+    return (selectedDeviceFromMix != nullptr) ?
+           selectedDeviceFromMix : getDeviceForAttributes(attributes);
 }
 
-audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource)
+sp<DeviceDescriptor> AudioPolicyManager::getDeviceForAttributes(const audio_attributes_t &attributes)
 {
-    return mEngine->getDeviceForInputSource(inputSource);
+    audio_devices_t device = mEngine->getDeviceForInputSource(attributes.source);
+    if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
+                strncmp(attributes.tags, "addr=", strlen("addr=")) == 0) {
+        return mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+                                                String8(attributes.tags + strlen("addr=")));
+    }
+    return mAvailableInputDevices.getDevice(device);
 }
 
 float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
@@ -5577,7 +5551,7 @@
     }
 
     if (device == AUDIO_DEVICE_NONE) {
-        device = outputDesc->device();
+        device = outputDesc->devices().types();
     }
 
     float volumeDb = computeVolume(stream, index, device);
@@ -5648,7 +5622,7 @@
                                            audio_devices_t device)
 {
     if (device == AUDIO_DEVICE_NONE) {
-        device = outputDesc->device();
+        device = outputDesc->devices().types();
     }
 
     ALOGVV("setStreamMute() stream %d, mute %d, mMuteCount %d device %04x",
@@ -5745,9 +5719,9 @@
     return false;
 }
 
-bool AudioPolicyManager::isStrategyActiveOnSameModule(const sp<AudioOutputDescriptor>& outputDesc,
-                                          routing_strategy strategy, uint32_t inPastMs,
-                                          nsecs_t sysTime) const
+bool AudioPolicyManager::isStrategyActiveOnSameModule(const sp<SwAudioOutputDescriptor>& outputDesc,
+                                                      routing_strategy strategy, uint32_t inPastMs,
+                                                      nsecs_t sysTime) const
 {
     for (size_t i = 0; i < mOutputs.size(); i++) {
         sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
@@ -5806,6 +5780,8 @@
             releaseAudioPatch(patchDesc->mHandle, patchDesc->mUid);
         }
     }
+
+    mHwModules.cleanUpForDevice(deviceDesc);
 }
 
 void AudioPolicyManager::modifySurroundFormats(
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 35dd87c..e99de16 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -218,6 +218,9 @@
 
         virtual status_t registerPolicyMixes(const Vector<AudioMix>& mixes);
         virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes);
+        virtual status_t setUidDeviceAffinities(uid_t uid,
+                const Vector<AudioDeviceTypeAddr>& devices);
+        virtual status_t removeUidDeviceAffinities(uid_t uid);
 
         virtual status_t startAudioSource(const struct audio_port_config *source,
                                           const audio_attributes_t *attributes,
@@ -310,36 +313,40 @@
         //  where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
         //  before updateDevicesAndOutputs() is called.
         virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy,
-                                                     bool fromCache);
+                                                     bool fromCache)
+        {
+            return getDevicesForStrategy(strategy, fromCache).types();
+        }
+
+        DeviceVector getDevicesForStrategy(routing_strategy strategy, bool fromCache);
 
         bool isStrategyActive(const sp<AudioOutputDescriptor>& outputDesc, routing_strategy strategy,
                               uint32_t inPastMs = 0, nsecs_t sysTime = 0) const;
 
-        bool isStrategyActiveOnSameModule(const sp<AudioOutputDescriptor>& outputDesc,
-                                                  routing_strategy strategy, uint32_t inPastMs = 0,
-                                                  nsecs_t sysTime = 0) const;
+        bool isStrategyActiveOnSameModule(const sp<SwAudioOutputDescriptor>& outputDesc,
+                                          routing_strategy strategy, uint32_t inPastMs = 0,
+                                          nsecs_t sysTime = 0) const;
 
         // change the route of the specified output. Returns the number of ms we have slept to
         // allow new routing to take effect in certain cases.
-        virtual uint32_t setOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
-                             audio_devices_t device,
-                             bool force = false,
-                             int delayMs = 0,
-                             audio_patch_handle_t *patchHandle = NULL,
-                             const char *address = nullptr,
-                             bool requiresMuteCheck = true);
+        uint32_t setOutputDevices(const sp<SwAudioOutputDescriptor>& outputDesc,
+                                  const DeviceVector &device,
+                                  bool force = false,
+                                  int delayMs = 0,
+                                  audio_patch_handle_t *patchHandle = NULL,
+                                  bool requiresMuteCheck = true);
         status_t resetOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
                                    int delayMs = 0,
                                    audio_patch_handle_t *patchHandle = NULL);
         status_t setInputDevice(audio_io_handle_t input,
-                                audio_devices_t device,
+                                const sp<DeviceDescriptor> &device,
                                 bool force = false,
                                 audio_patch_handle_t *patchHandle = NULL);
         status_t resetInputDevice(audio_io_handle_t input,
                                   audio_patch_handle_t *patchHandle = NULL);
 
         // select input device corresponding to requested audio source
-        virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource);
+        sp<DeviceDescriptor> getDeviceForAttributes(const audio_attributes_t &attributes);
 
         // compute the actual volume for a given stream according to the requested index and a particular
         // device
@@ -388,15 +395,13 @@
         // when a device is disconnected, checks if an output is not used any more and
         // returns its handle if any.
         // transfers the audio tracks and effects from one output thread to another accordingly.
-        status_t checkOutputsForDevice(const sp<DeviceDescriptor>& devDesc,
+        status_t checkOutputsForDevice(const sp<DeviceDescriptor>& device,
                                        audio_policy_dev_state_t state,
-                                       SortedVector<audio_io_handle_t>& outputs,
-                                       const String8& address);
+                                       SortedVector<audio_io_handle_t>& outputs);
 
-        status_t checkInputsForDevice(const sp<DeviceDescriptor>& devDesc,
+        status_t checkInputsForDevice(const sp<DeviceDescriptor>& device,
                                       audio_policy_dev_state_t state,
-                                      SortedVector<audio_io_handle_t>& inputs,
-                                      const String8& address);
+                                      SortedVector<audio_io_handle_t>& inputs);
 
         // close an output and its companion duplicating output.
         void closeOutput(audio_io_handle_t output);
@@ -434,8 +439,8 @@
         // must be called every time a condition that affects the device choice for a given output is
         // changed: connected device, phone state, force use, output start, output stop..
         // see getDeviceForStrategy() for the use of fromCache parameter
-        audio_devices_t getNewOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
-                                           bool fromCache);
+        DeviceVector getNewOutputDevices(const sp<SwAudioOutputDescriptor>& outputDesc,
+                                         bool fromCache);
 
         // updates cache of device used by all strategies (mDeviceForStrategy[])
         // must be called every time a condition that affects the device choice for a given strategy is
@@ -445,7 +450,7 @@
         void updateDevicesAndOutputs();
 
         // selects the most appropriate device on input for current state
-        audio_devices_t getNewInputDevice(const sp<AudioInputDescriptor>& inputDesc);
+        sp<DeviceDescriptor> getNewInputDevice(const sp<AudioInputDescriptor>& inputDesc);
 
         virtual uint32_t getMaxEffectsCpuLoad()
         {
@@ -457,16 +462,16 @@
             return mEffects.getMaxEffectsMemory();
         }
 
-        SortedVector<audio_io_handle_t> getOutputsForDevice(audio_devices_t device,
-                                                            const SwAudioOutputCollection& openOutputs);
+        SortedVector<audio_io_handle_t> getOutputsForDevices(
+                const DeviceVector &devices, const SwAudioOutputCollection& openOutputs);
 
         // mute/unmute strategies using an incompatible device combination
         // if muting, wait for the audio in pcm buffer to be drained before proceeding
         // if unmuting, unmute only after the specified delay
         // Returns the number of ms waited
         virtual uint32_t  checkDeviceMuteStrategies(const sp<AudioOutputDescriptor>& outputDesc,
-                                            audio_devices_t prevDevice,
-                                            uint32_t delayMs);
+                                                    audio_devices_t prevDeviceType,
+                                                    uint32_t delayMs);
 
         audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
                                        audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
@@ -474,13 +479,22 @@
                                        audio_channel_mask_t channelMask = AUDIO_CHANNEL_NONE,
                                        uint32_t samplingRate = 0);
         // samplingRate, format, channelMask are in/out and so may be modified
-        sp<IOProfile> getInputProfile(audio_devices_t device,
-                                      const String8& address,
+        sp<IOProfile> getInputProfile(const sp<DeviceDescriptor> & device,
                                       uint32_t& samplingRate,
                                       audio_format_t& format,
                                       audio_channel_mask_t& channelMask,
                                       audio_input_flags_t flags);
-        sp<IOProfile> getProfileForOutput(audio_devices_t device,
+        /**
+         * @brief getProfileForOutput
+         * @param devices vector of descriptors, may be empty if ignoring the device is required
+         * @param samplingRate
+         * @param format
+         * @param channelMask
+         * @param flags
+         * @param directOnly
+         * @return IOProfile to be used if found, nullptr otherwise
+         */
+        sp<IOProfile> getProfileForOutput(const DeviceVector &devices,
                                           uint32_t samplingRate,
                                           audio_format_t format,
                                           audio_channel_mask_t channelMask,
@@ -498,19 +512,19 @@
             return mAudioPatches.removeAudioPatch(handle);
         }
 
-        audio_devices_t availablePrimaryOutputDevices() const
+        DeviceVector availablePrimaryOutputDevices() const
         {
             if (!hasPrimaryOutput()) {
-                return AUDIO_DEVICE_NONE;
+                return DeviceVector();
             }
-            return mPrimaryOutput->supportedDevices() & mAvailableOutputDevices.types();
+            return mAvailableOutputDevices.filter(mPrimaryOutput->supportedDevices());
         }
-        audio_devices_t availablePrimaryInputDevices() const
+        DeviceVector availablePrimaryModuleInputDevices() const
         {
             if (!hasPrimaryOutput()) {
-                return AUDIO_DEVICE_NONE;
+                return DeviceVector();
             }
-            return mAvailableInputDevices.getDeviceTypesFromHwModule(
+            return mAvailableInputDevices.getDevicesFromHwModule(
                     mPrimaryOutput->getModuleHandle());
         }
         /**
@@ -527,8 +541,9 @@
             return (devices.size() > 0) ? devices.itemAt(0)->address() : String8("");
         }
 
-        uint32_t updateCallRouting(audio_devices_t rxDevice, uint32_t delayMs = 0);
-        sp<AudioPatch> createTelephonyPatch(bool isRx, audio_devices_t device, uint32_t delayMs);
+        uint32_t updateCallRouting(const DeviceVector &rxDevices, uint32_t delayMs = 0);
+        sp<AudioPatch> createTelephonyPatch(bool isRx, const sp<DeviceDescriptor> &device,
+                                            uint32_t delayMs);
         sp<DeviceDescriptor> findDevice(
                 const DeviceVector& devices, audio_devices_t device) const;
         audio_devices_t getModuleDeviceTypes(
@@ -578,7 +593,16 @@
         DeviceVector  mAvailableInputDevices;  // all available input devices
 
         bool    mLimitRingtoneVolume;        // limit ringtone volume to music volume if headset connected
-        audio_devices_t mDeviceForStrategy[NUM_STRATEGIES];
+
+        /**
+         * @brief mDevicesForStrategy vector of devices that are assigned for a given strategy.
+         * Note: in case of removal of device (@see setDeviceConnectionState), the device descriptor
+         * will be removed from the @see mAvailableOutputDevices or @see mAvailableInputDevices
+         * but the devices for strategies will be reevaluated within the
+         * @see setDeviceConnectionState function.
+         */
+        DeviceVector mDevicesForStrategy[NUM_STRATEGIES];
+
         float   mLastVoiceVolume;            // last voice volume value sent to audio HAL
         bool    mA2dpSuspended;  // true if A2DP output is suspended
 
@@ -634,13 +658,14 @@
 
         // Support for Multi-Stream Decoder (MSD) module
         sp<DeviceDescriptor> getMsdAudioInDevice() const;
+        DeviceVector getMsdAudioOutDevices() const;
         const AudioPatchCollection getMsdPatches() const;
-        status_t getBestMsdAudioProfileFor(audio_devices_t outputDevice,
+        status_t getBestMsdAudioProfileFor(const sp<DeviceDescriptor> &outputDevice,
                                            bool hwAvSync,
                                            audio_port_config *sourceConfig,
                                            audio_port_config *sinkConfig) const;
-        PatchBuilder buildMsdPatch(audio_devices_t outputDevice) const;
-        status_t setMsdPatch(audio_devices_t outputDevice = AUDIO_DEVICE_NONE);
+        PatchBuilder buildMsdPatch(const sp<DeviceDescriptor> &outputDevice) const;
+        status_t setMsdPatch(const sp<DeviceDescriptor> &outputDevice = nullptr);
 
         // If any, resolve any "dynamic" fields of an Audio Profiles collection
         void updateAudioProfiles(const sp<DeviceDescriptor>& devDesc, audio_io_handle_t ioHandle,
@@ -651,22 +676,12 @@
         // It can give a chance to HAL implementer to retrieve dynamic capabilities associated
         // to this device for example.
         // TODO avoid opening stream to retrieve capabilities of a profile.
-        void broadcastDeviceConnectionState(audio_devices_t device,
-                                            audio_policy_dev_state_t state,
-                                            const String8 &device_address);
+        void broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
+                                            audio_policy_dev_state_t state);
 
         // updates device caching and output for streams that can influence the
         //    routing of notifications
         void handleNotificationRoutingForStream(audio_stream_type_t stream);
-        // find the outputs on a given output descriptor that have the given address.
-        // to be called on an AudioOutputDescriptor whose supported devices (as defined
-        //   in mProfile->mSupportedDevices) matches the device whose address is to be matched.
-        // see deviceDistinguishesOnAddress(audio_devices_t) for whether the device type is one
-        //   where addresses are used to distinguish between one connected device and another.
-        void findIoHandlesByAddress(const sp<SwAudioOutputDescriptor>& desc /*in*/,
-                const audio_devices_t device /*in*/,
-                const String8& address /*in*/,
-                SortedVector<audio_io_handle_t>& outputs /*out*/);
         uint32_t curAudioPortGeneration() const { return mAudioPortGeneration; }
         // internal method, get audio_attributes_t from either a source audio_attributes_t
         // or audio_stream_type_t, respectively.
@@ -684,15 +699,14 @@
                 audio_output_flags_t *flags,
                 audio_port_handle_t *selectedDeviceId);
         // internal method to return the output handle for the given device and format
-        audio_io_handle_t getOutputForDevice(
-                audio_devices_t device,
+        audio_io_handle_t getOutputForDevices(
+                const DeviceVector &devices,
                 audio_session_t session,
                 audio_stream_type_t stream,
                 const audio_config_t *config,
                 audio_output_flags_t *flags);
         // internal method to return the input handle for the given device and format
-        audio_io_handle_t getInputForDevice(audio_devices_t device,
-                String8 address,
+        audio_io_handle_t getInputForDevice(const sp<DeviceDescriptor> &device,
                 audio_session_t session,
                 audio_source_t inputSource,
                 const audio_config_base_t *config,
@@ -710,14 +724,14 @@
 
         // select input device corresponding to requested audio source and return associated policy
         // mix if any. Calls getDeviceForInputSource().
-        audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource,
-                                                        AudioMix **policyMix = NULL);
+        sp<DeviceDescriptor> getDeviceAndMixForAttributes(const audio_attributes_t &attributes,
+                                                          AudioMix **policyMix = NULL);
 
         // Called by setDeviceConnectionState().
-        status_t setDeviceConnectionStateInt(audio_devices_t device,
-                                                          audio_policy_dev_state_t state,
-                                                          const char *device_address,
-                                                          const char *device_name);
+        status_t setDeviceConnectionStateInt(audio_devices_t deviceType,
+                                             audio_policy_dev_state_t state,
+                                             const char *device_address,
+                                             const char *device_name);
         void updateMono(audio_io_handle_t output) {
             AudioParameter param;
             param.addInt(String8(AudioParameter::keyMonoOutput), (int)mMasterMono);
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 29b0561..919a90d 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -330,11 +330,12 @@
         return BAD_VALUE;
     }
 
-    // HOTWORD and FM_TUNER are two special case sources > MAX.
+    // HOTWORD, FM_TUNER and ECHO_REFERENCE are special case sources > MAX.
     if (source < AUDIO_SOURCE_DEFAULT ||
             (source > AUDIO_SOURCE_MAX &&
              source != AUDIO_SOURCE_HOTWORD &&
-             source != AUDIO_SOURCE_FM_TUNER)) {
+             source != AUDIO_SOURCE_FM_TUNER &&
+             source != AUDIO_SOURCE_ECHO_REFERENCE)) {
         ALOGE("addSourceDefaultEffect(): Unsupported source type %d", source);
         return BAD_VALUE;
     }
@@ -534,7 +535,8 @@
     CAMCORDER_SRC_TAG,
     VOICE_REC_SRC_TAG,
     VOICE_COMM_SRC_TAG,
-    UNPROCESSED_SRC_TAG
+    UNPROCESSED_SRC_TAG,
+    VOICE_PERFORMANCE_SRC_TAG
 };
 
 // returns the audio_source_t enum corresponding to the input source name or
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 439764b..2c904d9 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -336,8 +336,11 @@
     }
 
     // already checked by client, but double-check in case the client wrapper is bypassed
-    if (attr->source < AUDIO_SOURCE_DEFAULT && attr->source >= AUDIO_SOURCE_CNT &&
-            attr->source != AUDIO_SOURCE_HOTWORD && attr->source != AUDIO_SOURCE_FM_TUNER) {
+    if ((attr->source < AUDIO_SOURCE_DEFAULT)
+            || (attr->source >= AUDIO_SOURCE_CNT
+                && attr->source != AUDIO_SOURCE_HOTWORD
+                && attr->source != AUDIO_SOURCE_FM_TUNER
+                && attr->source != AUDIO_SOURCE_ECHO_REFERENCE)) {
         return BAD_VALUE;
     }
 
@@ -367,7 +370,8 @@
 
     if ((attr->source == AUDIO_SOURCE_VOICE_UPLINK ||
         attr->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
-        attr->source == AUDIO_SOURCE_VOICE_CALL) &&
+        attr->source == AUDIO_SOURCE_VOICE_CALL ||
+        attr->source == AUDIO_SOURCE_ECHO_REFERENCE) &&
         !captureAudioOutputAllowed(pid, uid)) {
         return PERMISSION_DENIED;
     }
@@ -1037,6 +1041,31 @@
     }
 }
 
+status_t AudioPolicyService::setUidDeviceAffinities(uid_t uid,
+        const Vector<AudioDeviceTypeAddr>& devices) {
+    Mutex::Autolock _l(mLock);
+    if(!modifyAudioRoutingAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    AutoCallerClear acc;
+    return mAudioPolicyManager->setUidDeviceAffinities(uid, devices);
+}
+
+status_t AudioPolicyService::removeUidDeviceAffinities(uid_t uid) {
+    Mutex::Autolock _l(mLock);
+    if(!modifyAudioRoutingAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    AutoCallerClear acc;
+    return mAudioPolicyManager->removeUidDeviceAffinities(uid);
+}
+
 status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source,
                                               const audio_attributes_t *attributes,
                                               audio_port_handle_t *portId)
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index c44d816..959e757 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -199,6 +199,10 @@
 
     virtual status_t registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration);
 
+    virtual status_t setUidDeviceAffinities(uid_t uid, const Vector<AudioDeviceTypeAddr>& devices);
+
+    virtual status_t removeUidDeviceAffinities(uid_t uid);
+
     virtual status_t startAudioSource(const struct audio_port_config *source,
                                       const audio_attributes_t *attributes,
                                       audio_port_handle_t *portId);
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 56af152..24326bb 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -112,10 +112,34 @@
     std::set<audio_patch_handle_t> mActivePatches;
 };
 
+class PatchCountCheck {
+  public:
+    explicit PatchCountCheck(AudioPolicyManagerTestClient *client)
+            : mClient{client},
+              mInitialCount{mClient->getActivePatchesCount()} {}
+    void assertDelta(int delta) const {
+        ASSERT_EQ(mInitialCount + delta, mClient->getActivePatchesCount()); }
+    void assertNoChange() const { assertDelta(0); }
+  private:
+    const AudioPolicyManagerTestClient *mClient;
+    const size_t mInitialCount;
+};
+
 class AudioPolicyManagerTest : public testing::Test {
   protected:
-    virtual void SetUp();
-    virtual void TearDown();
+    void SetUp() override;
+    void TearDown() override;
+    virtual void SetUpConfig(AudioPolicyConfig *config) { (void)config; }
+
+    void dumpToLog();
+    void getOutputForAttr(
+            audio_port_handle_t *selectedDeviceId,
+            audio_format_t format,
+            int channelMask,
+            int sampleRate,
+            audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+            audio_port_handle_t *portId = nullptr);
+    PatchCountCheck snapPatchCount() { return PatchCountCheck(mClient.get()); }
 
     std::unique_ptr<AudioPolicyManagerTestClient> mClient;
     std::unique_ptr<AudioPolicyTestManager> mManager;
@@ -125,6 +149,7 @@
     mClient.reset(new AudioPolicyManagerTestClient);
     mManager.reset(new AudioPolicyTestManager(mClient.get()));
     mManager->getConfig().setDefault();
+    SetUpConfig(&mManager->getConfig());  // Subclasses may want to customize the config.
     ASSERT_EQ(NO_ERROR, mManager->initialize());
     ASSERT_EQ(NO_ERROR, mManager->initCheck());
 }
@@ -134,11 +159,7 @@
     mClient.reset();
 }
 
-TEST_F(AudioPolicyManagerTest, InitSuccess) {
-    // SetUp must finish with no assertions.
-}
-
-TEST_F(AudioPolicyManagerTest, Dump) {
+void AudioPolicyManagerTest::dumpToLog() {
     int pipefd[2];
     ASSERT_NE(-1, pipe(pipefd));
     pid_t cpid = fork();
@@ -168,10 +189,43 @@
     }
 }
 
+void AudioPolicyManagerTest::getOutputForAttr(
+        audio_port_handle_t *selectedDeviceId,
+        audio_format_t format,
+        int channelMask,
+        int sampleRate,
+        audio_output_flags_t flags,
+        audio_port_handle_t *portId) {
+    audio_attributes_t attr = {};
+    audio_io_handle_t output = AUDIO_PORT_HANDLE_NONE;
+    audio_stream_type_t stream = AUDIO_STREAM_DEFAULT;
+    audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+    config.sample_rate = sampleRate;
+    config.channel_mask = channelMask;
+    config.format = format;
+    *selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+    audio_port_handle_t localPortId;
+    if (!portId) portId = &localPortId;
+    *portId = AUDIO_PORT_HANDLE_NONE;
+    ASSERT_EQ(OK, mManager->getOutputForAttr(
+                    &attr, &output, AUDIO_SESSION_NONE, &stream, 0 /*uid*/, &config, &flags,
+                    selectedDeviceId, portId));
+    ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
+}
+
+
+TEST_F(AudioPolicyManagerTest, InitSuccess) {
+    // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTest, Dump) {
+    dumpToLog();
+}
+
 TEST_F(AudioPolicyManagerTest, CreateAudioPatchFailure) {
     audio_patch patch{};
     audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
-    const size_t patchCountBefore = mClient->getActivePatchesCount();
+    const PatchCountCheck patchCount = snapPatchCount();
     ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(nullptr, &handle, 0));
     ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(&patch, nullptr, 0));
     ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(&patch, &handle, 0));
@@ -198,20 +252,182 @@
     ASSERT_EQ(INVALID_OPERATION, mManager->createAudioPatch(&patch, &handle, 0));
     // Verify that the handle is left unchanged.
     ASSERT_EQ(AUDIO_PATCH_HANDLE_NONE, handle);
-    ASSERT_EQ(patchCountBefore, mClient->getActivePatchesCount());
+    patchCount.assertNoChange();
 }
 
 TEST_F(AudioPolicyManagerTest, CreateAudioPatchFromMix) {
     audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
     uid_t uid = 42;
-    const size_t patchCountBefore = mClient->getActivePatchesCount();
+    const PatchCountCheck patchCount = snapPatchCount();
     ASSERT_FALSE(mManager->getConfig().getAvailableInputDevices().isEmpty());
     PatchBuilder patchBuilder;
     patchBuilder.addSource(mManager->getConfig().getAvailableInputDevices()[0]).
             addSink(mManager->getConfig().getDefaultOutputDevice());
     ASSERT_EQ(NO_ERROR, mManager->createAudioPatch(patchBuilder.patch(), &handle, uid));
     ASSERT_NE(AUDIO_PATCH_HANDLE_NONE, handle);
-    ASSERT_EQ(patchCountBefore + 1, mClient->getActivePatchesCount());
+    patchCount.assertDelta(1);
 }
 
 // TODO: Add patch creation tests that involve already existing patch
+
+class AudioPolicyManagerTestMsd : public AudioPolicyManagerTest {
+  protected:
+    void SetUpConfig(AudioPolicyConfig *config) override;
+    void TearDown() override;
+
+    sp<DeviceDescriptor> mMsdOutputDevice;
+    sp<DeviceDescriptor> mMsdInputDevice;
+};
+
+void AudioPolicyManagerTestMsd::SetUpConfig(AudioPolicyConfig *config) {
+    // TODO: Consider using Serializer to load part of the config from a string.
+    mMsdOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_BUS);
+    sp<AudioProfile> pcmOutputProfile = new AudioProfile(
+            AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
+    sp<AudioProfile> ac3OutputProfile = new AudioProfile(
+            AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000);
+    mMsdOutputDevice->addAudioProfile(pcmOutputProfile);
+    mMsdOutputDevice->addAudioProfile(ac3OutputProfile);
+    mMsdInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUS);
+    // Match output profile from AudioPolicyConfig::setDefault.
+    sp<AudioProfile> pcmInputProfile = new AudioProfile(
+            AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO, 44100);
+    mMsdInputDevice->addAudioProfile(pcmInputProfile);
+    config->addAvailableDevice(mMsdOutputDevice);
+    config->addAvailableDevice(mMsdInputDevice);
+
+    sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/);
+    HwModuleCollection modules = config->getHwModules();
+    modules.add(msdModule);
+    config->setHwModules(modules);
+    mMsdOutputDevice->attach(msdModule);
+    mMsdInputDevice->attach(msdModule);
+
+    sp<OutputProfile> msdOutputProfile = new OutputProfile(String8("msd input"));
+    msdOutputProfile->addAudioProfile(pcmOutputProfile);
+    msdOutputProfile->addSupportedDevice(mMsdOutputDevice);
+    msdModule->addOutputProfile(msdOutputProfile);
+    sp<OutputProfile> msdCompressedOutputProfile =
+            new OutputProfile(String8("msd compressed input"));
+    msdCompressedOutputProfile->addAudioProfile(ac3OutputProfile);
+    msdCompressedOutputProfile->setFlags(
+            AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
+            AUDIO_OUTPUT_FLAG_NON_BLOCKING);
+    msdCompressedOutputProfile->addSupportedDevice(mMsdOutputDevice);
+    msdModule->addOutputProfile(msdCompressedOutputProfile);
+
+    sp<InputProfile> msdInputProfile = new InputProfile(String8("msd output"));
+    msdInputProfile->addAudioProfile(pcmInputProfile);
+    msdInputProfile->addSupportedDevice(mMsdInputDevice);
+    msdModule->addInputProfile(msdInputProfile);
+
+    // Add a profile with another encoding to the default device to test routing
+    // of streams that are not supported by MSD.
+    sp<AudioProfile> dtsOutputProfile = new AudioProfile(
+            AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000);
+    config->getDefaultOutputDevice()->addAudioProfile(dtsOutputProfile);
+    sp<OutputProfile> primaryEncodedOutputProfile = new OutputProfile(String8("encoded"));
+    primaryEncodedOutputProfile->addAudioProfile(dtsOutputProfile);
+    primaryEncodedOutputProfile->setFlags(AUDIO_OUTPUT_FLAG_DIRECT);
+    primaryEncodedOutputProfile->addSupportedDevice(config->getDefaultOutputDevice());
+    config->getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
+            addOutputProfile(primaryEncodedOutputProfile);
+}
+
+void AudioPolicyManagerTestMsd::TearDown() {
+    mMsdOutputDevice.clear();
+    mMsdInputDevice.clear();
+    AudioPolicyManagerTest::TearDown();
+}
+
+TEST_F(AudioPolicyManagerTestMsd, InitSuccess) {
+    ASSERT_TRUE(mMsdOutputDevice);
+    ASSERT_TRUE(mMsdInputDevice);
+}
+
+TEST_F(AudioPolicyManagerTestMsd, Dump) {
+    dumpToLog();
+}
+
+TEST_F(AudioPolicyManagerTestMsd, PatchCreationOnSetForceUse) {
+    const PatchCountCheck patchCount = snapPatchCount();
+    mManager->setForceUse(AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND,
+            AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS);
+    patchCount.assertDelta(1);
+}
+
+TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedRoutesToMsd) {
+    const PatchCountCheck patchCount = snapPatchCount();
+    audio_port_handle_t selectedDeviceId;
+    getOutputForAttr(&selectedDeviceId,
+            AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
+    ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
+    patchCount.assertDelta(1);
+}
+
+TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrPcmRoutesToMsd) {
+    const PatchCountCheck patchCount = snapPatchCount();
+    audio_port_handle_t selectedDeviceId;
+    getOutputForAttr(&selectedDeviceId,
+            AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
+    ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
+    patchCount.assertDelta(1);
+}
+
+TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedPlusPcmRoutesToMsd) {
+    const PatchCountCheck patchCount = snapPatchCount();
+    audio_port_handle_t selectedDeviceId;
+    getOutputForAttr(&selectedDeviceId,
+            AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
+    ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
+    patchCount.assertDelta(1);
+    getOutputForAttr(&selectedDeviceId,
+            AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
+    ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
+    patchCount.assertDelta(1);
+}
+
+TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrUnsupportedFormatBypassesMsd) {
+    const PatchCountCheck patchCount = snapPatchCount();
+    audio_port_handle_t selectedDeviceId;
+    getOutputForAttr(&selectedDeviceId,
+            AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
+    ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
+    patchCount.assertNoChange();
+}
+
+TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) {
+    // Switch between formats that are supported and not supported by MSD.
+    {
+        const PatchCountCheck patchCount = snapPatchCount();
+        audio_port_handle_t selectedDeviceId, portId;
+        getOutputForAttr(&selectedDeviceId,
+                AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
+                &portId);
+        ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
+        patchCount.assertDelta(1);
+        mManager->releaseOutput(portId);
+        patchCount.assertDelta(1);  // compared to the state at the block entry
+        // TODO: make PatchCountCheck asserts more obvious. It's easy to
+        // miss the fact that it is immutable.
+    }
+    {
+        const PatchCountCheck patchCount = snapPatchCount();
+        audio_port_handle_t selectedDeviceId, portId;
+        getOutputForAttr(&selectedDeviceId,
+                AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
+                &portId);
+        ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
+        patchCount.assertDelta(-1);
+        mManager->releaseOutput(portId);
+        patchCount.assertNoChange();
+    }
+    {
+        const PatchCountCheck patchCount = snapPatchCount();
+        audio_port_handle_t selectedDeviceId;
+        getOutputForAttr(&selectedDeviceId,
+                AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
+        ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
+        patchCount.assertNoChange();
+    }
+}
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 025f0b2..851dd69 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -83,6 +83,7 @@
         "libhidltransport",
         "libjpeg",
         "libmemunreachable",
+        "libsensorprivacy",
         "libstagefright_foundation",
         "android.frameworks.cameraservice.common@2.0",
         "android.frameworks.cameraservice.service@2.0",
@@ -100,6 +101,7 @@
         "libbinder",
         "libcamera_client",
         "libfmq",
+        "libsensorprivacy",
     ],
 
     include_dirs: [
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 6003607..c3113bf 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -54,6 +54,7 @@
 #include <media/IMediaHTTPService.h>
 #include <media/mediaplayer.h>
 #include <mediautils/BatteryNotifier.h>
+#include <sensorprivacy/SensorPrivacyManager.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/String16.h>
@@ -145,6 +146,8 @@
 
     mUidPolicy = new UidPolicy(this);
     mUidPolicy->registerSelf();
+    mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
+    mSensorPrivacyPolicy->registerSelf();
     sp<HidlCameraService> hcs = HidlCameraService::getInstance(this);
     if (hcs->registerAsService() != android::OK) {
         ALOGE("%s: Failed to register default android.frameworks.cameraservice.service@1.0",
@@ -230,6 +233,7 @@
 CameraService::~CameraService() {
     VendorTagDescriptor::clearGlobalVendorTagDescriptor();
     mUidPolicy->unregisterSelf();
+    mSensorPrivacyPolicy->unregisterSelf();
 }
 
 void CameraService::onNewProviderRegistered() {
@@ -951,6 +955,14 @@
                 clientName8.string(), clientUid, clientPid, cameraId.string());
     }
 
+    // If sensor privacy is enabled then prevent access to the camera
+    if (mSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
+        ALOGE("Access Denial: cannot use the camera when sensor privacy is enabled");
+        return STATUS_ERROR_FMT(ERROR_DISABLED,
+                "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" when sensor privacy "
+                "is enabled", clientName8.string(), clientUid, clientPid, cameraId.string());
+    }
+
     // Only use passed in clientPid to check permission. Use calling PID as the client PID that's
     // connected to camera service directly.
     originalClientPid = clientPid;
@@ -1603,9 +1615,10 @@
 
     switch(eventId) {
         case ICameraService::EVENT_USER_SWITCHED: {
-            // Try to register for UID policy updates, in case we're recovering
+            // Try to register for UID and sensor privacy policy updates, in case we're recovering
             // from a system server crash
             mUidPolicy->registerSelf();
+            mSensorPrivacyPolicy->registerSelf();
             doUserSwitch(/*newUserIds*/ args);
             break;
         }
@@ -2577,6 +2590,59 @@
 }
 
 // ----------------------------------------------------------------------------
+//                  SensorPrivacyPolicy
+// ----------------------------------------------------------------------------
+void CameraService::SensorPrivacyPolicy::registerSelf() {
+    Mutex::Autolock _l(mSensorPrivacyLock);
+    if (mRegistered) {
+        return;
+    }
+    SensorPrivacyManager spm;
+    spm.addSensorPrivacyListener(this);
+    mSensorPrivacyEnabled = spm.isSensorPrivacyEnabled();
+    status_t res = spm.linkToDeath(this);
+    if (res == OK) {
+        mRegistered = true;
+        ALOGV("SensorPrivacyPolicy: Registered with SensorPrivacyManager");
+    }
+}
+
+void CameraService::SensorPrivacyPolicy::unregisterSelf() {
+    Mutex::Autolock _l(mSensorPrivacyLock);
+    SensorPrivacyManager spm;
+    spm.removeSensorPrivacyListener(this);
+    spm.unlinkToDeath(this);
+    mRegistered = false;
+    ALOGV("SensorPrivacyPolicy: Unregistered with SensorPrivacyManager");
+}
+
+bool CameraService::SensorPrivacyPolicy::isSensorPrivacyEnabled() {
+    Mutex::Autolock _l(mSensorPrivacyLock);
+    return mSensorPrivacyEnabled;
+}
+
+binder::Status CameraService::SensorPrivacyPolicy::onSensorPrivacyChanged(bool enabled) {
+    {
+        Mutex::Autolock _l(mSensorPrivacyLock);
+        mSensorPrivacyEnabled = enabled;
+    }
+    // if sensor privacy is enabled then block all clients from accessing the camera
+    if (enabled) {
+        sp<CameraService> service = mService.promote();
+        if (service != nullptr) {
+            service->blockAllClients();
+        }
+    }
+    return binder::Status::ok();
+}
+
+void CameraService::SensorPrivacyPolicy::binderDied(const wp<IBinder>& /*who*/) {
+    Mutex::Autolock _l(mSensorPrivacyLock);
+    ALOGV("SensorPrivacyPolicy: SensorPrivacyManager has died");
+    mRegistered = false;
+}
+
+// ----------------------------------------------------------------------------
 //                  CameraState
 // ----------------------------------------------------------------------------
 
@@ -3062,6 +3128,18 @@
     }
 }
 
+void CameraService::blockAllClients() {
+    const auto clients = mActiveClientManager.getAll();
+    for (auto& current : clients) {
+        if (current != nullptr) {
+            const auto basicClient = current->getValue();
+            if (basicClient.get() != nullptr) {
+                basicClient->block();
+            }
+        }
+    }
+}
+
 // NOTE: This is a remote API - make sure all args are validated
 status_t CameraService::shellCommand(int in, int out, int err, const Vector<String16>& args) {
     if (!checkCallingPermission(sManageCameraPermission, nullptr, nullptr)) {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index d332f6e..a296198 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -18,6 +18,7 @@
 #define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
 
 #include <android/hardware/BnCameraService.h>
+#include <android/hardware/BnSensorPrivacyListener.h>
 #include <android/hardware/ICameraServiceListener.h>
 #include <android/hardware/ICameraServiceProxy.h>
 
@@ -554,8 +555,35 @@
         std::unordered_map<uid_t, bool> mOverrideUids;
     }; // class UidPolicy
 
+    // If sensor privacy is enabled then all apps, including those that are active, should be
+    // prevented from accessing the camera.
+    class SensorPrivacyPolicy : public hardware::BnSensorPrivacyListener,
+            public virtual IBinder::DeathRecipient {
+        public:
+            explicit SensorPrivacyPolicy(wp<CameraService> service)
+                    : mService(service), mSensorPrivacyEnabled(false), mRegistered(false) {}
+
+            void registerSelf();
+            void unregisterSelf();
+
+            bool isSensorPrivacyEnabled();
+
+            binder::Status onSensorPrivacyChanged(bool enabled);
+
+            // IBinder::DeathRecipient implementation
+            virtual void binderDied(const wp<IBinder> &who);
+
+        private:
+            wp<CameraService> mService;
+            Mutex mSensorPrivacyLock;
+            bool mSensorPrivacyEnabled;
+            bool mRegistered;
+    };
+
     sp<UidPolicy> mUidPolicy;
 
+    sp<SensorPrivacyPolicy> mSensorPrivacyPolicy;
+
     // Delay-load the Camera HAL module
     virtual void onFirstRef();
 
@@ -825,6 +853,9 @@
     // Blocks all clients from the UID
     void blockClientsForUid(uid_t uid);
 
+    // Blocks all active clients.
+    void blockAllClients();
+
     // Overrides the UID state as if it is idle
     status_t handleSetUidState(const Vector<String16>& args, int err);
 
diff --git a/services/mediacodec/MediaCodecUpdateService.cpp b/services/mediacodec/MediaCodecUpdateService.cpp
index aee890d..0e6892d 100644
--- a/services/mediacodec/MediaCodecUpdateService.cpp
+++ b/services/mediacodec/MediaCodecUpdateService.cpp
@@ -18,14 +18,10 @@
 //#define LOG_NDEBUG 0
 
 #include <android/dlext.h>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <dirent.h>
 #include <dlfcn.h>
 #include <media/CodecServiceRegistrant.h>
 #include <utils/Log.h>
-#include <ziparchive/zip_archive.h>
-#include <cutils/properties.h>
+#include <utils/String8.h>
 
 #include "MediaCodecUpdateService.h"
 
@@ -47,90 +43,53 @@
 }
 
 namespace android {
-namespace media {
 
-binder::Status MediaCodecUpdateService::loadPlugins(const ::std::string& apkPath) {
-    ALOGV("loadPlugins %s", apkPath.c_str());
+void loadFromApex(const char *libDirPath) {
+    ALOGV("loadFromApex: path=%s", libDirPath);
 
-    ZipArchiveHandle zipHandle;
-    void *registrantLib = NULL;
-    int32_t ret = OpenArchive(apkPath.c_str(), &zipHandle);
+    String8 libPath = String8(libDirPath) + "/libmedia_codecserviceregistrant.so";
 
-    if (ret == 0) {
-        char abilist32[PROPERTY_VALUE_MAX];
-        property_get("ro.product.cpu.abilist32", abilist32, "armeabi-v7a");
+    android_namespace_t *codecNs = android_create_namespace("codecs",
+            nullptr,  // ld_library_path
+            libDirPath,
+            ANDROID_NAMESPACE_TYPE_ISOLATED,
+            nullptr,  // permitted_when_isolated_path
+            nullptr); // parent
 
-        auto abis = base::Split(abilist32, ",");
-        if (abis.empty()) {
-            ALOGW("abilist is empty, trying armeabi-v7a ...");
-            abis.push_back("armeabi-v7a");
-        }
-
-        // TODO: Only try the first entry in abilist32 for now.
-        // We probably should try the next if it fails.
-        String8 libPathInApk = String8("lib/") + String8(abis[0].c_str());
-        String8 defaultLibPath = String8(apkPath.c_str()) + "!/" + libPathInApk;
-        String8 libPath = defaultLibPath + "/libmedia_codecserviceregistrant.so";
-        String8 zipEntryPath = libPathInApk + "/libmedia_codecserviceregistrant.so";
-
-        ZipEntry entry;
-        ret = FindEntry(zipHandle, ZipString(zipEntryPath), &entry);
-
-        if (ret == 0) {
-            android_namespace_t *codecNs = android_create_namespace("codecs",
-                    nullptr,  // ld_library_path
-                    defaultLibPath.c_str(),
-                    ANDROID_NAMESPACE_TYPE_ISOLATED,
-                    nullptr,  // permitted_when_isolated_path
-                    nullptr); // parent
-
-            if (codecNs != nullptr) {
-                String8 linked_libraries(LINKED_LIBRARIES);
-                if (android_link_namespaces(
-                        codecNs, nullptr, linked_libraries.c_str())) {
-                    const android_dlextinfo dlextinfo = {
-                            .flags = ANDROID_DLEXT_USE_NAMESPACE,
-                            .library_namespace = codecNs,
-                    };
-
-                    registrantLib = android_dlopen_ext(
-                            libPath.string(),
-                            RTLD_NOW | RTLD_LOCAL, &dlextinfo);
-
-                    if (registrantLib == NULL) {
-                        ALOGE("Failed to load lib from archive: %s", dlerror());
-                    }
-                } else {
-                    ALOGE("Failed to link namespace");
-                }
-            } else {
-                ALOGE("Failed to create codec namespace");
-            }
-        } else {
-            ALOGE("Failed to find entry (ret=%d)", ret);
-        }
-
-        CloseArchive(zipHandle);
-    } else {
-        ALOGE("Failed to open archive (ret=%d)", ret);
+    if (codecNs == nullptr) {
+        ALOGE("Failed to create codec namespace");
+        return;
     }
 
-    if (registrantLib) {
-        RegisterCodecServicesFunc registerCodecServices =
-                reinterpret_cast<RegisterCodecServicesFunc>(
-                dlsym(registrantLib, "RegisterCodecServices"));
-        if (registerCodecServices) {
-            registerCodecServices();
-        } else {
-            LOG(WARNING) << "Cannot register codec services "
-                    "-- corrupted library.";
-        }
-    } else {
-        LOG(ERROR) << "Cannot find codec service registrant.";
+    String8 linked_libraries(LINKED_LIBRARIES);
+    if (!android_link_namespaces(codecNs, nullptr, linked_libraries.c_str())) {
+        ALOGE("Failed to link namespace");
+        return;
     }
 
-    return binder::Status::ok();
+    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 media
 }   // namespace android
diff --git a/services/mediacodec/MediaCodecUpdateService.h b/services/mediacodec/MediaCodecUpdateService.h
index 7b7cee9..09d6dbe 100644
--- a/services/mediacodec/MediaCodecUpdateService.h
+++ b/services/mediacodec/MediaCodecUpdateService.h
@@ -17,24 +17,10 @@
 #ifndef ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
 #define ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
 
-#include <binder/BinderService.h>
-#include <android/media/BnMediaUpdateService.h>
-
 namespace android {
-namespace media {
 
-class MediaCodecUpdateService
-    : public BinderService<MediaCodecUpdateService>, public BnMediaUpdateService
-{
-    friend class BinderService<MediaCodecUpdateService>;
-public:
-    MediaCodecUpdateService() : BnMediaUpdateService() { }
-    virtual ~MediaCodecUpdateService() { }
-    static const char* getServiceName() { return "media.codec.update"; }
-    binder::Status loadPlugins(const ::std::string& apkPath);
-};
+void loadFromApex(const char *libDirPath);
 
-}   // namespace media
 }   // namespace android
 
 #endif  // ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
diff --git a/services/mediacodec/main_swcodecservice.cpp b/services/mediacodec/main_swcodecservice.cpp
index 79fea25..1168825 100644
--- a/services/mediacodec/main_swcodecservice.cpp
+++ b/services/mediacodec/main_swcodecservice.cpp
@@ -20,11 +20,7 @@
 // from LOCAL_C_INCLUDES
 #include "minijail.h"
 
-#include <android-base/properties.h>
-#include <binder/ProcessState.h>
-#include <dlfcn.h>
 #include <hidl/HidlTransportSupport.h>
-#include <media/CodecServiceRegistrant.h>
 
 #include "MediaCodecUpdateService.h"
 
@@ -49,32 +45,10 @@
     signal(SIGPIPE, SIG_IGN);
     SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
 
-    std::string value = base::GetProperty("ro.build.type", "unknown");
-    if (value == "userdebug" || value == "eng") {
-        media::MediaCodecUpdateService::instantiate();
-    }
-
-    android::ProcessState::self()->startThreadPool();
-
     ::android::hardware::configureRpcThreadpool(64, false);
 
-    // Registration of customized codec services
-    void *registrantLib = dlopen(
-            "libmedia_codecserviceregistrant.so",
-            RTLD_NOW | RTLD_LOCAL);
-    if (registrantLib) {
-        RegisterCodecServicesFunc registerCodecServices =
-                reinterpret_cast<RegisterCodecServicesFunc>(
-                dlsym(registrantLib, "RegisterCodecServices"));
-        if (registerCodecServices) {
-            registerCodecServices();
-        } else {
-            LOG(WARNING) << "Cannot register codec services "
-                    "-- corrupted library.";
-        }
-    } else {
-        LOG(ERROR) << "Cannot find codec service registrant.";
-    }
+    // codec libs are currently 32-bit only
+    loadFromApex("/apex/com.android.media.swcodec/lib");
 
     ::android::hardware::joinRpcThreadpool();
 }
diff --git a/services/mediacodec/registrant/Android.bp b/services/mediacodec/registrant/Android.bp
index 653317b..8c40ad1 100644
--- a/services/mediacodec/registrant/Android.bp
+++ b/services/mediacodec/registrant/Android.bp
@@ -1,5 +1,6 @@
 cc_library_shared {
     name: "libmedia_codecserviceregistrant",
+    vendor_available: true,
     srcs: [
         "CodecServiceRegistrant.cpp",
     ],
@@ -39,6 +40,7 @@
         "libcodec2_soft_opusdec",
         "libcodec2_soft_vp8dec",
         "libcodec2_soft_vp9dec",
+        "libcodec2_soft_av1dec",
         "libcodec2_soft_vp8enc",
         "libcodec2_soft_vp9enc",
         "libcodec2_soft_rawdec",
diff --git a/services/mediadrm/tests/Android.mk b/services/mediadrm/tests/Android.mk
deleted file mode 100644
index e2f7399..0000000
--- a/services/mediadrm/tests/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := DrmSessionManager_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-	DrmSessionManager_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libmediaplayerservice \
-	libutils \
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/include \
-	frameworks/av/media/libmediaplayerservice \
-
-LOCAL_CFLAGS += -Werror -Wall
-
-LOCAL_32_BIT_ONLY := true
-
-include $(BUILD_NATIVE_TEST)
-
diff --git a/services/mediadrm/tests/DrmSessionManager_test.cpp b/services/mediadrm/tests/DrmSessionManager_test.cpp
deleted file mode 100644
index de350a1..0000000
--- a/services/mediadrm/tests/DrmSessionManager_test.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "DrmSessionManager_test"
-#include <utils/Log.h>
-
-#include <gtest/gtest.h>
-
-#include "Drm.h"
-#include "DrmSessionClientInterface.h"
-#include "DrmSessionManager.h"
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/ProcessInfoInterface.h>
-
-namespace android {
-
-struct FakeProcessInfo : public ProcessInfoInterface {
-    FakeProcessInfo() {}
-    virtual ~FakeProcessInfo() {}
-
-    virtual bool getPriority(int pid, int* priority) {
-        // For testing, use pid as priority.
-        // Lower the value higher the priority.
-        *priority = pid;
-        return true;
-    }
-
-private:
-    DISALLOW_EVIL_CONSTRUCTORS(FakeProcessInfo);
-};
-
-struct FakeDrm : public DrmSessionClientInterface {
-    FakeDrm() {}
-    virtual ~FakeDrm() {}
-
-    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
-        mReclaimedSessions.push_back(sessionId);
-        return true;
-    }
-
-    const Vector<Vector<uint8_t> >& reclaimedSessions() const {
-        return mReclaimedSessions;
-    }
-
-private:
-    Vector<Vector<uint8_t> > mReclaimedSessions;
-
-    DISALLOW_EVIL_CONSTRUCTORS(FakeDrm);
-};
-
-static const int kTestPid1 = 30;
-static const int kTestPid2 = 20;
-static const uint8_t kTestSessionId1[] = {1, 2, 3};
-static const uint8_t kTestSessionId2[] = {4, 5, 6, 7, 8};
-static const uint8_t kTestSessionId3[] = {9, 0};
-
-class DrmSessionManagerTest : public ::testing::Test {
-public:
-    DrmSessionManagerTest()
-        : mDrmSessionManager(new DrmSessionManager(new FakeProcessInfo())),
-          mTestDrm1(new FakeDrm()),
-          mTestDrm2(new FakeDrm()) {
-        GetSessionId(kTestSessionId1, ARRAY_SIZE(kTestSessionId1), &mSessionId1);
-        GetSessionId(kTestSessionId2, ARRAY_SIZE(kTestSessionId2), &mSessionId2);
-        GetSessionId(kTestSessionId3, ARRAY_SIZE(kTestSessionId3), &mSessionId3);
-    }
-
-protected:
-    static void GetSessionId(const uint8_t* ids, size_t num, Vector<uint8_t>* sessionId) {
-        for (size_t i = 0; i < num; ++i) {
-            sessionId->push_back(ids[i]);
-        }
-    }
-
-    static void ExpectEqSessionInfo(const SessionInfo& info, sp<DrmSessionClientInterface> drm,
-            const Vector<uint8_t>& sessionId, int64_t timeStamp) {
-        EXPECT_EQ(drm, info.drm);
-        EXPECT_TRUE(isEqualSessionId(sessionId, info.sessionId));
-        EXPECT_EQ(timeStamp, info.timeStamp);
-    }
-
-    void addSession() {
-        mDrmSessionManager->addSession(kTestPid1, mTestDrm1, mSessionId1);
-        mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId2);
-        mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId3);
-        const PidSessionInfosMap& map = sessionMap();
-        EXPECT_EQ(2u, map.size());
-        ssize_t index1 = map.indexOfKey(kTestPid1);
-        ASSERT_GE(index1, 0);
-        const SessionInfos& infos1 = map[index1];
-        EXPECT_EQ(1u, infos1.size());
-        ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 0);
-
-        ssize_t index2 = map.indexOfKey(kTestPid2);
-        ASSERT_GE(index2, 0);
-        const SessionInfos& infos2 = map[index2];
-        EXPECT_EQ(2u, infos2.size());
-        ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId2, 1);
-        ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 2);
-    }
-
-    const PidSessionInfosMap& sessionMap() {
-        return mDrmSessionManager->mSessionMap;
-    }
-
-    void testGetLowestPriority() {
-        int pid;
-        int priority;
-        EXPECT_FALSE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
-
-        addSession();
-        EXPECT_TRUE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
-
-        EXPECT_EQ(kTestPid1, pid);
-        FakeProcessInfo processInfo;
-        int priority1;
-        processInfo.getPriority(kTestPid1, &priority1);
-        EXPECT_EQ(priority1, priority);
-    }
-
-    void testGetLeastUsedSession() {
-        sp<DrmSessionClientInterface> drm;
-        Vector<uint8_t> sessionId;
-        EXPECT_FALSE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
-
-        addSession();
-
-        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
-        EXPECT_EQ(mTestDrm1, drm);
-        EXPECT_TRUE(isEqualSessionId(mSessionId1, sessionId));
-
-        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
-        EXPECT_EQ(mTestDrm2, drm);
-        EXPECT_TRUE(isEqualSessionId(mSessionId2, sessionId));
-
-        // mSessionId2 is no longer the least used session.
-        mDrmSessionManager->useSession(mSessionId2);
-        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
-        EXPECT_EQ(mTestDrm2, drm);
-        EXPECT_TRUE(isEqualSessionId(mSessionId3, sessionId));
-    }
-
-    sp<DrmSessionManager> mDrmSessionManager;
-    sp<FakeDrm> mTestDrm1;
-    sp<FakeDrm> mTestDrm2;
-    Vector<uint8_t> mSessionId1;
-    Vector<uint8_t> mSessionId2;
-    Vector<uint8_t> mSessionId3;
-};
-
-TEST_F(DrmSessionManagerTest, addSession) {
-    addSession();
-}
-
-TEST_F(DrmSessionManagerTest, useSession) {
-    addSession();
-
-    mDrmSessionManager->useSession(mSessionId1);
-    mDrmSessionManager->useSession(mSessionId3);
-
-    const PidSessionInfosMap& map = sessionMap();
-    const SessionInfos& infos1 = map.valueFor(kTestPid1);
-    const SessionInfos& infos2 = map.valueFor(kTestPid2);
-    ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 3);
-    ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 4);
-}
-
-TEST_F(DrmSessionManagerTest, removeSession) {
-    addSession();
-
-    mDrmSessionManager->removeSession(mSessionId2);
-
-    const PidSessionInfosMap& map = sessionMap();
-    EXPECT_EQ(2u, map.size());
-    const SessionInfos& infos1 = map.valueFor(kTestPid1);
-    const SessionInfos& infos2 = map.valueFor(kTestPid2);
-    EXPECT_EQ(1u, infos1.size());
-    EXPECT_EQ(1u, infos2.size());
-    // mSessionId2 has been removed.
-    ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId3, 2);
-}
-
-TEST_F(DrmSessionManagerTest, removeDrm) {
-    addSession();
-
-    sp<FakeDrm> drm = new FakeDrm;
-    const uint8_t ids[] = {123};
-    Vector<uint8_t> sessionId;
-    GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
-    mDrmSessionManager->addSession(kTestPid2, drm, sessionId);
-
-    mDrmSessionManager->removeDrm(mTestDrm2);
-
-    const PidSessionInfosMap& map = sessionMap();
-    const SessionInfos& infos2 = map.valueFor(kTestPid2);
-    EXPECT_EQ(1u, infos2.size());
-    // mTestDrm2 has been removed.
-    ExpectEqSessionInfo(infos2[0], drm, sessionId, 3);
-}
-
-TEST_F(DrmSessionManagerTest, reclaimSession) {
-    EXPECT_FALSE(mDrmSessionManager->reclaimSession(kTestPid1));
-    addSession();
-
-    // calling pid priority is too low
-    EXPECT_FALSE(mDrmSessionManager->reclaimSession(50));
-
-    EXPECT_TRUE(mDrmSessionManager->reclaimSession(10));
-    EXPECT_EQ(1u, mTestDrm1->reclaimedSessions().size());
-    EXPECT_TRUE(isEqualSessionId(mSessionId1, mTestDrm1->reclaimedSessions()[0]));
-
-    mDrmSessionManager->removeSession(mSessionId1);
-
-    // add a session from a higher priority process.
-    sp<FakeDrm> drm = new FakeDrm;
-    const uint8_t ids[] = {1, 3, 5};
-    Vector<uint8_t> sessionId;
-    GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
-    mDrmSessionManager->addSession(15, drm, sessionId);
-
-    EXPECT_TRUE(mDrmSessionManager->reclaimSession(18));
-    EXPECT_EQ(1u, mTestDrm2->reclaimedSessions().size());
-    // mSessionId2 is reclaimed.
-    EXPECT_TRUE(isEqualSessionId(mSessionId2, mTestDrm2->reclaimedSessions()[0]));
-}
-
-TEST_F(DrmSessionManagerTest, getLowestPriority) {
-    testGetLowestPriority();
-}
-
-TEST_F(DrmSessionManagerTest, getLeastUsedSession_l) {
-    testGetLeastUsedSession();
-}
-
-} // namespace android
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index e31eadc..dd64881 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -40,12 +40,13 @@
 
 LOCAL_SRC_FILES := main_extractorservice.cpp
 LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils \
-    liblog libbase libicuuc libavservices_minijail
+    liblog libbase libandroidicu libavservices_minijail
 LOCAL_STATIC_LIBRARIES := libicuandroid_utils
 LOCAL_MODULE:= mediaextractor
 LOCAL_INIT_RC := mediaextractor.rc
 LOCAL_C_INCLUDES := frameworks/av/media/libmedia
 LOCAL_CFLAGS := -Wall -Werror
+LOCAL_SANITIZE := scudo
 include $(BUILD_EXECUTABLE)
 
 # service seccomp filter
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index 8b26178..0665930 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -59,6 +59,10 @@
     return CreateIDataSourceFromDataSource(source);
 }
 
+std::unordered_set<std::string> MediaExtractorService::getSupportedTypes() {
+    return MediaExtractorFactory::getSupportedTypes();
+}
+
 status_t MediaExtractorService::dump(int fd, const Vector<String16>& args) {
     return MediaExtractorFactory::dump(fd, args) || dumpExtractors(fd, args);
 }
diff --git a/services/mediaextractor/MediaExtractorService.h b/services/mediaextractor/MediaExtractorService.h
index 6007004..c9cebcf 100644
--- a/services/mediaextractor/MediaExtractorService.h
+++ b/services/mediaextractor/MediaExtractorService.h
@@ -37,6 +37,8 @@
 
     virtual sp<IDataSource> makeIDataSource(int fd, int64_t offset, int64_t length);
 
+    virtual std::unordered_set<std::string> getSupportedTypes();
+
     virtual status_t    dump(int fd, const Vector<String16>& args);
 
     virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
index 8d3359a..5f42711 100644
--- a/services/mediaextractor/main_extractorservice.cpp
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -42,6 +42,12 @@
 static const char kVendorSeccompPolicyPath[] =
         "/vendor/etc/seccomp_policy/mediaextractor.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";
+}
+
 int main(int argc __unused, char** argv)
 {
     limitProcessMemory(
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
index 6d9ed6f..607a03e 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
@@ -11,6 +11,7 @@
 mmap: 1
 madvise: 1
 openat: 1
+open: 1
 clock_gettime: 1
 writev: 1
 brk: 1
@@ -21,6 +22,7 @@
 getuid: 1
 setpriority: 1
 sigaltstack: 1
+fstat: 1
 fstatfs: 1
 newfstatat: 1
 restart_syscall: 1
diff --git a/services/soundtrigger/SoundTriggerHalHidl.cpp b/services/soundtrigger/SoundTriggerHalHidl.cpp
index 1d37a8e..68d54c7 100644
--- a/services/soundtrigger/SoundTriggerHalHidl.cpp
+++ b/services/soundtrigger/SoundTriggerHalHidl.cpp
@@ -168,18 +168,23 @@
     int ret;
     SoundModelHandle halHandle;
     sp<V2_1_ISoundTriggerHw> soundtrigger_2_1 = toService2_1(soundtrigger);
+    sp<V2_2_ISoundTriggerHw> soundtrigger_2_2 = toService2_2(soundtrigger);
     if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
-        if (!soundtrigger_2_1) {
-            ISoundTriggerHw::PhraseSoundModel halSoundModel;
-            convertPhraseSoundModelToHal(&halSoundModel, sound_model);
-            AutoMutex lock(mHalLock);
-            hidlReturn = soundtrigger->loadPhraseSoundModel(
-                    halSoundModel,
-                    this, modelId, [&](int32_t retval, auto res) {
-                        ret = retval;
-                        halHandle = res;
-                    });
-        } else {
+        if (soundtrigger_2_2) {
+            V2_2_ISoundTriggerHw::PhraseSoundModel halSoundModel;
+            auto result = convertPhraseSoundModelToHal(&halSoundModel, sound_model);
+            if (result.first) {
+                AutoMutex lock(mHalLock);
+                hidlReturn = soundtrigger_2_2->loadPhraseSoundModel_2_1(
+                        halSoundModel,
+                        this, modelId, [&](int32_t retval, auto res) {
+                            ret = retval;
+                            halHandle = res;
+                        });
+            } else {
+                return NO_MEMORY;
+            }
+        } else if (soundtrigger_2_1) {
             V2_1_ISoundTriggerHw::PhraseSoundModel halSoundModel;
             auto result = convertPhraseSoundModelToHal(&halSoundModel, sound_model);
             if (result.first) {
@@ -193,18 +198,32 @@
             } else {
                 return NO_MEMORY;
             }
-        }
-    } else {
-        if (!soundtrigger_2_1) {
-            ISoundTriggerHw::SoundModel halSoundModel;
-            convertSoundModelToHal(&halSoundModel, sound_model);
+        } else {
+            ISoundTriggerHw::PhraseSoundModel halSoundModel;
+            convertPhraseSoundModelToHal(&halSoundModel, sound_model);
             AutoMutex lock(mHalLock);
-            hidlReturn = soundtrigger->loadSoundModel(halSoundModel,
+            hidlReturn = soundtrigger->loadPhraseSoundModel(
+                    halSoundModel,
                     this, modelId, [&](int32_t retval, auto res) {
                         ret = retval;
                         halHandle = res;
                     });
-        } else {
+        }
+    } else {
+        if (soundtrigger_2_2) {
+            V2_2_ISoundTriggerHw::SoundModel halSoundModel;
+            auto result = convertSoundModelToHal(&halSoundModel, sound_model);
+            if (result.first) {
+                AutoMutex lock(mHalLock);
+                hidlReturn = soundtrigger_2_2->loadSoundModel_2_1(halSoundModel,
+                        this, modelId, [&](int32_t retval, auto res) {
+                            ret = retval;
+                            halHandle = res;
+                        });
+            } else {
+                return NO_MEMORY;
+            }
+        } else if (soundtrigger_2_1) {
             V2_1_ISoundTriggerHw::SoundModel halSoundModel;
             auto result = convertSoundModelToHal(&halSoundModel, sound_model);
             if (result.first) {
@@ -217,6 +236,15 @@
             } else {
                 return NO_MEMORY;
             }
+        } else {
+            ISoundTriggerHw::SoundModel halSoundModel;
+            convertSoundModelToHal(&halSoundModel, sound_model);
+            AutoMutex lock(mHalLock);
+            hidlReturn = soundtrigger->loadSoundModel(halSoundModel,
+                    this, modelId, [&](int32_t retval, auto res) {
+                        ret = retval;
+                        halHandle = res;
+                    });
         }
     }
 
@@ -282,16 +310,20 @@
     model->mRecognitionCookie = cookie;
 
     sp<V2_1_ISoundTriggerHw> soundtrigger_2_1 = toService2_1(soundtrigger);
+    sp<V2_2_ISoundTriggerHw> soundtrigger_2_2 = toService2_2(soundtrigger);
     Return<int32_t> hidlReturn(0);
 
-    if (!soundtrigger_2_1) {
-        ISoundTriggerHw::RecognitionConfig halConfig;
-        convertRecognitionConfigToHal(&halConfig, config);
-        {
+    if (soundtrigger_2_2) {
+        V2_2_ISoundTriggerHw::RecognitionConfig halConfig;
+        auto result = convertRecognitionConfigToHal(&halConfig, config);
+        if (result.first) {
             AutoMutex lock(mHalLock);
-            hidlReturn = soundtrigger->startRecognition(model->mHalHandle, halConfig, this, handle);
+            hidlReturn = soundtrigger_2_2->startRecognition_2_1(
+                    model->mHalHandle, halConfig, this, handle);
+        } else {
+            return NO_MEMORY;
         }
-    } else {
+    } else if (soundtrigger_2_1) {
         V2_1_ISoundTriggerHw::RecognitionConfig halConfig;
         auto result = convertRecognitionConfigToHal(&halConfig, config);
         if (result.first) {
@@ -301,6 +333,13 @@
         } else {
             return NO_MEMORY;
         }
+    } else {
+        ISoundTriggerHw::RecognitionConfig halConfig;
+        convertRecognitionConfigToHal(&halConfig, config);
+        {
+            AutoMutex lock(mHalLock);
+            hidlReturn = soundtrigger->startRecognition(model->mHalHandle, halConfig, this, handle);
+        }
     }
 
     if (!hidlReturn.isOk()) {
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 944abcc..fe2ccf2 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -765,10 +765,7 @@
             }
 
             recognitionEvent->capture_session = model->mCaptureSession;
-            // Don't reset the model state if this recognition event is a get-state response
-            if (recognitionEvent->status != RECOGNITION_STATUS_GET_STATE_RESPONSE) {
-                model->mState = Model::STATE_IDLE;
-            }
+            model->mState = Model::STATE_IDLE;
             clients.add(model->mModuleClient);
         }
     } break;