[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