Merge "camera2 ndk: Check for nullptr before assigning captureSequenceId."
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/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 66c509f..fc847ff 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -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;
         }
@@ -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);
 
@@ -568,16 +604,22 @@
     if (mPlugin == NULL) {
         mInitCheck = ERROR_UNSUPPORTED;
     } else {
-        if (!mPlugin->setListener(this).isOk()) {
-            mPlugin = NULL;
-            mPluginV1_1 = NULL;
-            mPluginV1_2 = NULL;
+        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;
 }
 
@@ -694,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,
@@ -720,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);
@@ -868,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/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/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/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/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 6efbfee..590358c 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -872,7 +872,7 @@
 
             ALOGV("readPage returned %zd", n);
 
-            return n == ERROR_END_OF_STREAM ? AMEDIA_ERROR_END_OF_STREAM : AMEDIA_ERROR_UNKNOWN;
+            return n < 0 ? (media_status_t) n : AMEDIA_ERROR_END_OF_STREAM;
         }
 
         // Prevent a harmless unsigned integer overflow by clamping to 0
diff --git a/media/libaudioclient/AudioPolicy.cpp b/media/libaudioclient/AudioPolicy.cpp
index 9601d6d..3ab38cd 100644
--- a/media/libaudioclient/AudioPolicy.cpp
+++ b/media/libaudioclient/AudioPolicy.cpp
@@ -143,11 +143,18 @@
     return NO_ERROR;
 }
 
-void AudioMix::excludeUid(uid_t uid) const {
+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/include/media/AudioPolicy.h b/media/libaudioclient/include/media/AudioPolicy.h
index 96e1235..786fb9a 100644
--- a/media/libaudioclient/include/media/AudioPolicy.h
+++ b/media/libaudioclient/include/media/AudioPolicy.h
@@ -100,7 +100,8 @@
     status_t readFromParcel(Parcel *parcel);
     status_t writeToParcel(Parcel *parcel) const;
 
-    void excludeUid(uid_t uid) const;
+    void setExcludeUid(uid_t uid) const;
+    void setMatchUid(uid_t uid) const;
 
     mutable Vector<AudioMixMatchCriterion> mCriteria;
     uint32_t        mMixType;
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 7d759e0..3efb5de 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -220,7 +220,6 @@
         "libexpat",
         "libcamera_client",
         "libstagefright_foundation",
-        "libmediaextractor",
         "libgui",
         "libdl",
         "libaudioutils",
@@ -277,7 +276,6 @@
         "libbinder",
         "libcutils",
         "liblog",
-        "libmediaextractor",
         "libmediandk",
         "libnativewindow",
         "libmediandk_utils",
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/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 38f42dc..b3f7404 100644
--- a/media/libmediaplayer2/Android.bp
+++ b/media/libmediaplayer2/Android.bp
@@ -21,7 +21,6 @@
         "libgui",
         "liblog",
         "libmedia_omx",
-        "libmediaextractor",
         "libstagefright_foundation",
         "libui",
         "libutils",
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/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/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/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/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 74b7340..cf4edae 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -127,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/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/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index dcf1ab8..027e593 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -25,6 +25,7 @@
     header_libs: [
         "libhardware_headers",
         "libstagefright_foundation_headers",
+        "media_ndk_headers",
         "media_plugin_headers",
     ],
 
@@ -64,8 +65,98 @@
         "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",
+    ],
+
+    clang: true,
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+    },
+}
+
+cc_library_static {
+    name: "libstagefright_foundation_without_imemory",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+    double_loadable: true,
+    include_dirs: [
+        "frameworks/av/include",
+        "frameworks/native/include",
+        "frameworks/native/libs/arect/include",
+        "frameworks/native/libs/nativebase/include",
+    ],
+
+    local_include_dirs: [
+        "include/media/stagefright/foundation",
+    ],
+
+    header_libs: [
+        "libhardware_headers",
+        "libstagefright_foundation_headers",
+        "media_ndk_headers",
+        "media_plugin_headers",
+    ],
+
+    export_header_lib_headers: [
+        "libstagefright_foundation_headers",
+        "media_plugin_headers",
+    ],
+
+    export_shared_lib_headers: [
+        "libbinder",
+    ],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wall",
+        "-DNO_IMEMORY",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libutils",
+        "libcutils",
+        "liblog",
+    ],
+
+    srcs: [
+        "AAtomizer.cpp",
+        "ABitReader.cpp",
+        "ABuffer.cpp",
+        "ADebug.cpp",
+        "AHandler.cpp",
+        "ALooper.cpp",
+        "ALooperRoster.cpp",
+        "AMessage.cpp",
+        "AString.cpp",
+        "AStringUtils.cpp",
+        "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",
diff --git a/media/libmediaextractor/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
similarity index 100%
rename from media/libmediaextractor/MediaBuffer.cpp
rename to media/libstagefright/foundation/MediaBuffer.cpp
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/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/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/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/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/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/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/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/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/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 776d98f..4d0916e 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -360,10 +360,12 @@
                 break;
             }
         }
-        if (!deviceMatch) {
+        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->excludeUid(uid);
+            mix->setExcludeUid(uid);
         }
     }
 
@@ -382,7 +384,7 @@
         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
+            if ((rule == RULE_EXCLUDE_UID || rule == RULE_MATCH_UID)
                     && uid == mix->mCriteria[j].mValue.mUid) {
                 foundUidRule = true;
                 criteriaToRemove.push_back(j);
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/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index 6101c8a..dd64881 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -46,6 +46,7 @@
 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/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(