summaryrefslogtreecommitdiffstats
path: root/drm
diff options
context:
space:
mode:
Diffstat (limited to 'drm')
-rw-r--r--drm/common/Android.bp2
-rw-r--r--drm/libdrmframework/plugins/common/util/Android.bp2
-rw-r--r--drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp3
-rw-r--r--drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp12
-rw-r--r--drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp2
-rw-r--r--drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp2
-rw-r--r--drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp2
-rw-r--r--drm/libdrmframework/plugins/passthru/Android.bp2
-rw-r--r--drm/libmediadrm/Android.bp83
-rw-r--r--drm/libmediadrm/CryptoHal.cpp67
-rw-r--r--drm/libmediadrm/DrmHal.cpp710
-rw-r--r--drm/libmediadrm/DrmMetrics.cpp422
-rw-r--r--drm/libmediadrm/DrmPluginPath.cpp2
-rw-r--r--drm/libmediadrm/DrmSessionManager.cpp4
-rw-r--r--drm/libmediadrm/ICrypto.cpp14
-rw-r--r--drm/libmediadrm/IDrm.cpp226
-rw-r--r--drm/libmediadrm/IDrmClient.cpp2
-rw-r--r--drm/libmediadrm/IMediaDrmService.cpp6
-rw-r--r--drm/libmediadrm/PluginMetricsReporting.cpp87
-rw-r--r--drm/libmediadrm/SharedLibrary.cpp2
-rw-r--r--drm/libmediadrm/protos/metrics.proto107
-rw-r--r--drm/libmediadrm/protos/plugin_metrics.proto50
-rw-r--r--drm/libmediadrm/tests/Android.bp53
-rw-r--r--drm/libmediadrm/tests/CounterMetric_test.cpp80
-rw-r--r--drm/libmediadrm/tests/DrmMetrics_test.cpp475
-rw-r--r--drm/libmediadrm/tests/EventMetric_test.cpp142
-rw-r--r--drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp7
-rw-r--r--drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h6
-rw-r--r--drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp2
-rw-r--r--drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp2
-rw-r--r--drm/mediacas/plugins/clearkey/JsonAssetLoader.cpp2
-rw-r--r--drm/mediacas/plugins/clearkey/ecm_generator.cpp2
-rw-r--r--drm/mediacas/plugins/clearkey/tests/ClearKeyFetcherTest.cpp2
-rw-r--r--drm/mediacas/plugins/mock/MockCasPlugin.cpp18
-rw-r--r--drm/mediacas/plugins/mock/MockCasPlugin.h2
-rw-r--r--drm/mediadrm/plugins/clearkey/common/Android.bp38
-rw-r--r--drm/mediadrm/plugins/clearkey/common/ClearKeyUUID.cpp (renamed from drm/mediadrm/plugins/clearkey/ClearKeyUUID.cpp)0
-rw-r--r--drm/mediadrm/plugins/clearkey/common/Utils.cpp (renamed from drm/mediadrm/plugins/clearkey/Utils.cpp)0
-rw-r--r--drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h (renamed from drm/mediadrm/plugins/clearkey/ClearKeyUUID.h)0
-rw-r--r--drm/mediadrm/plugins/clearkey/common/include/MimeType.h (renamed from drm/mediadrm/plugins/clearkey/MimeType.h)0
-rw-r--r--drm/mediadrm/plugins/clearkey/common/include/Utils.h (renamed from drm/mediadrm/plugins/clearkey/Utils.h)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/AesCtrDecryptor.cpp (renamed from drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/Android.bp (renamed from drm/mediadrm/plugins/clearkey/Android.bp)20
-rw-r--r--drm/mediadrm/plugins/clearkey/default/CreatePluginFactories.cpp (renamed from drm/mediadrm/plugins/clearkey/CreatePluginFactories.cpp)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/CryptoFactory.cpp (renamed from drm/mediadrm/plugins/clearkey/CryptoFactory.cpp)2
-rw-r--r--drm/mediadrm/plugins/clearkey/default/CryptoPlugin.cpp (renamed from drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/DrmFactory.cpp (renamed from drm/mediadrm/plugins/clearkey/DrmFactory.cpp)2
-rw-r--r--drm/mediadrm/plugins/clearkey/default/DrmPlugin.cpp (renamed from drm/mediadrm/plugins/clearkey/DrmPlugin.cpp)84
-rw-r--r--drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp (renamed from drm/mediadrm/plugins/clearkey/InitDataParser.cpp)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/JsonWebKey.cpp (renamed from drm/mediadrm/plugins/clearkey/JsonWebKey.cpp)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/Session.cpp (renamed from drm/mediadrm/plugins/clearkey/Session.cpp)2
-rw-r--r--drm/mediadrm/plugins/clearkey/default/SessionLibrary.cpp (renamed from drm/mediadrm/plugins/clearkey/SessionLibrary.cpp)2
-rw-r--r--drm/mediadrm/plugins/clearkey/default/include/AesCtrDecryptor.h (renamed from drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/include/ClearKeyDrmProperties.h41
-rw-r--r--drm/mediadrm/plugins/clearkey/default/include/ClearKeyTypes.h (renamed from drm/mediadrm/plugins/clearkey/ClearKeyTypes.h)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/include/CreatePluginFactories.h (renamed from drm/mediadrm/plugins/clearkey/CreatePluginFactories.h)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/include/CryptoFactory.h (renamed from drm/mediadrm/plugins/clearkey/CryptoFactory.h)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/include/CryptoPlugin.h (renamed from drm/mediadrm/plugins/clearkey/CryptoPlugin.h)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/include/DrmFactory.h (renamed from drm/mediadrm/plugins/clearkey/DrmFactory.h)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/include/DrmPlugin.h (renamed from drm/mediadrm/plugins/clearkey/DrmPlugin.h)51
-rw-r--r--drm/mediadrm/plugins/clearkey/default/include/InitDataParser.h (renamed from drm/mediadrm/plugins/clearkey/InitDataParser.h)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/include/JsonWebKey.h (renamed from drm/mediadrm/plugins/clearkey/JsonWebKey.h)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/include/Session.h (renamed from drm/mediadrm/plugins/clearkey/Session.h)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/include/SessionLibrary.h (renamed from drm/mediadrm/plugins/clearkey/SessionLibrary.h)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/tests/AesCtrDecryptorUnittest.cpp (renamed from drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/tests/Android.bp (renamed from drm/mediadrm/plugins/clearkey/tests/Android.bp)4
-rw-r--r--drm/mediadrm/plugins/clearkey/default/tests/InitDataParserUnittest.cpp (renamed from drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp)0
-rw-r--r--drm/mediadrm/plugins/clearkey/default/tests/JsonWebKeyUnittest.cpp (renamed from drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp)0
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/AesCtrDecryptor.cpp86
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/Android.bp68
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/Base64.cpp175
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/Buffer.cpp53
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/CreatePluginFactories.cpp44
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/CryptoFactory.cpp67
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp185
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp77
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp573
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp163
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp275
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/Session.cpp95
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp90
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.1-service.clearkey.rc6
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/AesCtrDecryptor.h50
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/Base64.h46
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/Buffer.h62
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h54
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyTypes.h55
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/CreatePluginFactories.h42
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/CryptoFactory.h60
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h104
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h60
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h343
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h56
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/JsonWebKey.h62
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/Session.h71
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/SessionLibrary.h66
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/include/TypeConvert.h77
-rw-r--r--drm/mediadrm/plugins/clearkey/hidl/service.cpp54
-rw-r--r--drm/mediadrm/plugins/mock/Android.bp2
99 files changed, 5648 insertions, 421 deletions
diff --git a/drm/common/Android.bp b/drm/common/Android.bp
index 0098c89630..1552c3f340 100644
--- a/drm/common/Android.bp
+++ b/drm/common/Android.bp
@@ -33,6 +33,8 @@ cc_library_static {
"ReadWriteUtils.cpp",
],
+ cflags: ["-Wall", "-Werror"],
+
static_libs: ["libbinder"],
export_include_dirs: ["include"],
diff --git a/drm/libdrmframework/plugins/common/util/Android.bp b/drm/libdrmframework/plugins/common/util/Android.bp
index 0c0b6f26fa..7372eb774e 100644
--- a/drm/libdrmframework/plugins/common/util/Android.bp
+++ b/drm/libdrmframework/plugins/common/util/Android.bp
@@ -19,5 +19,7 @@ cc_library_static {
srcs: ["src/MimeTypeUtil.cpp"],
+ cflags: ["-Wall", "-Werror"],
+
export_include_dirs: ["include"],
}
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
index 3f0f5f78e0..28a78aa21a 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
@@ -21,6 +21,9 @@ cc_library_shared {
"-DUSE_64BIT_DRM_API",
// The flag below turns on local debug printouts
//"-DDRM_OMA_FL_ENGINE_DEBUG",
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-variable",
],
srcs: ["src/FwdLockEngine.cpp"],
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
index 830def931c..73eea89249 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
@@ -502,8 +502,8 @@ status_t FwdLockEngine::onOpenDecryptSession(int /* uniqueId */,
int retVal = FwdLockFile_CheckHeaderIntegrity(fileDesc);
DecodeSession* decodeSession = new DecodeSession(fileDesc);
- if (retVal && NULL != decodeSession) {
- decodeSessionMap.addValue(decryptHandle->decryptId, decodeSession);
+ if (retVal && NULL != decodeSession &&
+ decodeSessionMap.addValue(decryptHandle->decryptId, decodeSession)) {
const char *pmime= FwdLockFile_GetContentType(fileDesc);
String8 contentType = String8(pmime == NULL ? "" : pmime);
contentType.toLower();
@@ -513,7 +513,11 @@ status_t FwdLockEngine::onOpenDecryptSession(int /* uniqueId */,
decryptHandle->decryptInfo = NULL;
result = DRM_NO_ERROR;
} else {
- LOG_VERBOSE("FwdLockEngine::onOpenDecryptSession Integrity Check failed for the fd");
+ if (retVal && NULL != decodeSession) {
+ LOG_VERBOSE("FwdLockEngine::onOpenDecryptSession Integrity Check failed for the fd");
+ } else {
+ LOG_VERBOSE("FwdLockEngine::onOpenDecryptSession DecodeSesssion insertion failed");
+ }
FwdLockFile_detach(fileDesc);
delete decodeSession;
}
@@ -631,7 +635,7 @@ ssize_t FwdLockEngine::onRead(int /* uniqueId */,
ssize_t size = -1;
if (NULL != decryptHandle &&
- decodeSessionMap.isCreated(decryptHandle->decryptId) &&
+ decodeSessionMap.isCreated(decryptHandle->decryptId) &&
NULL != buffer &&
numBytes > -1) {
DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp
index 698f278058..3be327ad95 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp
@@ -19,6 +19,8 @@ cc_library_static {
srcs: ["FwdLockGlue.c"],
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: ["libcrypto"],
export_include_dirs: ["."],
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp
index 33f2fe0702..d4e04b8218 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp
@@ -19,6 +19,8 @@ cc_library_static {
srcs: ["FwdLockConv.c"],
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: ["libcrypto"],
static_libs: ["libfwdlock-common"],
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp
index b6d7a06e84..0bf2737c6f 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp
@@ -19,6 +19,8 @@ cc_library_static {
srcs: ["FwdLockFile.c"],
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: ["libcrypto"],
static_libs: ["libfwdlock-common"],
diff --git a/drm/libdrmframework/plugins/passthru/Android.bp b/drm/libdrmframework/plugins/passthru/Android.bp
index 1dcf89cc07..05b6440a0b 100644
--- a/drm/libdrmframework/plugins/passthru/Android.bp
+++ b/drm/libdrmframework/plugins/passthru/Android.bp
@@ -32,5 +32,7 @@ cc_library_shared {
cflags: [
// Set the following flag to enable the decryption passthru flow
//"-DENABLE_PASSTHRU_DECRYPTION",
+ "-Wall",
+ "-Werror",
],
}
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index f90656434d..4991e50e8e 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -2,10 +2,11 @@
// libmediadrm
//
-cc_library_shared {
+// TODO: change it back to cc_library_shared when MediaPlayer2 switches to
+// using NdkMediaDrm, instead of MediaDrm.java.
+cc_library {
name: "libmediadrm",
-
srcs: [
"DrmPluginPath.cpp",
"DrmSessionManager.cpp",
@@ -13,29 +14,26 @@ cc_library_shared {
"IDrm.cpp",
"IDrmClient.cpp",
"IMediaDrmService.cpp",
- "PluginMetricsReporting.cpp",
"SharedLibrary.cpp",
"DrmHal.cpp",
"CryptoHal.cpp",
- "protos/plugin_metrics.proto",
],
- proto: {
- type: "lite",
- },
-
shared_libs: [
"libbinder",
"libcutils",
"libdl",
"liblog",
+ "libmediadrmmetrics_lite",
"libmediametrics",
"libmediautils",
+ "libprotobuf-cpp-lite",
"libstagefright_foundation",
"libutils",
"android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "libhidlallocatorutils",
"libhidlbase",
- "libhidlmemory",
"libhidltransport",
],
@@ -44,3 +42,70 @@ cc_library_shared {
"-Wall",
],
}
+
+// This is the version of the drm metrics configured for protobuf lite.
+cc_library_shared {
+ name: "libmediadrmmetrics_lite",
+ srcs: [
+ "DrmMetrics.cpp",
+ "PluginMetricsReporting.cpp",
+ "protos/metrics.proto",
+ ],
+
+ proto: {
+ export_proto_headers: true,
+ type: "lite",
+ },
+ shared_libs: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "libbase",
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libmediametrics",
+ "libprotobuf-cpp-lite",
+ "libstagefright_foundation",
+ "libutils",
+ ],
+ cflags: [
+ // Suppress unused parameter and no error options. These cause problems
+ // with the when using the map type in a proto definition.
+ "-Wno-unused-parameter",
+ "-Wno-error",
+ ],
+}
+
+// This is the version of the drm metrics library configured for full protobuf.
+cc_library_shared {
+ name: "libmediadrmmetrics_full",
+ srcs: [
+ "DrmMetrics.cpp",
+ "PluginMetricsReporting.cpp",
+ "protos/metrics.proto",
+ ],
+
+ proto: {
+ export_proto_headers: true,
+ type: "full",
+ },
+ shared_libs: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "libbase",
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libmediametrics",
+ "libprotobuf-cpp-full",
+ "libstagefright_foundation",
+ "libutils",
+ ],
+ cflags: [
+ // Suppress unused parameter and no error options. These cause problems
+ // when using the map type in a proto definition.
+ "-Wno-unused-parameter",
+ "-Wno-error",
+ ],
+}
+
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index 5dd25639ca..3035c5a250 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -22,13 +22,14 @@
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <binder/IMemory.h>
-#include <cutils/native_handle.h>
-#include <media/CryptoHal.h>
+#include <hidlmemory/FrameworkUtils.h>
#include <media/hardware/CryptoAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaErrors.h>
+#include <mediadrm/CryptoHal.h>
+
using ::android::hardware::drm::V1_0::BufferType;
using ::android::hardware::drm::V1_0::DestinationBuffer;
@@ -117,15 +118,24 @@ Vector<sp<ICryptoFactory>> CryptoHal::makeCryptoFactories() {
auto manager = ::IServiceManager::getService();
if (manager != NULL) {
- manager->listByInterface(ICryptoFactory::descriptor,
+ manager->listByInterface(drm::V1_0::ICryptoFactory::descriptor,
+ [&factories](const hidl_vec<hidl_string> &registered) {
+ for (const auto &instance : registered) {
+ auto factory = drm::V1_0::ICryptoFactory::getService(instance);
+ if (factory != NULL) {
+ ALOGD("found drm@1.0 ICryptoFactory %s", instance.c_str());
+ factories.push_back(factory);
+ }
+ }
+ }
+ );
+ manager->listByInterface(drm::V1_1::ICryptoFactory::descriptor,
[&factories](const hidl_vec<hidl_string> &registered) {
for (const auto &instance : registered) {
- auto factory = ICryptoFactory::getService(instance);
+ auto factory = drm::V1_1::ICryptoFactory::getService(instance);
if (factory != NULL) {
+ ALOGD("found drm@1.1 ICryptoFactory %s", instance.c_str());
factories.push_back(factory);
- ALOGI("makeCryptoFactories: factory instance %s is %s",
- instance.c_str(),
- factory->isRemote() ? "Remote" : "Not Remote");
}
}
}
@@ -136,7 +146,7 @@ Vector<sp<ICryptoFactory>> CryptoHal::makeCryptoFactories() {
// must be in passthrough mode, load the default passthrough service
auto passthrough = ICryptoFactory::getService();
if (passthrough != NULL) {
- ALOGI("makeCryptoFactories: using default crypto instance");
+ ALOGI("makeCryptoFactories: using default passthrough crypto instance");
factories.push_back(passthrough);
} else {
ALOGE("Failed to find any crypto factories");
@@ -213,10 +223,14 @@ bool CryptoHal::requiresSecureDecoderComponent(const char *mime) const {
Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) {
- return mInitCheck;
+ return false;
}
- return mPlugin->requiresSecureDecoderComponent(hidl_string(mime));
+ Return<bool> hResult = mPlugin->requiresSecureDecoderComponent(hidl_string(mime));
+ if (!hResult.isOk()) {
+ return false;
+ }
+ return hResult;
}
@@ -227,26 +241,20 @@ bool CryptoHal::requiresSecureDecoderComponent(const char *mime) const {
* are sent by providing an offset into the heap and a buffer size.
*/
int32_t CryptoHal::setHeapBase(const sp<IMemoryHeap>& heap) {
+ using ::android::hardware::fromHeap;
+ using ::android::hardware::HidlMemory;
+
if (heap == NULL) {
ALOGE("setHeapBase(): heap is NULL");
return -1;
}
- native_handle_t* nativeHandle = native_handle_create(1, 0);
- if (!nativeHandle) {
- ALOGE("setHeapBase(), failed to create native handle");
- return -1;
- }
Mutex::Autolock autoLock(mLock);
int32_t seqNum = mHeapSeqNum++;
-
- int fd = heap->getHeapID();
- nativeHandle->data[0] = fd;
- auto hidlHandle = hidl_handle(nativeHandle);
- auto hidlMemory = hidl_memory("ashmem", hidlHandle, heap->getSize());
+ sp<HidlMemory> hidlMemory = fromHeap(heap);
mHeapBases.add(seqNum, HeapBase(mNextBufferId, heap->getSize()));
- Return<void> hResult = mPlugin->setSharedBufferBase(hidlMemory, mNextBufferId++);
+ Return<void> hResult = mPlugin->setSharedBufferBase(*hidlMemory, mNextBufferId++);
ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
return seqNum;
}
@@ -254,7 +262,22 @@ int32_t CryptoHal::setHeapBase(const sp<IMemoryHeap>& heap) {
void CryptoHal::clearHeapBase(int32_t seqNum) {
Mutex::Autolock autoLock(mLock);
- mHeapBases.removeItem(seqNum);
+ /*
+ * Clear the remote shared memory mapping by setting the shared
+ * buffer base to a null hidl_memory.
+ *
+ * TODO: Add a releaseSharedBuffer method in a future DRM HAL
+ * API version to make this explicit.
+ */
+ ssize_t index = mHeapBases.indexOfKey(seqNum);
+ if (index >= 0) {
+ if (mPlugin != NULL) {
+ uint32_t bufferId = mHeapBases[index].getBufferId();
+ Return<void> hResult = mPlugin->setSharedBufferBase(hidl_memory(), bufferId);
+ ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
+ }
+ mHeapBases.removeItem(seqNum);
+ }
}
status_t CryptoHal::toSharedBuffer(const sp<IMemory>& memory, int32_t seqNum, ::SharedBuffer* buffer) {
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index bc37557ed5..cf08610173 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -16,48 +16,81 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "DrmHal"
+#include <iomanip>
+
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
-#include <android/hardware/drm/1.0/IDrmFactory.h>
-#include <android/hardware/drm/1.0/IDrmPlugin.h>
#include <android/hardware/drm/1.0/types.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl/ServiceManagement.h>
-#include <media/DrmHal.h>
-#include <media/DrmSessionClientInterface.h>
-#include <media/DrmSessionManager.h>
+#include <media/EventMetric.h>
#include <media/PluginMetricsReporting.h>
#include <media/drm/DrmAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaErrors.h>
-
-using ::android::hardware::drm::V1_0::EventType;
-using ::android::hardware::drm::V1_0::IDrmFactory;
-using ::android::hardware::drm::V1_0::IDrmPlugin;
-using ::android::hardware::drm::V1_0::KeyedVector;
-using ::android::hardware::drm::V1_0::KeyRequestType;
-using ::android::hardware::drm::V1_0::KeyStatus;
-using ::android::hardware::drm::V1_0::KeyStatusType;
-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::Status;
+#include <mediadrm/DrmHal.h>
+#include <mediadrm/DrmSessionClientInterface.h>
+#include <mediadrm/DrmSessionManager.h>
+
+using drm::V1_0::KeyedVector;
+using drm::V1_0::KeyStatusType;
+using drm::V1_0::KeyType;
+using drm::V1_0::KeyValue;
+using drm::V1_1::HdcpLevel;;
+using drm::V1_0::SecureStop;
+using drm::V1_1::SecureStopRelease;
+using drm::V1_0::SecureStopId;
+using drm::V1_1::SecurityLevel;
+using drm::V1_0::Status;
+using ::android::hardware::drm::V1_1::DrmMetricGroup;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::os::PersistableBundle;
using ::android::sp;
+namespace {
+
+// This constant corresponds to the PROPERTY_DEVICE_UNIQUE_ID constant
+// in the MediaDrm API.
+constexpr char kPropertyDeviceUniqueId[] = "deviceUniqueId";
+constexpr char kEqualsSign[] = "=";
+
+template<typename T>
+std::string toBase64StringNoPad(const T* data, size_t size) {
+ // Note that the base 64 conversion only works with arrays of single-byte
+ // values. If the source is empty or is not an array of single-byte values,
+ // return empty string.
+ if (size == 0 || sizeof(data[0]) != 1) {
+ return "";
+ }
+
+ android::AString outputString;
+ encodeBase64(data, size, &outputString);
+ // Remove trailing equals padding if it exists.
+ while (outputString.size() > 0 && outputString.endsWith(kEqualsSign)) {
+ outputString.erase(outputString.size() - 1, 1);
+ }
+
+ return std::string(outputString.c_str(), outputString.size());
+}
+
+} // anonymous namespace
+
namespace android {
+#define INIT_CHECK() {if (mInitCheck != OK) return mInitCheck;}
+
static inline int getCallingPid() {
return IPCThreadState::self()->getCallingPid();
}
@@ -89,6 +122,42 @@ static hidl_string toHidlString(const String8& string) {
return hidl_string(string.string());
}
+static DrmPlugin::SecurityLevel toSecurityLevel(SecurityLevel level) {
+ switch(level) {
+ case SecurityLevel::SW_SECURE_CRYPTO:
+ return DrmPlugin::kSecurityLevelSwSecureCrypto;
+ case SecurityLevel::SW_SECURE_DECODE:
+ return DrmPlugin::kSecurityLevelSwSecureDecode;
+ case SecurityLevel::HW_SECURE_CRYPTO:
+ return DrmPlugin::kSecurityLevelHwSecureCrypto;
+ case SecurityLevel::HW_SECURE_DECODE:
+ return DrmPlugin::kSecurityLevelHwSecureDecode;
+ case SecurityLevel::HW_SECURE_ALL:
+ return DrmPlugin::kSecurityLevelHwSecureAll;
+ default:
+ return DrmPlugin::kSecurityLevelUnknown;
+ }
+}
+
+static DrmPlugin::HdcpLevel toHdcpLevel(HdcpLevel level) {
+ switch(level) {
+ case HdcpLevel::HDCP_NONE:
+ return DrmPlugin::kHdcpNone;
+ case HdcpLevel::HDCP_V1:
+ return DrmPlugin::kHdcpV1;
+ case HdcpLevel::HDCP_V2:
+ return DrmPlugin::kHdcpV2;
+ case HdcpLevel::HDCP_V2_1:
+ return DrmPlugin::kHdcpV2_1;
+ case HdcpLevel::HDCP_V2_2:
+ return DrmPlugin::kHdcpV2_2;
+ case HdcpLevel::HDCP_NO_OUTPUT:
+ return DrmPlugin::kHdcpNoOutput;
+ default:
+ return DrmPlugin::kHdcpLevelUnknown;
+ }
+}
+
static ::KeyedVector toHidlKeyedVector(const KeyedVector<String8, String8>&
keyedVector) {
@@ -121,6 +190,15 @@ static List<Vector<uint8_t>> toSecureStops(const hidl_vec<SecureStop>&
return secureStops;
}
+static List<Vector<uint8_t>> toSecureStopIds(const hidl_vec<SecureStopId>&
+ hSecureStopIds) {
+ List<Vector<uint8_t>> secureStopIds;
+ for (size_t i = 0; i < hSecureStopIds.size(); i++) {
+ secureStopIds.push_back(toVector(hSecureStopIds[i]));
+ }
+ return secureStopIds;
+}
+
static status_t toStatusT(Status status) {
switch (status) {
case Status::OK:
@@ -196,35 +274,63 @@ DrmHal::DrmHal()
}
void DrmHal::closeOpenSessions() {
- if (mPlugin != NULL) {
- for (size_t i = 0; i < mOpenSessions.size(); i++) {
- mPlugin->closeSession(toHidlVec(mOpenSessions[i]));
- DrmSessionManager::Instance()->removeSession(mOpenSessions[i]);
- }
+ Mutex::Autolock autoLock(mLock);
+ auto openSessions = mOpenSessions;
+ for (size_t i = 0; i < openSessions.size(); i++) {
+ mLock.unlock();
+ closeSession(openSessions[i]);
+ mLock.lock();
}
mOpenSessions.clear();
}
DrmHal::~DrmHal() {
- closeOpenSessions();
DrmSessionManager::Instance()->removeDrm(mDrmSessionClient);
}
+void DrmHal::cleanup() {
+ closeOpenSessions();
+
+ Mutex::Autolock autoLock(mLock);
+ reportPluginMetrics();
+ reportFrameworkMetrics();
+
+ setListener(NULL);
+ mInitCheck = NO_INIT;
+
+ if (mPlugin != NULL) {
+ if (!mPlugin->setListener(NULL).isOk()) {
+ mInitCheck = DEAD_OBJECT;
+ }
+ }
+ mPlugin.clear();
+ mPluginV1_1.clear();
+}
+
Vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
Vector<sp<IDrmFactory>> factories;
auto manager = hardware::defaultServiceManager();
if (manager != NULL) {
- manager->listByInterface(IDrmFactory::descriptor,
+ manager->listByInterface(drm::V1_0::IDrmFactory::descriptor,
+ [&factories](const hidl_vec<hidl_string> &registered) {
+ for (const auto &instance : registered) {
+ auto factory = drm::V1_0::IDrmFactory::getService(instance);
+ if (factory != NULL) {
+ ALOGD("found drm@1.0 IDrmFactory %s", instance.c_str());
+ factories.push_back(factory);
+ }
+ }
+ }
+ );
+ manager->listByInterface(drm::V1_1::IDrmFactory::descriptor,
[&factories](const hidl_vec<hidl_string> &registered) {
for (const auto &instance : registered) {
- auto factory = IDrmFactory::getService(instance);
+ auto factory = drm::V1_1::IDrmFactory::getService(instance);
if (factory != NULL) {
+ ALOGD("found drm@1.1 IDrmFactory %s", instance.c_str());
factories.push_back(factory);
- ALOGI("makeDrmFactories: factory instance %s is %s",
- instance.c_str(),
- factory->isRemote() ? "Remote" : "Not Remote");
}
}
}
@@ -235,7 +341,7 @@ Vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
// must be in passthrough mode, load the default passthrough service
auto passthrough = IDrmFactory::getService();
if (passthrough != NULL) {
- ALOGI("makeDrmFactories: using default drm instance");
+ ALOGI("makeDrmFactories: using default passthrough drm instance");
factories.push_back(passthrough);
} else {
ALOGE("Failed to find any drm factories");
@@ -246,6 +352,8 @@ Vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
sp<IDrmPlugin> DrmHal::makeDrmPlugin(const sp<IDrmFactory>& factory,
const uint8_t uuid[16], const String8& appPackageName) {
+ mAppPackageName = appPackageName;
+ mMetrics.SetAppPackageName(appPackageName);
sp<IDrmPlugin> plugin;
Return<void> hResult = factory->createPlugin(uuid, appPackageName.string(),
@@ -284,6 +392,7 @@ status_t DrmHal::setListener(const sp<IDrmClient>& listener)
Return<void> DrmHal::sendEvent(EventType hEventType,
const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data) {
+ mMetrics.mEventCounter.Increment(hEventType);
mEventLock.lock();
sp<IDrmClient> listener = mListener;
@@ -374,12 +483,21 @@ Return<void> DrmHal::sendKeysChange(const hidl_vec<uint8_t>& sessionId,
break;
}
obj.writeInt32(type);
+ mMetrics.mKeyStatusChangeCounter.Increment(keyStatus.type);
}
obj.writeInt32(hasNewUsableKey);
Mutex::Autolock lock(mNotifyLock);
listener->notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &obj);
+ } else {
+ // There's no listener. But we still want to count the key change
+ // events.
+ size_t nKeys = keyStatusList.size();
+ for (size_t i = 0; i < nKeys; i++) {
+ mMetrics.mKeyStatusChangeCounter.Increment(keyStatusList[i].type);
+ }
}
+
return Void();
}
@@ -407,6 +525,9 @@ status_t DrmHal::createPlugin(const uint8_t uuid[16],
for (size_t i = 0; i < mFactories.size(); i++) {
if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
mPlugin = makeDrmPlugin(mFactories[i], uuid, appPackageName);
+ if (mPlugin != NULL) {
+ mPluginV1_1 = drm::V1_1::IDrmPlugin::castFrom(mPlugin);
+ }
}
}
@@ -424,46 +545,66 @@ status_t DrmHal::createPlugin(const uint8_t uuid[16],
}
status_t DrmHal::destroyPlugin() {
- Mutex::Autolock autoLock(mLock);
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- closeOpenSessions();
- reportMetrics();
- setListener(NULL);
- mInitCheck = NO_INIT;
-
- if (mPlugin != NULL) {
- if (!mPlugin->setListener(NULL).isOk()) {
- mInitCheck = DEAD_OBJECT;
- }
- }
- mPlugin.clear();
+ cleanup();
return OK;
}
-status_t DrmHal::openSession(Vector<uint8_t> &sessionId) {
+status_t DrmHal::openSession(DrmPlugin::SecurityLevel level,
+ Vector<uint8_t> &sessionId) {
Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
- if (mInitCheck != OK) {
- return mInitCheck;
+ SecurityLevel hSecurityLevel;
+ bool setSecurityLevel = true;
+
+ switch(level) {
+ case DrmPlugin::kSecurityLevelSwSecureCrypto:
+ hSecurityLevel = SecurityLevel::SW_SECURE_CRYPTO;
+ break;
+ case DrmPlugin::kSecurityLevelSwSecureDecode:
+ hSecurityLevel = SecurityLevel::SW_SECURE_DECODE;
+ break;
+ case DrmPlugin::kSecurityLevelHwSecureCrypto:
+ hSecurityLevel = SecurityLevel::HW_SECURE_CRYPTO;
+ break;
+ case DrmPlugin::kSecurityLevelHwSecureDecode:
+ hSecurityLevel = SecurityLevel::HW_SECURE_DECODE;
+ break;
+ case DrmPlugin::kSecurityLevelHwSecureAll:
+ hSecurityLevel = SecurityLevel::HW_SECURE_ALL;
+ break;
+ case DrmPlugin::kSecurityLevelMax:
+ setSecurityLevel = false;
+ break;
+ default:
+ return ERROR_DRM_CANNOT_HANDLE;
}
status_t err = UNKNOWN_ERROR;
-
bool retry = true;
do {
hidl_vec<uint8_t> hSessionId;
- Return<void> hResult = mPlugin->openSession(
- [&](Status status, const hidl_vec<uint8_t>& id) {
- if (status == Status::OK) {
- sessionId = toVector(id);
+ Return<void> hResult;
+ if (mPluginV1_1 == NULL || !setSecurityLevel) {
+ hResult = mPlugin->openSession(
+ [&](Status status,const hidl_vec<uint8_t>& id) {
+ if (status == Status::OK) {
+ sessionId = toVector(id);
+ }
+ err = toStatusT(status);
}
- err = toStatusT(status);
- }
- );
+ );
+ } else {
+ hResult = mPluginV1_1->openSession_1_1(hSecurityLevel,
+ [&](Status status, const hidl_vec<uint8_t>& id) {
+ if (status == Status::OK) {
+ sessionId = toVector(id);
+ }
+ err = toStatusT(status);
+ }
+ );
+ }
if (!hResult.isOk()) {
err = DEAD_OBJECT;
@@ -485,16 +626,16 @@ status_t DrmHal::openSession(Vector<uint8_t> &sessionId) {
DrmSessionManager::Instance()->addSession(getCallingPid(),
mDrmSessionClient, sessionId);
mOpenSessions.push(sessionId);
+ mMetrics.SetSessionStart(sessionId);
}
+
+ mMetrics.mOpenSessionCounter.Increment(err);
return err;
}
status_t DrmHal::closeSession(Vector<uint8_t> const &sessionId) {
Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
Return<Status> status = mPlugin->closeSession(toHidlVec(sessionId));
if (status.isOk()) {
@@ -507,9 +648,12 @@ status_t DrmHal::closeSession(Vector<uint8_t> const &sessionId) {
}
}
}
- reportMetrics();
- return toStatusT(status);
+ status_t response = toStatusT(status);
+ mMetrics.SetSessionEnd(sessionId);
+ mMetrics.mCloseSessionCounter.Increment(response);
+ return response;
}
+ mMetrics.mCloseSessionCounter.Increment(DEAD_OBJECT);
return DEAD_OBJECT;
}
@@ -519,10 +663,8 @@ status_t DrmHal::getKeyRequest(Vector<uint8_t> const &sessionId,
String8> const &optionalParameters, Vector<uint8_t> &request,
String8 &defaultUrl, DrmPlugin::KeyRequestType *keyRequestType) {
Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
+ EventTimer<status_t> keyRequestTimer(&mMetrics.mGetKeyRequestTimeUs);
DrmSessionManager::Instance()->useSession(sessionId);
@@ -534,6 +676,7 @@ status_t DrmHal::getKeyRequest(Vector<uint8_t> const &sessionId,
} else if (keyType == DrmPlugin::kKeyType_Release) {
hKeyType = KeyType::RELEASE;
} else {
+ keyRequestTimer.SetAttribute(BAD_VALUE);
return BAD_VALUE;
}
@@ -541,23 +684,63 @@ status_t DrmHal::getKeyRequest(Vector<uint8_t> const &sessionId,
status_t err = UNKNOWN_ERROR;
+ if (mPluginV1_1 != NULL) {
+ Return<void> 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,
- KeyRequestType hKeyRequestType, const hidl_string& hDefaultUrl) {
+ drm::V1_0::KeyRequestType hKeyRequestType,
+ const hidl_string& hDefaultUrl) {
if (status == Status::OK) {
request = toVector(hRequest);
defaultUrl = toString8(hDefaultUrl);
switch (hKeyRequestType) {
- case KeyRequestType::INITIAL:
+ case drm::V1_0::KeyRequestType::INITIAL:
*keyRequestType = DrmPlugin::kKeyRequestType_Initial;
break;
- case KeyRequestType::RENEWAL:
+ case drm::V1_0::KeyRequestType::RENEWAL:
*keyRequestType = DrmPlugin::kKeyRequestType_Renewal;
break;
- case KeyRequestType::RELEASE:
+ case drm::V1_0::KeyRequestType::RELEASE:
*keyRequestType = DrmPlugin::kKeyRequestType_Release;
break;
default:
@@ -568,16 +751,17 @@ status_t DrmHal::getKeyRequest(Vector<uint8_t> const &sessionId,
}
});
- return hResult.isOk() ? err : DEAD_OBJECT;
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ keyRequestTimer.SetAttribute(err);
+ return err;
}
status_t DrmHal::provideKeyResponse(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &response, Vector<uint8_t> &keySetId) {
Mutex::Autolock autoLock(mLock);
+ EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
DrmSessionManager::Instance()->useSession(sessionId);
@@ -592,41 +776,35 @@ status_t DrmHal::provideKeyResponse(Vector<uint8_t> const &sessionId,
err = toStatusT(status);
}
);
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ keyResponseTimer.SetAttribute(err);
+ return err;
}
status_t DrmHal::removeKeys(Vector<uint8_t> const &keySetId) {
Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- return toStatusT(mPlugin->removeKeys(toHidlVec(keySetId)));
+ Return<Status> status = mPlugin->removeKeys(toHidlVec(keySetId));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
}
status_t DrmHal::restoreKeys(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keySetId) {
Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
DrmSessionManager::Instance()->useSession(sessionId);
- return toStatusT(mPlugin->restoreKeys(toHidlVec(sessionId),
- toHidlVec(keySetId)));
+ Return<Status> status = mPlugin->restoreKeys(toHidlVec(sessionId),
+ toHidlVec(keySetId));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
}
status_t DrmHal::queryKeyStatus(Vector<uint8_t> const &sessionId,
KeyedVector<String8, String8> &infoMap) const {
Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
DrmSessionManager::Instance()->useSession(sessionId);
@@ -650,10 +828,7 @@ status_t DrmHal::getProvisionRequest(String8 const &certType,
String8 const &certAuthority, Vector<uint8_t> &request,
String8 &defaultUrl) {
Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
status_t err = UNKNOWN_ERROR;
@@ -669,16 +844,15 @@ status_t DrmHal::getProvisionRequest(String8 const &certType,
}
);
- return hResult.isOk() ? err : DEAD_OBJECT;
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ mMetrics.mGetProvisionRequestCounter.Increment(err);
+ return err;
}
status_t DrmHal::provideProvisionResponse(Vector<uint8_t> const &response,
Vector<uint8_t> &certificate, Vector<uint8_t> &wrappedKey) {
Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
status_t err = UNKNOWN_ERROR;
@@ -693,15 +867,14 @@ status_t DrmHal::provideProvisionResponse(Vector<uint8_t> const &response,
}
);
- return hResult.isOk() ? err : DEAD_OBJECT;
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ mMetrics.mProvideProvisionResponseCounter.Increment(err);
+ return err;
}
status_t DrmHal::getSecureStops(List<Vector<uint8_t>> &secureStops) {
Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
status_t err = UNKNOWN_ERROR;
@@ -718,13 +891,36 @@ status_t DrmHal::getSecureStops(List<Vector<uint8_t>> &secureStops) {
}
-status_t DrmHal::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
+status_t DrmHal::getSecureStopIds(List<Vector<uint8_t>> &secureStopIds) {
Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) {
return mInitCheck;
}
+ if (mPluginV1_1 == NULL) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPluginV1_1->getSecureStopIds(
+ [&](Status status, const hidl_vec<SecureStopId>& hSecureStopIds) {
+ if (status == Status::OK) {
+ secureStopIds = toSecureStopIds(hSecureStopIds);
+ }
+ err = toStatusT(status);
+ }
+ );
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+
+status_t DrmHal::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
status_t err = UNKNOWN_ERROR;
Return<void> hResult = mPlugin->getSecureStop(toHidlVec(ssid),
@@ -741,22 +937,132 @@ status_t DrmHal::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &sec
status_t DrmHal::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ Return<Status> status(Status::ERROR_DRM_UNKNOWN);
+ if (mPluginV1_1 != NULL) {
+ SecureStopRelease secureStopRelease;
+ secureStopRelease.opaqueData = toHidlVec(ssRelease);
+ status = mPluginV1_1->releaseSecureStops(secureStopRelease);
+ } else {
+ status = mPlugin->releaseSecureStop(toHidlVec(ssRelease));
+ }
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHal::removeSecureStop(Vector<uint8_t> const &ssid) {
+ Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) {
return mInitCheck;
}
- return toStatusT(mPlugin->releaseSecureStop(toHidlVec(ssRelease)));
+ if (mPluginV1_1 == NULL) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ Return<Status> status = mPluginV1_1->removeSecureStop(toHidlVec(ssid));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
}
-status_t DrmHal::releaseAllSecureStops() {
+status_t DrmHal::removeAllSecureStops() {
Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
- if (mInitCheck != OK) {
- return mInitCheck;
+ Return<Status> status(Status::ERROR_DRM_UNKNOWN);
+ if (mPluginV1_1 != NULL) {
+ status = mPluginV1_1->removeAllSecureStops();
+ } else {
+ status = mPlugin->releaseAllSecureStops();
+ }
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHal::getHdcpLevels(DrmPlugin::HdcpLevel *connected,
+ DrmPlugin::HdcpLevel *max) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (connected == NULL || max == NULL) {
+ return BAD_VALUE;
+ }
+ status_t err = UNKNOWN_ERROR;
+
+ if (mPluginV1_1 == NULL) {
+ return ERROR_DRM_CANNOT_HANDLE;
}
- return toStatusT(mPlugin->releaseAllSecureStops());
+ *connected = DrmPlugin::kHdcpLevelUnknown;
+ *max = DrmPlugin::kHdcpLevelUnknown;
+
+ Return<void> hResult = mPluginV1_1->getHdcpLevels(
+ [&](Status status, const HdcpLevel& hConnected, const HdcpLevel& hMax) {
+ if (status == Status::OK) {
+ *connected = toHdcpLevel(hConnected);
+ *max = toHdcpLevel(hMax);
+ }
+ err = toStatusT(status);
+ }
+ );
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::getNumberOfSessions(uint32_t *open, uint32_t *max) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (open == NULL || max == NULL) {
+ return BAD_VALUE;
+ }
+ status_t err = UNKNOWN_ERROR;
+
+ *open = 0;
+ *max = 0;
+
+ if (mPluginV1_1 == NULL) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ Return<void> hResult = mPluginV1_1->getNumberOfSessions(
+ [&](Status status, uint32_t hOpen, uint32_t hMax) {
+ if (status == Status::OK) {
+ *open = hOpen;
+ *max = hMax;
+ }
+ err = toStatusT(status);
+ }
+ );
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::getSecurityLevel(Vector<uint8_t> const &sessionId,
+ DrmPlugin::SecurityLevel *level) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (level == NULL) {
+ return BAD_VALUE;
+ }
+ status_t err = UNKNOWN_ERROR;
+
+ if (mPluginV1_1 == NULL) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ *level = DrmPlugin::kSecurityLevelUnknown;
+
+ Return<void> hResult = mPluginV1_1->getSecurityLevel(toHidlVec(sessionId),
+ [&](Status status, SecurityLevel hLevel) {
+ if (status == Status::OK) {
+ *level = toSecurityLevel(hLevel);
+ }
+ err = toStatusT(status);
+ }
+ );
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
}
status_t DrmHal::getPropertyString(String8 const &name, String8 &value ) const {
@@ -767,10 +1073,7 @@ status_t DrmHal::getPropertyString(String8 const &name, String8 &value ) const {
status_t DrmHal::getPropertyStringInternal(String8 const &name, String8 &value) const {
// This function is internal to the class and should only be called while
// mLock is already held.
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
status_t err = UNKNOWN_ERROR;
@@ -794,10 +1097,7 @@ status_t DrmHal::getPropertyByteArray(String8 const &name, Vector<uint8_t> &valu
status_t DrmHal::getPropertyByteArrayInternal(String8 const &name, Vector<uint8_t> &value ) const {
// This function is internal to the class and should only be called while
// mLock is already held.
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
status_t err = UNKNOWN_ERROR;
@@ -810,73 +1110,106 @@ status_t DrmHal::getPropertyByteArrayInternal(String8 const &name, Vector<uint8_
}
);
- return hResult.isOk() ? err : DEAD_OBJECT;
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ if (name == kPropertyDeviceUniqueId) {
+ mMetrics.mGetDeviceUniqueIdCounter.Increment(err);
+ }
+ return err;
}
status_t DrmHal::setPropertyString(String8 const &name, String8 const &value ) const {
Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- Status status = mPlugin->setPropertyString(toHidlString(name),
+ Return<Status> status = mPlugin->setPropertyString(toHidlString(name),
toHidlString(value));
- return toStatusT(status);
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
}
status_t DrmHal::setPropertyByteArray(String8 const &name,
Vector<uint8_t> const &value ) const {
Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- Status status = mPlugin->setPropertyByteArray(toHidlString(name),
+ Return<Status> status = mPlugin->setPropertyByteArray(toHidlString(name),
toHidlVec(value));
- return toStatusT(status);
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
}
+status_t DrmHal::getMetrics(PersistableBundle* metrics) {
+ if (metrics == nullptr) {
+ return UNEXPECTED_NULL;
+ }
+ mMetrics.Export(metrics);
+
+ // Append vendor metrics if they are supported.
+ if (mPluginV1_1 != NULL) {
+ String8 vendor;
+ String8 description;
+ if (getPropertyStringInternal(String8("vendor"), vendor) != OK
+ || vendor.isEmpty()) {
+ ALOGE("Get vendor failed or is empty");
+ vendor = "NONE";
+ }
+ if (getPropertyStringInternal(String8("description"), description) != OK
+ || description.isEmpty()) {
+ ALOGE("Get description failed or is empty.");
+ description = "NONE";
+ }
+ vendor += ".";
+ vendor += description;
+
+ hidl_vec<DrmMetricGroup> pluginMetrics;
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> status = mPluginV1_1->getMetrics(
+ [&](Status status, hidl_vec<DrmMetricGroup> pluginMetrics) {
+ if (status != Status::OK) {
+ ALOGV("Error getting plugin metrics: %d", status);
+ } else {
+ PersistableBundle pluginBundle;
+ if (MediaDrmMetrics::HidlMetricsToBundle(
+ pluginMetrics, &pluginBundle) == OK) {
+ metrics->putPersistableBundle(String16(vendor), pluginBundle);
+ }
+ }
+ err = toStatusT(status);
+ });
+ return status.isOk() ? err : DEAD_OBJECT;
+ }
+
+ return OK;
+}
status_t DrmHal::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
String8 const &algorithm) {
Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
DrmSessionManager::Instance()->useSession(sessionId);
- Status status = mPlugin->setCipherAlgorithm(toHidlVec(sessionId),
+ Return<Status> status = mPlugin->setCipherAlgorithm(toHidlVec(sessionId),
toHidlString(algorithm));
- return toStatusT(status);
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
}
status_t DrmHal::setMacAlgorithm(Vector<uint8_t> const &sessionId,
String8 const &algorithm) {
Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
DrmSessionManager::Instance()->useSession(sessionId);
- Status status = mPlugin->setMacAlgorithm(toHidlVec(sessionId),
+ Return<Status> status = mPlugin->setMacAlgorithm(toHidlVec(sessionId),
toHidlString(algorithm));
- return toStatusT(status);
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
}
status_t DrmHal::encrypt(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keyId, Vector<uint8_t> const &input,
Vector<uint8_t> const &iv, Vector<uint8_t> &output) {
Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
DrmSessionManager::Instance()->useSession(sessionId);
@@ -899,10 +1232,7 @@ status_t DrmHal::decrypt(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keyId, Vector<uint8_t> const &input,
Vector<uint8_t> const &iv, Vector<uint8_t> &output) {
Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
DrmSessionManager::Instance()->useSession(sessionId);
@@ -925,10 +1255,7 @@ status_t DrmHal::sign(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keyId, Vector<uint8_t> const &message,
Vector<uint8_t> &signature) {
Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
DrmSessionManager::Instance()->useSession(sessionId);
@@ -951,10 +1278,7 @@ status_t DrmHal::verify(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keyId, Vector<uint8_t> const &message,
Vector<uint8_t> const &signature, bool &match) {
Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
DrmSessionManager::Instance()->useSession(sessionId);
@@ -979,10 +1303,7 @@ status_t DrmHal::signRSA(Vector<uint8_t> const &sessionId,
String8 const &algorithm, Vector<uint8_t> const &message,
Vector<uint8_t> const &wrappedKey, Vector<uint8_t> &signature) {
Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
+ INIT_CHECK();
if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) {
return -EPERM;
@@ -1007,17 +1328,7 @@ status_t DrmHal::signRSA(Vector<uint8_t> const &sessionId,
void DrmHal::binderDied(const wp<IBinder> &the_late_who __unused)
{
- Mutex::Autolock autoLock(mLock);
- closeOpenSessions();
- setListener(NULL);
- mInitCheck = NO_INIT;
-
- if (mPlugin != NULL) {
- if (!mPlugin->setListener(NULL).isOk()) {
- mInitCheck = DEAD_OBJECT;
- }
- }
- mPlugin.clear();
+ cleanup();
}
void DrmHal::writeByteArray(Parcel &obj, hidl_vec<uint8_t> const &vec)
@@ -1030,18 +1341,55 @@ void DrmHal::writeByteArray(Parcel &obj, hidl_vec<uint8_t> const &vec)
}
}
-void DrmHal::reportMetrics() const
+void DrmHal::reportFrameworkMetrics() const
+{
+ MediaAnalyticsItem item("mediadrm");
+ item.generateSessionID();
+ item.setPkgName(mMetrics.GetAppPackageName().c_str());
+ String8 vendor;
+ String8 description;
+ status_t result = getPropertyStringInternal(String8("vendor"), vendor);
+ if (result != OK) {
+ ALOGE("Failed to get vendor from drm plugin: %d", result);
+ } else {
+ item.setCString("vendor", vendor.c_str());
+ }
+ result = getPropertyStringInternal(String8("description"), description);
+ if (result != OK) {
+ ALOGE("Failed to get description from drm plugin: %d", result);
+ } else {
+ item.setCString("description", description.c_str());
+ }
+
+ std::string serializedMetrics;
+ result = mMetrics.GetSerializedMetrics(&serializedMetrics);
+ if (result != OK) {
+ ALOGE("Failed to serialize framework metrics: %d", result);
+ }
+ std::string b64EncodedMetrics = toBase64StringNoPad(serializedMetrics.data(),
+ serializedMetrics.size());
+ if (!b64EncodedMetrics.empty()) {
+ item.setCString("serialized_metrics", b64EncodedMetrics.c_str());
+ }
+ if (!item.selfrecord()) {
+ ALOGE("Failed to self record framework metrics");
+ }
+}
+
+void DrmHal::reportPluginMetrics() const
{
- Vector<uint8_t> metrics;
+ Vector<uint8_t> metricsVector;
String8 vendor;
String8 description;
if (getPropertyStringInternal(String8("vendor"), vendor) == OK &&
getPropertyStringInternal(String8("description"), description) == OK &&
- getPropertyByteArrayInternal(String8("metrics"), metrics) == OK) {
- status_t res = android::reportDrmPluginMetrics(
- metrics, vendor, description);
+ getPropertyByteArrayInternal(String8("metrics"), metricsVector) == OK) {
+ std::string metricsString = toBase64StringNoPad(metricsVector.array(),
+ metricsVector.size());
+ status_t res = android::reportDrmPluginMetrics(metricsString, vendor,
+ description, mAppPackageName);
if (res != OK) {
- ALOGE("Metrics were retrieved but could not be reported: %i", res);
+ ALOGE("Metrics were retrieved but could not be reported: %d", res);
}
}
}
diff --git a/drm/libmediadrm/DrmMetrics.cpp b/drm/libmediadrm/DrmMetrics.cpp
new file mode 100644
index 0000000000..4fed707017
--- /dev/null
+++ b/drm/libmediadrm/DrmMetrics.cpp
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "DrmMetrics"
+#include <iomanip>
+#include <utility>
+
+#include <android-base/macros.h>
+#include <media/stagefright/foundation/base64.h>
+#include <mediadrm/DrmMetrics.h>
+#include <sys/time.h>
+#include <utils/Log.h>
+#include <utils/Timers.h>
+
+#include "protos/metrics.pb.h"
+
+using ::android::String16;
+using ::android::String8;
+using ::android::drm_metrics::DrmFrameworkMetrics;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::drm::V1_0::EventType;
+using ::android::hardware::drm::V1_0::KeyStatusType;
+using ::android::hardware::drm::V1_1::DrmMetricGroup;
+using ::android::os::PersistableBundle;
+
+namespace {
+
+template <typename T> std::string GetAttributeName(T type);
+
+template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
+ static const char *type_names[] = {"USABLE", "EXPIRED",
+ "OUTPUT_NOT_ALLOWED", "STATUS_PENDING",
+ "INTERNAL_ERROR"};
+ if (((size_t)type) > arraysize(type_names)) {
+ return "UNKNOWN_TYPE";
+ }
+ return type_names[(size_t)type];
+}
+
+template <> std::string GetAttributeName<EventType>(EventType type) {
+ static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED",
+ "KEY_EXPIRED", "VENDOR_DEFINED",
+ "SESSION_RECLAIMED"};
+ if (((size_t)type) > arraysize(type_names)) {
+ return "UNKNOWN_TYPE";
+ }
+ return type_names[(size_t)type];
+}
+
+template <typename T>
+void ExportCounterMetric(const android::CounterMetric<T> &counter,
+ PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+ std::string success_count_name = counter.metric_name() + ".ok.count";
+ std::string error_count_name = counter.metric_name() + ".error.count";
+ std::vector<int64_t> status_values;
+ counter.ExportValues(
+ [&](const android::status_t status, const int64_t value) {
+ if (status == android::OK) {
+ metrics->putLong(android::String16(success_count_name.c_str()),
+ value);
+ } else {
+ int64_t total_errors(0);
+ metrics->getLong(android::String16(error_count_name.c_str()),
+ &total_errors);
+ metrics->putLong(android::String16(error_count_name.c_str()),
+ total_errors + value);
+ status_values.push_back(status);
+ }
+ });
+ if (!status_values.empty()) {
+ std::string error_list_name = counter.metric_name() + ".error.list";
+ metrics->putLongVector(android::String16(error_list_name.c_str()),
+ status_values);
+ }
+}
+
+template <typename T>
+void ExportCounterMetricWithAttributeNames(
+ const android::CounterMetric<T> &counter, PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+ counter.ExportValues([&](const T &attribute, const int64_t value) {
+ std::string name = counter.metric_name() + "." +
+ GetAttributeName(attribute) + ".count";
+ metrics->putLong(android::String16(name.c_str()), value);
+ });
+}
+
+template <typename T>
+void ExportEventMetric(const android::EventMetric<T> &event,
+ PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+ std::string success_count_name = event.metric_name() + ".ok.count";
+ std::string error_count_name = event.metric_name() + ".error.count";
+ std::string timing_name = event.metric_name() + ".ok.average_time_micros";
+ std::vector<int64_t> status_values;
+ event.ExportValues([&](const android::status_t &status,
+ const android::EventStatistics &value) {
+ if (status == android::OK) {
+ metrics->putLong(android::String16(success_count_name.c_str()),
+ value.count);
+ metrics->putLong(android::String16(timing_name.c_str()),
+ value.mean);
+ } else {
+ int64_t total_errors(0);
+ metrics->getLong(android::String16(error_count_name.c_str()),
+ &total_errors);
+ metrics->putLong(android::String16(error_count_name.c_str()),
+ total_errors + value.count);
+ status_values.push_back(status);
+ }
+ });
+ if (!status_values.empty()) {
+ std::string error_list_name = event.metric_name() + ".error.list";
+ metrics->putLongVector(android::String16(error_list_name.c_str()),
+ status_values);
+ }
+}
+
+void ExportSessionLifespans(
+ const std::map<std::string, std::pair<int64_t, int64_t>> &mSessionLifespans,
+ PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+
+ if (mSessionLifespans.empty()) {
+ return;
+ }
+
+ PersistableBundle startTimesBundle;
+ PersistableBundle endTimesBundle;
+ for (auto it = mSessionLifespans.begin(); it != mSessionLifespans.end();
+ it++) {
+ String16 key(it->first.c_str(), it->first.size());
+ startTimesBundle.putLong(key, it->second.first);
+ endTimesBundle.putLong(key, it->second.second);
+ }
+ metrics->putPersistableBundle(
+ android::String16("drm.mediadrm.session_start_times_ms"),
+ startTimesBundle);
+ metrics->putPersistableBundle(
+ android::String16("drm.mediadrm.session_end_times_ms"), endTimesBundle);
+}
+
+std::string ToHexString(const android::Vector<uint8_t> &sessionId) {
+ std::ostringstream out;
+ out << std::hex << std::setfill('0');
+ for (size_t i = 0; i < sessionId.size(); i++) {
+ out << std::setw(2) << (int)(sessionId[i]);
+ }
+ return out.str();
+}
+
+template <typename CT>
+void SetValue(const String16 &name, DrmMetricGroup::ValueType type,
+ const CT &value, PersistableBundle *bundle) {
+ switch (type) {
+ case DrmMetricGroup::ValueType::INT64_TYPE:
+ bundle->putLong(name, value.int64Value);
+ break;
+ case DrmMetricGroup::ValueType::DOUBLE_TYPE:
+ bundle->putDouble(name, value.doubleValue);
+ break;
+ case DrmMetricGroup::ValueType::STRING_TYPE:
+ bundle->putString(name, String16(value.stringValue.c_str()));
+ break;
+ default:
+ ALOGE("Unexpected value type: %hhu", type);
+ }
+}
+
+inline String16 MakeIndexString(unsigned int index) {
+ std::string str("[");
+ str.append(std::to_string(index));
+ str.append("]");
+ return String16(str.c_str());
+}
+
+} // namespace
+
+namespace android {
+
+MediaDrmMetrics::MediaDrmMetrics()
+ : mOpenSessionCounter("drm.mediadrm.open_session", "status"),
+ mCloseSessionCounter("drm.mediadrm.close_session", "status"),
+ mGetKeyRequestTimeUs("drm.mediadrm.get_key_request", "status"),
+ mProvideKeyResponseTimeUs("drm.mediadrm.provide_key_response", "status"),
+ mGetProvisionRequestCounter("drm.mediadrm.get_provision_request",
+ "status"),
+ mProvideProvisionResponseCounter(
+ "drm.mediadrm.provide_provision_response", "status"),
+ mKeyStatusChangeCounter("drm.mediadrm.key_status_change",
+ "key_status_type"),
+ mEventCounter("drm.mediadrm.event", "event_type"),
+ mGetDeviceUniqueIdCounter("drm.mediadrm.get_device_unique_id", "status") {
+}
+
+void MediaDrmMetrics::SetSessionStart(
+ const android::Vector<uint8_t> &sessionId) {
+ std::string sessionIdHex = ToHexString(sessionId);
+ mSessionLifespans[sessionIdHex] =
+ std::make_pair(GetCurrentTimeMs(), (int64_t)0);
+}
+
+void MediaDrmMetrics::SetSessionEnd(const android::Vector<uint8_t> &sessionId) {
+ std::string sessionIdHex = ToHexString(sessionId);
+ int64_t endTimeMs = GetCurrentTimeMs();
+ if (mSessionLifespans.find(sessionIdHex) != mSessionLifespans.end()) {
+ mSessionLifespans[sessionIdHex] =
+ std::make_pair(mSessionLifespans[sessionIdHex].first, endTimeMs);
+ } else {
+ mSessionLifespans[sessionIdHex] = std::make_pair((int64_t)0, endTimeMs);
+ }
+}
+
+void MediaDrmMetrics::Export(PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+ ExportCounterMetric(mOpenSessionCounter, metrics);
+ ExportCounterMetric(mCloseSessionCounter, metrics);
+ ExportEventMetric(mGetKeyRequestTimeUs, metrics);
+ ExportEventMetric(mProvideKeyResponseTimeUs, metrics);
+ ExportCounterMetric(mGetProvisionRequestCounter, metrics);
+ ExportCounterMetric(mProvideProvisionResponseCounter, metrics);
+ ExportCounterMetricWithAttributeNames(mKeyStatusChangeCounter, metrics);
+ ExportCounterMetricWithAttributeNames(mEventCounter, metrics);
+ ExportCounterMetric(mGetDeviceUniqueIdCounter, metrics);
+ ExportSessionLifespans(mSessionLifespans, metrics);
+}
+
+status_t MediaDrmMetrics::GetSerializedMetrics(std::string *serializedMetrics) {
+
+ if (!serializedMetrics) {
+ ALOGE("serializedMetrics was unexpectedly null.");
+ return UNEXPECTED_NULL;
+ }
+
+ DrmFrameworkMetrics metrics;
+
+ mOpenSessionCounter.ExportValues(
+ [&](const android::status_t status, const int64_t value) {
+ DrmFrameworkMetrics::Counter *counter =
+ metrics.add_open_session_counter();
+ counter->set_count(value);
+ counter->mutable_attributes()->set_error_code(status);
+ });
+
+ mCloseSessionCounter.ExportValues(
+ [&](const android::status_t status, const int64_t value) {
+ DrmFrameworkMetrics::Counter *counter =
+ metrics.add_close_session_counter();
+ counter->set_count(value);
+ counter->mutable_attributes()->set_error_code(status);
+ });
+
+ mGetProvisionRequestCounter.ExportValues(
+ [&](const android::status_t status, const int64_t value) {
+ DrmFrameworkMetrics::Counter *counter =
+ metrics.add_get_provisioning_request_counter();
+ counter->set_count(value);
+ counter->mutable_attributes()->set_error_code(status);
+ });
+
+ mProvideProvisionResponseCounter.ExportValues(
+ [&](const android::status_t status, const int64_t value) {
+ DrmFrameworkMetrics::Counter *counter =
+ metrics.add_provide_provisioning_response_counter();
+ counter->set_count(value);
+ counter->mutable_attributes()->set_error_code(status);
+ });
+
+ mKeyStatusChangeCounter.ExportValues(
+ [&](const KeyStatusType key_status_type, const int64_t value) {
+ DrmFrameworkMetrics::Counter *counter =
+ metrics.add_key_status_change_counter();
+ counter->set_count(value);
+ counter->mutable_attributes()->set_key_status_type(
+ (uint32_t)key_status_type);
+ });
+
+ mEventCounter.ExportValues(
+ [&](const EventType event_type, const int64_t value) {
+ DrmFrameworkMetrics::Counter *counter =
+ metrics.add_event_callback_counter();
+ counter->set_count(value);
+ counter->mutable_attributes()->set_event_type((uint32_t)event_type);
+ });
+
+ mGetDeviceUniqueIdCounter.ExportValues(
+ [&](const status_t status, const int64_t value) {
+ DrmFrameworkMetrics::Counter *counter =
+ metrics.add_get_device_unique_id_counter();
+ counter->set_count(value);
+ counter->mutable_attributes()->set_error_code(status);
+ });
+
+ mGetKeyRequestTimeUs.ExportValues(
+ [&](const status_t status, const EventStatistics &stats) {
+ DrmFrameworkMetrics::DistributionMetric *metric =
+ metrics.add_get_key_request_time_us();
+ metric->set_min(stats.min);
+ metric->set_max(stats.max);
+ metric->set_mean(stats.mean);
+ metric->set_operation_count(stats.count);
+ metric->set_variance(stats.sum_squared_deviation / stats.count);
+ metric->mutable_attributes()->set_error_code(status);
+ });
+
+ mProvideKeyResponseTimeUs.ExportValues(
+ [&](const status_t status, const EventStatistics &stats) {
+ DrmFrameworkMetrics::DistributionMetric *metric =
+ metrics.add_provide_key_response_time_us();
+ metric->set_min(stats.min);
+ metric->set_max(stats.max);
+ metric->set_mean(stats.mean);
+ metric->set_operation_count(stats.count);
+ metric->set_variance(stats.sum_squared_deviation / stats.count);
+ metric->mutable_attributes()->set_error_code(status);
+ });
+
+ for (const auto &sessionLifespan : mSessionLifespans) {
+ auto *map = metrics.mutable_session_lifetimes();
+
+ (*map)[sessionLifespan.first].set_start_time_ms(
+ sessionLifespan.second.first);
+ (*map)[sessionLifespan.first].set_end_time_ms(
+ sessionLifespan.second.second);
+ }
+
+ if (!metrics.SerializeToString(serializedMetrics)) {
+ ALOGE("Failed to serialize metrics.");
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+int64_t MediaDrmMetrics::GetCurrentTimeMs() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return ((int64_t)tv.tv_sec * 1000) + ((int64_t)tv.tv_usec / 1000);
+}
+
+status_t MediaDrmMetrics::HidlMetricsToBundle(
+ const hidl_vec<DrmMetricGroup> &hidlMetricGroups,
+ PersistableBundle *bundleMetricGroups) {
+ if (bundleMetricGroups == nullptr) {
+ return UNEXPECTED_NULL;
+ }
+ if (hidlMetricGroups.size() == 0) {
+ return OK;
+ }
+
+ int groupIndex = 0;
+ std::map<String16, int> indexMap;
+ for (const auto &hidlMetricGroup : hidlMetricGroups) {
+ PersistableBundle bundleMetricGroup;
+ for (const auto &hidlMetric : hidlMetricGroup.metrics) {
+ String16 metricName(hidlMetric.name.c_str());
+ PersistableBundle bundleMetric;
+ // Add metric component values.
+ for (const auto &value : hidlMetric.values) {
+ SetValue(String16(value.componentName.c_str()), value.type,
+ value, &bundleMetric);
+ }
+ // Set metric attributes.
+ PersistableBundle bundleMetricAttributes;
+ for (const auto &attribute : hidlMetric.attributes) {
+ SetValue(String16(attribute.name.c_str()), attribute.type,
+ attribute, &bundleMetricAttributes);
+ }
+ // Add attributes to the bundle metric.
+ bundleMetric.putPersistableBundle(String16("attributes"),
+ bundleMetricAttributes);
+ // Add one layer of indirection, allowing for repeated metric names.
+ PersistableBundle repeatedMetrics;
+ bundleMetricGroup.getPersistableBundle(metricName,
+ &repeatedMetrics);
+ int index = indexMap[metricName];
+ repeatedMetrics.putPersistableBundle(MakeIndexString(index),
+ bundleMetric);
+ indexMap[metricName] = ++index;
+
+ // Add the bundle metric to the group of metrics.
+ bundleMetricGroup.putPersistableBundle(metricName,
+ repeatedMetrics);
+ }
+ // Add the bundle metric group to the collection of groups.
+ bundleMetricGroups->putPersistableBundle(MakeIndexString(groupIndex++),
+ bundleMetricGroup);
+ }
+
+ return OK;
+}
+
+} // namespace android
diff --git a/drm/libmediadrm/DrmPluginPath.cpp b/drm/libmediadrm/DrmPluginPath.cpp
index c760825788..ac8607c278 100644
--- a/drm/libmediadrm/DrmPluginPath.cpp
+++ b/drm/libmediadrm/DrmPluginPath.cpp
@@ -19,7 +19,7 @@
#include <utils/Log.h>
#include <cutils/properties.h>
-#include <media/DrmPluginPath.h>
+#include <mediadrm/DrmPluginPath.h>
namespace android {
diff --git a/drm/libmediadrm/DrmSessionManager.cpp b/drm/libmediadrm/DrmSessionManager.cpp
index 02270d087c..375644ce87 100644
--- a/drm/libmediadrm/DrmSessionManager.cpp
+++ b/drm/libmediadrm/DrmSessionManager.cpp
@@ -21,9 +21,9 @@
#include <binder/IPCThreadState.h>
#include <binder/IProcessInfoService.h>
#include <binder/IServiceManager.h>
-#include <media/DrmSessionManager.h>
-#include <media/DrmSessionClientInterface.h>
#include <media/stagefright/ProcessInfo.h>
+#include <mediadrm/DrmSessionClientInterface.h>
+#include <mediadrm/DrmSessionManager.h>
#include <unistd.h>
#include <utils/String8.h>
diff --git a/drm/libmediadrm/ICrypto.cpp b/drm/libmediadrm/ICrypto.cpp
index ee5ea936c4..a2594aa2d8 100644
--- a/drm/libmediadrm/ICrypto.cpp
+++ b/drm/libmediadrm/ICrypto.cpp
@@ -19,10 +19,10 @@
#include <binder/Parcel.h>
#include <binder/IMemory.h>
#include <cutils/log.h>
-#include <media/ICrypto.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
+#include <mediadrm/ICrypto.h>
#include <utils/Log.h>
namespace android {
@@ -346,10 +346,10 @@ status_t BnCrypto::onTransact(
return OK;
}
- CryptoPlugin::SubSample *subSamples =
- new CryptoPlugin::SubSample[numSubSamples];
+ std::unique_ptr<CryptoPlugin::SubSample[]> subSamples =
+ std::make_unique<CryptoPlugin::SubSample[]>(numSubSamples);
- data.read(subSamples,
+ data.read(subSamples.get(),
sizeof(CryptoPlugin::SubSample) * numSubSamples);
DestinationBuffer destination;
@@ -407,7 +407,7 @@ status_t BnCrypto::onTransact(
result = -EINVAL;
} else {
result = decrypt(key, iv, mode, pattern, source, offset,
- subSamples, numSubSamples, destination, &errorDetailMsg);
+ subSamples.get(), numSubSamples, destination, &errorDetailMsg);
}
reply->writeInt32(result);
@@ -426,9 +426,7 @@ status_t BnCrypto::onTransact(
}
}
- delete[] subSamples;
- subSamples = NULL;
-
+ subSamples.reset();
return OK;
}
diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp
index 8ff6e6a0c4..509961fb10 100644
--- a/drm/libmediadrm/IDrm.cpp
+++ b/drm/libmediadrm/IDrm.cpp
@@ -19,10 +19,10 @@
#include <utils/Log.h>
#include <binder/Parcel.h>
-#include <media/IDrm.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
+#include <mediadrm/IDrm.h>
namespace android {
@@ -46,6 +46,7 @@ enum {
GET_PROPERTY_BYTE_ARRAY,
SET_PROPERTY_STRING,
SET_PROPERTY_BYTE_ARRAY,
+ GET_METRICS,
SET_CIPHER_ALGORITHM,
SET_MAC_ALGORITHM,
ENCRYPT,
@@ -55,7 +56,12 @@ enum {
VERIFY,
SET_LISTENER,
GET_SECURE_STOP,
- RELEASE_ALL_SECURE_STOPS
+ REMOVE_ALL_SECURE_STOPS,
+ GET_HDCP_LEVELS,
+ GET_NUMBER_OF_SESSIONS,
+ GET_SECURITY_LEVEL,
+ REMOVE_SECURE_STOP,
+ GET_SECURE_STOP_IDS
};
struct BpDrm : public BpInterface<IDrm> {
@@ -114,9 +120,11 @@ struct BpDrm : public BpInterface<IDrm> {
return reply.readInt32();
}
- virtual status_t openSession(Vector<uint8_t> &sessionId) {
+ virtual status_t openSession(DrmPlugin::SecurityLevel securityLevel,
+ Vector<uint8_t> &sessionId) {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+ data.writeInt32(securityLevel);
status_t status = remote()->transact(OPEN_SESSION, data, &reply);
if (status != OK) {
@@ -297,6 +305,25 @@ struct BpDrm : public BpInterface<IDrm> {
return reply.readInt32();
}
+ virtual status_t getSecureStopIds(List<Vector<uint8_t> > &secureStopIds) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+ status_t status = remote()->transact(GET_SECURE_STOP_IDS, data, &reply);
+ if (status != OK) {
+ return status;
+ }
+
+ secureStopIds.clear();
+ uint32_t count = reply.readInt32();
+ for (size_t i = 0; i < count; i++) {
+ Vector<uint8_t> secureStopId;
+ readVector(reply, secureStopId);
+ secureStopIds.push_back(secureStopId);
+ }
+ return reply.readInt32();
+ }
+
virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
@@ -324,11 +351,24 @@ struct BpDrm : public BpInterface<IDrm> {
return reply.readInt32();
}
- virtual status_t releaseAllSecureStops() {
+ virtual status_t removeSecureStop(Vector<uint8_t> const &ssid) {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- status_t status = remote()->transact(RELEASE_ALL_SECURE_STOPS, data, &reply);
+ writeVector(data, ssid);
+ status_t status = remote()->transact(REMOVE_SECURE_STOP, data, &reply);
+ if (status != OK) {
+ return status;
+ }
+
+ return reply.readInt32();
+ }
+
+ virtual status_t removeAllSecureStops() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+ status_t status = remote()->transact(REMOVE_ALL_SECURE_STOPS, data, &reply);
if (status != OK) {
return status;
}
@@ -350,6 +390,65 @@ struct BpDrm : public BpInterface<IDrm> {
return reply.readInt32();
}
+ virtual status_t getHdcpLevels(DrmPlugin::HdcpLevel *connected,
+ DrmPlugin::HdcpLevel *max) const {
+ Parcel data, reply;
+
+ if (connected == NULL || max == NULL) {
+ return BAD_VALUE;
+ }
+
+ data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+ status_t status = remote()->transact(GET_HDCP_LEVELS, data, &reply);
+ if (status != OK) {
+ return status;
+ }
+
+ *connected = static_cast<DrmPlugin::HdcpLevel>(reply.readInt32());
+ *max = static_cast<DrmPlugin::HdcpLevel>(reply.readInt32());
+ return reply.readInt32();
+ }
+
+ virtual status_t getNumberOfSessions(uint32_t *open, uint32_t *max) const {
+ Parcel data, reply;
+
+ if (open == NULL || max == NULL) {
+ return BAD_VALUE;
+ }
+
+ data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+ status_t status = remote()->transact(GET_NUMBER_OF_SESSIONS, data, &reply);
+ if (status != OK) {
+ return status;
+ }
+
+ *open = reply.readInt32();
+ *max = reply.readInt32();
+ return reply.readInt32();
+ }
+
+ virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
+ DrmPlugin::SecurityLevel *level) const {
+ Parcel data, reply;
+
+ if (level == NULL) {
+ return BAD_VALUE;
+ }
+
+ data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+ writeVector(data, sessionId);
+ status_t status = remote()->transact(GET_SECURITY_LEVEL, data, &reply);
+ if (status != OK) {
+ return status;
+ }
+
+ *level = static_cast<DrmPlugin::SecurityLevel>(reply.readInt32());
+ return reply.readInt32();
+ }
+
virtual status_t getPropertyByteArray(String8 const &name, Vector<uint8_t> &value) const {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
@@ -393,6 +492,35 @@ struct BpDrm : public BpInterface<IDrm> {
return reply.readInt32();
}
+ virtual status_t getMetrics(os::PersistableBundle *metrics) {
+ if (metrics == NULL) {
+ return BAD_VALUE;
+ }
+ Parcel data, reply;
+ data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+ status_t status = remote()->transact(GET_METRICS, data, &reply);
+ if (status != OK) {
+ return status;
+ }
+ // The reply data is ordered as
+ // 1) 32 bit integer reply followed by
+ // 2) Serialized PersistableBundle containing metrics.
+ status_t reply_status;
+ if (reply.readInt32(&reply_status) != OK
+ || reply_status != OK) {
+ ALOGE("Failed to read getMetrics response code from parcel. %d",
+ reply_status);
+ return reply_status;
+ }
+
+ status = metrics->readFromParcel(&reply);
+ if (status != OK) {
+ ALOGE("Failed to read metrics from parcel. %d", status);
+ return status;
+ }
+ return reply_status;
+ }
virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
String8 const &algorithm) {
@@ -615,8 +743,10 @@ status_t BnDrm::onTransact(
case OPEN_SESSION:
{
CHECK_INTERFACE(IDrm, data, reply);
+ DrmPlugin::SecurityLevel level =
+ static_cast<DrmPlugin::SecurityLevel>(data.readInt32());
Vector<uint8_t> sessionId;
- status_t result = openSession(sessionId);
+ status_t result = openSession(level, sessionId);
writeVector(reply, sessionId);
reply->writeInt32(result);
return OK;
@@ -761,6 +891,24 @@ status_t BnDrm::onTransact(
return OK;
}
+ case GET_SECURE_STOP_IDS:
+ {
+ CHECK_INTERFACE(IDrm, data, reply);
+ List<Vector<uint8_t> > secureStopIds;
+ status_t result = getSecureStopIds(secureStopIds);
+ size_t count = secureStopIds.size();
+ reply->writeInt32(count);
+ List<Vector<uint8_t> >::iterator iter = secureStopIds.begin();
+ while(iter != secureStopIds.end()) {
+ size_t size = iter->size();
+ reply->writeInt32(size);
+ reply->write(iter->array(), iter->size());
+ iter++;
+ }
+ reply->writeInt32(result);
+ return OK;
+ }
+
case GET_SECURE_STOP:
{
CHECK_INTERFACE(IDrm, data, reply);
@@ -781,10 +929,54 @@ status_t BnDrm::onTransact(
return OK;
}
- case RELEASE_ALL_SECURE_STOPS:
+ case REMOVE_SECURE_STOP:
+ {
+ CHECK_INTERFACE(IDrm, data, reply);
+ Vector<uint8_t> ssid;
+ readVector(data, ssid);
+ reply->writeInt32(removeSecureStop(ssid));
+ return OK;
+ }
+
+ case REMOVE_ALL_SECURE_STOPS:
+ {
+ CHECK_INTERFACE(IDrm, data, reply);
+ reply->writeInt32(removeAllSecureStops());
+ return OK;
+ }
+
+ case GET_HDCP_LEVELS:
+ {
+ CHECK_INTERFACE(IDrm, data, reply);
+ DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
+ DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
+ status_t result = getHdcpLevels(&connected, &max);
+ reply->writeInt32(connected);
+ reply->writeInt32(max);
+ reply->writeInt32(result);
+ return OK;
+ }
+
+ case GET_NUMBER_OF_SESSIONS:
{
CHECK_INTERFACE(IDrm, data, reply);
- reply->writeInt32(releaseAllSecureStops());
+ uint32_t open = 0, max = 0;
+ status_t result = getNumberOfSessions(&open, &max);
+ reply->writeInt32(open);
+ reply->writeInt32(max);
+ reply->writeInt32(result);
+ return OK;
+ }
+
+ case GET_SECURITY_LEVEL:
+ {
+ CHECK_INTERFACE(IDrm, data, reply);
+ Vector<uint8_t> sessionId;
+ readVector(data, sessionId);
+ DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
+ status_t result = getSecurityLevel(sessionId, &level);
+ reply->writeInt32(level);
+ reply->writeInt32(result);
return OK;
}
@@ -829,6 +1021,24 @@ status_t BnDrm::onTransact(
return OK;
}
+ case GET_METRICS:
+ {
+ CHECK_INTERFACE(IDrm, data, reply);
+
+ os::PersistableBundle metrics;
+ status_t result = getMetrics(&metrics);
+ // The reply data is ordered as
+ // 1) 32 bit integer reply followed by
+ // 2) Serialized PersistableBundle containing metrics.
+ // Only write the metrics if the getMetrics result was
+ // OK and we successfully added the status to reply.
+ status_t parcel_result = reply->writeInt32(result);
+ if (result == OK && parcel_result == OK) {
+ parcel_result = metrics.writeToParcel(reply);
+ }
+ return parcel_result;
+ }
+
case SET_CIPHER_ALGORITHM:
{
CHECK_INTERFACE(IDrm, data, reply);
diff --git a/drm/libmediadrm/IDrmClient.cpp b/drm/libmediadrm/IDrmClient.cpp
index 444201fff4..357de9d6b1 100644
--- a/drm/libmediadrm/IDrmClient.cpp
+++ b/drm/libmediadrm/IDrmClient.cpp
@@ -24,7 +24,7 @@
#include <binder/Parcel.h>
#include <media/IMediaPlayerClient.h>
-#include <media/IDrmClient.h>
+#include <mediadrm/IDrmClient.h>
namespace android {
diff --git a/drm/libmediadrm/IMediaDrmService.cpp b/drm/libmediadrm/IMediaDrmService.cpp
index 84812dc01d..f320d0bb76 100644
--- a/drm/libmediadrm/IMediaDrmService.cpp
+++ b/drm/libmediadrm/IMediaDrmService.cpp
@@ -20,9 +20,9 @@
#include <binder/Parcel.h>
#include <binder/IMemory.h>
-#include <media/ICrypto.h>
-#include <media/IDrm.h>
-#include <media/IMediaDrmService.h>
+#include <mediadrm/ICrypto.h>
+#include <mediadrm/IDrm.h>
+#include <mediadrm/IMediaDrmService.h>
#include <utils/Errors.h> // for status_t
#include <utils/String8.h>
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index 57ff5b8207..5cb48bf678 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -16,83 +16,35 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "PluginMetricsReporting"
-#include <utils/Log.h>
#include <media/PluginMetricsReporting.h>
+#include <inttypes.h>
+
#include <media/MediaAnalyticsItem.h>
+#include <utils/Log.h>
-#include "protos/plugin_metrics.pb.h"
namespace android {
namespace {
-using android::drm_metrics::MetricsGroup;
-using android::drm_metrics::MetricsGroup_Metric;
-using android::drm_metrics::MetricsGroup_Metric_MetricValue;
-
-const char* const kParentAttribute = "/parent/external";
+constexpr char kSerializedMetricsField[] = "serialized_metrics";
-status_t reportMetricsGroup(const MetricsGroup& metricsGroup,
- const String8& batchName,
- const int64_t* parentId) {
- MediaAnalyticsItem analyticsItem(batchName.c_str());
+status_t reportVendorMetrics(const std::string& metrics,
+ const String8& name,
+ const String8& appPackageName) {
+ MediaAnalyticsItem analyticsItem(name.c_str());
analyticsItem.generateSessionID();
- int64_t sessionId = analyticsItem.getSessionID();
- if (parentId != NULL) {
- analyticsItem.setInt64(kParentAttribute, *parentId);
- }
-
- // Report the package name.
- if (metricsGroup.has_app_package_name()) {
- AString app_package_name(metricsGroup.app_package_name().c_str(),
- metricsGroup.app_package_name().size());
- analyticsItem.setPkgName(app_package_name);
- }
-
- for (int i = 0; i < metricsGroup.metric_size(); ++i) {
- const MetricsGroup_Metric& metric = metricsGroup.metric(i);
- if (!metric.has_name()) {
- ALOGE("Metric with no name.");
- return BAD_VALUE;
- }
-
- if (!metric.has_value()) {
- ALOGE("Metric with no value.");
- return BAD_VALUE;
- }
- const MetricsGroup_Metric_MetricValue& value = metric.value();
- if (value.has_int_value()) {
- analyticsItem.setInt64(metric.name().c_str(),
- value.int_value());
- } else if (value.has_double_value()) {
- analyticsItem.setDouble(metric.name().c_str(),
- value.double_value());
- } else if (value.has_string_value()) {
- analyticsItem.setCString(metric.name().c_str(),
- value.string_value().c_str());
- } else {
- ALOGE("Metric Value with no actual value.");
- return BAD_VALUE;
- }
+ std::string app_package_name(appPackageName.c_str(), appPackageName.size());
+ analyticsItem.setPkgName(app_package_name);
+ if (metrics.size() > 0) {
+ analyticsItem.setCString(kSerializedMetricsField, metrics.c_str());
}
- analyticsItem.setFinalized(true);
if (!analyticsItem.selfrecord()) {
- // Note the cast to int is because we build on 32 and 64 bit.
- // The cast prevents a peculiar printf problem where one format cannot
- // satisfy both.
- ALOGE("selfrecord() returned false. sessioId %d", (int) sessionId);
- }
-
- for (int i = 0; i < metricsGroup.metric_sub_group_size(); ++i) {
- const MetricsGroup& subGroup = metricsGroup.metric_sub_group(i);
- status_t res = reportMetricsGroup(subGroup, batchName, &sessionId);
- if (res != OK) {
- return res;
- }
+ ALOGE("selfrecord() returned false. sessioId %" PRId64, analyticsItem.getSessionID());
}
return OK;
@@ -114,21 +66,16 @@ String8 sanitize(const String8& input) {
} // namespace
-status_t reportDrmPluginMetrics(const Vector<uint8_t>& serializedMetrics,
+status_t reportDrmPluginMetrics(const std::string& b64EncodedMetrics,
const String8& vendor,
- const String8& description) {
- MetricsGroup root_metrics_group;
- if (!root_metrics_group.ParseFromArray(serializedMetrics.array(),
- serializedMetrics.size())) {
- ALOGE("Failure to parse.");
- return BAD_VALUE;
- }
+ const String8& description,
+ const String8& appPackageName) {
String8 name = String8::format("drm.vendor.%s.%s",
sanitize(vendor).c_str(),
sanitize(description).c_str());
- return reportMetricsGroup(root_metrics_group, name, NULL);
+ return reportVendorMetrics(b64EncodedMetrics, name, appPackageName);
}
} // namespace android
diff --git a/drm/libmediadrm/SharedLibrary.cpp b/drm/libmediadrm/SharedLibrary.cpp
index bebafa8bb3..b2d635def8 100644
--- a/drm/libmediadrm/SharedLibrary.cpp
+++ b/drm/libmediadrm/SharedLibrary.cpp
@@ -19,7 +19,7 @@
#include <dlfcn.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/SharedLibrary.h>
+#include <mediadrm/SharedLibrary.h>
#include <utils/Log.h>
namespace android {
diff --git a/drm/libmediadrm/protos/metrics.proto b/drm/libmediadrm/protos/metrics.proto
new file mode 100644
index 0000000000..6160e6f272
--- /dev/null
+++ b/drm/libmediadrm/protos/metrics.proto
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package android.drm_metrics;
+
+
+// This message contains the specific metrics captured by DrmMetrics. It is
+// used for serializing and logging metrics.
+// next id: 11.
+message DrmFrameworkMetrics {
+ // TODO: Consider using extensions.
+
+ // Attributes are associated with a recorded value. E.g. A counter may
+ // represent a count of an operation returning a specific error code. The
+ // error code will be an attribute.
+ message Attributes {
+ // Reserved for compatibility with logging proto.
+ reserved 2 to 13;
+
+ // A general purpose error code where 0 means OK.
+ optional int32 error_code = 1;
+
+ // Defined at ::android::hardware::drm::V1_0::KeyStatusType;
+ optional uint32 key_status_type = 14;
+
+ // Defined at ::android::hardware::drm::V1_0::EventType;
+ optional uint32 event_type = 15;
+ }
+
+ // The Counter message is used to store a count value with an associated
+ // Attribute.
+ message Counter {
+ optional uint64 count = 1;
+ // Represents the attributes associated with this counter instance.
+ optional Attributes attributes = 2;
+ }
+
+ // The DistributionMetric is meant to capture the moments of a normally
+ // distributed (or approximately normal) value.
+ message DistributionMetric {
+ optional float min = 1;
+ optional float max = 2;
+ optional float mean = 3;
+ optional double variance = 4;
+ optional uint64 operation_count = 5;
+
+ // Represents the attributes assocated with this distribution metric
+ // instance.
+ optional Attributes attributes = 6;
+ }
+
+ message SessionLifetime {
+ // Start time of the session in milliseconds since epoch.
+ optional uint64 start_time_ms = 1;
+ // End time of the session in milliseconds since epoch.
+ optional uint64 end_time_ms = 2;
+ }
+
+ // The count of open session operations. Each instance has a specific error
+ // code associated with it.
+ repeated Counter open_session_counter = 1;
+
+ // The count of close session operations. Each instance has a specific error
+ // code associated with it.
+ repeated Counter close_session_counter = 2;
+
+ // Count and execution time of getKeyRequest calls.
+ repeated DistributionMetric get_key_request_time_us = 3;
+
+ // Count and execution time of provideKeyResponse calls.
+ repeated DistributionMetric provide_key_response_time_us = 4;
+
+ // Count of getProvisionRequest calls.
+ repeated Counter get_provisioning_request_counter = 5;
+
+ // Count of provideProvisionResponse calls.
+ repeated Counter provide_provisioning_response_counter = 6;
+
+ // Count of key status events broken out by status type.
+ repeated Counter key_status_change_counter = 7;
+
+ // Count of events broken out by event type
+ repeated Counter event_callback_counter = 8;
+
+ // Count getPropertyByteArray calls to retrieve the device unique id.
+ repeated Counter get_device_unique_id_counter = 9;
+
+ // Session ids to lifetime (start and end time) map.
+ // Session ids are strings of hex-encoded byte arrays.
+ map<string, SessionLifetime> session_lifetimes = 10;
+}
+
diff --git a/drm/libmediadrm/protos/plugin_metrics.proto b/drm/libmediadrm/protos/plugin_metrics.proto
deleted file mode 100644
index 7e3bcf5304..0000000000
--- a/drm/libmediadrm/protos/plugin_metrics.proto
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.drm_metrics;
-
-// need this if we are using libprotobuf-cpp-2.3.0-lite
-option optimize_for = LITE_RUNTIME;
-
-// The MetricsGroup is a collection of metric name/value pair instances
-// that can be serialized and provided to a caller.
-message MetricsGroup {
- message Metric {
- message MetricValue {
- // Exactly one of the following values must be set.
- optional int64 int_value = 1;
- optional double double_value = 2;
- optional string string_value = 3;
- }
-
- // The name of the metric. Must be valid UTF-8. Required.
- optional string name = 1;
-
- // The value of the metric. Required.
- optional MetricValue value = 2;
- }
-
- // The list of name/value pairs of metrics.
- repeated Metric metric = 1;
-
- // Allow multiple sub groups of metrics.
- repeated MetricsGroup metric_sub_group = 2;
-
- // Name of the application package associated with the metrics.
- optional string app_package_name = 3;
-}
diff --git a/drm/libmediadrm/tests/Android.bp b/drm/libmediadrm/tests/Android.bp
new file mode 100644
index 0000000000..66c906f2e9
--- /dev/null
+++ b/drm/libmediadrm/tests/Android.bp
@@ -0,0 +1,53 @@
+// Build definitions for unit tests.
+
+cc_test {
+ name: "CounterMetric_test",
+ srcs: ["CounterMetric_test.cpp"],
+ shared_libs: ["libmediadrm"],
+ include_dirs: ["frameworks/av/include/media"],
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
+
+cc_test {
+ name: "DrmMetrics_test",
+ srcs: ["DrmMetrics_test.cpp"],
+ shared_libs: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libmediadrmmetrics_full",
+ "libmediametrics",
+ "libprotobuf-cpp-full",
+ "libutils",
+ ],
+ static_libs: ["libgmock"],
+ include_dirs: [
+ "frameworks/av/include/media",
+ ],
+ cflags: [
+ // Suppress unused parameter and no error options. These cause problems
+ // when using the map type in a proto definition.
+ "-Wno-unused-parameter",
+ "-Wno-error",
+ ]
+}
+
+cc_test {
+ name: "EventMetric_test",
+ srcs: ["EventMetric_test.cpp"],
+ shared_libs: [
+ "liblog",
+ "libmediadrm",
+ "libutils",
+ ],
+ include_dirs: ["frameworks/av/include/media"],
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
diff --git a/drm/libmediadrm/tests/CounterMetric_test.cpp b/drm/libmediadrm/tests/CounterMetric_test.cpp
new file mode 100644
index 0000000000..6bca0dafe2
--- /dev/null
+++ b/drm/libmediadrm/tests/CounterMetric_test.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "CounterMetric.h"
+
+namespace android {
+
+/**
+ * Unit tests for the CounterMetric class.
+ */
+class CounterMetricTest : public ::testing::Test {
+};
+
+TEST_F(CounterMetricTest, IntDataTypeEmpty) {
+ CounterMetric<int> metric("MyMetricName", "MetricAttributeName");
+
+ std::map<int, int64_t> values;
+
+ metric.ExportValues(
+ [&] (int attribute_value, int64_t value) {
+ values[attribute_value] = value;
+ });
+
+ EXPECT_TRUE(values.empty());
+}
+
+TEST_F(CounterMetricTest, IntDataType) {
+ CounterMetric<int> metric("MyMetricName", "MetricAttributeName");
+
+ std::map<int, int64_t> values;
+
+ metric.Increment(7);
+ metric.Increment(8);
+ metric.Increment(8);
+
+ metric.ExportValues(
+ [&] (int attribute_value, int64_t value) {
+ values[attribute_value] = value;
+ });
+
+ ASSERT_EQ(2u, values.size());
+ EXPECT_EQ(1, values[7]);
+ EXPECT_EQ(2, values[8]);
+}
+
+TEST_F(CounterMetricTest, StringDataType) {
+ CounterMetric<std::string> metric("MyMetricName", "MetricAttributeName");
+
+ std::map<std::string, int64_t> values;
+
+ metric.Increment("a");
+ metric.Increment("b");
+ metric.Increment("b");
+
+ metric.ExportValues(
+ [&] (std::string attribute_value, int64_t value) {
+ values[attribute_value] = value;
+ });
+
+ ASSERT_EQ(2u, values.size());
+ EXPECT_EQ(1, values["a"]);
+ EXPECT_EQ(2, values["b"]);
+}
+
+} // namespace android
diff --git a/drm/libmediadrm/tests/DrmMetrics_test.cpp b/drm/libmediadrm/tests/DrmMetrics_test.cpp
new file mode 100644
index 0000000000..64aa9d0c99
--- /dev/null
+++ b/drm/libmediadrm/tests/DrmMetrics_test.cpp
@@ -0,0 +1,475 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DrmMetricsTest"
+#include "mediadrm/DrmMetrics.h"
+
+#include <android/hardware/drm/1.0/types.h>
+#include <android/hardware/drm/1.1/types.h>
+#include <binder/PersistableBundle.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/util/message_differencer.h>
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+
+#include "protos/metrics.pb.h"
+
+using ::android::drm_metrics::DrmFrameworkMetrics;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::drm::V1_0::EventType;
+using ::android::hardware::drm::V1_0::KeyStatusType;
+using ::android::hardware::drm::V1_0::Status;
+using ::android::hardware::drm::V1_1::DrmMetricGroup;
+using ::android::os::PersistableBundle;
+using ::google::protobuf::util::MessageDifferencer;
+using ::google::protobuf::TextFormat;
+
+namespace android {
+
+/**
+ * Unit tests for the MediaDrmMetrics class.
+ */
+class MediaDrmMetricsTest : public ::testing::Test {};
+
+/**
+ * This derived class mocks the clock for testing purposes.
+ */
+class FakeMediaDrmMetrics : public MediaDrmMetrics {
+ public:
+ FakeMediaDrmMetrics() : MediaDrmMetrics(), time_(0) {};
+
+ int64_t GetCurrentTimeMs() { return time_++; }
+ int64_t time_;
+};
+
+TEST_F(MediaDrmMetricsTest, EmptySuccess) {
+ MediaDrmMetrics metrics;
+ PersistableBundle bundle;
+
+ metrics.Export(&bundle);
+ EXPECT_TRUE(bundle.empty());
+}
+
+TEST_F(MediaDrmMetricsTest, AllValuesSuccessCounts) {
+ MediaDrmMetrics metrics;
+
+ metrics.mOpenSessionCounter.Increment(OK);
+ metrics.mCloseSessionCounter.Increment(OK);
+
+ {
+ EventTimer<status_t> get_key_request_timer(&metrics.mGetKeyRequestTimeUs);
+ EventTimer<status_t> provide_key_response_timer(
+ &metrics.mProvideKeyResponseTimeUs);
+ get_key_request_timer.SetAttribute(OK);
+ provide_key_response_timer.SetAttribute(OK);
+ }
+
+ metrics.mGetProvisionRequestCounter.Increment(OK);
+ metrics.mProvideProvisionResponseCounter.Increment(OK);
+ metrics.mGetDeviceUniqueIdCounter.Increment(OK);
+
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE);
+ metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
+
+ PersistableBundle bundle;
+
+ metrics.Export(&bundle);
+ EXPECT_EQ(11U, bundle.size());
+
+ // Verify the list of pairs of int64 metrics.
+ std::vector<std::pair<std::string, int64_t>> expected_values = {
+ { "drm.mediadrm.open_session.ok.count", 1 },
+ { "drm.mediadrm.close_session.ok.count", 1 },
+ { "drm.mediadrm.get_key_request.ok.count", 1 },
+ { "drm.mediadrm.provide_key_response.ok.count", 1 },
+ { "drm.mediadrm.get_provision_request.ok.count", 1 },
+ { "drm.mediadrm.provide_provision_response.ok.count", 1 },
+ { "drm.mediadrm.key_status_change.USABLE.count", 1 },
+ { "drm.mediadrm.event.PROVISION_REQUIRED.count", 1 },
+ { "drm.mediadrm.get_device_unique_id.ok.count", 1 }};
+ for (const auto& expected_pair : expected_values) {
+ String16 key(expected_pair.first.c_str());
+ int64_t value = -1;
+ EXPECT_TRUE(bundle.getLong(key, &value))
+ << "Unexpected error retrieviing key: " << key;
+ EXPECT_EQ(expected_pair.second, value)
+ << "Unexpected value for " << expected_pair.first << ". " << value;
+ }
+
+ // Validate timing values exist.
+ String16 get_key_request_key(
+ "drm.mediadrm.get_key_request.ok.average_time_micros");
+ String16 provide_key_response_key(
+ "drm.mediadrm.provide_key_response.ok.average_time_micros");
+ int64_t value = -1;
+ EXPECT_TRUE(bundle.getLong(get_key_request_key, &value));
+ EXPECT_GE(value, 0);
+ value = -1;
+ EXPECT_TRUE(bundle.getLong(provide_key_response_key, &value));
+ EXPECT_GE(value, 0);
+}
+
+TEST_F(MediaDrmMetricsTest, AllValuesFull) {
+ MediaDrmMetrics metrics;
+
+ metrics.mOpenSessionCounter.Increment(OK);
+ metrics.mOpenSessionCounter.Increment(UNEXPECTED_NULL);
+
+ metrics.mCloseSessionCounter.Increment(OK);
+ metrics.mCloseSessionCounter.Increment(UNEXPECTED_NULL);
+
+ for (status_t s : {OK, UNEXPECTED_NULL}) {
+ {
+ EventTimer<status_t> get_key_request_timer(&metrics.mGetKeyRequestTimeUs);
+ EventTimer<status_t> provide_key_response_timer(
+ &metrics.mProvideKeyResponseTimeUs);
+ get_key_request_timer.SetAttribute(s);
+ provide_key_response_timer.SetAttribute(s);
+ }
+ }
+
+ metrics.mGetProvisionRequestCounter.Increment(OK);
+ metrics.mGetProvisionRequestCounter.Increment(UNEXPECTED_NULL);
+ metrics.mProvideProvisionResponseCounter.Increment(OK);
+ metrics.mProvideProvisionResponseCounter.Increment(UNEXPECTED_NULL);
+ metrics.mGetDeviceUniqueIdCounter.Increment(OK);
+ metrics.mGetDeviceUniqueIdCounter.Increment(UNEXPECTED_NULL);
+
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE);
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::EXPIRED);
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::OUTPUTNOTALLOWED);
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::STATUSPENDING);
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::INTERNALERROR);
+ metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
+ metrics.mEventCounter.Increment(EventType::KEY_NEEDED);
+ metrics.mEventCounter.Increment(EventType::KEY_EXPIRED);
+ metrics.mEventCounter.Increment(EventType::VENDOR_DEFINED);
+ metrics.mEventCounter.Increment(EventType::SESSION_RECLAIMED);
+
+ android::Vector<uint8_t> sessionId1;
+ sessionId1.push_back(1);
+ sessionId1.push_back(2);
+ android::Vector<uint8_t> sessionId2;
+ sessionId2.push_back(3);
+ sessionId2.push_back(4);
+ String16 hexSessionId1("0102");
+ String16 hexSessionId2("0304");
+
+ metrics.SetSessionStart(sessionId1);
+ metrics.SetSessionStart(sessionId2);
+ metrics.SetSessionEnd(sessionId2);
+ metrics.SetSessionEnd(sessionId1);
+
+ PersistableBundle bundle;
+ metrics.Export(&bundle);
+ EXPECT_EQ(35U, bundle.size());
+
+ // Verify the list of pairs of int64 metrics.
+ std::vector<std::pair<std::string, int64_t>> expected_values = {
+ { "drm.mediadrm.open_session.ok.count", 1 },
+ { "drm.mediadrm.close_session.ok.count", 1 },
+ { "drm.mediadrm.get_key_request.ok.count", 1 },
+ { "drm.mediadrm.provide_key_response.ok.count", 1 },
+ { "drm.mediadrm.get_provision_request.ok.count", 1 },
+ { "drm.mediadrm.provide_provision_response.ok.count", 1 },
+ { "drm.mediadrm.get_device_unique_id.ok.count", 1 },
+ { "drm.mediadrm.open_session.error.count", 1 },
+ { "drm.mediadrm.close_session.error.count", 1 },
+ { "drm.mediadrm.get_key_request.error.count", 1 },
+ { "drm.mediadrm.provide_key_response.error.count", 1 },
+ { "drm.mediadrm.get_provision_request.error.count", 1 },
+ { "drm.mediadrm.provide_provision_response.error.count", 1 },
+ { "drm.mediadrm.get_device_unique_id.error.count", 1 },
+ { "drm.mediadrm.key_status_change.USABLE.count", 1 },
+ { "drm.mediadrm.key_status_change.EXPIRED.count", 1 },
+ { "drm.mediadrm.key_status_change.OUTPUT_NOT_ALLOWED.count", 1 },
+ { "drm.mediadrm.key_status_change.STATUS_PENDING.count", 1 },
+ { "drm.mediadrm.key_status_change.INTERNAL_ERROR.count", 1 },
+ { "drm.mediadrm.event.PROVISION_REQUIRED.count", 1 },
+ { "drm.mediadrm.event.KEY_NEEDED.count", 1 },
+ { "drm.mediadrm.event.KEY_EXPIRED.count", 1 },
+ { "drm.mediadrm.event.VENDOR_DEFINED.count", 1 },
+ { "drm.mediadrm.event.SESSION_RECLAIMED.count", 1 }};
+ for (const auto& expected_pair : expected_values) {
+ String16 key(expected_pair.first.c_str());
+ int64_t value = -1;
+ EXPECT_TRUE(bundle.getLong(key, &value))
+ << "Unexpected error retrieviing key: " << key;
+ EXPECT_EQ(expected_pair.second, value)
+ << "Unexpected value for " << expected_pair.first << ". " << value;
+ }
+
+ // Verify the error lists
+ std::vector<std::pair<std::string, std::vector<int64_t>>> expected_vector_values = {
+ { "drm.mediadrm.close_session.error.list", { UNEXPECTED_NULL } },
+ { "drm.mediadrm.get_device_unique_id.error.list", { UNEXPECTED_NULL } },
+ { "drm.mediadrm.get_key_request.error.list", { UNEXPECTED_NULL } },
+ { "drm.mediadrm.get_provision_request.error.list", { UNEXPECTED_NULL } },
+ { "drm.mediadrm.open_session.error.list", { UNEXPECTED_NULL } },
+ { "drm.mediadrm.provide_key_response.error.list", { UNEXPECTED_NULL } },
+ { "drm.mediadrm.provide_provision_response.error.list", { UNEXPECTED_NULL } }};
+ for (const auto& expected_pair : expected_vector_values) {
+ String16 key(expected_pair.first.c_str());
+ std::vector<int64_t> values;
+ EXPECT_TRUE(bundle.getLongVector(key, &values))
+ << "Unexpected error retrieviing key: " << key;
+ for (auto expected : expected_pair.second) {
+ EXPECT_TRUE(std::find(values.begin(), values.end(), expected) != values.end())
+ << "Could not find " << expected << " for key " << expected_pair.first;
+ }
+ }
+
+ // Verify the lifespans
+ PersistableBundle start_times;
+ PersistableBundle end_times;
+ String16 start_time_key("drm.mediadrm.session_start_times_ms");
+ String16 end_time_key("drm.mediadrm.session_end_times_ms");
+ ASSERT_TRUE(bundle.getPersistableBundle(start_time_key, &start_times));
+ ASSERT_TRUE(bundle.getPersistableBundle(end_time_key, &end_times));
+ EXPECT_EQ(2U, start_times.size());
+ EXPECT_EQ(2U, end_times.size());
+ int64_t start_time, end_time;
+ for (const auto& sid : { hexSessionId1, hexSessionId2 }) {
+ start_time = -1;
+ end_time = -1;
+ EXPECT_TRUE(start_times.getLong(sid, &start_time));
+ EXPECT_TRUE(end_times.getLong(sid, &end_time));
+ EXPECT_GT(start_time, 0);
+ EXPECT_GE(end_time, start_time);
+ }
+
+ // Validate timing values exist.
+ String16 get_key_request_key(
+ "drm.mediadrm.get_key_request.ok.average_time_micros");
+ String16 provide_key_response_key(
+ "drm.mediadrm.provide_key_response.ok.average_time_micros");
+ int64_t value = -1;
+ EXPECT_TRUE(bundle.getLong(get_key_request_key, &value));
+ EXPECT_GE(value, 0);
+ value = -1;
+ EXPECT_TRUE(bundle.getLong(provide_key_response_key, &value));
+ EXPECT_GE(value, 0);
+}
+
+
+TEST_F(MediaDrmMetricsTest, CounterValuesProtoSerialization) {
+ MediaDrmMetrics metrics;
+
+ metrics.mOpenSessionCounter.Increment(OK);
+ metrics.mOpenSessionCounter.Increment(UNEXPECTED_NULL);
+ metrics.mCloseSessionCounter.Increment(OK);
+ metrics.mCloseSessionCounter.Increment(UNEXPECTED_NULL);
+
+ metrics.mGetProvisionRequestCounter.Increment(OK);
+ metrics.mGetProvisionRequestCounter.Increment(UNEXPECTED_NULL);
+ metrics.mProvideProvisionResponseCounter.Increment(OK);
+ metrics.mProvideProvisionResponseCounter.Increment(UNEXPECTED_NULL);
+ metrics.mGetDeviceUniqueIdCounter.Increment(OK);
+ metrics.mGetDeviceUniqueIdCounter.Increment(UNEXPECTED_NULL);
+
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE);
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::EXPIRED);
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::OUTPUTNOTALLOWED);
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::STATUSPENDING);
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::INTERNALERROR);
+ metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
+ metrics.mEventCounter.Increment(EventType::KEY_NEEDED);
+ metrics.mEventCounter.Increment(EventType::KEY_EXPIRED);
+ metrics.mEventCounter.Increment(EventType::VENDOR_DEFINED);
+ metrics.mEventCounter.Increment(EventType::SESSION_RECLAIMED);
+
+ std::string serializedMetrics;
+ ASSERT_EQ(OK, metrics.GetSerializedMetrics(&serializedMetrics));
+
+ DrmFrameworkMetrics metricsProto;
+ ASSERT_TRUE(metricsProto.ParseFromString(serializedMetrics));
+
+ std::string expectedMetrics =
+ "open_session_counter { count: 1 attributes { error_code: -0x7FFFFFF8 } } "
+ "open_session_counter { count: 1 attributes { error_code: 0 } } "
+ "close_session_counter { count: 1 attributes { error_code: -0x7FFFFFF8 } } "
+ "close_session_counter { count: 1 attributes { error_code: 0 } } "
+ "get_provisioning_request_counter { count: 1 attributes { error_code: -0x7FFFFFF8 } } "
+ "get_provisioning_request_counter { count: 1 attributes { error_code: 0 } } "
+ "provide_provisioning_response_counter { count: 1 attributes { error_code: -0x7ffffff8 } } "
+ "provide_provisioning_response_counter { count: 1 attributes { error_code: 0 } } "
+ "get_device_unique_id_counter { count: 1 attributes { error_code: -0x7ffffff8 } } "
+ "get_device_unique_id_counter { count: 1 attributes { error_code: 0 } } "
+ "key_status_change_counter { count: 1 attributes { key_status_type: 0 } } "
+ "key_status_change_counter { count: 1 attributes { key_status_type: 1 } } "
+ "key_status_change_counter { count: 1 attributes { key_status_type: 2 } } "
+ "key_status_change_counter { count: 1 attributes { key_status_type: 3 } } "
+ "key_status_change_counter { count: 1 attributes { key_status_type: 4 } } "
+ "event_callback_counter { count: 1 attributes { event_type: 0 } } "
+ "event_callback_counter { count: 1 attributes { event_type: 1 } } "
+ "event_callback_counter { count: 1 attributes { event_type: 2 } } "
+ "event_callback_counter { count: 1 attributes { event_type: 3 } } "
+ "event_callback_counter { count: 1 attributes { event_type: 4 } } ";
+
+ DrmFrameworkMetrics expectedMetricsProto;
+ ASSERT_TRUE(TextFormat::MergeFromString(expectedMetrics, &expectedMetricsProto));
+
+ std::string diffString;
+ MessageDifferencer differ;
+ differ.ReportDifferencesToString(&diffString);
+ ASSERT_TRUE(differ.Compare(expectedMetricsProto, metricsProto))
+ << diffString;
+}
+
+TEST_F(MediaDrmMetricsTest, TimeMetricsProtoSerialization) {
+ MediaDrmMetrics metrics;
+
+ for (status_t s : {OK, UNEXPECTED_NULL}) {
+ double time = 0;
+ for (int i = 0; i < 5; i++) {
+ time += 1.0;
+ metrics.mGetKeyRequestTimeUs.Record(time, s);
+ metrics.mProvideKeyResponseTimeUs.Record(time, s);
+ }
+ }
+
+ std::string serializedMetrics;
+ ASSERT_EQ(OK, metrics.GetSerializedMetrics(&serializedMetrics));
+
+ DrmFrameworkMetrics metricsProto;
+ ASSERT_TRUE(metricsProto.ParseFromString(serializedMetrics));
+
+ std::string expectedMetrics =
+ "get_key_request_time_us { "
+ " min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 "
+ " attributes { error_code: -0x7FFFFFF8 } "
+ "} "
+ "get_key_request_time_us { "
+ " min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 "
+ " attributes { error_code: 0 } "
+ "} "
+ "provide_key_response_time_us { "
+ " min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 "
+ " attributes { error_code: -0x7FFFFFF8 } "
+ "} "
+ "provide_key_response_time_us { "
+ " min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 "
+ " attributes { error_code: 0 } "
+ "} ";
+
+ DrmFrameworkMetrics expectedMetricsProto;
+ ASSERT_TRUE(TextFormat::MergeFromString(expectedMetrics, &expectedMetricsProto));
+
+ std::string diffString;
+ MessageDifferencer differ;
+ differ.ReportDifferencesToString(&diffString);
+ ASSERT_TRUE(differ.Compare(expectedMetricsProto, metricsProto))
+ << diffString;
+}
+
+TEST_F(MediaDrmMetricsTest, SessionLifetimeProtoSerialization) {
+ // Use the fake so the clock is predictable;
+ FakeMediaDrmMetrics metrics;
+
+ android::Vector<uint8_t> sessionId1;
+ sessionId1.push_back(1);
+ sessionId1.push_back(2);
+ android::Vector<uint8_t> sessionId2;
+ sessionId2.push_back(3);
+ sessionId2.push_back(4);
+
+ metrics.SetSessionStart(sessionId1);
+ metrics.SetSessionStart(sessionId2);
+ metrics.SetSessionEnd(sessionId2);
+ metrics.SetSessionEnd(sessionId1);
+
+ std::string serializedMetrics;
+ ASSERT_EQ(OK, metrics.GetSerializedMetrics(&serializedMetrics));
+
+ DrmFrameworkMetrics metricsProto;
+ ASSERT_TRUE(metricsProto.ParseFromString(serializedMetrics));
+
+ std::string expectedMetrics =
+ "session_lifetimes: { "
+ " key: '0102' "
+ " value { start_time_ms: 0 end_time_ms: 3 } "
+ "} "
+ "session_lifetimes: { "
+ " key: '0304' "
+ " value { start_time_ms: 1 end_time_ms: 2 } "
+ "} ";
+
+ DrmFrameworkMetrics expectedMetricsProto;
+ ASSERT_TRUE(TextFormat::MergeFromString(expectedMetrics, &expectedMetricsProto));
+
+ std::string diffString;
+ MessageDifferencer differ;
+ differ.ReportDifferencesToString(&diffString);
+ ASSERT_TRUE(differ.Compare(expectedMetricsProto, metricsProto))
+ << diffString;
+}
+
+TEST_F(MediaDrmMetricsTest, HidlToBundleMetricsEmpty) {
+ hidl_vec<DrmMetricGroup> hidlMetricGroups;
+ PersistableBundle bundleMetricGroups;
+
+ ASSERT_EQ(OK, MediaDrmMetrics::HidlMetricsToBundle(hidlMetricGroups, &bundleMetricGroups));
+ ASSERT_EQ(0U, bundleMetricGroups.size());
+}
+
+TEST_F(MediaDrmMetricsTest, HidlToBundleMetricsMultiple) {
+ DrmMetricGroup hidlMetricGroup =
+ { { {
+ "open_session_ok",
+ { { "status", DrmMetricGroup::ValueType::INT64_TYPE,
+ (int64_t) Status::OK, 0.0, "" } },
+ { { "count", DrmMetricGroup::ValueType::INT64_TYPE, 3, 0.0, "" } }
+ },
+ {
+ "close_session_not_opened",
+ { { "status", DrmMetricGroup::ValueType::INT64_TYPE,
+ (int64_t) Status::ERROR_DRM_SESSION_NOT_OPENED, 0.0, "" } },
+ { { "count", DrmMetricGroup::ValueType::INT64_TYPE, 7, 0.0, "" } }
+ } } };
+
+ PersistableBundle bundleMetricGroups;
+ ASSERT_EQ(OK, MediaDrmMetrics::HidlMetricsToBundle(hidl_vec<DrmMetricGroup>({hidlMetricGroup}),
+ &bundleMetricGroups));
+ ASSERT_EQ(1U, bundleMetricGroups.size());
+ PersistableBundle bundleMetricGroup;
+ ASSERT_TRUE(bundleMetricGroups.getPersistableBundle(String16("[0]"), &bundleMetricGroup));
+ ASSERT_EQ(2U, bundleMetricGroup.size());
+
+ // Verify each metric.
+ PersistableBundle metric;
+ ASSERT_TRUE(bundleMetricGroup.getPersistableBundle(String16("open_session_ok"), &metric));
+ PersistableBundle metricInstance;
+ ASSERT_TRUE(metric.getPersistableBundle(String16("[0]"), &metricInstance));
+ int64_t value = 0;
+ ASSERT_TRUE(metricInstance.getLong(String16("count"), &value));
+ ASSERT_EQ(3, value);
+ PersistableBundle attributeBundle;
+ ASSERT_TRUE(metricInstance.getPersistableBundle(String16("attributes"), &attributeBundle));
+ ASSERT_TRUE(attributeBundle.getLong(String16("status"), &value));
+ ASSERT_EQ((int64_t) Status::OK, value);
+
+ ASSERT_TRUE(bundleMetricGroup.getPersistableBundle(String16("close_session_not_opened"),
+ &metric));
+ ASSERT_TRUE(metric.getPersistableBundle(String16("[0]"), &metricInstance));
+ ASSERT_TRUE(metricInstance.getLong(String16("count"), &value));
+ ASSERT_EQ(7, value);
+ ASSERT_TRUE(metricInstance.getPersistableBundle(String16("attributes"), &attributeBundle));
+ value = 0;
+ ASSERT_TRUE(attributeBundle.getLong(String16("status"), &value));
+ ASSERT_EQ((int64_t) Status::ERROR_DRM_SESSION_NOT_OPENED, value);
+}
+
+} // namespace android
diff --git a/drm/libmediadrm/tests/EventMetric_test.cpp b/drm/libmediadrm/tests/EventMetric_test.cpp
new file mode 100644
index 0000000000..eb6c4f684b
--- /dev/null
+++ b/drm/libmediadrm/tests/EventMetric_test.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "EventMetric.h"
+
+namespace android {
+
+/**
+ * Unit tests for the EventMetric class.
+ */
+
+TEST(EventMetricTest, IntDataTypeEmpty) {
+ EventMetric<int> metric("MyMetricName", "MetricAttributeName");
+
+ std::map<int, EventStatistics> values;
+
+ metric.ExportValues(
+ [&] (int attribute_value, const EventStatistics& value) {
+ values[attribute_value] = value;
+ });
+
+ EXPECT_TRUE(values.empty());
+}
+
+TEST(EventMetricTest, IntDataType) {
+ EventMetric<int> metric("MyMetricName", "MetricAttributeName");
+
+ std::map<int, EventStatistics> values;
+
+ metric.Record(4, 7);
+ metric.Record(5, 8);
+ metric.Record(5, 8);
+ metric.Record(5, 8);
+ metric.Record(6, 8);
+ metric.Record(6, 8);
+ metric.Record(6, 8);
+
+ metric.ExportValues(
+ [&] (int attribute_value, const EventStatistics& value) {
+ values[attribute_value] = value;
+ });
+
+ ASSERT_EQ(2u, values.size());
+ EXPECT_EQ(4, values[7].min);
+ EXPECT_EQ(4, values[7].max);
+ EXPECT_EQ(4, values[7].mean);
+ EXPECT_EQ(1, values[7].count);
+
+ EXPECT_EQ(5, values[8].min);
+ EXPECT_EQ(6, values[8].max);
+ // This is an approximate value because of the technique we're using.
+ EXPECT_NEAR(5.5, values[8].mean, 0.2);
+ EXPECT_EQ(6, values[8].count);
+}
+
+TEST(EventMetricTest, StringDataType) {
+ EventMetric<std::string> metric("MyMetricName", "MetricAttributeName");
+
+ std::map<std::string, EventStatistics> values;
+
+ metric.Record(1, "a");
+ metric.Record(2, "b");
+ metric.Record(2, "b");
+ metric.Record(3, "b");
+ metric.Record(3, "b");
+
+ metric.ExportValues(
+ [&] (std::string attribute_value, const EventStatistics& value) {
+ values[attribute_value] = value;
+ });
+
+ ASSERT_EQ(2u, values.size());
+ EXPECT_EQ(1, values["a"].min);
+ EXPECT_EQ(1, values["a"].max);
+ EXPECT_EQ(1, values["a"].mean);
+ EXPECT_EQ(1, values["a"].count);
+
+ EXPECT_EQ(2, values["b"].min);
+ EXPECT_EQ(3, values["b"].max);
+ EXPECT_NEAR(2.5, values["b"].mean, 0.2);
+ EXPECT_EQ(4, values["b"].count);
+}
+
+// Helper class that allows us to mock the clock.
+template<typename AttributeType>
+class MockEventTimer : public EventTimer<AttributeType> {
+ public:
+ explicit MockEventTimer(nsecs_t time_delta_ns,
+ EventMetric<AttributeType>* metric)
+ : EventTimer<AttributeType>(metric) {
+ // Pretend the event started earlier.
+ this->start_time_ = systemTime() - time_delta_ns;
+ }
+};
+
+TEST(EventTimerTest, IntDataType) {
+ EventMetric<int> metric("MyMetricName", "MetricAttributeName");
+
+ for (int i = 0; i < 5; i++) {
+ {
+ // Add a mock time delta.
+ MockEventTimer<int> metric_timer(i * 1000000, &metric);
+ metric_timer.SetAttribute(i % 2);
+ }
+ }
+
+ std::map<int, EventStatistics> values;
+ metric.ExportValues(
+ [&] (int attribute_value, const EventStatistics& value) {
+ values[attribute_value] = value;
+ });
+
+ ASSERT_EQ(2u, values.size());
+ EXPECT_LT(values[0].min, values[0].max);
+ EXPECT_GE(4000, values[0].max);
+ EXPECT_GT(values[0].mean, values[0].min);
+ EXPECT_LE(values[0].mean, values[0].max);
+ EXPECT_EQ(3, values[0].count);
+
+ EXPECT_LT(values[1].min, values[1].max);
+ EXPECT_GE(3000, values[1].max);
+ EXPECT_GT(values[1].mean, values[1].min);
+ EXPECT_LE(values[1].mean, values[1].max);
+ EXPECT_EQ(2, values[1].count);
+}
+
+} // namespace android
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
index e27631fc53..73ed8c3637 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
@@ -55,7 +55,7 @@ status_t ClearKeyCasFactory::queryPlugins(
status_t ClearKeyCasFactory::createPlugin(
int32_t CA_system_id,
- uint64_t appData,
+ void *appData,
CasPluginCallback callback,
CasPlugin **plugin) {
if (!isSystemIdSupported(CA_system_id)) {
@@ -83,7 +83,7 @@ status_t ClearKeyDescramblerFactory::createPlugin(
///////////////////////////////////////////////////////////////////////////////
ClearKeyCasPlugin::ClearKeyCasPlugin(
- uint64_t appData, CasPluginCallback callback)
+ void *appData, CasPluginCallback callback)
: mCallback(callback), mAppData(appData) {
ALOGV("CTOR");
}
@@ -347,6 +347,9 @@ ssize_t ClearKeyCasSession::decrypt(
return ERROR_CAS_CANNOT_HANDLE;
}
+ scramblingControl = (DescramblerPlugin::ScramblingControl)
+ (scramblingControl & DescramblerPlugin::kScrambling_Mask_Key);
+
AES_KEY contentKey;
if (scramblingControl != DescramblerPlugin::kScrambling_Unscrambled) {
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
index b7134e4038..42cfb8f2fb 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
@@ -44,7 +44,7 @@ public:
std::vector<CasPluginDescriptor> *descriptors) const override;
virtual status_t createPlugin(
int32_t CA_system_id,
- uint64_t appData,
+ void *appData,
CasPluginCallback callback,
CasPlugin **plugin) override;
};
@@ -62,7 +62,7 @@ public:
class ClearKeyCasPlugin : public CasPlugin {
public:
- ClearKeyCasPlugin(uint64_t appData, CasPluginCallback callback);
+ ClearKeyCasPlugin(void *appData, CasPluginCallback callback);
virtual ~ClearKeyCasPlugin();
virtual status_t setPrivateData(
@@ -94,7 +94,7 @@ private:
Mutex mKeyFetcherLock;
std::unique_ptr<KeyFetcher> mKeyFetcher;
CasPluginCallback mCallback;
- uint64_t mAppData;
+ void* mAppData;
};
class ClearKeyDescramblerPlugin : public DescramblerPlugin {
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp b/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp
index cb69f911ff..eaa3390d0b 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp
@@ -89,7 +89,7 @@ status_t ClearKeyFetcher::ObtainKey(const sp<ABuffer>& buffer,
// asset_id change. If it sends an EcmContainer with 2 Ecms with different
// asset_ids (old and new) then it might be best to prefetch the Emm.
if ((asset_.id() != 0) && (*asset_id != asset_.id())) {
- ALOGW("Asset_id change from %" PRIu64 " to %" PRIu64, asset_.id(), *asset_id);
+ ALOGW("Asset_id change from %llu to %" PRIu64, asset_.id(), *asset_id);
asset_.Clear();
}
diff --git a/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp b/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp
index faea00816c..4b4051d5bb 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp
@@ -95,7 +95,7 @@ void ClearKeySessionLibrary::destroySession(const CasSessionId& sessionId) {
void ClearKeySessionLibrary::destroyPlugin(CasPlugin *plugin) {
Mutex::Autolock lock(mSessionsLock);
- for (ssize_t index = mIDToSessionMap.size() - 1; index >= 0; index--) {
+ for (ssize_t index = (ssize_t)mIDToSessionMap.size() - 1; index >= 0; index--) {
sp<ClearKeyCasSession> session = mIDToSessionMap.valueAt(index);
if (session->getPlugin() == plugin) {
mIDToSessionMap.removeItemsAt(index);
diff --git a/drm/mediacas/plugins/clearkey/JsonAssetLoader.cpp b/drm/mediacas/plugins/clearkey/JsonAssetLoader.cpp
index 6e1004caa1..ee8dba3194 100644
--- a/drm/mediacas/plugins/clearkey/JsonAssetLoader.cpp
+++ b/drm/mediacas/plugins/clearkey/JsonAssetLoader.cpp
@@ -36,8 +36,6 @@ const String8 kEncryptionKeyTag("encryption_key");
const String8 kCasTypeTag("cas_type");
const String8 kBase64Padding("=");
-const uint32_t kKeyLength = 16;
-
JsonAssetLoader::JsonAssetLoader() {
}
diff --git a/drm/mediacas/plugins/clearkey/ecm_generator.cpp b/drm/mediacas/plugins/clearkey/ecm_generator.cpp
index 7d296590e4..218ce35d98 100644
--- a/drm/mediacas/plugins/clearkey/ecm_generator.cpp
+++ b/drm/mediacas/plugins/clearkey/ecm_generator.cpp
@@ -38,8 +38,6 @@ const uint32_t kContentKeyByteSize = 16;
const uint16_t kTotalEcmSize =
kEcmClearFieldsSize + kContentKeyByteSize; // clear fields + clear key
-const uint32_t kKeyLength = 16;
-
#define UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32_t *>(_p))
static uint32_t Load32(const void *p) {
diff --git a/drm/mediacas/plugins/clearkey/tests/ClearKeyFetcherTest.cpp b/drm/mediacas/plugins/clearkey/tests/ClearKeyFetcherTest.cpp
index ace086ac00..d12cfebd70 100644
--- a/drm/mediacas/plugins/clearkey/tests/ClearKeyFetcherTest.cpp
+++ b/drm/mediacas/plugins/clearkey/tests/ClearKeyFetcherTest.cpp
@@ -93,7 +93,7 @@ TEST_F(ClearKeyFetcherTest, Success) {
uint64_t asset_id;
std::vector<KeyFetcher::KeyInfo> keys;
EXPECT_EQ(OK, fetcher.ObtainKey(ecm_, &asset_id, &keys));
- EXPECT_EQ(2, keys.size());
+ EXPECT_EQ(2U, keys.size());
EXPECT_EQ(0, keys[0].key_id);
EXPECT_EQ(content_key_[0]->size(), keys[0].key_bytes->size());
EXPECT_EQ(0, memcmp(content_key_[0]->data(),
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.cpp b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
index 18cd9a4cda..8404a83935 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.cpp
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
@@ -49,8 +49,8 @@ status_t MockCasFactory::queryPlugins(
status_t MockCasFactory::createPlugin(
int32_t CA_system_id,
- uint64_t appData,
- CasPluginCallback callback,
+ void* /*appData*/,
+ CasPluginCallback /*callback*/,
CasPlugin **plugin) {
if (!isSystemIdSupported(CA_system_id)) {
return BAD_VALUE;
@@ -98,7 +98,7 @@ MockCasPlugin::~MockCasPlugin() {
MockSessionLibrary::get()->destroyPlugin(this);
}
-status_t MockCasPlugin::setPrivateData(const CasData &data) {
+status_t MockCasPlugin::setPrivateData(const CasData& /*data*/) {
ALOGV("setPrivateData");
return OK;
}
@@ -123,7 +123,7 @@ status_t MockCasPlugin::closeSession(const CasSessionId &sessionId) {
}
status_t MockCasPlugin::setSessionPrivateData(
- const CasSessionId &sessionId, const CasData &data) {
+ const CasSessionId &sessionId, const CasData& /*data*/) {
ALOGV("setSessionPrivateData: sessionId=%s",
arrayToString(sessionId).string());
Mutex::Autolock lock(mLock);
@@ -146,7 +146,7 @@ status_t MockCasPlugin::processEcm(
if (session == NULL) {
return BAD_VALUE;
}
- ALOGV("ECM: size=%d", ecm.size());
+ ALOGV("ECM: size=%zu", ecm.size());
ALOGV("ECM: data=%s", arrayToString(ecm).string());
return OK;
@@ -156,14 +156,14 @@ status_t MockCasPlugin::processEmm(const CasEmm& emm) {
ALOGV("processEmm");
Mutex::Autolock lock(mLock);
- ALOGV("EMM: size=%d", emm.size());
+ ALOGV("EMM: size=%zu", emm.size());
ALOGV("EMM: data=%s", arrayToString(emm).string());
return OK;
}
status_t MockCasPlugin::sendEvent(
- int32_t event, int arg, const CasData &eventData) {
+ int32_t event, int /*arg*/, const CasData& /*eventData*/) {
ALOGV("sendEvent: event=%d", event);
Mutex::Autolock lock(mLock);
@@ -178,7 +178,7 @@ status_t MockCasPlugin::provision(const String8 &str) {
}
status_t MockCasPlugin::refreshEntitlements(
- int32_t refreshType, const CasData &refreshData) {
+ int32_t /*refreshType*/, const CasData &refreshData) {
ALOGV("refreshEntitlements: refreshData=%s", arrayToString(refreshData).string());
Mutex::Autolock lock(mLock);
@@ -216,7 +216,7 @@ ssize_t MockDescramblerPlugin::descramble(
int32_t srcOffset,
void *dstPtr,
int32_t dstOffset,
- AString *errorDetailMsg) {
+ AString* /*errorDetailMsg*/) {
ALOGV("MockDescramblerPlugin::descramble(secure=%d, sctrl=%d,"
"subSamples=%s, srcPtr=%p, dstPtr=%p, srcOffset=%d, dstOffset=%d)",
(int)secure, (int)scramblingControl,
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.h b/drm/mediacas/plugins/mock/MockCasPlugin.h
index 9632492e99..81069906ed 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.h
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.h
@@ -39,7 +39,7 @@ public:
std::vector<CasPluginDescriptor> *descriptors) const override;
virtual status_t createPlugin(
int32_t CA_system_id,
- uint64_t appData,
+ void *appData,
CasPluginCallback callback,
CasPlugin **plugin) override;
};
diff --git a/drm/mediadrm/plugins/clearkey/common/Android.bp b/drm/mediadrm/plugins/clearkey/common/Android.bp
new file mode 100644
index 0000000000..2c674e1f29
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+ name: "libclearkeycommon",
+ vendor: true,
+
+ srcs: [
+ "ClearKeyUUID.cpp",
+ "Utils.cpp",
+ ],
+
+ cflags: ["-Wall", "-Werror"],
+
+ include_dirs: ["frameworks/av/include"],
+
+ shared_libs: ["libutils"],
+
+ export_include_dirs: ["include"],
+
+ sanitize: {
+ integer_overflow: true,
+ },
+}
+
diff --git a/drm/mediadrm/plugins/clearkey/ClearKeyUUID.cpp b/drm/mediadrm/plugins/clearkey/common/ClearKeyUUID.cpp
index 0259a42a15..0259a42a15 100644
--- a/drm/mediadrm/plugins/clearkey/ClearKeyUUID.cpp
+++ b/drm/mediadrm/plugins/clearkey/common/ClearKeyUUID.cpp
diff --git a/drm/mediadrm/plugins/clearkey/Utils.cpp b/drm/mediadrm/plugins/clearkey/common/Utils.cpp
index 93c643b636..93c643b636 100644
--- a/drm/mediadrm/plugins/clearkey/Utils.cpp
+++ b/drm/mediadrm/plugins/clearkey/common/Utils.cpp
diff --git a/drm/mediadrm/plugins/clearkey/ClearKeyUUID.h b/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h
index ac99418619..ac99418619 100644
--- a/drm/mediadrm/plugins/clearkey/ClearKeyUUID.h
+++ b/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h
diff --git a/drm/mediadrm/plugins/clearkey/MimeType.h b/drm/mediadrm/plugins/clearkey/common/include/MimeType.h
index 085f17a3e8..085f17a3e8 100644
--- a/drm/mediadrm/plugins/clearkey/MimeType.h
+++ b/drm/mediadrm/plugins/clearkey/common/include/MimeType.h
diff --git a/drm/mediadrm/plugins/clearkey/Utils.h b/drm/mediadrm/plugins/clearkey/common/include/Utils.h
index 25431247e0..25431247e0 100644
--- a/drm/mediadrm/plugins/clearkey/Utils.h
+++ b/drm/mediadrm/plugins/clearkey/common/include/Utils.h
diff --git a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp b/drm/mediadrm/plugins/clearkey/default/AesCtrDecryptor.cpp
index f7106b275e..f7106b275e 100644
--- a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/AesCtrDecryptor.cpp
diff --git a/drm/mediadrm/plugins/clearkey/Android.bp b/drm/mediadrm/plugins/clearkey/default/Android.bp
index 2973fcff54..7ba57088cc 100644
--- a/drm/mediadrm/plugins/clearkey/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/default/Android.bp
@@ -16,10 +16,10 @@
cc_library_shared {
name: "libdrmclearkeyplugin",
+ vendor: true,
srcs: [
"AesCtrDecryptor.cpp",
- "ClearKeyUUID.cpp",
"CreatePluginFactories.cpp",
"CryptoFactory.cpp",
"CryptoPlugin.cpp",
@@ -29,12 +29,12 @@ cc_library_shared {
"JsonWebKey.cpp",
"Session.cpp",
"SessionLibrary.cpp",
- "Utils.cpp",
],
- vendor: true,
relative_install_path: "mediadrm",
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: [
"libcrypto",
"liblog",
@@ -42,15 +42,23 @@ cc_library_shared {
"libutils",
],
- static_libs: ["libjsmn"],
+ static_libs: [
+ "libclearkeycommon",
+ "libjsmn"
+ ],
+
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+ export_static_lib_headers: ["libjsmn"],
include_dirs: [
"frameworks/native/include",
"frameworks/av/include",
],
- export_include_dirs: ["."],
- export_static_lib_headers: ["libjsmn"],
+ sanitize: {
+ integer_overflow: true,
+ },
}
//########################################################################
diff --git a/drm/mediadrm/plugins/clearkey/CreatePluginFactories.cpp b/drm/mediadrm/plugins/clearkey/default/CreatePluginFactories.cpp
index ec1420e723..ec1420e723 100644
--- a/drm/mediadrm/plugins/clearkey/CreatePluginFactories.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/CreatePluginFactories.cpp
diff --git a/drm/mediadrm/plugins/clearkey/CryptoFactory.cpp b/drm/mediadrm/plugins/clearkey/default/CryptoFactory.cpp
index eeb64c3d34..f15f92b12e 100644
--- a/drm/mediadrm/plugins/clearkey/CryptoFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/CryptoFactory.cpp
@@ -15,7 +15,7 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "ClearKeyCryptoPlugin"
+#define LOG_TAG "ClearKeyCryptoFactory"
#include <utils/Log.h>
#include <utils/Errors.h>
diff --git a/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/default/CryptoPlugin.cpp
index ee97976387..ee97976387 100644
--- a/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/CryptoPlugin.cpp
diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/default/DrmFactory.cpp
index c83321b2e6..8301e40757 100644
--- a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/DrmFactory.cpp
@@ -15,7 +15,7 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "ClearKeyCryptoPlugin"
+#define LOG_TAG "ClearKeyDrmFactory"
#include <utils/Log.h>
#include <utils/Errors.h>
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/default/DrmPlugin.cpp
index ec07d87b1c..1b8b8c1e65 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/DrmPlugin.cpp
@@ -15,14 +15,14 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "ClearKeyCryptoPlugin"
+#define LOG_TAG "ClearKeyDrmPlugin"
#include <utils/Log.h>
#include <media/stagefright/MediaErrors.h>
#include <utils/StrongPointer.h>
#include "DrmPlugin.h"
-
+#include "ClearKeyDrmProperties.h"
#include "Session.h"
namespace {
@@ -44,7 +44,22 @@ using android::sp;
DrmPlugin::DrmPlugin(SessionLibrary* sessionLibrary)
: mSessionLibrary(sessionLibrary) {
+
mPlayPolicy.clear();
+ initProperties();
+}
+
+void DrmPlugin::initProperties() {
+ mStringProperties.clear();
+ mStringProperties.add(kVendorKey, kVendorValue);
+ mStringProperties.add(kVersionKey, kVersionValue);
+ mStringProperties.add(kPluginDescriptionKey, kPluginDescriptionValue);
+ mStringProperties.add(kAlgorithmsKey, kAlgorithmsValue);
+ mStringProperties.add(kListenerTestSupportKey, kListenerTestSupportValue);
+
+ Vector<uint8_t> testDeviceId;
+ testDeviceId.appendArray(kTestDeviceIdData, sizeof(kTestDeviceIdData) / sizeof(uint8_t));
+ mByteArrayProperties.add(kDeviceIdKey, testDeviceId);
}
status_t DrmPlugin::openSession(Vector<uint8_t>& sessionId) {
@@ -122,22 +137,63 @@ status_t DrmPlugin::provideKeyResponse(
return res;
}
+status_t DrmPlugin::getPropertyByteArray(
+ const String8& name, Vector<uint8_t>& value) const {
+ ssize_t index = mByteArrayProperties.indexOfKey(name);
+ if (index < 0) {
+ ALOGE("App requested unknown property: %s", name.string());
+ return android::ERROR_DRM_CANNOT_HANDLE;
+ }
+ value = mByteArrayProperties.valueAt(index);
+ return android::OK;
+}
+
+status_t DrmPlugin::setPropertyByteArray(
+ const String8& name, const Vector<uint8_t>& value)
+{
+ UNUSED(value);
+ if (0 == name.compare(kDeviceIdKey)) {
+ ALOGD("Cannot set immutable property: %s", name.string());
+ return android::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ // Setting of undefined properties is not supported
+ ALOGE("Failed to set property byte array, key=%s", name.string());
+ return android::ERROR_DRM_CANNOT_HANDLE;
+}
+
status_t DrmPlugin::getPropertyString(
const String8& name, String8& value) const {
- if (name == "vendor") {
- value = "Google";
- } else if (name == "version") {
- value = "1.0";
- } else if (name == "description") {
- value = "ClearKey CDM";
- } else if (name == "algorithms") {
- value = "";
- } else if (name == "listenerTestSupport") {
- value = "true";
- } else {
- ALOGE("App requested unknown string property %s", name.string());
+ ssize_t index = mStringProperties.indexOfKey(name);
+ if (index < 0) {
+ ALOGE("App requested unknown property: %s", name.string());
+ return android::ERROR_DRM_CANNOT_HANDLE;
+ }
+ value = mStringProperties.valueAt(index);
+ return android::OK;
+}
+
+status_t DrmPlugin::setPropertyString(
+ const String8& name, const String8& value) {
+ String8 immutableKeys;
+ immutableKeys.appendFormat("%s,%s,%s,%s",
+ kAlgorithmsKey.string(), kPluginDescriptionKey.string(),
+ kVendorKey.string(), kVersionKey.string());
+ if (immutableKeys.contains(name.string())) {
+ ALOGD("Cannot set immutable property: %s", name.string());
+ return android::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ ssize_t index = mStringProperties.indexOfKey(name);
+ if (index < 0) {
+ ALOGE("Cannot set undefined property string, key=%s", name.string());
return android::ERROR_DRM_CANNOT_HANDLE;
}
+
+ if (mStringProperties.add(name, value) < 0) {
+ ALOGE("Failed to set property string, key=%s", name.string());
+ return android::ERROR_DRM_UNKNOWN;
+ }
return android::OK;
}
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp
index caff3939be..caff3939be 100644
--- a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp
diff --git a/drm/mediadrm/plugins/clearkey/JsonWebKey.cpp b/drm/mediadrm/plugins/clearkey/default/JsonWebKey.cpp
index 53ffae4ccd..53ffae4ccd 100644
--- a/drm/mediadrm/plugins/clearkey/JsonWebKey.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/JsonWebKey.cpp
diff --git a/drm/mediadrm/plugins/clearkey/Session.cpp b/drm/mediadrm/plugins/clearkey/default/Session.cpp
index d210f5e610..b3ceaeca51 100644
--- a/drm/mediadrm/plugins/clearkey/Session.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/Session.cpp
@@ -15,7 +15,7 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "ClearKeyCryptoPlugin"
+#define LOG_TAG "ClearKeySession"
#include <utils/Log.h>
#include <media/stagefright/MediaErrors.h>
diff --git a/drm/mediadrm/plugins/clearkey/SessionLibrary.cpp b/drm/mediadrm/plugins/clearkey/default/SessionLibrary.cpp
index 0419f9776a..529230ea74 100644
--- a/drm/mediadrm/plugins/clearkey/SessionLibrary.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/SessionLibrary.cpp
@@ -15,7 +15,7 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "ClearKeyCryptoPlugin"
+#define LOG_TAG "ClearKeySessionLibrary"
#include <utils/Log.h>
#include <utils/String8.h>
diff --git a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h b/drm/mediadrm/plugins/clearkey/default/include/AesCtrDecryptor.h
index edb84458a7..edb84458a7 100644
--- a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
+++ b/drm/mediadrm/plugins/clearkey/default/include/AesCtrDecryptor.h
diff --git a/drm/mediadrm/plugins/clearkey/default/include/ClearKeyDrmProperties.h b/drm/mediadrm/plugins/clearkey/default/include/ClearKeyDrmProperties.h
new file mode 100644
index 0000000000..a99e17447e
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/default/include/ClearKeyDrmProperties.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEARKEY_DRM_PROPERTIES_H_
+#define CLEARKEY_DRM_PROPERTIES_H_
+
+#include <utils/String8.h>
+
+namespace clearkeydrm {
+
+static const android::String8 kVendorKey("vendor");
+static const android::String8 kVendorValue("Google");
+static const android::String8 kVersionKey("version");
+static const android::String8 kVersionValue("1.0");
+static const android::String8 kPluginDescriptionKey("description");
+static const android::String8 kPluginDescriptionValue("ClearKey CDM");
+static const android::String8 kAlgorithmsKey("algorithms");
+static const android::String8 kAlgorithmsValue("");
+static const android::String8 kListenerTestSupportKey("listenerTestSupport");
+static const android::String8 kListenerTestSupportValue("true");
+
+static const android::String8 kDeviceIdKey("deviceId");
+static const uint8_t kTestDeviceIdData[] =
+ {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+} // namespace clearkeydrm
+
+#endif // CLEARKEY_DRM_PROPERTIES_H_
diff --git a/drm/mediadrm/plugins/clearkey/ClearKeyTypes.h b/drm/mediadrm/plugins/clearkey/default/include/ClearKeyTypes.h
index a28959ae5a..a28959ae5a 100644
--- a/drm/mediadrm/plugins/clearkey/ClearKeyTypes.h
+++ b/drm/mediadrm/plugins/clearkey/default/include/ClearKeyTypes.h
diff --git a/drm/mediadrm/plugins/clearkey/CreatePluginFactories.h b/drm/mediadrm/plugins/clearkey/default/include/CreatePluginFactories.h
index d9acec1ad6..d9acec1ad6 100644
--- a/drm/mediadrm/plugins/clearkey/CreatePluginFactories.h
+++ b/drm/mediadrm/plugins/clearkey/default/include/CreatePluginFactories.h
diff --git a/drm/mediadrm/plugins/clearkey/CryptoFactory.h b/drm/mediadrm/plugins/clearkey/default/include/CryptoFactory.h
index 568bc4b0e4..568bc4b0e4 100644
--- a/drm/mediadrm/plugins/clearkey/CryptoFactory.h
+++ b/drm/mediadrm/plugins/clearkey/default/include/CryptoFactory.h
diff --git a/drm/mediadrm/plugins/clearkey/CryptoPlugin.h b/drm/mediadrm/plugins/clearkey/default/include/CryptoPlugin.h
index a6d2f7be71..a6d2f7be71 100644
--- a/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/default/include/CryptoPlugin.h
diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.h b/drm/mediadrm/plugins/clearkey/default/include/DrmFactory.h
index 0bc0843929..0bc0843929 100644
--- a/drm/mediadrm/plugins/clearkey/DrmFactory.h
+++ b/drm/mediadrm/plugins/clearkey/default/include/DrmFactory.h
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/default/include/DrmPlugin.h
index f37a70699a..4fa42e50af 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/default/include/DrmPlugin.h
@@ -133,30 +133,47 @@ public:
return android::ERROR_DRM_CANNOT_HANDLE;
}
- virtual status_t getPropertyString(
- const String8& name, String8& value) const;
+ virtual status_t getHdcpLevels(HdcpLevel *connectedLevel,
+ HdcpLevel *maxLevel) const {
+ UNUSED(connectedLevel);
+ UNUSED(maxLevel);
+ return android::ERROR_DRM_CANNOT_HANDLE;
+ }
- virtual status_t getPropertyByteArray(
- const String8& name, Vector<uint8_t>& value) const {
- UNUSED(name);
- UNUSED(value);
+
+ virtual status_t getNumberOfSessions(uint32_t *currentSessions,
+ uint32_t *maxSessions) const {
+ UNUSED(currentSessions);
+ UNUSED(maxSessions);
return android::ERROR_DRM_CANNOT_HANDLE;
}
- virtual status_t setPropertyString(
- const String8& name, const String8& value) {
- UNUSED(name);
- UNUSED(value);
+ virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
+ SecurityLevel *level) const {
+ UNUSED(sessionId);
+ UNUSED(level);
return android::ERROR_DRM_CANNOT_HANDLE;
}
- virtual status_t setPropertyByteArray(
- const String8& name, const Vector<uint8_t>& value) {
- UNUSED(name);
- UNUSED(value);
+ virtual status_t setSecurityLevel(Vector<uint8_t> const &sessionId,
+ const SecurityLevel& level) {
+ UNUSED(sessionId);
+ UNUSED(level);
return android::ERROR_DRM_CANNOT_HANDLE;
}
+ virtual status_t getPropertyString(
+ const String8& name, String8& value) const;
+
+ virtual status_t getPropertyByteArray(
+ const String8& name, Vector<uint8_t>& value) const;
+
+ virtual status_t setPropertyString(
+ const String8& name, const String8& value);
+
+ virtual status_t setPropertyByteArray(
+ const String8& name, const Vector<uint8_t>& value);
+
virtual status_t setCipherAlgorithm(
const Vector<uint8_t>& sessionId, const String8& algorithm) {
if (sessionId.size() == 0 || algorithm.size() == 0) {
@@ -242,9 +259,13 @@ public:
}
private:
+ void initProperties();
void setPlayPolicy();
- android::KeyedVector<android::String8, android::String8> mPlayPolicy;
+ android::KeyedVector<String8, String8> mPlayPolicy;
+ android::KeyedVector<String8, String8> mStringProperties;
+ android::KeyedVector<String8, Vector<uint8_t>> mByteArrayProperties;
+
SessionLibrary* mSessionLibrary;
DISALLOW_EVIL_CONSTRUCTORS(DrmPlugin);
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.h b/drm/mediadrm/plugins/clearkey/default/include/InitDataParser.h
index a9707bfdbc..a9707bfdbc 100644
--- a/drm/mediadrm/plugins/clearkey/InitDataParser.h
+++ b/drm/mediadrm/plugins/clearkey/default/include/InitDataParser.h
diff --git a/drm/mediadrm/plugins/clearkey/JsonWebKey.h b/drm/mediadrm/plugins/clearkey/default/include/JsonWebKey.h
index 6ae50eecfe..6ae50eecfe 100644
--- a/drm/mediadrm/plugins/clearkey/JsonWebKey.h
+++ b/drm/mediadrm/plugins/clearkey/default/include/JsonWebKey.h
diff --git a/drm/mediadrm/plugins/clearkey/Session.h b/drm/mediadrm/plugins/clearkey/default/include/Session.h
index 09335069df..09335069df 100644
--- a/drm/mediadrm/plugins/clearkey/Session.h
+++ b/drm/mediadrm/plugins/clearkey/default/include/Session.h
diff --git a/drm/mediadrm/plugins/clearkey/SessionLibrary.h b/drm/mediadrm/plugins/clearkey/default/include/SessionLibrary.h
index 6236fff47c..6236fff47c 100644
--- a/drm/mediadrm/plugins/clearkey/SessionLibrary.h
+++ b/drm/mediadrm/plugins/clearkey/default/include/SessionLibrary.h
diff --git a/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp b/drm/mediadrm/plugins/clearkey/default/tests/AesCtrDecryptorUnittest.cpp
index 5db8290a91..5db8290a91 100644
--- a/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/tests/AesCtrDecryptorUnittest.cpp
diff --git a/drm/mediadrm/plugins/clearkey/tests/Android.bp b/drm/mediadrm/plugins/clearkey/default/tests/Android.bp
index 0fcfc6436b..4419865705 100644
--- a/drm/mediadrm/plugins/clearkey/tests/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/default/tests/Android.bp
@@ -21,12 +21,16 @@ cc_test {
name: "ClearKeyDrmUnitTest",
vendor: true,
+ cflags: ["-Wall", "-Werror"],
+
srcs: [
"AesCtrDecryptorUnittest.cpp",
"InitDataParserUnittest.cpp",
"JsonWebKeyUnittest.cpp",
],
+ static_libs: ["libclearkeycommon"],
+
shared_libs: [
"libcrypto",
"libdrmclearkeyplugin",
diff --git a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp b/drm/mediadrm/plugins/clearkey/default/tests/InitDataParserUnittest.cpp
index 8c496566cc..8c496566cc 100644
--- a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/tests/InitDataParserUnittest.cpp
diff --git a/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp b/drm/mediadrm/plugins/clearkey/default/tests/JsonWebKeyUnittest.cpp
index d9f3ea6703..d9f3ea6703 100644
--- a/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/tests/JsonWebKeyUnittest.cpp
diff --git a/drm/mediadrm/plugins/clearkey/hidl/AesCtrDecryptor.cpp b/drm/mediadrm/plugins/clearkey/hidl/AesCtrDecryptor.cpp
new file mode 100644
index 0000000000..2fce07902e
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/AesCtrDecryptor.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "hidl_ClearkeyDecryptor"
+#include <utils/Log.h>
+
+#include <openssl/aes.h>
+
+#include "AesCtrDecryptor.h"
+#include "ClearKeyTypes.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::hardware::drm::V1_0::SubSample;
+using ::android::hardware::drm::V1_0::Status;
+
+static const size_t kBlockBitCount = kBlockSize * 8;
+
+Status AesCtrDecryptor::decrypt(
+ const std::vector<uint8_t>& key,
+ const Iv iv, const uint8_t* source,
+ uint8_t* destination,
+ const std::vector<SubSample> subSamples,
+ size_t numSubSamples,
+ size_t* bytesDecryptedOut) {
+ uint32_t blockOffset = 0;
+ uint8_t previousEncryptedCounter[kBlockSize];
+ memset(previousEncryptedCounter, 0, kBlockSize);
+
+ if (key.size() != kBlockSize || (sizeof(Iv) / sizeof(uint8_t)) != kBlockSize) {
+ android_errorWriteLog(0x534e4554, "63982768");
+ return Status::ERROR_DRM_DECRYPT;
+ }
+
+ size_t offset = 0;
+ AES_KEY opensslKey;
+ AES_set_encrypt_key(key.data(), kBlockBitCount, &opensslKey);
+ Iv opensslIv;
+ memcpy(opensslIv, iv, sizeof(opensslIv));
+
+ for (size_t i = 0; i < numSubSamples; ++i) {
+ const SubSample& subSample = subSamples[i];
+
+ if (subSample.numBytesOfClearData > 0) {
+ memcpy(destination + offset, source + offset,
+ subSample.numBytesOfClearData);
+ offset += subSample.numBytesOfClearData;
+ }
+
+ if (subSample.numBytesOfEncryptedData > 0) {
+ AES_ctr128_encrypt(source + offset, destination + offset,
+ subSample.numBytesOfEncryptedData, &opensslKey,
+ opensslIv, previousEncryptedCounter,
+ &blockOffset);
+ offset += subSample.numBytesOfEncryptedData;
+ }
+ }
+
+ *bytesDecryptedOut = offset;
+ return Status::OK;
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Android.bp b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
new file mode 100644
index 0000000000..341d4f645d
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
@@ -0,0 +1,68 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+ name: "android.hardware.drm@1.1-service.clearkey",
+ vendor: true,
+
+ srcs: [
+ "AesCtrDecryptor.cpp",
+ "Base64.cpp",
+ "Buffer.cpp",
+ "CreatePluginFactories.cpp",
+ "CryptoFactory.cpp",
+ "CryptoPlugin.cpp",
+ "DrmFactory.cpp",
+ "DrmPlugin.cpp",
+ "InitDataParser.cpp",
+ "JsonWebKey.cpp",
+ "Session.cpp",
+ "SessionLibrary.cpp",
+ "service.cpp",
+ ],
+
+ relative_install_path: "hw",
+
+ cflags: ["-Wall", "-Werror"],
+ init_rc: ["android.hardware.drm@1.1-service.clearkey.rc"],
+
+ shared_libs: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "libbase",
+ "libbinder",
+ "libcrypto",
+ "libhidlbase",
+ "libhidlmemory",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libclearkeycommon",
+ "libjsmn",
+ ],
+
+ local_include_dirs: ["include"],
+
+ export_static_lib_headers: ["libjsmn"],
+
+ sanitize: {
+ integer_overflow: true,
+ },
+}
+
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Base64.cpp b/drm/mediadrm/plugins/clearkey/hidl/Base64.cpp
new file mode 100644
index 0000000000..c2ed7513f4
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/Base64.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Base64.h"
+
+#include <string>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+sp<Buffer> decodeBase64(const std::string &s) {
+ size_t n = s.size();
+
+ if ((n % 4) != 0) {
+ return nullptr;
+ }
+
+ size_t padding = 0;
+ if (n >= 1 && s.c_str()[n - 1] == '=') {
+ padding = 1;
+
+ if (n >= 2 && s.c_str()[n - 2] == '=') {
+ padding = 2;
+
+ if (n >= 3 && s.c_str()[n - 3] == '=') {
+ padding = 3;
+ }
+ }
+ }
+
+ // We divide first to avoid overflow. It's OK to do this because we
+ // already made sure that n % 4 == 0.
+ size_t outLen = (n / 4) * 3 - padding;
+
+ sp<Buffer> buffer = new Buffer(outLen);
+ uint8_t *out = buffer->data();
+ if (out == nullptr || buffer->size() < outLen) {
+ return nullptr;
+ }
+
+ size_t j = 0;
+ uint32_t accum = 0;
+ for (size_t i = 0; i < n; ++i) {
+ char c = s.c_str()[i];
+ unsigned value;
+ if (c >= 'A' && c <= 'Z') {
+ value = c - 'A';
+ } else if (c >= 'a' && c <= 'z') {
+ value = 26 + c - 'a';
+ } else if (c >= '0' && c <= '9') {
+ value = 52 + c - '0';
+ } else if (c == '+' || c == '-') {
+ value = 62;
+ } else if (c == '/' || c == '_') {
+ value = 63;
+ } else if (c != '=') {
+ return nullptr;
+ } else {
+ if (i < n - padding) {
+ return nullptr;
+ }
+
+ value = 0;
+ }
+
+ accum = (accum << 6) | value;
+
+ if (((i + 1) % 4) == 0) {
+ if (j < outLen) { out[j++] = (accum >> 16); }
+ if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
+ if (j < outLen) { out[j++] = accum & 0xff; }
+
+ accum = 0;
+ }
+ }
+
+ return buffer;
+}
+
+static char encode6Bit(unsigned x) {
+ if (x <= 25) {
+ return 'A' + x;
+ } else if (x <= 51) {
+ return 'a' + x - 26;
+ } else if (x <= 61) {
+ return '0' + x - 52;
+ } else if (x == 62) {
+ return '+';
+ } else {
+ return '/';
+ }
+}
+
+void encodeBase64(const void *_data, size_t size, std::string *out) {
+ out->clear();
+
+ const uint8_t *data = (const uint8_t *)_data;
+
+ size_t i;
+ for (i = 0; i < (size / 3) * 3; i += 3) {
+ uint8_t x1 = data[i];
+ uint8_t x2 = data[i + 1];
+ uint8_t x3 = data[i + 2];
+
+ out->push_back(encode6Bit(x1 >> 2));
+ out->push_back(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
+ out->push_back(encode6Bit((x2 << 2 | x3 >> 6) & 0x3f));
+ out->push_back(encode6Bit(x3 & 0x3f));
+ }
+ switch (size % 3) {
+ case 0:
+ break;
+ case 2:
+ {
+ uint8_t x1 = data[i];
+ uint8_t x2 = data[i + 1];
+ out->push_back(encode6Bit(x1 >> 2));
+ out->push_back(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
+ out->push_back(encode6Bit((x2 << 2) & 0x3f));
+ out->push_back('=');
+ break;
+ }
+ default:
+ {
+ uint8_t x1 = data[i];
+ out->push_back(encode6Bit(x1 >> 2));
+ out->push_back(encode6Bit((x1 << 4) & 0x3f));
+ out->append("==");
+ break;
+ }
+ }
+}
+
+void encodeBase64Url(const void *_data, size_t size, std::string *out) {
+ encodeBase64(_data, size, out);
+
+ if ((std::string::npos != out->find("+")) ||
+ (std::string::npos != out->find("/"))) {
+ size_t outLen = out->size();
+ char *base64url = new char[outLen];
+ for (size_t i = 0; i < outLen; ++i) {
+ if (out->c_str()[i] == '+')
+ base64url[i] = '-';
+ else if (out->c_str()[i] == '/')
+ base64url[i] = '_';
+ else
+ base64url[i] = out->c_str()[i];
+ }
+
+ out->assign(base64url, outLen);
+ delete[] base64url;
+ }
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Buffer.cpp b/drm/mediadrm/plugins/clearkey/hidl/Buffer.cpp
new file mode 100644
index 0000000000..e58f58a379
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/Buffer.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Buffer.h"
+
+#include <android/hardware/drm/1.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+Buffer::Buffer(size_t capacity)
+ : mRangeOffset(0),
+ mOwnsData(true) {
+ mData = malloc(capacity);
+ if (mData == nullptr) {
+ mCapacity = 0;
+ mRangeLength = 0;
+ } else {
+ mCapacity = capacity;
+ mRangeLength = capacity;
+ }
+}
+
+Buffer::~Buffer() {
+ if (mOwnsData) {
+ if (mData != nullptr) {
+ free(mData);
+ mData = nullptr;
+ }
+ }
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CreatePluginFactories.cpp b/drm/mediadrm/plugins/clearkey/hidl/CreatePluginFactories.cpp
new file mode 100644
index 0000000000..1ba5c6a9ec
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/CreatePluginFactories.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CreatePluginFactories.h"
+
+#include "CryptoFactory.h"
+#include "DrmFactory.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+extern "C" {
+
+IDrmFactory* createDrmFactory() {
+ return new DrmFactory();
+}
+
+ICryptoFactory* createCryptoFactory() {
+ return new CryptoFactory();
+}
+
+} // extern "C"
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CryptoFactory.cpp b/drm/mediadrm/plugins/clearkey/hidl/CryptoFactory.cpp
new file mode 100644
index 0000000000..0848cef1f2
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/CryptoFactory.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "hidl_ClearKeyCryptoFactory"
+#include <utils/Log.h>
+
+#include "CryptoFactory.h"
+
+#include "ClearKeyUUID.h"
+#include "CryptoPlugin.h"
+#include "TypeConvert.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+Return<bool> CryptoFactory::isCryptoSchemeSupported(
+ const hidl_array<uint8_t, 16> &uuid)
+{
+ return clearkeydrm::isClearKeyUUID(uuid.data());
+}
+
+Return<void> CryptoFactory::createPlugin(
+ const hidl_array<uint8_t, 16> &uuid,
+ const hidl_vec<uint8_t> &initData,
+ createPlugin_cb _hidl_cb) {
+
+ if (!isCryptoSchemeSupported(uuid.data())) {
+ ALOGE("Clearkey Drm HAL: failed to create clearkey plugin, " \
+ "invalid crypto scheme");
+ _hidl_cb(Status::BAD_VALUE, nullptr);
+ return Void();
+ }
+
+ CryptoPlugin *cryptoPlugin = new CryptoPlugin(initData);
+ Status status = cryptoPlugin->getInitStatus();
+ if (status == Status::OK) {
+ _hidl_cb(Status::OK, cryptoPlugin);
+ } else {
+ delete cryptoPlugin;
+ _hidl_cb(status, nullptr);
+ }
+ return Void();
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
new file mode 100644
index 0000000000..f33f94e711
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "hidl_ClearKeyCryptoPlugin"
+#include <utils/Log.h>
+
+#include "CryptoPlugin.h"
+#include "SessionLibrary.h"
+#include "TypeConvert.h"
+
+#include <hidlmemory/mapping.h>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::hardware::drm::V1_0::BufferType;
+
+Return<void> CryptoPlugin::setSharedBufferBase(
+ const hidl_memory& base, uint32_t bufferId) {
+ sp<IMemory> hidlMemory = mapMemory(base);
+ ALOGE_IF(hidlMemory == nullptr, "mapMemory returns nullptr");
+
+ // allow mapMemory to return nullptr
+ mSharedBufferMap[bufferId] = hidlMemory;
+ 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(
+ 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_cb _hidl_cb) {
+ UNUSED(pattern);
+
+ if (secure) {
+ _hidl_cb(Status::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,
+ "source decrypt buffer base not set");
+ return Void();
+ }
+
+ 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,
+ "destination decrypt buffer base not set");
+ return Void();
+ }
+ }
+
+ sp<IMemory> sourceBase = mSharedBufferMap[source.bufferId];
+ if (sourceBase == nullptr) {
+ _hidl_cb(Status::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");
+ return Void();
+ }
+
+ uint8_t *base = static_cast<uint8_t *>
+ (static_cast<void *>(sourceBase->getPointer()));
+ uint8_t* srcPtr = static_cast<uint8_t *>(base + source.offset + offset);
+ void* destPtr = NULL;
+ if (destination.type == BufferType::SHARED_MEMORY) {
+ 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");
+ return Void();
+ }
+
+ if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
+ return Void();
+ }
+ destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
+ } else if (destination.type == BufferType::NATIVE_HANDLE) {
+ native_handle_t *handle = const_cast<native_handle_t *>(
+ destination.secureMemory.getNativeHandle());
+ destPtr = static_cast<void *>(handle);
+ }
+
+ // Calculate the output buffer size and determine if any subsamples are
+ // encrypted.
+ size_t destSize = 0;
+ bool haveEncryptedSubsamples = false;
+ for (size_t i = 0; i < subSamples.size(); i++) {
+ const SubSample &subSample = subSamples[i];
+ destSize += subSample.numBytesOfClearData;
+ destSize += subSample.numBytesOfEncryptedData;
+ if (subSample.numBytesOfEncryptedData > 0) {
+ haveEncryptedSubsamples = true;
+ }
+ }
+
+ if (mode == Mode::UNENCRYPTED) {
+ if (haveEncryptedSubsamples) {
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
+ "Encrypted subsamples found in allegedly unencrypted data.");
+ return Void();
+ }
+
+ size_t offset = 0;
+ for (size_t i = 0; i < subSamples.size(); ++i) {
+ const SubSample& subSample = subSamples[i];
+ if (subSample.numBytesOfClearData != 0) {
+ memcpy(reinterpret_cast<uint8_t*>(destPtr) + offset,
+ reinterpret_cast<const uint8_t*>(srcPtr) + offset,
+ subSample.numBytesOfClearData);
+ offset += subSample.numBytesOfClearData;
+ }
+ }
+
+ _hidl_cb(Status::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,
+ static_cast<uint8_t*>(destPtr), toVector(subSamples), &bytesDecrypted);
+ if (res == Status::OK) {
+ _hidl_cb(Status::OK, static_cast<ssize_t>(bytesDecrypted), "");
+ return Void();
+ } else {
+ _hidl_cb(Status::ERROR_DRM_DECRYPT, static_cast<ssize_t>(res),
+ "Decryption Error");
+ return Void();
+ }
+ } else {
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
+ "Selected encryption mode is not supported by the ClearKey DRM Plugin.");
+ return Void();
+ }
+}
+
+Return<Status> CryptoPlugin::setMediaDrmSession(
+ const hidl_vec<uint8_t>& sessionId) {
+ if (!sessionId.size()) {
+ mSession = nullptr;
+ } else {
+ mSession = SessionLibrary::get()->findSession(sessionId);
+ if (!mSession.get()) {
+ return Status::ERROR_DRM_SESSION_NOT_OPENED;
+ }
+ }
+ return Status::OK;
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
new file mode 100644
index 0000000000..77557f9da9
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "hidl_ClearKeyDrmFactory"
+#include <utils/Log.h>
+
+#include <utils/Errors.h>
+
+#include "DrmFactory.h"
+
+#include "DrmPlugin.h"
+#include "ClearKeyUUID.h"
+#include "MimeType.h"
+#include "SessionLibrary.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::hardware::drm::V1_0::Status;
+using ::android::hardware::Void;
+
+Return<bool> DrmFactory::isCryptoSchemeSupported(
+ const hidl_array<uint8_t, 16>& uuid) {
+ return clearkeydrm::isClearKeyUUID(uuid.data());
+}
+
+Return<bool> DrmFactory::isContentTypeSupported(const hidl_string &mimeType) {
+ // This should match the mimeTypes handed by InitDataParser.
+ return mimeType == kIsoBmffVideoMimeType ||
+ mimeType == kIsoBmffAudioMimeType ||
+ mimeType == kCencInitDataFormat ||
+ mimeType == kWebmVideoMimeType ||
+ mimeType == kWebmAudioMimeType ||
+ mimeType == kWebmInitDataFormat;
+}
+
+Return<void> DrmFactory::createPlugin(
+ const hidl_array<uint8_t, 16>& uuid,
+ const hidl_string& appPackageName,
+ createPlugin_cb _hidl_cb) {
+ UNUSED(appPackageName);
+
+ DrmPlugin *plugin = NULL;
+ if (!isCryptoSchemeSupported(uuid.data())) {
+ ALOGE("Clear key Drm HAL: failed to create drm plugin, " \
+ "invalid crypto scheme");
+ _hidl_cb(Status::BAD_VALUE, plugin);
+ return Void();
+ }
+
+ plugin = new DrmPlugin(SessionLibrary::get());
+ _hidl_cb(Status::OK, plugin);
+ return Void();
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
new file mode 100644
index 0000000000..d51e29dc57
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -0,0 +1,573 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "hidl_ClearKeyPlugin"
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include "DrmPlugin.h"
+#include "ClearKeyDrmProperties.h"
+#include "Session.h"
+#include "TypeConvert.h"
+
+namespace {
+const int kSecureStopIdStart = 100;
+const std::string kStreaming("Streaming");
+const std::string kOffline("Offline");
+const std::string kTrue("True");
+
+const std::string kQueryKeyLicenseType("LicenseType");
+ // Value: "Streaming" or "Offline"
+const std::string kQueryKeyPlayAllowed("PlayAllowed");
+ // Value: "True" or "False"
+const std::string kQueryKeyRenewAllowed("RenewAllowed");
+ // Value: "True" or "False"
+
+const int kSecureStopIdSize = 10;
+
+std::vector<uint8_t> uint32ToVector(uint32_t value) {
+ // 10 bytes to display max value 4294967295 + one byte null terminator
+ char buffer[kSecureStopIdSize];
+ memset(buffer, 0, kSecureStopIdSize);
+ snprintf(buffer, kSecureStopIdSize, "%" PRIu32, value);
+ return std::vector<uint8_t>(buffer, buffer + sizeof(buffer));
+}
+
+}; // unnamed namespace
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+DrmPlugin::DrmPlugin(SessionLibrary* sessionLibrary)
+ : mSessionLibrary(sessionLibrary),
+ mOpenSessionOkCount(0),
+ mCloseSessionOkCount(0),
+ mCloseSessionNotOpenedCount(0),
+ mNextSecureStopId(kSecureStopIdStart) {
+ mPlayPolicy.clear();
+ initProperties();
+ mSecureStops.clear();
+}
+
+void DrmPlugin::initProperties() {
+ mStringProperties.clear();
+ mStringProperties[kVendorKey] = kVendorValue;
+ mStringProperties[kVersionKey] = kVersionValue;
+ mStringProperties[kPluginDescriptionKey] = kPluginDescriptionValue;
+ mStringProperties[kAlgorithmsKey] = kAlgorithmsValue;
+ mStringProperties[kListenerTestSupportKey] = kListenerTestSupportValue;
+
+ std::vector<uint8_t> valueVector;
+ valueVector.clear();
+ valueVector.insert(valueVector.end(),
+ kTestDeviceIdData, kTestDeviceIdData + sizeof(kTestDeviceIdData) / sizeof(uint8_t));
+ mByteArrayProperties[kDeviceIdKey] = valueVector;
+
+ valueVector.clear();
+ valueVector.insert(valueVector.end(),
+ kMetricsData, kMetricsData + sizeof(kMetricsData) / sizeof(uint8_t));
+ mByteArrayProperties[kMetricsKey] = valueVector;
+}
+
+// The secure stop in ClearKey implementation is not installed securely.
+// This function merely creates a test environment for testing secure stops APIs.
+// The content in this secure stop is implementation dependent, the clearkey
+// secureStop does not serve as a reference implementation.
+void DrmPlugin::installSecureStop(const hidl_vec<uint8_t>& sessionId) {
+ ClearkeySecureStop clearkeySecureStop;
+ clearkeySecureStop.id = uint32ToVector(++mNextSecureStopId);
+ clearkeySecureStop.data.assign(sessionId.begin(), sessionId.end());
+
+ mSecureStops.insert(std::pair<std::vector<uint8_t>, ClearkeySecureStop>(
+ clearkeySecureStop.id, clearkeySecureStop));
+}
+
+Return<void> DrmPlugin::openSession(openSession_cb _hidl_cb) {
+ sp<Session> session = mSessionLibrary->createSession();
+ std::vector<uint8_t> sessionId = session->sessionId();
+
+ Status status = setSecurityLevel(sessionId, SecurityLevel::SW_SECURE_CRYPTO);
+ _hidl_cb(status, toHidlVec(sessionId));
+ mOpenSessionOkCount++;
+ return Void();
+}
+
+Return<void> DrmPlugin::openSession_1_1(SecurityLevel securityLevel,
+ openSession_1_1_cb _hidl_cb) {
+ sp<Session> session = mSessionLibrary->createSession();
+ std::vector<uint8_t> sessionId = session->sessionId();
+
+ Status status = setSecurityLevel(sessionId, securityLevel);
+ _hidl_cb(status, toHidlVec(sessionId));
+ mOpenSessionOkCount++;
+ return Void();
+}
+
+Return<Status> DrmPlugin::closeSession(const hidl_vec<uint8_t>& sessionId) {
+ if (sessionId.size() == 0) {
+ return Status::BAD_VALUE;
+ }
+
+ sp<Session> session = mSessionLibrary->findSession(toVector(sessionId));
+ if (session.get()) {
+ mCloseSessionOkCount++;
+ mSessionLibrary->destroySession(session);
+ return Status::OK;
+ }
+ mCloseSessionNotOpenedCount++;
+ return Status::ERROR_DRM_SESSION_NOT_OPENED;
+}
+
+Status 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,
+ std::string *defaultUrl) {
+ UNUSED(optionalParameters);
+
+ *defaultUrl = "";
+ *keyRequestType = KeyRequestType::UNKNOWN;
+ *request = std::vector<uint8_t>();
+
+ if (scope.size() == 0) {
+ return Status::BAD_VALUE;
+ }
+
+ if (keyType != KeyType::STREAMING) {
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ sp<Session> session = mSessionLibrary->findSession(toVector(scope));
+ if (!session.get()) {
+ return Status::ERROR_DRM_SESSION_NOT_OPENED;
+ }
+
+ Status status = session->getKeyRequest(initData, mimeType, request);
+ *keyRequestType = KeyRequestType::INITIAL;
+ return status;
+}
+
+Return<void> DrmPlugin::getKeyRequest(
+ const hidl_vec<uint8_t>& scope,
+ const hidl_vec<uint8_t>& initData,
+ const hidl_string& mimeType,
+ KeyType keyType,
+ const hidl_vec<KeyValue>& optionalParameters,
+ getKeyRequest_cb _hidl_cb) {
+ UNUSED(optionalParameters);
+
+ KeyRequestType keyRequestType = KeyRequestType::UNKNOWN;
+ std::string defaultUrl("");
+ std::vector<uint8_t> request;
+ Status status = getKeyRequestCommon(
+ scope, initData, mimeType, keyType, optionalParameters,
+ &request, &keyRequestType, &defaultUrl);
+
+ _hidl_cb(status, toHidlVec(request),
+ static_cast<drm::V1_0::KeyRequestType>(keyRequestType),
+ hidl_string(defaultUrl));
+ return Void();
+}
+
+Return<void> DrmPlugin::getKeyRequest_1_1(
+ 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_1_cb _hidl_cb) {
+ UNUSED(optionalParameters);
+
+ KeyRequestType keyRequestType = KeyRequestType::UNKNOWN;
+ std::string defaultUrl("");
+ std::vector<uint8_t> request;
+ Status status = getKeyRequestCommon(
+ scope, initData, mimeType, keyType, optionalParameters,
+ &request, &keyRequestType, &defaultUrl);
+
+ _hidl_cb(status, toHidlVec(request), keyRequestType, hidl_string(defaultUrl));
+ return Void();
+}
+
+void DrmPlugin::setPlayPolicy() {
+ mPlayPolicy.clear();
+
+ KeyValue policy;
+ policy.key = kQueryKeyLicenseType;
+ policy.value = kStreaming;
+ mPlayPolicy.push_back(policy);
+
+ policy.key = kQueryKeyPlayAllowed;
+ policy.value = kTrue;
+ mPlayPolicy.push_back(policy);
+
+ policy.key = kQueryKeyRenewAllowed;
+ mPlayPolicy.push_back(policy);
+}
+
+Return<void> DrmPlugin::provideKeyResponse(
+ const hidl_vec<uint8_t>& scope,
+ const hidl_vec<uint8_t>& response,
+ provideKeyResponse_cb _hidl_cb) {
+ if (scope.size() == 0 || response.size() == 0) {
+ // Returns empty keySetId
+ _hidl_cb(Status::BAD_VALUE, hidl_vec<uint8_t>());
+ return Void();
+ }
+
+ sp<Session> session = mSessionLibrary->findSession(toVector(scope));
+ if (!session.get()) {
+ _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, hidl_vec<uint8_t>());
+ return Void();
+ }
+
+ setPlayPolicy();
+ std::vector<uint8_t> keySetId;
+ Status status = session->provideKeyResponse(response);
+ if (status == Status::OK) {
+ // This is for testing AMediaDrm_setOnEventListener only.
+ sendEvent(EventType::VENDOR_DEFINED, 0, scope);
+ keySetId.clear();
+ }
+
+ installSecureStop(scope);
+
+ // Returns status and empty keySetId
+ _hidl_cb(status, toHidlVec(keySetId));
+ return Void();
+}
+
+Return<void> DrmPlugin::getPropertyString(
+ const hidl_string& propertyName, getPropertyString_cb _hidl_cb) {
+ std::string name(propertyName.c_str());
+ std::string value;
+
+ if (name == kVendorKey) {
+ value = mStringProperties[kVendorKey];
+ } else if (name == kVersionKey) {
+ value = mStringProperties[kVersionKey];
+ } else if (name == kPluginDescriptionKey) {
+ value = mStringProperties[kPluginDescriptionKey];
+ } else if (name == kAlgorithmsKey) {
+ value = mStringProperties[kAlgorithmsKey];
+ } else if (name == kListenerTestSupportKey) {
+ value = mStringProperties[kListenerTestSupportKey];
+ } else {
+ ALOGE("App requested unknown string property %s", name.c_str());
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, "");
+ return Void();
+ }
+ _hidl_cb(Status::OK, value.c_str());
+ return Void();
+}
+
+Return<void> DrmPlugin::getPropertyByteArray(
+ const hidl_string& propertyName, getPropertyByteArray_cb _hidl_cb) {
+ std::map<std::string, std::vector<uint8_t> >::iterator itr =
+ mByteArrayProperties.find(std::string(propertyName.c_str()));
+ if (itr == mByteArrayProperties.end()) {
+ ALOGE("App requested unknown property: %s", propertyName.c_str());
+ _hidl_cb(Status::BAD_VALUE, std::vector<uint8_t>());
+ return Void();
+ }
+ _hidl_cb(Status::OK, itr->second);
+ return Void();
+
+}
+
+Return<Status> DrmPlugin::setPropertyString(
+ const hidl_string& name, const hidl_string& value) {
+ std::string immutableKeys;
+ immutableKeys.append(kAlgorithmsKey + ",");
+ immutableKeys.append(kPluginDescriptionKey + ",");
+ immutableKeys.append(kVendorKey + ",");
+ immutableKeys.append(kVersionKey + ",");
+
+ std::string key = std::string(name.c_str());
+ if (immutableKeys.find(key) != std::string::npos) {
+ ALOGD("Cannot set immutable property: %s", key.c_str());
+ return Status::BAD_VALUE;
+ }
+
+ std::map<std::string, std::string>::iterator itr =
+ mStringProperties.find(key);
+ if (itr == mStringProperties.end()) {
+ ALOGE("Cannot set undefined property string, key=%s", key.c_str());
+ return Status::BAD_VALUE;
+ }
+
+ mStringProperties[key] = std::string(value.c_str());
+ return Status::OK;
+}
+
+Return<Status> DrmPlugin::setPropertyByteArray(
+ const hidl_string& name, const hidl_vec<uint8_t>& value) {
+ UNUSED(value);
+ if (name == kDeviceIdKey) {
+ ALOGD("Cannot set immutable property: %s", name.c_str());
+ return Status::BAD_VALUE;
+ }
+
+ // Setting of undefined properties is not supported
+ ALOGE("Failed to set property byte array, key=%s", name.c_str());
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+}
+
+Return<void> DrmPlugin::queryKeyStatus(
+ const hidl_vec<uint8_t>& sessionId,
+ queryKeyStatus_cb _hidl_cb) {
+
+ if (sessionId.size() == 0) {
+ // Returns empty key status KeyValue pair
+ _hidl_cb(Status::BAD_VALUE, hidl_vec<KeyValue>());
+ return Void();
+ }
+
+ std::vector<KeyValue> infoMapVec;
+ infoMapVec.clear();
+
+ KeyValue keyValuePair;
+ for (size_t i = 0; i < mPlayPolicy.size(); ++i) {
+ keyValuePair.key = mPlayPolicy[i].key;
+ keyValuePair.value = mPlayPolicy[i].value;
+ infoMapVec.push_back(keyValuePair);
+ }
+ _hidl_cb(Status::OK, toHidlVec(infoMapVec));
+ return Void();
+}
+
+Return<void> DrmPlugin::getNumberOfSessions(getNumberOfSessions_cb _hidl_cb) {
+ uint32_t currentSessions = mSessionLibrary->numOpenSessions();
+ uint32_t maxSessions = 10;
+ _hidl_cb(Status::OK, currentSessions, maxSessions);
+ return Void();
+}
+
+Return<void> DrmPlugin::getSecurityLevel(const hidl_vec<uint8_t>& sessionId,
+ getSecurityLevel_cb _hidl_cb) {
+ if (sessionId.size() == 0) {
+ _hidl_cb(Status::BAD_VALUE, SecurityLevel::UNKNOWN);
+ return Void();
+ }
+
+ std::vector<uint8_t> sid = toVector(sessionId);
+ sp<Session> session = mSessionLibrary->findSession(sid);
+ if (!session.get()) {
+ _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, SecurityLevel::UNKNOWN);
+ return Void();
+ }
+
+ std::map<std::vector<uint8_t>, SecurityLevel>::iterator itr =
+ mSecurityLevel.find(sid);
+ if (itr == mSecurityLevel.end()) {
+ ALOGE("Session id not found");
+ _hidl_cb(Status::ERROR_DRM_INVALID_STATE, SecurityLevel::UNKNOWN);
+ return Void();
+ }
+
+ _hidl_cb(Status::OK, itr->second);
+ return Void();
+}
+
+Return<Status> DrmPlugin::setSecurityLevel(const hidl_vec<uint8_t>& sessionId,
+ SecurityLevel level) {
+ if (sessionId.size() == 0) {
+ ALOGE("Invalid empty session id");
+ return Status::BAD_VALUE;
+ }
+
+ if (level > SecurityLevel::SW_SECURE_CRYPTO) {
+ ALOGE("Cannot set security level > max");
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ std::vector<uint8_t> sid = toVector(sessionId);
+ sp<Session> session = mSessionLibrary->findSession(sid);
+ if (!session.get()) {
+ return Status::ERROR_DRM_SESSION_NOT_OPENED;
+ }
+
+ std::map<std::vector<uint8_t>, SecurityLevel>::iterator itr =
+ mSecurityLevel.find(sid);
+ if (itr != mSecurityLevel.end()) {
+ mSecurityLevel[sid] = level;
+ } else {
+ if (!mSecurityLevel.insert(
+ std::pair<std::vector<uint8_t>, SecurityLevel>(sid, level)).second) {
+ ALOGE("Failed to set security level");
+ return Status::ERROR_DRM_INVALID_STATE;
+ }
+ }
+ return Status::OK;
+}
+
+Return<void> DrmPlugin::getMetrics(getMetrics_cb _hidl_cb) {
+ // Set the open session count metric.
+ DrmMetricGroup::Attribute openSessionOkAttribute = {
+ "status", DrmMetricGroup::ValueType::INT64_TYPE, (int64_t) Status::OK, 0.0, ""
+ };
+ DrmMetricGroup::Value openSessionMetricValue = {
+ "count", DrmMetricGroup::ValueType::INT64_TYPE, mOpenSessionOkCount, 0.0, ""
+ };
+ DrmMetricGroup::Metric openSessionMetric = {
+ "open_session", { openSessionOkAttribute }, { openSessionMetricValue }
+ };
+
+ // Set the close session count metric.
+ DrmMetricGroup::Attribute closeSessionOkAttribute = {
+ "status", DrmMetricGroup::ValueType::INT64_TYPE, (int64_t) Status::OK, 0.0, ""
+ };
+ DrmMetricGroup::Value closeSessionMetricValue = {
+ "count", DrmMetricGroup::ValueType::INT64_TYPE, mCloseSessionOkCount, 0.0, ""
+ };
+ DrmMetricGroup::Metric closeSessionMetric = {
+ "close_session", { closeSessionOkAttribute }, { closeSessionMetricValue }
+ };
+
+ // Set the close session, not opened metric.
+ DrmMetricGroup::Attribute closeSessionNotOpenedAttribute = {
+ "status", DrmMetricGroup::ValueType::INT64_TYPE,
+ (int64_t) Status::ERROR_DRM_SESSION_NOT_OPENED, 0.0, ""
+ };
+ DrmMetricGroup::Value closeSessionNotOpenedMetricValue = {
+ "count", DrmMetricGroup::ValueType::INT64_TYPE, mCloseSessionNotOpenedCount, 0.0, ""
+ };
+ DrmMetricGroup::Metric closeSessionNotOpenedMetric = {
+ "close_session", { closeSessionNotOpenedAttribute }, { closeSessionNotOpenedMetricValue }
+ };
+
+ DrmMetricGroup metrics = { { openSessionMetric, closeSessionMetric,
+ closeSessionNotOpenedMetric } };
+
+ _hidl_cb(Status::OK, hidl_vec<DrmMetricGroup>({metrics}));
+ return Void();
+}
+
+Return<void> DrmPlugin::getSecureStops(getSecureStops_cb _hidl_cb) {
+ std::vector<SecureStop> stops;
+ for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
+ ClearkeySecureStop clearkeyStop = itr->second;
+ std::vector<uint8_t> stopVec;
+ stopVec.insert(stopVec.end(), clearkeyStop.id.begin(), clearkeyStop.id.end());
+ stopVec.insert(stopVec.end(), clearkeyStop.data.begin(), clearkeyStop.data.end());
+
+ SecureStop stop;
+ stop.opaqueData = toHidlVec(stopVec);
+ stops.push_back(stop);
+ }
+ _hidl_cb(Status::OK, stops);
+ return Void();
+}
+
+Return<void> DrmPlugin::getSecureStop(const hidl_vec<uint8_t>& secureStopId,
+ getSecureStop_cb _hidl_cb) {
+ SecureStop stop;
+ auto itr = mSecureStops.find(toVector(secureStopId));
+ if (itr != mSecureStops.end()) {
+ ClearkeySecureStop clearkeyStop = itr->second;
+ std::vector<uint8_t> stopVec;
+ stopVec.insert(stopVec.end(), clearkeyStop.id.begin(), clearkeyStop.id.end());
+ stopVec.insert(stopVec.end(), clearkeyStop.data.begin(), clearkeyStop.data.end());
+
+ stop.opaqueData = toHidlVec(stopVec);
+ _hidl_cb(Status::OK, stop);
+ } else {
+ _hidl_cb(Status::BAD_VALUE, stop);
+ }
+
+ return Void();
+}
+
+Return<Status> DrmPlugin::releaseSecureStop(const hidl_vec<uint8_t>& secureStopId) {
+ return removeSecureStop(secureStopId);
+}
+
+Return<Status> DrmPlugin::releaseAllSecureStops() {
+ return removeAllSecureStops();
+}
+
+Return<void> DrmPlugin::getSecureStopIds(getSecureStopIds_cb _hidl_cb) {
+ std::vector<SecureStopId> ids;
+ for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
+ ids.push_back(itr->first);
+ }
+
+ _hidl_cb(Status::OK, toHidlVec(ids));
+ return Void();
+}
+
+Return<Status> DrmPlugin::releaseSecureStops(const SecureStopRelease& ssRelease) {
+ if (ssRelease.opaqueData.size() == 0) {
+ return Status::BAD_VALUE;
+ }
+
+ Status status = Status::OK;
+ std::vector<uint8_t> input = toVector(ssRelease.opaqueData);
+
+ // The format of opaqueData is shared between the server
+ // and the drm service. The clearkey implementation consists of:
+ // count - number of secure stops
+ // list of fixed length secure stops
+ size_t countBufferSize = sizeof(uint32_t);
+ uint32_t count = 0;
+ sscanf(reinterpret_cast<char*>(input.data()), "%04" PRIu32, &count);
+
+ // Avoid divide by 0 below.
+ if (count == 0) {
+ return Status::BAD_VALUE;
+ }
+
+ size_t secureStopSize = (input.size() - countBufferSize) / count;
+ uint8_t buffer[secureStopSize];
+ size_t offset = countBufferSize; // skip the count
+ for (size_t i = 0; i < count; ++i, offset += secureStopSize) {
+ memcpy(buffer, input.data() + offset, secureStopSize);
+ std::vector<uint8_t> id(buffer, buffer + kSecureStopIdSize);
+
+ status = removeSecureStop(toHidlVec(id));
+ if (Status::OK != status) break;
+ }
+
+ return status;
+}
+
+Return<Status> DrmPlugin::removeSecureStop(const hidl_vec<uint8_t>& secureStopId) {
+ if (1 != mSecureStops.erase(toVector(secureStopId))) {
+ return Status::BAD_VALUE;
+ }
+ return Status::OK;
+}
+
+Return<Status> DrmPlugin::removeAllSecureStops() {
+ mSecureStops.clear();
+ mNextSecureStopId = kSecureStopIdStart;
+ return Status::OK;
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
new file mode 100644
index 0000000000..e2bb6517ea
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "hidl_InitDataParser"
+
+#include <algorithm>
+#include <utils/Log.h>
+
+#include "InitDataParser.h"
+
+#include "Base64.h"
+
+#include "ClearKeyUUID.h"
+#include "MimeType.h"
+#include "Utils.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+namespace {
+ const size_t kKeyIdSize = 16;
+ const size_t kSystemIdSize = 16;
+}
+
+std::vector<uint8_t> StrToVector(const std::string& str) {
+ std::vector<uint8_t> vec(str.begin(), str.end());
+ return vec;
+}
+
+Status InitDataParser::parse(const std::vector<uint8_t>& initData,
+ const std::string& type,
+ std::vector<uint8_t>* licenseRequest) {
+ // Build a list of the key IDs
+ std::vector<const uint8_t*> keyIds;
+
+ if (type == kIsoBmffVideoMimeType ||
+ type == kIsoBmffAudioMimeType ||
+ type == kCencInitDataFormat) {
+ Status res = parsePssh(initData, &keyIds);
+ if (res != Status::OK) {
+ return res;
+ }
+ } else if (type == kWebmVideoMimeType ||
+ type == kWebmAudioMimeType ||
+ type == kWebmInitDataFormat) {
+ // WebM "init data" is just a single key ID
+ if (initData.size() != kKeyIdSize) {
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+ keyIds.push_back(initData.data());
+ } else {
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ // Build the request
+ std::string requestJson = generateRequest(keyIds);
+ std::vector<uint8_t> requestJsonVec = StrToVector(requestJson);
+
+ licenseRequest->clear();
+ licenseRequest->insert(licenseRequest->end(), requestJsonVec.begin(), requestJsonVec.end());
+ return Status::OK;
+}
+
+Status InitDataParser::parsePssh(const std::vector<uint8_t>& initData,
+ std::vector<const uint8_t*>* keyIds) {
+ size_t readPosition = 0;
+
+ // Validate size field
+ uint32_t expectedSize = initData.size();
+ expectedSize = htonl(expectedSize);
+ if (memcmp(&initData[readPosition], &expectedSize,
+ sizeof(expectedSize)) != 0) {
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+ readPosition += sizeof(expectedSize);
+
+ // Validate PSSH box identifier
+ const char psshIdentifier[4] = {'p', 's', 's', 'h'};
+ if (memcmp(&initData[readPosition], psshIdentifier,
+ sizeof(psshIdentifier)) != 0) {
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+ readPosition += sizeof(psshIdentifier);
+
+ // Validate EME version number
+ const uint8_t psshVersion1[4] = {1, 0, 0, 0};
+ if (memcmp(&initData[readPosition], psshVersion1,
+ sizeof(psshVersion1)) != 0) {
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+ readPosition += sizeof(psshVersion1);
+
+ // Validate system ID
+ if (!clearkeydrm::isClearKeyUUID(&initData[readPosition])) {
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+ readPosition += kSystemIdSize;
+
+ // Read key ID count
+ uint32_t keyIdCount;
+ memcpy(&keyIdCount, &initData[readPosition], sizeof(keyIdCount));
+ keyIdCount = ntohl(keyIdCount);
+ readPosition += sizeof(keyIdCount);
+ if (readPosition + ((uint64_t)keyIdCount * kKeyIdSize) !=
+ initData.size() - sizeof(uint32_t)) {
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ // Calculate the key ID offsets
+ for (uint32_t i = 0; i < keyIdCount; ++i) {
+ size_t keyIdPosition = readPosition + (i * kKeyIdSize);
+ keyIds->push_back(&initData[keyIdPosition]);
+ }
+ return Status::OK;
+}
+
+std::string InitDataParser::generateRequest(const std::vector<const uint8_t*>& keyIds) {
+ const std::string kRequestPrefix("{\"kids\":[");
+ const std::string kRequestSuffix("],\"type\":\"temporary\"}");
+
+ std::string request(kRequestPrefix);
+ std::string encodedId;
+ for (size_t i = 0; i < keyIds.size(); ++i) {
+ encodedId.clear();
+ encodeBase64Url(keyIds[i], kKeyIdSize, &encodedId);
+ if (i != 0) {
+ request.append(",");
+ }
+ request.push_back('\"');
+ request.append(encodedId);
+ request.push_back('\"');
+ }
+ request.append(kRequestSuffix);
+
+ // Android's Base64 encoder produces padding. EME forbids padding.
+ const char kBase64Padding = '=';
+ request.erase(std::remove(request.begin(), request.end(), kBase64Padding), request.end());
+
+ return request;
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp b/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp
new file mode 100644
index 0000000000..cccb41ecc4
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "hidl_JsonWebKey"
+
+#include <utils/Log.h>
+
+#include "JsonWebKey.h"
+
+#include "Base64.h"
+
+namespace {
+const std::string kKeysTag("keys");
+const std::string kKeyTypeTag("kty");
+const std::string kSymmetricKeyValue("oct");
+const std::string kKeyTag("k");
+const std::string kKeyIdTag("kid");
+const std::string kBase64Padding("=");
+}
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+JsonWebKey::JsonWebKey() {
+}
+
+JsonWebKey::~JsonWebKey() {
+}
+
+/*
+ * Parses a JSON Web Key Set string, initializes a KeyMap with key id:key
+ * pairs from the JSON Web Key Set. Both key ids and keys are base64url
+ * encoded. The KeyMap contains base64url decoded key id:key pairs.
+ *
+ * @return Returns false for errors, true for success.
+ */
+bool JsonWebKey::extractKeysFromJsonWebKeySet(const std::string& jsonWebKeySet,
+ KeyMap* keys) {
+
+ keys->clear();
+
+ if (!parseJsonWebKeySet(jsonWebKeySet, &mJsonObjects)) {
+ return false;
+ }
+
+ // mJsonObjects[0] contains the entire JSON Web Key Set, including
+ // all the base64 encoded keys. Each key is also stored separately as
+ // a JSON object in mJsonObjects[1..n] where n is the total
+ // number of keys in the set.
+ if (!isJsonWebKeySet(mJsonObjects[0])) {
+ return false;
+ }
+
+ std::string encodedKey, encodedKeyId;
+ std::vector<uint8_t> decodedKey, decodedKeyId;
+
+ // mJsonObjects[1] contains the first JSON Web Key in the set
+ for (size_t i = 1; i < mJsonObjects.size(); ++i) {
+ encodedKeyId.clear();
+ encodedKey.clear();
+
+ if (!parseJsonObject(mJsonObjects[i], &mTokens))
+ return false;
+
+ if (findKey(mJsonObjects[i], &encodedKeyId, &encodedKey)) {
+ if (encodedKeyId.empty() || encodedKey.empty()) {
+ ALOGE("Must have both key id and key in the JsonWebKey set.");
+ continue;
+ }
+
+ if (!decodeBase64String(encodedKeyId, &decodedKeyId)) {
+ ALOGE("Failed to decode key id(%s)", encodedKeyId.c_str());
+ continue;
+ }
+
+ if (!decodeBase64String(encodedKey, &decodedKey)) {
+ ALOGE("Failed to decode key(%s)", encodedKey.c_str());
+ continue;
+ }
+
+ keys->insert(std::pair<std::vector<uint8_t>,
+ std::vector<uint8_t> >(decodedKeyId, decodedKey));
+ }
+ }
+ return true;
+}
+
+bool JsonWebKey::decodeBase64String(const std::string& encodedText,
+ std::vector<uint8_t>* decodedText) {
+
+ decodedText->clear();
+
+ // encodedText should not contain padding characters as per EME spec.
+ if (encodedText.find(kBase64Padding) != std::string::npos) {
+ return false;
+ }
+
+ // Since decodeBase64() requires padding characters,
+ // add them so length of encodedText is exactly a multiple of 4.
+ int remainder = encodedText.length() % 4;
+ std::string paddedText(encodedText);
+ if (remainder > 0) {
+ for (int i = 0; i < 4 - remainder; ++i) {
+ paddedText.append(kBase64Padding);
+ }
+ }
+
+ sp<Buffer> buffer = decodeBase64(paddedText);
+ if (buffer == nullptr) {
+ ALOGE("Malformed base64 encoded content found.");
+ return false;
+ }
+
+ decodedText->insert(decodedText->end(), buffer->base(), buffer->base() + buffer->size());
+ return true;
+}
+
+bool JsonWebKey::findKey(const std::string& jsonObject, std::string* keyId,
+ std::string* encodedKey) {
+
+ std::string key, value;
+
+ // Only allow symmetric key, i.e. "kty":"oct" pair.
+ if (jsonObject.find(kKeyTypeTag) != std::string::npos) {
+ findValue(kKeyTypeTag, &value);
+ if (0 != value.compare(kSymmetricKeyValue))
+ return false;
+ }
+
+ if (jsonObject.find(kKeyIdTag) != std::string::npos) {
+ findValue(kKeyIdTag, keyId);
+ }
+
+ if (jsonObject.find(kKeyTag) != std::string::npos) {
+ findValue(kKeyTag, encodedKey);
+ }
+ return true;
+}
+
+void JsonWebKey::findValue(const std::string &key, std::string* value) {
+ value->clear();
+ const char* valueToken;
+ for (std::vector<std::string>::const_iterator nextToken = mTokens.begin();
+ nextToken != mTokens.end(); ++nextToken) {
+ if (0 == (*nextToken).compare(key)) {
+ if (nextToken + 1 == mTokens.end())
+ break;
+ valueToken = (*(nextToken + 1)).c_str();
+ value->assign(valueToken);
+ nextToken++;
+ break;
+ }
+ }
+}
+
+bool JsonWebKey::isJsonWebKeySet(const std::string& jsonObject) const {
+ if (jsonObject.find(kKeysTag) == std::string::npos) {
+ ALOGE("JSON Web Key does not contain keys.");
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Parses a JSON objects string and initializes a vector of tokens.
+ *
+ * @return Returns false for errors, true for success.
+ */
+bool JsonWebKey::parseJsonObject(const std::string& jsonObject,
+ std::vector<std::string>* tokens) {
+ jsmn_parser parser;
+
+ jsmn_init(&parser);
+ int numTokens = jsmn_parse(&parser,
+ jsonObject.c_str(), jsonObject.size(), nullptr, 0);
+ if (numTokens < 0) {
+ ALOGE("Parser returns error code=%d", numTokens);
+ return false;
+ }
+
+ unsigned int jsmnTokensSize = numTokens * sizeof(jsmntok_t);
+ mJsmnTokens.clear();
+ mJsmnTokens.resize(jsmnTokensSize);
+
+ jsmn_init(&parser);
+ int status = jsmn_parse(&parser, jsonObject.c_str(),
+ jsonObject.size(), mJsmnTokens.data(), numTokens);
+ if (status < 0) {
+ ALOGE("Parser returns error code=%d", status);
+ return false;
+ }
+
+ tokens->clear();
+ std::string token;
+ const char *pjs;
+ for (int j = 0; j < numTokens; ++j) {
+ pjs = jsonObject.c_str() + mJsmnTokens[j].start;
+ if (mJsmnTokens[j].type == JSMN_STRING ||
+ mJsmnTokens[j].type == JSMN_PRIMITIVE) {
+ token.assign(pjs, mJsmnTokens[j].end - mJsmnTokens[j].start);
+ tokens->push_back(token);
+ }
+ }
+ return true;
+}
+
+/*
+ * Parses JSON Web Key Set string and initializes a vector of JSON objects.
+ *
+ * @return Returns false for errors, true for success.
+ */
+bool JsonWebKey::parseJsonWebKeySet(const std::string& jsonWebKeySet,
+ std::vector<std::string>* jsonObjects) {
+ if (jsonWebKeySet.empty()) {
+ ALOGE("Empty JSON Web Key");
+ return false;
+ }
+
+ // The jsmn parser only supports unicode encoding.
+ jsmn_parser parser;
+
+ // Computes number of tokens. A token marks the type, offset in
+ // the original string.
+ jsmn_init(&parser);
+ int numTokens = jsmn_parse(&parser,
+ jsonWebKeySet.c_str(), jsonWebKeySet.size(), nullptr, 0);
+ if (numTokens < 0) {
+ ALOGE("Parser returns error code=%d", numTokens);
+ return false;
+ }
+
+ unsigned int jsmnTokensSize = numTokens * sizeof(jsmntok_t);
+ mJsmnTokens.resize(jsmnTokensSize);
+
+ jsmn_init(&parser);
+ int status = jsmn_parse(&parser, jsonWebKeySet.c_str(),
+ jsonWebKeySet.size(), mJsmnTokens.data(), numTokens);
+ if (status < 0) {
+ ALOGE("Parser returns error code=%d", status);
+ return false;
+ }
+
+ std::string token;
+ const char *pjs;
+ for (int i = 0; i < numTokens; ++i) {
+ pjs = jsonWebKeySet.c_str() + mJsmnTokens[i].start;
+ if (mJsmnTokens[i].type == JSMN_OBJECT) {
+ token.assign(pjs, mJsmnTokens[i].end - mJsmnTokens[i].start);
+ jsonObjects->push_back(token);
+ }
+ }
+ return true;
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Session.cpp b/drm/mediadrm/plugins/clearkey/hidl/Session.cpp
new file mode 100644
index 0000000000..07c9269c68
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/Session.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "hidl_ClearKeySession"
+#include <utils/Log.h>
+
+#include "Session.h"
+#include "Utils.h"
+
+#include "AesCtrDecryptor.h"
+#include "InitDataParser.h"
+#include "JsonWebKey.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::hardware::drm::V1_0::KeyValue;
+using ::android::hardware::drm::V1_0::Status;
+using ::android::hardware::drm::V1_0::SubSample;
+using ::android::hardware::Return;
+using ::android::sp;
+
+using android::Mutex;
+
+Status Session::getKeyRequest(
+ const std::vector<uint8_t>& initData,
+ const std::string& mimeType,
+ std::vector<uint8_t>* keyRequest) const {
+ InitDataParser parser;
+ return parser.parse(initData, mimeType, keyRequest);
+}
+
+Status Session::provideKeyResponse(const std::vector<uint8_t>& response) {
+ std::string responseString(
+ reinterpret_cast<const char*>(response.data()), response.size());
+ KeyMap keys;
+
+ Mutex::Autolock lock(mMapLock);
+ JsonWebKey parser;
+ if (parser.extractKeysFromJsonWebKeySet(responseString, &keys)) {
+ for (auto &key : keys) {
+ std::string first(key.first.begin(), key.first.end());
+ std::string second(key.second.begin(), key.second.end());
+ mKeyMap.insert(std::pair<std::vector<uint8_t>,
+ std::vector<uint8_t> >(key.first, key.second));
+ }
+ return Status::OK;
+ } else {
+ return Status::ERROR_DRM_UNKNOWN;
+ }
+}
+
+Status 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);
+
+ 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;
+ }
+
+ AesCtrDecryptor decryptor;
+ return decryptor.decrypt(
+ itr->second /*key*/, iv, srcPtr, destPtr, subSamples,
+ subSamples.size(), bytesDecryptedOut);
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp b/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp
new file mode 100644
index 0000000000..b4319e6a45
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "hidl_ClearKeySessionLibrary"
+#include <utils/Log.h>
+
+#include "SessionLibrary.h"
+#include "Utils.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+
+Mutex SessionLibrary::sSingletonLock;
+SessionLibrary* SessionLibrary::sSingleton = NULL;
+
+SessionLibrary* SessionLibrary::get() {
+ Mutex::Autolock lock(sSingletonLock);
+
+ if (sSingleton == NULL) {
+ ALOGD("Instantiating Session Library Singleton.");
+ sSingleton = new SessionLibrary();
+ }
+
+ return sSingleton;
+}
+
+sp<Session> SessionLibrary::createSession() {
+ Mutex::Autolock lock(mSessionsLock);
+
+ char sessionIdRaw[16];
+ snprintf(sessionIdRaw, sizeof(sessionIdRaw), "%u", mNextSessionId);
+
+ mNextSessionId += 1;
+
+ std::vector<uint8_t> sessionId;
+ sessionId.insert(sessionId.end(), sessionIdRaw,
+ sessionIdRaw + sizeof(sessionIdRaw) / sizeof(uint8_t));
+
+ mSessions.insert(std::pair<std::vector<uint8_t>,
+ sp<Session> >(sessionId, new Session(sessionId)));
+ std::map<std::vector<uint8_t>, sp<Session> >::iterator itr = mSessions.find(sessionId);
+ if (itr != mSessions.end()) {
+ return itr->second;
+ } else {
+ return nullptr;
+ }
+}
+
+sp<Session> SessionLibrary::findSession(
+ const std::vector<uint8_t>& sessionId) {
+ Mutex::Autolock lock(mSessionsLock);
+ std::map<std::vector<uint8_t>, sp<Session> >::iterator itr = mSessions.find(sessionId);
+ if (itr != mSessions.end()) {
+ return itr->second;
+ } else {
+ return nullptr;
+ }
+}
+
+void SessionLibrary::destroySession(const sp<Session>& session) {
+ Mutex::Autolock lock(mSessionsLock);
+ mSessions.erase(session->sessionId());
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.1-service.clearkey.rc b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.1-service.clearkey.rc
new file mode 100644
index 0000000000..ffe856a55d
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.1-service.clearkey.rc
@@ -0,0 +1,6 @@
+service vendor.drm-clearkey-hal-1-1 /vendor/bin/hw/android.hardware.drm@1.1-service.clearkey
+ class hal
+ user media
+ group media mediadrm
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/AesCtrDecryptor.h b/drm/mediadrm/plugins/clearkey/hidl/include/AesCtrDecryptor.h
new file mode 100644
index 0000000000..0c7ef20fdf
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/AesCtrDecryptor.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEARKEY_AES_CTR_DECRYPTOR_H_
+#define CLEARKEY_AES_CTR_DECRYPTOR_H_
+
+#include "ClearKeyTypes.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::hardware::drm::V1_0::Status;
+using ::android::hardware::drm::V1_0::SubSample;
+
+class AesCtrDecryptor {
+public:
+ AesCtrDecryptor() {}
+
+ Status decrypt(const std::vector<uint8_t>& key, const Iv iv,
+ const uint8_t* source, uint8_t* destination,
+ const std::vector<SubSample> subSamples, size_t numSubSamples,
+ size_t* bytesDecryptedOut);
+
+private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(AesCtrDecryptor);
+};
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // CLEARKEY_AES_CTR_DECRYPTOR_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/Base64.h b/drm/mediadrm/plugins/clearkey/hidl/include/Base64.h
new file mode 100644
index 0000000000..4a385bdb6e
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/Base64.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BASE_64_H_
+
+#define BASE_64_H_
+
+#include <android/hardware/drm/1.0/types.h>
+
+#include "Buffer.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::sp;
+
+struct Buffer;
+
+sp<Buffer> decodeBase64(const std::string &s);
+void encodeBase64(const void *data, size_t size, std::string *out);
+
+void encodeBase64Url(const void *data, size_t size, std::string *out);
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // BASE_64_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/Buffer.h b/drm/mediadrm/plugins/clearkey/hidl/include/Buffer.h
new file mode 100644
index 0000000000..5bbb28aa14
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/Buffer.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BUFFER_H_
+#define BUFFER_H_
+
+#include <android/hardware/drm/1.0/types.h>
+#include <utils/RefBase.h>
+
+#include "ClearKeyTypes.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::sp;
+
+struct Buffer : public RefBase {
+ explicit Buffer(size_t capacity);
+
+ uint8_t *base() { return reinterpret_cast<uint8_t *>(mData); }
+ uint8_t *data() { return reinterpret_cast<uint8_t *>(mData) + mRangeOffset; }
+ size_t capacity() const { return mCapacity; }
+ size_t size() const { return mRangeLength; }
+ size_t offset() const { return mRangeOffset; }
+
+protected:
+ virtual ~Buffer();
+
+private:
+ void *mData;
+ size_t mCapacity;
+ size_t mRangeOffset;
+ size_t mRangeLength;
+
+ bool mOwnsData;
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(Buffer);
+};
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // BUFFER_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
new file mode 100644
index 0000000000..d65b25c37f
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEARKEY_DRM_PROPERTIES_H_
+#define CLEARKEY_DRM_PROPERTIES_H_
+
+#include <string.h>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+static const std::string kVendorKey("vendor");
+static const std::string kVendorValue("Google");
+static const std::string kVersionKey("version");
+static const std::string kVersionValue("1.1");
+static const std::string kPluginDescriptionKey("description");
+static const std::string kPluginDescriptionValue("ClearKey CDM");
+static const std::string kAlgorithmsKey("algorithms");
+static const std::string kAlgorithmsValue("");
+static const std::string kListenerTestSupportKey("listenerTestSupport");
+static const std::string kListenerTestSupportValue("true");
+
+static const std::string kDeviceIdKey("deviceId");
+static const uint8_t kTestDeviceIdData[] =
+ {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+// TODO stub out metrics for nw
+static const std::string kMetricsKey("metrics");
+static const uint8_t kMetricsData[] = { 0 };
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // CLEARKEY_DRM_PROPERTIES_H_
+
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyTypes.h b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyTypes.h
new file mode 100644
index 0000000000..46cb5e4dd5
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyTypes.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEARKEY_MACROS_H_
+#define CLEARKEY_MACROS_H_
+
+#include <android/hardware/drm/1.0/types.h>
+
+#include <map>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::hardware::drm::V1_0::KeyValue;
+using ::android::hardware::hidl_vec;
+
+const uint8_t kBlockSize = 16; //AES_BLOCK_SIZE;
+typedef uint8_t KeyId[kBlockSize];
+typedef uint8_t Iv[kBlockSize];
+
+typedef ::android::hardware::drm::V1_0::SubSample SubSample;
+typedef std::map<std::vector<uint8_t>, std::vector<uint8_t> > KeyMap;
+
+#define CLEARKEY_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&) = delete; \
+ void operator=(const TypeName&) = delete;
+
+#define CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(TypeName) \
+ TypeName() = delete; \
+ TypeName(const TypeName&) = delete; \
+ void operator=(const TypeName&) = delete;
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // CLEARKEY_MACROS_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/CreatePluginFactories.h b/drm/mediadrm/plugins/clearkey/hidl/include/CreatePluginFactories.h
new file mode 100644
index 0000000000..99520277f2
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/CreatePluginFactories.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEARKEY_CREATE_PLUGIN_FACTORIES_H_
+#define CLEARKEY_CREATE_PLUGIN_FACTORIES_H_
+
+#include <android/hardware/drm/1.1/ICryptoFactory.h>
+#include <android/hardware/drm/1.1/IDrmFactory.h>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::hardware::drm::V1_1::ICryptoFactory;
+using ::android::hardware::drm::V1_1::IDrmFactory;
+
+extern "C" {
+ IDrmFactory* createDrmFactory();
+ ICryptoFactory* createCryptoFactory();
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+#endif // CLEARKEY_CREATE_PLUGIN_FACTORIES_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/CryptoFactory.h b/drm/mediadrm/plugins/clearkey/hidl/include/CryptoFactory.h
new file mode 100644
index 0000000000..175ab761fa
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/CryptoFactory.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEARKEY_CRYPTO_FACTORY_H_
+#define CLEARKEY_CRYPTO_FACTORY_H_
+
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.1/ICryptoFactory.h>
+
+#include "ClearKeyTypes.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::hardware::drm::V1_1::ICryptoFactory;
+using ::android::hardware::drm::V1_0::ICryptoPlugin;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+
+struct CryptoFactory : public ICryptoFactory {
+ CryptoFactory() {}
+ virtual ~CryptoFactory() {}
+
+ Return<bool> isCryptoSchemeSupported(const hidl_array<uint8_t, 16>& uuid)
+ override;
+
+ Return<void> createPlugin(
+ const hidl_array<uint8_t, 16>& uuid,
+ const hidl_vec<uint8_t>& initData,
+ createPlugin_cb _hidl_cb) override;
+
+private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(CryptoFactory);
+
+};
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // CLEARKEY_CRYPTO_FACTORY_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h
new file mode 100644
index 0000000000..6a738066d0
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEARKEY_CRYPTO_PLUGIN_H_
+#define CLEARKEY_CRYPTO_PLUGIN_H_
+
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+
+#include "ClearKeyTypes.h"
+#include "Session.h"
+#include "Utils.h"
+
+namespace {
+ static const size_t KEY_ID_SIZE = 16;
+ static const size_t KEY_IV_SIZE = 16;
+}
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+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;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::sp;
+
+struct CryptoPlugin : public ICryptoPlugin {
+ explicit CryptoPlugin(const hidl_vec<uint8_t>& sessionId) {
+ mInitStatus = setMediaDrmSession(sessionId);
+ }
+ virtual ~CryptoPlugin() {}
+
+ Return<bool> requiresSecureDecoderComponent(const hidl_string& mime) {
+ UNUSED(mime);
+ return false;
+ }
+
+ Return<void> notifyResolution(uint32_t width, uint32_t height) {
+ UNUSED(width);
+ UNUSED(height);
+ return Void();
+ }
+
+ Return<void> decrypt(
+ 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_cb _hidl_cb);
+
+ Return<void> setSharedBufferBase(const hidl_memory& base,
+ uint32_t bufferId);
+
+ Return<Status> setMediaDrmSession(const hidl_vec<uint8_t>& sessionId);
+
+ Return<Status> getInitStatus() const { return mInitStatus; }
+
+private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(CryptoPlugin);
+
+ std::map<uint32_t, sp<IMemory> > mSharedBufferMap;
+ sp<Session> mSession;
+ Status mInitStatus;
+};
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // CLEARKEY_CRYPTO_PLUGIN_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
new file mode 100644
index 0000000000..6f581955b5
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEARKEY_DRM_FACTORY_H_
+#define CLEARKEY_DRM_FACTORY_H_
+
+#include <android/hardware/drm/1.1/IDrmPlugin.h>
+#include <android/hardware/drm/1.1/IDrmFactory.h>
+
+#include "ClearKeyTypes.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+
+struct DrmFactory : public IDrmFactory {
+ DrmFactory() {}
+ virtual ~DrmFactory() {}
+
+ Return<bool> isCryptoSchemeSupported(const hidl_array<uint8_t, 16>& uuid)
+ override;
+
+ Return<bool> isContentTypeSupported(const hidl_string &mimeType)
+ override;
+
+ Return<void> createPlugin(
+ const hidl_array<uint8_t, 16>& uuid,
+ const hidl_string& appPackageName,
+ createPlugin_cb _hidl_cb) override;
+
+private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(DrmFactory);
+};
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // CLEARKEY_DRM_FACTORY_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
new file mode 100644
index 0000000000..fb0695aaef
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEARKEY_DRM_PLUGIN_H_
+#define CLEARKEY_DRM_PLUGIN_H_
+
+#include <android/hardware/drm/1.1/IDrmPlugin.h>
+
+#include <stdio.h>
+#include <map>
+
+#include "SessionLibrary.h"
+#include "Utils.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+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::IDrmPlugin;
+using ::android::hardware::drm::V1_1::KeyRequestType;
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct DrmPlugin : public IDrmPlugin {
+ explicit DrmPlugin(SessionLibrary* sessionLibrary);
+
+ virtual ~DrmPlugin() {}
+
+ Return<void> openSession(openSession_cb _hidl_cb) override;
+ Return<void> openSession_1_1(SecurityLevel securityLevel,
+ openSession_cb _hidl_cb) override;
+
+ Return<Status> closeSession(const hidl_vec<uint8_t>& sessionId) override;
+
+ Return<void> getKeyRequest(
+ const hidl_vec<uint8_t>& scope,
+ const hidl_vec<uint8_t>& initData,
+ const hidl_string& mimeType,
+ KeyType keyType,
+ const hidl_vec<KeyValue>& optionalParameters,
+ getKeyRequest_cb _hidl_cb) override;
+
+ Return<void> getKeyRequest_1_1(
+ 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_1_cb _hidl_cb) override;
+
+ Return<void> provideKeyResponse(
+ const hidl_vec<uint8_t>& scope,
+ const hidl_vec<uint8_t>& response,
+ provideKeyResponse_cb _hidl_cb) override;
+
+ Return<Status> removeKeys(const hidl_vec<uint8_t>& sessionId) {
+ if (sessionId.size() == 0) {
+ return Status::BAD_VALUE;
+ }
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ Return<Status> restoreKeys(
+ const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keySetId) {
+
+ if (sessionId.size() == 0 || keySetId.size() == 0) {
+ return Status::BAD_VALUE;
+ }
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ Return<void> queryKeyStatus(
+ const hidl_vec<uint8_t>& sessionId,
+ queryKeyStatus_cb _hidl_cb) override;
+
+ Return<void> getProvisionRequest(
+ const hidl_string& certificateType,
+ const hidl_string& certificateAuthority,
+ getProvisionRequest_cb _hidl_cb) {
+ UNUSED(certificateType);
+ UNUSED(certificateAuthority);
+
+ hidl_string defaultUrl;
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, hidl_vec<uint8_t>(), defaultUrl);
+ return Void();
+ }
+
+ Return<void> provideProvisionResponse(
+ const hidl_vec<uint8_t>& response,
+ provideProvisionResponse_cb _hidl_cb) {
+
+ if (response.size() == 0) {
+ _hidl_cb(Status::BAD_VALUE, hidl_vec<uint8_t>(), hidl_vec<uint8_t>());
+ return Void();
+ }
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, hidl_vec<uint8_t>(), hidl_vec<uint8_t>());
+ return Void();
+ }
+
+ Return<void> getHdcpLevels(getHdcpLevels_cb _hidl_cb) {
+ HdcpLevel connectedLevel = HdcpLevel::HDCP_NONE;
+ HdcpLevel maxLevel = HdcpLevel::HDCP_NO_OUTPUT;
+ _hidl_cb(Status::OK, connectedLevel, maxLevel);
+ return Void();
+ }
+
+ Return<void> getNumberOfSessions(getNumberOfSessions_cb _hidl_cb) override;
+
+ Return<void> getSecurityLevel(const hidl_vec<uint8_t>& sessionId,
+ getSecurityLevel_cb _hidl_cb) override;
+
+ Return<void> getMetrics(getMetrics_cb _hidl_cb) override;
+
+ Return<void> getPropertyString(
+ const hidl_string& name,
+ getPropertyString_cb _hidl_cb) override;
+
+ Return<void> getPropertyByteArray(
+ const hidl_string& name,
+ getPropertyByteArray_cb _hidl_cb) override;
+
+ Return<Status> setPropertyString(
+ const hidl_string& name, const hidl_string& value) override;
+
+ Return<Status> setPropertyByteArray(
+ const hidl_string& name, const hidl_vec<uint8_t>& value) override;
+
+ Return<Status> setCipherAlgorithm(
+ const hidl_vec<uint8_t>& sessionId, const hidl_string& algorithm) {
+ if (sessionId.size() == 0 || algorithm.size() == 0) {
+ return Status::BAD_VALUE;
+ }
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ Return<Status> setMacAlgorithm(
+ const hidl_vec<uint8_t>& sessionId, const hidl_string& algorithm) {
+ if (sessionId.size() == 0 || algorithm.size() == 0) {
+ return Status::BAD_VALUE;
+ }
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ Return<void> encrypt(
+ const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keyId,
+ const hidl_vec<uint8_t>& input,
+ const hidl_vec<uint8_t>& iv,
+ encrypt_cb _hidl_cb) {
+ if (sessionId.size() == 0 || keyId.size() == 0 ||
+ input.size() == 0 || iv.size() == 0) {
+ _hidl_cb(Status::BAD_VALUE, hidl_vec<uint8_t>());
+ return Void();
+ }
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, hidl_vec<uint8_t>());
+ return Void();
+ }
+
+ Return<void> decrypt(
+ const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keyId,
+ const hidl_vec<uint8_t>& input,
+ const hidl_vec<uint8_t>& iv,
+ decrypt_cb _hidl_cb) {
+ if (sessionId.size() == 0 || keyId.size() == 0 ||
+ input.size() == 0 || iv.size() == 0) {
+ _hidl_cb(Status::BAD_VALUE, hidl_vec<uint8_t>());
+ return Void();
+ }
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, hidl_vec<uint8_t>());
+ return Void();
+ }
+
+ Return<void> sign(
+ const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keyId,
+ const hidl_vec<uint8_t>& message,
+ sign_cb _hidl_cb) {
+ if (sessionId.size() == 0 || keyId.size() == 0 ||
+ message.size() == 0) {
+ _hidl_cb(Status::BAD_VALUE, hidl_vec<uint8_t>());
+ return Void();
+ }
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, hidl_vec<uint8_t>());
+ return Void();
+ }
+
+ Return<void> verify(
+ const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keyId,
+ const hidl_vec<uint8_t>& message,
+ const hidl_vec<uint8_t>& signature,
+ verify_cb _hidl_cb) {
+
+ if (sessionId.size() == 0 || keyId.size() == 0 ||
+ message.size() == 0 || signature.size() == 0) {
+ _hidl_cb(Status::BAD_VALUE, false);
+ return Void();
+ }
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, false);
+ return Void();
+ }
+
+ Return<void> signRSA(
+ const hidl_vec<uint8_t>& sessionId,
+ const hidl_string& algorithm,
+ const hidl_vec<uint8_t>& message,
+ const hidl_vec<uint8_t>& wrappedKey,
+ signRSA_cb _hidl_cb) {
+ if (sessionId.size() == 0 || algorithm.size() == 0 ||
+ message.size() == 0 || wrappedKey.size() == 0) {
+ _hidl_cb(Status::BAD_VALUE, hidl_vec<uint8_t>());
+ return Void();
+ }
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, hidl_vec<uint8_t>());
+ return Void();
+ }
+
+ Return<void> setListener(const sp<IDrmPluginListener>& listener) {
+ mListener = listener;
+ return Void();
+ };
+
+ Return<void> sendEvent(EventType eventType, const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& data) {
+ if (mListener != NULL) {
+ mListener->sendEvent(eventType, sessionId, data);
+ } else {
+ ALOGE("Null event listener, event not sent");
+ }
+ return Void();
+ }
+
+ Return<void> sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId, int64_t expiryTimeInMS) {
+ if (mListener != NULL) {
+ mListener->sendExpirationUpdate(sessionId, expiryTimeInMS);
+ } else {
+ ALOGE("Null event listener, event not sent");
+ }
+ return Void();
+ }
+
+ Return<void> sendKeysChange(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey) {
+ if (mListener != NULL) {
+ mListener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
+ } else {
+ ALOGE("Null event listener, event not sent");
+ }
+ return Void();
+ }
+
+ Return<void> getSecureStops(getSecureStops_cb _hidl_cb);
+
+ Return<void> getSecureStop(const hidl_vec<uint8_t>& secureStopId,
+ getSecureStop_cb _hidl_cb);
+
+ Return<Status> releaseSecureStop(const hidl_vec<uint8_t>& ssRelease);
+
+ Return<Status> releaseAllSecureStops();
+
+ Return<void> getSecureStopIds(getSecureStopIds_cb _hidl_cb);
+
+ Return<Status> releaseSecureStops(const SecureStopRelease& ssRelease);
+
+ Return<Status> removeSecureStop(const hidl_vec<uint8_t>& secureStopId);
+
+ Return<Status> removeAllSecureStops();
+
+private:
+ void initProperties();
+ void installSecureStop(const hidl_vec<uint8_t>& sessionId);
+ void setPlayPolicy();
+
+ Return<Status> setSecurityLevel(const hidl_vec<uint8_t>& sessionId,
+ SecurityLevel level);
+
+ Status 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,
+ std::string *defaultUrl);
+
+ struct ClearkeySecureStop {
+ std::vector<uint8_t> id;
+ std::vector<uint8_t> data;
+ };
+
+ std::map<std::vector<uint8_t>, ClearkeySecureStop> mSecureStops;
+ std::vector<KeyValue> mPlayPolicy;
+ std::map<std::string, std::string> mStringProperties;
+ std::map<std::string, std::vector<uint8_t> > mByteArrayProperties;
+ std::map<std::vector<uint8_t>, SecurityLevel> mSecurityLevel;
+ sp<IDrmPluginListener> mListener;
+ SessionLibrary *mSessionLibrary;
+ int64_t mOpenSessionOkCount;
+ int64_t mCloseSessionOkCount;
+ int64_t mCloseSessionNotOpenedCount;
+ uint32_t mNextSecureStopId;
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(DrmPlugin);
+};
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // CLEARKEY_DRM_PLUGIN_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h b/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h
new file mode 100644
index 0000000000..3189c4aeb2
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEARKEY_INIT_DATA_PARSER_H_
+#define CLEARKEY_INIT_DATA_PARSER_H_
+
+#include <android/hardware/drm/1.0/types.h>
+
+#include "ClearKeyTypes.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::hardware::drm::V1_0::Status;
+
+class InitDataParser {
+public:
+ InitDataParser() {}
+
+ Status parse(const std::vector<uint8_t>& initData,
+ const std::string& type,
+ std::vector<uint8_t>* licenseRequest);
+
+private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(InitDataParser);
+
+ Status parsePssh(const std::vector<uint8_t>& initData,
+ std::vector<const uint8_t*>* keyIds);
+
+ std::string generateRequest(
+ const std::vector<const uint8_t*>& keyIds);
+};
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // CLEARKEY_INIT_DATA_PARSER_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/JsonWebKey.h b/drm/mediadrm/plugins/clearkey/hidl/include/JsonWebKey.h
new file mode 100644
index 0000000000..4ab034cd74
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/JsonWebKey.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef CLEARKEY_JSON_WEB_KEY_H_
+#define CLEARKEY_JSON_WEB_KEY_H_
+
+#include "jsmn.h"
+#include "Utils.h"
+#include "ClearKeyTypes.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+class JsonWebKey {
+ public:
+ JsonWebKey();
+ virtual ~JsonWebKey();
+
+ bool extractKeysFromJsonWebKeySet(const std::string& jsonWebKeySet,
+ KeyMap* keys);
+
+ private:
+ std::vector<jsmntok_t> mJsmnTokens;
+ std::vector<std::string> mJsonObjects;
+ std::vector<std::string> mTokens;
+
+ bool decodeBase64String(const std::string& encodedText,
+ std::vector<uint8_t>* decodedText);
+ bool findKey(const std::string& jsonObject, std::string* keyId,
+ std::string* encodedKey);
+ void findValue(const std::string &key, std::string* value);
+ bool isJsonWebKeySet(const std::string& jsonObject) const;
+ bool parseJsonObject(const std::string& jsonObject,
+ std::vector<std::string>* tokens);
+ bool parseJsonWebKeySet(const std::string& jsonWebKeySet,
+ std::vector<std::string>* jsonObjects);
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(JsonWebKey);
+};
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // CLEARKEY_JSON_WEB_KEY_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/Session.h b/drm/mediadrm/plugins/clearkey/hidl/include/Session.h
new file mode 100644
index 0000000000..cddfca5eba
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/Session.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEARKEY_SESSION_H_
+#define CLEARKEY_SESSION_H_
+
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <vector>
+
+#include "ClearKeyTypes.h"
+
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::hardware::drm::V1_0::Status;
+using ::android::hardware::drm::V1_0::SubSample;
+
+class Session : public RefBase {
+public:
+ explicit Session(const std::vector<uint8_t>& sessionId)
+ : mSessionId(sessionId) {}
+ virtual ~Session() {}
+
+ const std::vector<uint8_t>& sessionId() const { return mSessionId; }
+
+ Status getKeyRequest(
+ const std::vector<uint8_t>& mimeType,
+ const std::string& initDataType,
+ std::vector<uint8_t>* keyRequest) const;
+
+ Status provideKeyResponse(
+ const std::vector<uint8_t>& response);
+
+ Status decrypt(
+ const KeyId keyId, const Iv iv, const uint8_t* srcPtr,
+ uint8_t* dstPtr, const std::vector<SubSample> subSamples,
+ size_t* bytesDecryptedOut);
+
+private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(Session);
+
+ const std::vector<uint8_t> mSessionId;
+ KeyMap mKeyMap;
+ Mutex mMapLock;
+};
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // CLEARKEY_SESSION_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/SessionLibrary.h b/drm/mediadrm/plugins/clearkey/hidl/include/SessionLibrary.h
new file mode 100644
index 0000000000..326a0c100d
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/SessionLibrary.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEARKEY_SESSION_LIBRARY_H_
+#define CLEARKEY_SESSION_LIBRARY_H_
+
+#include <utils/RefBase.h>
+#include <utils/Mutex.h>
+
+#include "ClearKeyTypes.h"
+#include "Session.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::sp;
+
+class SessionLibrary : public RefBase {
+public:
+ static SessionLibrary* get();
+
+ sp<Session> createSession();
+
+ sp<Session> findSession(
+ const std::vector<uint8_t>& sessionId);
+
+ void destroySession(const sp<Session>& session);
+
+ size_t numOpenSessions() const { return mSessions.size(); }
+
+private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(SessionLibrary);
+
+ SessionLibrary() : mNextSessionId(1) {}
+
+ static Mutex sSingletonLock;
+ static SessionLibrary* sSingleton;
+
+ Mutex mSessionsLock;
+ uint32_t mNextSessionId;
+ std::map<std::vector<uint8_t>, sp<Session> > mSessions;
+};
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // CLEARKEY_SESSION_LIBRARY_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/TypeConvert.h b/drm/mediadrm/plugins/clearkey/hidl/include/TypeConvert.h
new file mode 100644
index 0000000000..cc06329b84
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/TypeConvert.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEARKEY_ANDROID_HARDWARE_DRM_V1_1_TYPECONVERT
+#define CLEARKEY_ANDROID_HARDWARE_DRM_V1_1_TYPECONVERT
+
+#include <vector>
+
+#include <android/hardware/drm/1.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_vec;
+
+template<typename T> const hidl_vec<T> toHidlVec(const std::vector<T> &vec) {
+ hidl_vec<T> hVec;
+ hVec.setToExternal(const_cast<T *>(vec.data()), vec.size());
+ return hVec;
+}
+
+template<typename T> hidl_vec<T> toHidlVec(std::vector<T> &vec) {
+ hidl_vec<T> hVec;
+ hVec.setToExternal(vec.data(), vec.size());
+ return hVec;
+}
+
+template<typename T> const std::vector<T> toVector(const hidl_vec<T> &hVec) {
+ std::vector<T> vec;
+ vec.assign(hVec.data(), hVec.data() + hVec.size());
+ return *const_cast<const std::vector<T> *>(&vec);
+}
+
+template<typename T> std::vector<T> toVector(hidl_vec<T> &hVec) {
+ std::vector<T> vec;
+ vec.assign(hVec.data(), hVec.data() + hVec.size());
+ return vec;
+}
+
+template<typename T, size_t SIZE> const std::vector<T> toVector(
+ const hidl_array<T, SIZE> &hArray) {
+ std::vector<T> vec;
+ vec.assign(hArray.data(), hArray.data() + hArray.size());
+ return vec;
+}
+
+template<typename T, size_t SIZE> std::vector<T> toVector(
+ hidl_array<T, SIZE> &hArray) {
+ std::vector<T> vec;
+ vec.assign(hArray.data(), hArray.data() + hArray.size());
+ return vec;
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // CLEARKEY_ANDROID_HARDWARE_DRM_V1_1_TYPECONVERT
diff --git a/drm/mediadrm/plugins/clearkey/hidl/service.cpp b/drm/mediadrm/plugins/clearkey/hidl/service.cpp
new file mode 100644
index 0000000000..6a97b720d2
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/service.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "android.hardware.drm@1.1-service.clearkey"
+
+#include <CryptoFactory.h>
+#include <DrmFactory.h>
+
+#include <android-base/logging.h>
+#include <binder/ProcessState.h>
+#include <hidl/HidlTransportSupport.h>
+
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::sp;
+
+using android::hardware::drm::V1_1::ICryptoFactory;
+using android::hardware::drm::V1_1::IDrmFactory;
+using android::hardware::drm::V1_1::clearkey::CryptoFactory;
+using android::hardware::drm::V1_1::clearkey::DrmFactory;
+
+
+int main(int /* argc */, char** /* argv */) {
+ ALOGD("android.hardware.drm@1.1-service.clearkey starting...");
+
+ // The DRM HAL may communicate to other vendor components via
+ // /dev/vndbinder
+ android::ProcessState::initWithDriver("/dev/vndbinder");
+
+ sp<IDrmFactory> drmFactory = new DrmFactory;
+ sp<ICryptoFactory> cryptoFactory = new CryptoFactory;
+
+ configureRpcThreadpool(8, true /* callerWillJoin */);
+
+ // Setup hwbinder service
+ CHECK_EQ(drmFactory->registerAsService("clearkey"), android::NO_ERROR)
+ << "Failed to register Clearkey Factory HAL";
+ CHECK_EQ(cryptoFactory->registerAsService("clearkey"), android::NO_ERROR)
+ << "Failed to register Clearkey Crypto HAL";
+
+ joinRpcThreadpool();
+}
diff --git a/drm/mediadrm/plugins/mock/Android.bp b/drm/mediadrm/plugins/mock/Android.bp
index abd18840f3..dd2ad7b454 100644
--- a/drm/mediadrm/plugins/mock/Android.bp
+++ b/drm/mediadrm/plugins/mock/Android.bp
@@ -32,5 +32,7 @@ cc_library_shared {
cflags: [
// Set the following flag to enable the decryption passthru flow
//"-DENABLE_PASSTHRU_DECRYPTION",
+ "-Wall",
+ "-Werror",
],
}