1 /* 2 * Copyright 2017, 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 17 //#define LOG_NDEBUG 0 18 #define LOG_TAG "JDataSourceCallback-JNI" 19 #include <utils/Log.h> 20 21 #include "android_media_DataSourceCallback.h" 22 23 #include "log/log.h" 24 #include "jni.h" 25 #include <nativehelper/JNIHelp.h> 26 27 #include <drm/drm_framework_common.h> 28 #include <mediaplayer2/JavaVMHelper.h> 29 #include <media/stagefright/foundation/ADebug.h> 30 #include <nativehelper/ScopedLocalRef.h> 31 32 namespace android { 33 34 static const size_t kBufferSize = 64 * 1024; 35 36 JDataSourceCallback::JDataSourceCallback(JNIEnv* env, jobject source) 37 : mJavaObjStatus(OK), 38 mSizeIsCached(false), 39 mCachedSize(0) { 40 mDataSourceCallbackObj = env->NewGlobalRef(source); 41 CHECK(mDataSourceCallbackObj != NULL); 42 43 ScopedLocalRef<jclass> media2DataSourceClass(env, env->GetObjectClass(mDataSourceCallbackObj)); 44 CHECK(media2DataSourceClass.get() != NULL); 45 46 mReadAtMethod = env->GetMethodID(media2DataSourceClass.get(), "readAt", "(J[BII)I"); 47 CHECK(mReadAtMethod != NULL); 48 mGetSizeMethod = env->GetMethodID(media2DataSourceClass.get(), "getSize", "()J"); 49 CHECK(mGetSizeMethod != NULL); 50 mCloseMethod = env->GetMethodID(media2DataSourceClass.get(), "close", "()V"); 51 CHECK(mCloseMethod != NULL); 52 53 ScopedLocalRef<jbyteArray> tmp(env, env->NewByteArray(kBufferSize)); 54 mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get()); 55 CHECK(mByteArrayObj != NULL); 56 } 57 58 JDataSourceCallback::~JDataSourceCallback() { 59 JNIEnv* env = JavaVMHelper::getJNIEnv(); 60 env->DeleteGlobalRef(mDataSourceCallbackObj); 61 env->DeleteGlobalRef(mByteArrayObj); 62 } 63 64 status_t JDataSourceCallback::initCheck() const { 65 return OK; 66 } 67 68 ssize_t JDataSourceCallback::readAt(off64_t offset, void *data, size_t size) { 69 Mutex::Autolock lock(mLock); 70 71 if (mJavaObjStatus != OK) { 72 return -1; 73 } 74 if (size > kBufferSize) { 75 size = kBufferSize; 76 } 77 78 JNIEnv* env = JavaVMHelper::getJNIEnv(); 79 jint numread = env->CallIntMethod(mDataSourceCallbackObj, mReadAtMethod, 80 (jlong)offset, mByteArrayObj, (jint)0, (jint)size); 81 if (env->ExceptionCheck()) { 82 ALOGW("An exception occurred in readAt()"); 83 jniLogException(env, ANDROID_LOG_WARN, LOG_TAG); 84 env->ExceptionClear(); 85 mJavaObjStatus = UNKNOWN_ERROR; 86 return -1; 87 } 88 if (numread < 0) { 89 if (numread != -1) { 90 ALOGW("An error occurred in readAt()"); 91 mJavaObjStatus = UNKNOWN_ERROR; 92 return -1; 93 } else { 94 // numread == -1 indicates EOF 95 return 0; 96 } 97 } 98 if ((size_t)numread > size) { 99 ALOGE("readAt read too many bytes."); 100 mJavaObjStatus = UNKNOWN_ERROR; 101 return -1; 102 } 103 104 ALOGV("readAt %lld / %zu => %d.", (long long)offset, size, numread); 105 env->GetByteArrayRegion(mByteArrayObj, 0, numread, (jbyte*)data); 106 return numread; 107 } 108 109 status_t JDataSourceCallback::getSize(off64_t* size) { 110 Mutex::Autolock lock(mLock); 111 112 if (mJavaObjStatus != OK) { 113 return UNKNOWN_ERROR; 114 } 115 if (mSizeIsCached) { 116 *size = mCachedSize; 117 return OK; 118 } 119 120 JNIEnv* env = JavaVMHelper::getJNIEnv(); 121 *size = env->CallLongMethod(mDataSourceCallbackObj, mGetSizeMethod); 122 if (env->ExceptionCheck()) { 123 ALOGW("An exception occurred in getSize()"); 124 jniLogException(env, ANDROID_LOG_WARN, LOG_TAG); 125 env->ExceptionClear(); 126 // After returning an error, size shouldn't be used by callers. 127 *size = UNKNOWN_ERROR; 128 mJavaObjStatus = UNKNOWN_ERROR; 129 return UNKNOWN_ERROR; 130 } 131 132 // The minimum size should be -1, which indicates unknown size. 133 if (*size < 0) { 134 *size = -1; 135 } 136 137 mCachedSize = *size; 138 mSizeIsCached = true; 139 return OK; 140 } 141 142 void JDataSourceCallback::close() { 143 Mutex::Autolock lock(mLock); 144 145 JNIEnv* env = JavaVMHelper::getJNIEnv(); 146 env->CallVoidMethod(mDataSourceCallbackObj, mCloseMethod); 147 // The closed state is effectively the same as an error state. 148 mJavaObjStatus = UNKNOWN_ERROR; 149 } 150 151 String8 JDataSourceCallback::toString() { 152 return String8::format("JDataSourceCallback(pid %d, uid %d)", getpid(), getuid()); 153 } 154 155 String8 JDataSourceCallback::getMIMEType() const { 156 return String8("application/octet-stream"); 157 } 158 159 } // namespace android 160