diff options
author | Sven Gothel <[email protected]> | 2020-06-27 14:49:38 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-06-27 14:49:38 +0200 |
commit | 83e0c7f75b4206701c1b9c62ebd4282f50f92a31 (patch) | |
tree | bb1ff53fd21564de75a7387451811fdade45961f /java | |
parent | 406c56e2ebe96358ffd6000b033e0f99f87c66ac (diff) |
Notify DBTNativeDownlink when its native JavaUplink -> JavaGlobalObj counterpart gets destructed
DBTNativeDownlink.notifyDeleted() gets called from native destructor,
so isValid and nativeInstance can be set accordingly.
This resolves a periodic crash when GATTHandler flushes it's GATTServices and linked resources.
Here the DBTGATTService.java's DBTNativeDownlink still holds the native instance handle
and as it gets finalized after the native object, accessing it post mortem causes a SIGSEGV.
Diffstat (limited to 'java')
-rw-r--r-- | java/direct_bt/tinyb/DBTNativeDownlink.java | 14 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTDevice.cxx | 1 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTManager.cxx | 2 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTNativeDownlink.cxx | 22 | ||||
-rw-r--r-- | java/jni/direct_bt/helper_dbt.cxx | 11 | ||||
-rw-r--r-- | java/jni/direct_bt/helper_dbt.hpp | 7 |
6 files changed, 49 insertions, 8 deletions
diff --git a/java/direct_bt/tinyb/DBTNativeDownlink.java b/java/direct_bt/tinyb/DBTNativeDownlink.java index 5e4e3a71..b0b87057 100644 --- a/java/direct_bt/tinyb/DBTNativeDownlink.java +++ b/java/direct_bt/tinyb/DBTNativeDownlink.java @@ -64,12 +64,22 @@ public abstract class DBTNativeDownlink return; } isValid = false; - clearNativeJavaObject(nativeInstance); + deleteNativeJavaObject(nativeInstance); deleteImpl(); nativeInstance = 0; } /** + * Called from native JavaUplink dtor -> JavaGlobalObj dtor, + * i.e. native instance destructed in native land. + */ + private synchronized void notifyDeleted() { + // System.err.println("***** notifyDeleted: "+getClass().getSimpleName()+": valid "+isValid+" -> false, handle 0x"+Long.toHexString(nativeInstance)+" -> null"); + isValid = false; + nativeInstance = 0; + } + + /** * Deletes the native instance. * <p> * Called via {@link #delete()} and at this point this java reference @@ -79,5 +89,5 @@ public abstract class DBTNativeDownlink protected abstract void deleteImpl(); private native void initNativeJavaObject(final long nativeInstance); - private native void clearNativeJavaObject(final long nativeInstance); + private native void deleteNativeJavaObject(final long nativeInstance); } diff --git a/java/jni/direct_bt/DBTDevice.cxx b/java/jni/direct_bt/DBTDevice.cxx index 958fdba2..0a75b77c 100644 --- a/java/jni/direct_bt/DBTDevice.cxx +++ b/java/jni/direct_bt/DBTDevice.cxx @@ -252,6 +252,7 @@ void Java_direct_1bt_tinyb_DBTDevice_deleteImpl(JNIEnv *env, jobject obj) DBTDevice *device = getInstance<DBTDevice>(env, obj); device->remove(); // No delete: DBTDevice instance owned by DBTAdapter + // However, device->remove() might issue destruction } catch(...) { rethrow_and_raise_java_exception(env); } diff --git a/java/jni/direct_bt/DBTManager.cxx b/java/jni/direct_bt/DBTManager.cxx index 58478f3e..560a0f92 100644 --- a/java/jni/direct_bt/DBTManager.cxx +++ b/java/jni/direct_bt/DBTManager.cxx @@ -45,7 +45,7 @@ void Java_direct_1bt_tinyb_DBTManager_initImpl(JNIEnv *env, jobject obj, jboolea DBTManager *manager = &DBTManager::get(BTMode::BT_MODE_LE); // special: static singleton setInstance<DBTManager>(env, obj, manager); java_exception_check_and_throw(env, E_FILE_LINE); - manager->setJavaObject( std::shared_ptr<JavaAnonObj>( new JavaGlobalObj(obj) ) ); + manager->setJavaObject( std::shared_ptr<JavaAnonObj>( new JavaGlobalObj(obj, nullptr) ) ); JavaGlobalObj::check(manager->getJavaObject(), E_FILE_LINE); DBG_PRINT("Java_direct_1bt_tinyb_DBTManager_init: Manager %s", manager->toString().c_str()); } catch(...) { diff --git a/java/jni/direct_bt/DBTNativeDownlink.cxx b/java/jni/direct_bt/DBTNativeDownlink.cxx index fdfacf5e..77afbd7f 100644 --- a/java/jni/direct_bt/DBTNativeDownlink.cxx +++ b/java/jni/direct_bt/DBTNativeDownlink.cxx @@ -40,7 +40,20 @@ void Java_direct_1bt_tinyb_DBTNativeDownlink_initNativeJavaObject(JNIEnv *env, j { try { JavaUplink *javaUplink = castInstance<JavaUplink>(nativeInstance); - std::shared_ptr<JavaGlobalObj> jobjRef( new JavaGlobalObj(obj) ); + if( nullptr == javaUplink ) { + throw InternalError("NativeInstance JavaUplink is NULL", E_FILE_LINE); + } + jclass javaClazz = search_class(env, obj); + java_exception_check_and_throw(env, E_FILE_LINE); + if( nullptr == javaClazz ) { + throw InternalError("DBTNativeDownlink class not found", E_FILE_LINE); + } + jmethodID mNotifyDeleted = search_method(env, javaClazz, "notifyDeleted", "()V", false); + java_exception_check_and_throw(env, E_FILE_LINE); + if( nullptr == mNotifyDeleted ) { + throw InternalError("DBTNativeDownlink class has no notifyDeleted() method, for "+javaUplink->toString(), E_FILE_LINE); + } + std::shared_ptr<JavaGlobalObj> jobjRef( new JavaGlobalObj(obj, mNotifyDeleted) ); javaUplink->setJavaObject( jobjRef ); JavaGlobalObj::check(javaUplink->getJavaObject(), E_FILE_LINE); DBG_PRINT("Java_direct_1bt_tinyb_DBTNativeDownlink_initNativeJavaObject %p -> %s", javaUplink, javaUplink->toString().c_str()); @@ -49,12 +62,15 @@ void Java_direct_1bt_tinyb_DBTNativeDownlink_initNativeJavaObject(JNIEnv *env, j } } -void Java_direct_1bt_tinyb_DBTNativeDownlink_clearNativeJavaObject(JNIEnv *env, jobject obj, jlong nativeInstance) +void Java_direct_1bt_tinyb_DBTNativeDownlink_deleteNativeJavaObject(JNIEnv *env, jobject obj, jlong nativeInstance) { (void)obj; try { JavaUplink *javaUplink = castInstance<JavaUplink>(nativeInstance); - DBG_PRINT("Java_direct_1bt_tinyb_DBTNativeDownlink_clearNativeJavaObject %p -> %s", javaUplink, javaUplink->toString().c_str()); + if( nullptr == javaUplink ) { + throw InternalError("NativeInstance JavaUplink is NULL", E_FILE_LINE); + } + DBG_PRINT("Java_direct_1bt_tinyb_DBTNativeDownlink_deleteNativeJavaObject %p -> %s", javaUplink, javaUplink->toString().c_str()); javaUplink->setJavaObject(nullptr); } catch(...) { rethrow_and_raise_java_exception(env); diff --git a/java/jni/direct_bt/helper_dbt.cxx b/java/jni/direct_bt/helper_dbt.cxx index b1690edf..7c0920db 100644 --- a/java/jni/direct_bt/helper_dbt.cxx +++ b/java/jni/direct_bt/helper_dbt.cxx @@ -67,3 +67,14 @@ jstring direct_bt::fromBDAddressTypeToJavaAddressType(JNIEnv *env, BDAddressType return from_string_to_jstring(env, jStringEmpty); } } + +JavaGlobalObj::~JavaGlobalObj() { + jobject obj = javaObjectRef.getObject(); + if( nullptr == obj || nullptr == mNotifyDeleted ) { + return; + } + JNIEnv *env = *jni_env; + env->CallVoidMethod(obj, mNotifyDeleted); + java_exception_check_and_throw(env, E_FILE_LINE); +} + diff --git a/java/jni/direct_bt/helper_dbt.hpp b/java/jni/direct_bt/helper_dbt.hpp index 40e2c609..d71104e7 100644 --- a/java/jni/direct_bt/helper_dbt.hpp +++ b/java/jni/direct_bt/helper_dbt.hpp @@ -59,6 +59,7 @@ namespace direct_bt { class JavaGlobalObj : public JavaAnonObj { private: JNIGlobalRef javaObjectRef; + jmethodID mNotifyDeleted; public: static inline void check(const std::shared_ptr<JavaAnonObj> & shref, const char* file, int line) { @@ -80,13 +81,16 @@ namespace direct_bt { } return true; } - JavaGlobalObj(jobject obj) : javaObjectRef(obj) { } + JavaGlobalObj(jobject obj, jmethodID mNotifyDeleted) + : javaObjectRef(obj), mNotifyDeleted(mNotifyDeleted) { } JavaGlobalObj(const JavaGlobalObj &o) noexcept = default; JavaGlobalObj(JavaGlobalObj &&o) noexcept = default; JavaGlobalObj& operator=(const JavaGlobalObj &o) noexcept = default; JavaGlobalObj& operator=(JavaGlobalObj &&o) noexcept = default; + virtual ~JavaGlobalObj(); + std::string toString() const override { const uint64_t ref = (uint64_t)(void*)javaObjectRef.getObject(); return "JavaGlobalObj["+uint64HexString(ref, true)+"]"; @@ -113,7 +117,6 @@ namespace direct_bt { } }; - jclass search_class(JNIEnv *env, JavaUplink &object); template <typename T> |