android_media_MediaCrypto.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. * Copyright 2012, The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. //#define LOG_NDEBUG 0
  17. #define LOG_TAG "MediaCrypto-JNI"
  18. #include <utils/Log.h>
  19. #include "android_media_MediaCrypto.h"
  20. #include "android_runtime/AndroidRuntime.h"
  21. #include "jni.h"
  22. #include <nativehelper/JNIHelp.h>
  23. #include <binder/IServiceManager.h>
  24. #include <cutils/properties.h>
  25. #include <media/stagefright/foundation/ADebug.h>
  26. #include <mediadrm/ICrypto.h>
  27. #include <mediadrm/IMediaDrmService.h>
  28. namespace android {
  29. struct fields_t {
  30. jfieldID context;
  31. };
  32. static fields_t gFields;
  33. static sp<JCrypto> getCrypto(JNIEnv *env, jobject thiz) {
  34. return (JCrypto *)env->GetLongField(thiz, gFields.context);
  35. }
  36. JCrypto::JCrypto(
  37. JNIEnv *env, jobject thiz,
  38. const uint8_t uuid[16], const void *initData, size_t initSize) {
  39. mObject = env->NewWeakGlobalRef(thiz);
  40. mCrypto = MakeCrypto(uuid, initData, initSize);
  41. }
  42. JCrypto::~JCrypto() {
  43. if (mCrypto != NULL) {
  44. mCrypto->destroyPlugin();
  45. }
  46. mCrypto.clear();
  47. JNIEnv *env = AndroidRuntime::getJNIEnv();
  48. env->DeleteWeakGlobalRef(mObject);
  49. mObject = NULL;
  50. }
  51. // static
  52. sp<ICrypto> JCrypto::MakeCrypto() {
  53. sp<IServiceManager> sm = initdefaultServiceManager();
  54. sp<IBinder> binder = sm->getService(String16("media.drm"));
  55. sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
  56. if (service == NULL) {
  57. return NULL;
  58. }
  59. sp<ICrypto> crypto = service->makeCrypto();
  60. if (crypto == NULL || (crypto->initCheck() != OK && crypto->initCheck() != NO_INIT)) {
  61. return NULL;
  62. }
  63. return crypto;
  64. }
  65. // static
  66. sp<ICrypto> JCrypto::MakeCrypto(
  67. const uint8_t uuid[16], const void *initData, size_t initSize) {
  68. sp<ICrypto> crypto = MakeCrypto();
  69. if (crypto == NULL) {
  70. return NULL;
  71. }
  72. status_t err = crypto->createPlugin(uuid, initData, initSize);
  73. if (err != OK) {
  74. return NULL;
  75. }
  76. return crypto;
  77. }
  78. bool JCrypto::requiresSecureDecoderComponent(const char *mime) const {
  79. if (mCrypto == NULL) {
  80. return false;
  81. }
  82. return mCrypto->requiresSecureDecoderComponent(mime);
  83. }
  84. // static
  85. bool JCrypto::IsCryptoSchemeSupported(const uint8_t uuid[16]) {
  86. sp<ICrypto> crypto = MakeCrypto();
  87. if (crypto == NULL) {
  88. return false;
  89. }
  90. return crypto->isCryptoSchemeSupported(uuid);
  91. }
  92. status_t JCrypto::initCheck() const {
  93. return mCrypto == NULL ? NO_INIT : OK;
  94. }
  95. // static
  96. sp<ICrypto> JCrypto::GetCrypto(JNIEnv *env, jobject obj) {
  97. jclass clazz = env->FindClass("android/media/MediaCrypto");
  98. CHECK(clazz != NULL);
  99. if (!env->IsInstanceOf(obj, clazz)) {
  100. return NULL;
  101. }
  102. sp<JCrypto> jcrypto = getCrypto(env, obj);
  103. if (jcrypto == NULL) {
  104. return NULL;
  105. }
  106. return jcrypto->mCrypto;
  107. }
  108. // JNI conversion utilities
  109. static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
  110. Vector<uint8_t> vector;
  111. size_t length = env->GetArrayLength(byteArray);
  112. vector.insertAt((size_t)0, length);
  113. env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
  114. return vector;
  115. }
  116. } // namespace android
  117. using namespace android;
  118. static sp<JCrypto> setCrypto(
  119. JNIEnv *env, jobject thiz, const sp<JCrypto> &crypto) {
  120. sp<JCrypto> old = (JCrypto *)env->GetLongField(thiz, gFields.context);
  121. if (crypto != NULL) {
  122. crypto->incStrong(thiz);
  123. }
  124. if (old != NULL) {
  125. old->decStrong(thiz);
  126. }
  127. env->SetLongField(thiz, gFields.context, (jlong)crypto.get());
  128. return old;
  129. }
  130. static void android_media_MediaCrypto_release(JNIEnv *env, jobject thiz) {
  131. setCrypto(env, thiz, NULL);
  132. }
  133. static void android_media_MediaCrypto_native_init(JNIEnv *env) {
  134. jclass clazz = env->FindClass("android/media/MediaCrypto");
  135. CHECK(clazz != NULL);
  136. gFields.context = env->GetFieldID(clazz, "mNativeContext", "J");
  137. CHECK(gFields.context != NULL);
  138. }
  139. static void android_media_MediaCrypto_native_setup(
  140. JNIEnv *env, jobject thiz,
  141. jbyteArray uuidObj, jbyteArray initDataObj) {
  142. jsize uuidLength = env->GetArrayLength(uuidObj);
  143. if (uuidLength != 16) {
  144. jniThrowException(
  145. env,
  146. "java/lang/IllegalArgumentException",
  147. NULL);
  148. return;
  149. }
  150. jboolean isCopy;
  151. jbyte *uuid = env->GetByteArrayElements(uuidObj, &isCopy);
  152. jsize initDataLength = 0;
  153. jbyte *initData = NULL;
  154. if (initDataObj != NULL) {
  155. initDataLength = env->GetArrayLength(initDataObj);
  156. initData = env->GetByteArrayElements(initDataObj, &isCopy);
  157. }
  158. sp<JCrypto> crypto = new JCrypto(
  159. env, thiz, (const uint8_t *)uuid, initData, initDataLength);
  160. status_t err = crypto->initCheck();
  161. if (initDataObj != NULL) {
  162. env->ReleaseByteArrayElements(initDataObj, initData, 0);
  163. initData = NULL;
  164. }
  165. env->ReleaseByteArrayElements(uuidObj, uuid, 0);
  166. uuid = NULL;
  167. if (err != OK) {
  168. jniThrowException(
  169. env,
  170. "android/media/MediaCryptoException",
  171. "Failed to instantiate crypto object.");
  172. return;
  173. }
  174. setCrypto(env,thiz, crypto);
  175. }
  176. static void android_media_MediaCrypto_native_finalize(
  177. JNIEnv *env, jobject thiz) {
  178. android_media_MediaCrypto_release(env, thiz);
  179. }
  180. static jboolean android_media_MediaCrypto_isCryptoSchemeSupportedNative(
  181. JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj) {
  182. jsize uuidLength = env->GetArrayLength(uuidObj);
  183. if (uuidLength != 16) {
  184. jniThrowException(
  185. env,
  186. "java/lang/IllegalArgumentException",
  187. NULL);
  188. return JNI_FALSE;
  189. }
  190. jboolean isCopy;
  191. jbyte *uuid = env->GetByteArrayElements(uuidObj, &isCopy);
  192. bool result = JCrypto::IsCryptoSchemeSupported((const uint8_t *)uuid);
  193. env->ReleaseByteArrayElements(uuidObj, uuid, 0);
  194. uuid = NULL;
  195. return result ? JNI_TRUE : JNI_FALSE;
  196. }
  197. static jboolean android_media_MediaCrypto_requiresSecureDecoderComponent(
  198. JNIEnv *env, jobject thiz, jstring mimeObj) {
  199. if (mimeObj == NULL) {
  200. jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
  201. return JNI_FALSE;
  202. }
  203. sp<JCrypto> crypto = getCrypto(env, thiz);
  204. if (crypto == NULL) {
  205. jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
  206. return JNI_FALSE;
  207. }
  208. const char *mime = env->GetStringUTFChars(mimeObj, NULL);
  209. if (mime == NULL) {
  210. return JNI_FALSE;
  211. }
  212. bool result = crypto->requiresSecureDecoderComponent(mime);
  213. env->ReleaseStringUTFChars(mimeObj, mime);
  214. mime = NULL;
  215. return result ? JNI_TRUE : JNI_FALSE;
  216. }
  217. static void android_media_MediaCrypto_setMediaDrmSession(
  218. JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
  219. if (jsessionId == NULL) {
  220. jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
  221. return;
  222. }
  223. sp<ICrypto> crypto = JCrypto::GetCrypto(env, thiz);
  224. if (crypto == NULL) {
  225. jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
  226. return;
  227. }
  228. Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
  229. status_t err = crypto->setMediaDrmSession(sessionId);
  230. if (err != OK) {
  231. String8 msg("setMediaDrmSession failed");
  232. if (err == ERROR_DRM_SESSION_NOT_OPENED) {
  233. msg += ": session not opened";
  234. } else if (err == ERROR_UNSUPPORTED) {
  235. msg += ": not supported by this crypto scheme";
  236. } else if (err == NO_INIT) {
  237. msg += ": crypto plugin not initialized";
  238. } else {
  239. msg.appendFormat(": general failure (%d)", err);
  240. }
  241. jniThrowException(env, "android/media/MediaCryptoException", msg.string());
  242. }
  243. }
  244. static const JNINativeMethod gMethods[] = {
  245. { "release", "()V", (void *)android_media_MediaCrypto_release },
  246. { "native_init", "()V", (void *)android_media_MediaCrypto_native_init },
  247. { "native_setup", "([B[B)V",
  248. (void *)android_media_MediaCrypto_native_setup },
  249. { "native_finalize", "()V",
  250. (void *)android_media_MediaCrypto_native_finalize },
  251. { "isCryptoSchemeSupportedNative", "([B)Z",
  252. (void *)android_media_MediaCrypto_isCryptoSchemeSupportedNative },
  253. { "requiresSecureDecoderComponent", "(Ljava/lang/String;)Z",
  254. (void *)android_media_MediaCrypto_requiresSecureDecoderComponent },
  255. { "setMediaDrmSession", "([B)V",
  256. (void *)android_media_MediaCrypto_setMediaDrmSession },
  257. };
  258. int register_android_media_Crypto(JNIEnv *env) {
  259. return AndroidRuntime::registerNativeMethods(env,
  260. "android/media/MediaCrypto", gMethods, NELEM(gMethods));
  261. }