aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2020-06-27 14:49:38 +0200
committerSven Gothel <[email protected]>2020-06-27 14:49:38 +0200
commit83e0c7f75b4206701c1b9c62ebd4282f50f92a31 (patch)
treebb1ff53fd21564de75a7387451811fdade45961f /java
parent406c56e2ebe96358ffd6000b033e0f99f87c66ac (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.java14
-rw-r--r--java/jni/direct_bt/DBTDevice.cxx1
-rw-r--r--java/jni/direct_bt/DBTManager.cxx2
-rw-r--r--java/jni/direct_bt/DBTNativeDownlink.cxx22
-rw-r--r--java/jni/direct_bt/helper_dbt.cxx11
-rw-r--r--java/jni/direct_bt/helper_dbt.hpp7
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>