Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 17524dc0 authored by James Dong's avatar James Dong
Browse files

Clean up JNI code

o Move the Set/Map/Iterator calls from JNI to Java
o The JNI function receives arrays instead of Maps
o Removed Set/Iterator calls from the Java code as suggested

Change-Id: I34068bf24b61abaf2833dad1f65abc733ed760dd
parent 588f280f
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -68,7 +68,21 @@ public class MediaMetadataRetriever
     * @param headers the headers to be sent together with the request for the data
     * @throws IllegalArgumentException If the URI is invalid.
     */
    public native void setDataSource(String uri, Map<String, String> headers)
    public void setDataSource(String uri,  Map<String, String> headers)
            throws IllegalArgumentException {
        int i = 0;
        String[] keys = new String[headers.size()];
        String[] values = new String[headers.size()];
        for (Map.Entry<String, String> entry: headers.entrySet()) {
            keys[i] = entry.getKey();
            values[i] = entry.getValue();
            ++i;
        }
        _setDataSource(uri, keys, values);
    }

    private native void _setDataSource(
        String uri, String[] keys, String[] values)
        throws IllegalArgumentException;

    /**
+17 −2
Original line number Diff line number Diff line
@@ -799,7 +799,22 @@ public class MediaPlayer
     * @throws IllegalStateException if it is called in an invalid state
     * @hide pending API council
     */
    public native void setDataSource(String path,  Map<String, String> headers)
    public void setDataSource(String path, Map<String, String> headers)
            throws IOException, IllegalArgumentException, IllegalStateException
    {
        int i = 0;
        String[] keys = new String[headers.size()];
        String[] values = new String[headers.size()];
        for (Map.Entry<String, String> entry: headers.entrySet()) {
            keys[i] = entry.getKey();
            values[i] = entry.getValue();
            ++i;
        }
        _setDataSource(path, keys, values);
    }

    private native void _setDataSource(
        String path, String[] keys, String[] values)
        throws IOException, IllegalArgumentException, IllegalStateException;

    /**
+36 −93
Original line number Diff line number Diff line
@@ -79,7 +79,9 @@ static void setRetriever(JNIEnv* env, jobject thiz, int retriever)

static void
android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
        JNIEnv *env, jobject thiz, jstring path, jobject headers) {
        JNIEnv *env, jobject thiz, jstring path,
        jobjectArray keys, jobjectArray values) {

    LOGV("setDataSource");
    MediaMetadataRetriever* retriever = getRetriever(env, thiz);
    if (retriever == 0) {
@@ -103,10 +105,17 @@ android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
    }

    String8 pathStr(tmp);

    env->ReleaseStringUTFChars(path, tmp);
    tmp = NULL;

    int nKeyValuePairs = env->GetArrayLength(keys);
    if (nKeyValuePairs != env->GetArrayLength(values)) {
        LOGE("keys and values have different length: %d <--> %d",
            nKeyValuePairs, env->GetArrayLength(values));
        jniThrowException(
                env, "java/lang/IllegalArgumentException", NULL);
        return;
    }
    // Don't let somebody trick us in to reading some random block of memory
    if (strncmp("mem://", pathStr.string(), 6) == 0) {
        jniThrowException(
@@ -114,110 +123,38 @@ android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
        return;
    }

    // headers is a Map<String, String>.
    // We build a similar KeyedVector out of it.
    KeyedVector<String8, String8> headersVector;
    if (headers) {
        // Get the Map's entry Set.
        jclass mapClass = env->FindClass("java/util/Map");
        if (mapClass == NULL) {
            return;
        }

        jmethodID entrySet =
            env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
        if (entrySet == NULL) {
            return;
        }

        jobject set = env->CallObjectMethod(headers, entrySet);
        if (set == NULL) {
            return;
        }

        // Obtain an iterator over the Set
        jclass setClass = env->FindClass("java/util/Set");
        if (setClass == NULL) {
            return;
        }

        jmethodID iterator =
            env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
        if (iterator == NULL) {
            return;
        }

        jobject iter = env->CallObjectMethod(set, iterator);
        if (iter == NULL) {
            return;
        }

        // Get the Iterator method IDs
        jclass iteratorClass = env->FindClass("java/util/Iterator");
        if (iteratorClass == NULL) {
            return;
        }
        jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
        if (hasNext == NULL) {
            return;
        }

        jmethodID next =
            env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
        if (next == NULL) {
            return;
        }

        // Get the Entry class method IDs
        jclass entryClass = env->FindClass("java/util/Map$Entry");
        if (entryClass == NULL) {
            return;
        }

        jmethodID getKey =
            env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
        if (getKey == NULL) {
            return;
        }

        jmethodID getValue =
            env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
        if (getValue == NULL) {
            return;
        }

        // Iterate over the entry Set
        while (env->CallBooleanMethod(iter, hasNext)) {
            jobject entry = env->CallObjectMethod(iter, next);
            jstring key = (jstring) env->CallObjectMethod(entry, getKey);
            jstring value = (jstring) env->CallObjectMethod(entry, getValue);
    for (int i = 0; i < nKeyValuePairs; ++i) {
        // No need to check on the ArrayIndexOutOfBoundsException, since
        // it won't happen here.
        jstring key = (jstring) env->GetObjectArrayElement(keys, i);
        jstring value = (jstring) env->GetObjectArrayElement(values, i);

        const char* keyStr = env->GetStringUTFChars(key, NULL);
            if (!keyStr) {  // Out of memory
        if (!keyStr) {  // OutOfMemoryError
            return;
        }

        const char* valueStr = env->GetStringUTFChars(value, NULL);
            if (!valueStr) {  // Out of memory
        if (!valueStr) {  // OutOfMemoryError
            env->ReleaseStringUTFChars(key, keyStr);
            return;
        }

        headersVector.add(String8(keyStr), String8(valueStr));

            env->DeleteLocalRef(entry);
        env->ReleaseStringUTFChars(key, keyStr);
            env->DeleteLocalRef(key);
        env->ReleaseStringUTFChars(value, valueStr);
        env->DeleteLocalRef(key);
        env->DeleteLocalRef(value);
        }

    }

    process_media_retriever_call(
            env,
            retriever->setDataSource(
                pathStr.string(), headers ? &headersVector : NULL),
                pathStr.string(), nKeyValuePairs > 0 ? &headersVector : NULL),

            "java/lang/RuntimeException",
            "setDataSource failed");
@@ -226,7 +163,7 @@ android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
static void android_media_MediaMetadataRetriever_setDataSource(
        JNIEnv *env, jobject thiz, jstring path) {
    android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
            env, thiz, path, NULL);
            env, thiz, path, NULL, NULL);
}

static void android_media_MediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
@@ -539,7 +476,13 @@ static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobje
// JNI mapping between Java methods and native methods
static JNINativeMethod nativeMethods[] = {
        {"setDataSource",   "(Ljava/lang/String;)V", (void *)android_media_MediaMetadataRetriever_setDataSource},
        {"setDataSource",   "(Ljava/lang/String;Ljava/util/Map;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders},

        {
            "_setDataSource",
            "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
            (void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders
        },

        {"setDataSource",   "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
        {"_getFrameAtTime", "(JI)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
        {"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata},
+37 −95
Original line number Diff line number Diff line
@@ -186,7 +186,9 @@ static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStat

static void
android_media_MediaPlayer_setDataSourceAndHeaders(
        JNIEnv *env, jobject thiz, jstring path, jobject headers) {
        JNIEnv *env, jobject thiz, jstring path,
        jobjectArray keys, jobjectArray values) {

    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -207,112 +209,46 @@ android_media_MediaPlayer_setDataSourceAndHeaders(
    env->ReleaseStringUTFChars(path, tmp);
    tmp = NULL;

    // headers is a Map<String, String>.
    // We build a similar KeyedVector out of it.
    KeyedVector<String8, String8> headersVector;
    if (headers) {
        // Get the Map's entry Set.
        jclass mapClass = env->FindClass("java/util/Map");
        if (mapClass == NULL) {
            return;
        }

        jmethodID entrySet =
            env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
        if (entrySet == NULL) {
            return;
        }

        jobject set = env->CallObjectMethod(headers, entrySet);
        if (set == NULL) {
            return;
        }

        // Obtain an iterator over the Set
        jclass setClass = env->FindClass("java/util/Set");
        if (setClass == NULL) {
            return;
        }

        jmethodID iterator =
            env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
        if (iterator == NULL) {
            return;
        }

        jobject iter = env->CallObjectMethod(set, iterator);
        if (iter == NULL) {
            return;
        }

        // Get the Iterator method IDs
        jclass iteratorClass = env->FindClass("java/util/Iterator");
        if (iteratorClass == NULL) {
            return;
        }

        jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
        if (hasNext == NULL) {
            return;
        }

        jmethodID next =
            env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
        if (next == NULL) {
            return;
        }

        // Get the Entry class method IDs
        jclass entryClass = env->FindClass("java/util/Map$Entry");
        if (entryClass == NULL) {
            return;
        }

        jmethodID getKey =
            env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
        if (getKey == NULL) {
            return;
        }

        jmethodID getValue =
            env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
        if (getValue == NULL) {
    int nKeyValuePairs = env->GetArrayLength(keys);
    if (nKeyValuePairs != env->GetArrayLength(values)) {
        LOGE("keys and values have different length: %d <-> %d",
            nKeyValuePairs, env->GetArrayLength(values));
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return;
    }

        // Iterate over the entry Set
        while (env->CallBooleanMethod(iter, hasNext)) {
            jobject entry = env->CallObjectMethod(iter, next);
            jstring key = (jstring) env->CallObjectMethod(entry, getKey);
            jstring value = (jstring) env->CallObjectMethod(entry, getValue);
    // We build a KeyedVector out of the key and val arrays
    KeyedVector<String8, String8> headersVector;
    for (int i = 0; i < nKeyValuePairs; ++i) {
        // No need to check ArrayIndexOutOfBoundsException, since we
        // know it won't happen here.
        jstring key = (jstring) env->GetObjectArrayElement(keys, i);
        jstring val = (jstring) env->GetObjectArrayElement(values, i);

        const char* keyStr = env->GetStringUTFChars(key, NULL);
            if (!keyStr) {  // Out of memory
        if (!keyStr) {  // OutOfMemoryError
            return;
        }

            const char* valueStr = env->GetStringUTFChars(value, NULL);
            if (!valueStr) {  // Out of memory
        const char* valueStr = env->GetStringUTFChars(val, NULL);
        if (!valueStr) {  // OutOfMemoryError
            env->ReleaseStringUTFChars(key, keyStr);
            return;
        }

        headersVector.add(String8(keyStr), String8(valueStr));

            env->DeleteLocalRef(entry);
        env->ReleaseStringUTFChars(key, keyStr);
        env->ReleaseStringUTFChars(val, valueStr);
        env->DeleteLocalRef(key);
            env->ReleaseStringUTFChars(value, valueStr);
            env->DeleteLocalRef(value);
        }

        env->DeleteLocalRef(val);
    }

    LOGV("setDataSource: path %s", pathStr);
    status_t opStatus =
        mp->setDataSource(
                pathStr,
                headers ? &headersVector : NULL);
                nKeyValuePairs > 0? &headersVector : NULL);

    process_media_player_call(
            env, thiz, opStatus, "java/io/IOException",
@@ -322,7 +258,7 @@ android_media_MediaPlayer_setDataSourceAndHeaders(
static void
android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)
{
    android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, 0);
    android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, NULL, NULL);
}

static void
@@ -851,7 +787,13 @@ android_media_MediaPlayer_getParameter(JNIEnv *env, jobject thiz, jint key, jobj

static JNINativeMethod gMethods[] = {
    {"setDataSource",       "(Ljava/lang/String;)V",            (void *)android_media_MediaPlayer_setDataSource},
    {"setDataSource",       "(Ljava/lang/String;Ljava/util/Map;)V",(void *)android_media_MediaPlayer_setDataSourceAndHeaders},

    {
        "_setDataSource",
        "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
        (void *)android_media_MediaPlayer_setDataSourceAndHeaders
    },

    {"setDataSource",       "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
    {"_setVideoSurfaceOrSurfaceTexture", "()V",                 (void *)android_media_MediaPlayer_setVideoSurfaceOrSurfaceTexture},
    {"prepare",             "()V",                              (void *)android_media_MediaPlayer_prepare},