[Android] [PATCH] fix android7 crash

Thomas Guillem thomas at gllm.fr
Wed Feb 11 12:28:43 CET 2015


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 dc42de3..83021c3 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 6562ac7..0cb4817 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 d67a94c..46b9b89 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 52ff726..083162b 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 332f9af..393f2c5 100644
--- a/libvlc/jni/utils.h
+++ b/libvlc/jni/utils.h
@@ -26,6 +26,7 @@
 #include <vlc/libvlc_media_list.h>
 
 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 664d02c..50fded2 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<VLCObject>(this);
+    }
+    private static void dispatchEventFromWeakNative(Object weak, int eventType, long arg1, long arg2) {
+        VLCObject obj = ((WeakReference<VLCObject>)weak).get();
+        if (obj != null)
+            obj.dispatchEventFromNative(eventType, arg1, arg2);
+    }
 }
-- 
2.1.3



More information about the Android mailing list