Add additional error conditions to MediaDrm

New codes are being added to handle resource
contention, lost session state, frame size too
large and insufficient security level for
decryption. Also cleans up inconsistent use of
tamper detected error where invalid state error
should have been used.

bug:111504510
bug:111505796
test:cts and gts media test cases

Change-Id: I28ca04cdc8ce64047d189fcf4d59bab24208e1a7
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/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/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,