From e8078cdba9efd8cca8e82df30b5d0d06faa6b557 Mon Sep 17 00:00:00 2001 From: Thomas Guillem Date: Wed, 11 Feb 2015 12:03:50 +0100 Subject: [PATCH] fix android7 crash android7 doesn't have NewWeakGlobalRef, use a compat function for this API and before. --- libvlc/jni/java_event_thread.c | 27 +++++++--- libvlc/jni/java_event_thread.h | 3 +- libvlc/jni/libvlcjni-vlcobject.c | 29 ++++++++--- libvlc/jni/libvlcjni.c | 51 ++++++++++++++----- libvlc/jni/utils.h | 3 ++ libvlc/src/org/videolan/libvlc/VLCObject.java | 12 +++++ 6 files changed, 99 insertions(+), 26 deletions(-) diff --git a/libvlc/jni/java_event_thread.c b/libvlc/jni/java_event_thread.c index dc42de3b3..83021c33b 100644 --- a/libvlc/jni/java_event_thread.c +++ b/libvlc/jni/java_event_thread.c @@ -48,7 +48,8 @@ struct java_event_thread { pthread_cond_t cond; pthread_t thread; EVENT_QUEUE queue; - jweak jobj; + jweak jweak; + jobject jweakCompat; }; static void * @@ -83,9 +84,15 @@ JavaEventThread_thread(void *data) pthread_mutex_unlock(&p_java_event_thread->lock); - (*env)->CallVoidMethod(env, p_java_event_thread->jobj, - fields.VLCObject.dispatchEventFromNativeID, - p_jevent->type, p_jevent->arg1, p_jevent->arg2); + if (p_java_event_thread->jweak) + (*env)->CallVoidMethod(env, p_java_event_thread->jweak, + fields.VLCObject.dispatchEventFromNativeID, + p_jevent->type, p_jevent->arg1, p_jevent->arg2); + else + (*env)->CallStaticVoidMethod(env, fields.VLCObject.clazz, + fields.VLCObject.dispatchEventFromWeakNativeID, + p_java_event_thread->jweakCompat, + p_jevent->type, p_jevent->arg1, p_jevent->arg2); pthread_mutex_lock(&p_java_event_thread->lock); @@ -112,9 +119,14 @@ end: } java_event_thread * -JavaEventThread_create(jweak jobj, bool b_sync) +JavaEventThread_create(jweak jweak, jobject jweakCompat, bool b_sync) { - java_event_thread *p_java_event_thread = calloc(1, sizeof(java_event_thread)); + java_event_thread *p_java_event_thread; + + if (!jweak && !jweakCompat) + return NULL; + + p_java_event_thread = calloc(1, sizeof(java_event_thread)); if (!p_java_event_thread) return NULL; @@ -122,7 +134,8 @@ JavaEventThread_create(jweak jobj, bool b_sync) pthread_cond_init(&p_java_event_thread->cond, NULL); TAILQ_INIT(&p_java_event_thread->queue); - p_java_event_thread->jobj = jobj; + p_java_event_thread->jweak = jweak; + p_java_event_thread->jweakCompat = jweakCompat; p_java_event_thread->b_run = true; p_java_event_thread->b_sync = b_sync; pthread_create(&p_java_event_thread->thread, NULL, diff --git a/libvlc/jni/java_event_thread.h b/libvlc/jni/java_event_thread.h index 6562ac7c2..0cb4817b7 100644 --- a/libvlc/jni/java_event_thread.h +++ b/libvlc/jni/java_event_thread.h @@ -37,7 +37,8 @@ struct java_event /* if b_sync is true, calls to JavaEventThread_add will return only when events * are handled by Java Side */ -java_event_thread *JavaEventThread_create(jweak jobj, bool b_sync); +java_event_thread *JavaEventThread_create(jweak jweak, jobject jweakCompat, + bool b_sync); void JavaEventThread_destroy(java_event_thread *p_java_event_thread); int JavaEventThread_add(java_event_thread *p_java_event_thread, java_event *p_java_event); diff --git a/libvlc/jni/libvlcjni-vlcobject.c b/libvlc/jni/libvlcjni-vlcobject.c index d67a94c07..46b9b8925 100644 --- a/libvlc/jni/libvlcjni-vlcobject.c +++ b/libvlc/jni/libvlcjni-vlcobject.c @@ -27,7 +27,8 @@ struct vlcjni_object_owner { - jweak thiz; + jweak weak; + jobject weakCompat; libvlc_event_manager_t *p_event_manager; const int *p_events; @@ -73,8 +74,18 @@ VLCJniObject_newFromLibVlc(JNIEnv *env, jobject thiz, p_obj->p_libvlc = p_libvlc; libvlc_retain(p_libvlc); - p_obj->p_owner->thiz = (*env)->NewWeakGlobalRef(env, thiz); - if (!p_obj->p_owner->thiz) + if (fields.VLCObject.getWeakReferenceID) + { + jobject weakCompat = (*env)->CallObjectMethod(env, thiz, + fields.VLCObject.getWeakReferenceID); + if (weakCompat) + { + p_obj->p_owner->weakCompat = (*env)->NewGlobalRef(env, weakCompat); + (*env)->DeleteLocalRef(env, weakCompat); + } + } else + p_obj->p_owner->weak = (*env)->NewWeakGlobalRef(env, thiz); + if (!p_obj->p_owner->weak && !p_obj->p_owner->weakCompat) goto error; VLCJniObject_setInstance(env, thiz, p_obj); @@ -104,8 +115,13 @@ VLCJniObject_release(JNIEnv *env, jobject thiz, vlcjni_object *p_obj) if (p_obj->p_libvlc) libvlc_release(p_obj->p_libvlc); - if (p_obj->p_owner && p_obj->p_owner->thiz) - (*env)->DeleteWeakGlobalRef(env, p_obj->p_owner->thiz); + if (p_obj->p_owner) + { + if (p_obj->p_owner->weak) + (*env)->DeleteWeakGlobalRef(env, p_obj->p_owner->weak); + else if (p_obj->p_owner->weakCompat) + (*env)->DeleteGlobalRef(env, p_obj->p_owner->weakCompat); + } free(p_obj->p_owner); free(p_obj); @@ -128,7 +144,8 @@ VLCJniObject_eventCallback(const libvlc_event_t *ev, void *data) if (!p_obj->p_owner->p_java_event_thread) { p_obj->p_owner->p_java_event_thread = - JavaEventThread_create(p_obj->p_owner->thiz, true); + JavaEventThread_create(p_obj->p_owner->weak, + p_obj->p_owner->weakCompat, true); if (!p_obj->p_owner->p_java_event_thread) return; } diff --git a/libvlc/jni/libvlcjni.c b/libvlc/jni/libvlcjni.c index 52ff72653..083162b34 100644 --- a/libvlc/jni/libvlcjni.c +++ b/libvlc/jni/libvlcjni.c @@ -224,16 +224,18 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) pthread_mutex_init(&vout_android_lock, NULL); pthread_cond_init(&vout_android_surf_attached, NULL); -#define GET_CLASS(clazz, str) do { \ +#define GET_CLASS(clazz, str, b_globlal) do { \ (clazz) = (*env)->FindClass(env, (str)); \ if (!(clazz)) { \ LOGE("FindClass(%s) failed", (str)); \ return -1; \ } \ - (clazz) = (jclass) (*env)->NewGlobalRef(env, (clazz)); \ - if (!(clazz)) { \ - LOGE("NewGlobalRef(%s) failed", (str)); \ - return -1; \ + if (b_globlal) { \ + (clazz) = (jclass) (*env)->NewGlobalRef(env, (clazz)); \ + if (!(clazz)) { \ + LOGE("NewGlobalRef(%s) failed", (str)); \ + return -1; \ + } \ } \ } while (0) @@ -245,20 +247,28 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) } \ } while (0) + jclass Version_clazz; + jfieldID SDK_INT_fieldID; + + GET_CLASS(Version_clazz, "android/os/Build$VERSION", false); + GET_ID(GetStaticFieldID, SDK_INT_fieldID, Version_clazz, "SDK_INT", "I"); + fields.SDK_INT = (*env)->GetStaticIntField(env, Version_clazz, + SDK_INT_fieldID); + GET_CLASS(fields.IllegalStateException.clazz, - "java/lang/IllegalStateException"); + "java/lang/IllegalStateException", true); GET_CLASS(fields.IllegalArgumentException.clazz, - "java/lang/IllegalArgumentException"); + "java/lang/IllegalArgumentException", true); GET_CLASS(fields.String.clazz, - "java/lang/String"); + "java/lang/String", true); GET_CLASS(fields.LibVLC.clazz, - "org/videolan/libvlc/LibVLC"); + "org/videolan/libvlc/LibVLC", true); GET_CLASS(fields.VLCObject.clazz, - "org/videolan/libvlc/VLCObject"); + "org/videolan/libvlc/VLCObject", true); GET_CLASS(fields.Media.clazz, - "org/videolan/libvlc/Media"); + "org/videolan/libvlc/Media", true); GET_CLASS(fields.Media.Track.clazz, - "org/videolan/libvlc/Media$Track"); + "org/videolan/libvlc/Media$Track", true); GET_ID(GetStaticMethodID, fields.LibVLC.onNativeCrashID, @@ -275,6 +285,23 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) fields.VLCObject.clazz, "dispatchEventFromNative", "(IJJ)V"); + if (fields.SDK_INT <= 7) + { + LOGE("fields.SDK_INT is less than 7: using compat WeakReference"); + GET_ID(GetMethodID, + fields.VLCObject.getWeakReferenceID, + fields.VLCObject.clazz, + "getWeakReference", "()Ljava/lang/Object;"); + GET_ID(GetStaticMethodID, + fields.VLCObject.dispatchEventFromWeakNativeID, + fields.VLCObject.clazz, + "dispatchEventFromWeakNative", "(Ljava/lang/Object;IJJ)V"); + } else + { + fields.VLCObject.getWeakReferenceID = NULL; + fields.VLCObject.dispatchEventFromWeakNativeID = NULL; + } + GET_ID(GetStaticMethodID, fields.Media.createAudioTrackFromNativeID, fields.Media.clazz, diff --git a/libvlc/jni/utils.h b/libvlc/jni/utils.h index 332f9afbf..393f2c516 100644 --- a/libvlc/jni/utils.h +++ b/libvlc/jni/utils.h @@ -26,6 +26,7 @@ #include struct fields { + jint SDK_INT; struct { jclass clazz; } IllegalStateException; @@ -43,6 +44,8 @@ struct fields { jclass clazz; jfieldID mInstanceID; jmethodID dispatchEventFromNativeID; + jmethodID getWeakReferenceID; + jmethodID dispatchEventFromWeakNativeID; } VLCObject; struct { struct { diff --git a/libvlc/src/org/videolan/libvlc/VLCObject.java b/libvlc/src/org/videolan/libvlc/VLCObject.java index 664d02c5d..50fded241 100644 --- a/libvlc/src/org/videolan/libvlc/VLCObject.java +++ b/libvlc/src/org/videolan/libvlc/VLCObject.java @@ -23,6 +23,8 @@ package org.videolan.libvlc; import android.os.Handler; import android.os.Looper; +import java.lang.ref.WeakReference; + public abstract class VLCObject { private final static String TAG = "LibVLC/VlcObject"; @@ -215,4 +217,14 @@ public abstract class VLCObject { mHandler.post(new EventRunnable(mEventListener, event)); } private final native void nativeDetachEvents(); + + /* used only before API 7: substitute for NewWeakGlobalRef */ + private Object getWeakReference() { + return new WeakReference(this); + } + private static void dispatchEventFromWeakNative(Object weak, int eventType, long arg1, long arg2) { + VLCObject obj = ((WeakReference)weak).get(); + if (obj != null) + obj.dispatchEventFromNative(eventType, arg1, arg2); + } } -- GitLab