aboutsummaryrefslogtreecommitdiffstats
path: root/java/jni/direct_bt/DBTAdapter.cxx
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2020-05-28 19:23:48 +0200
committerSven Gothel <[email protected]>2020-05-28 19:23:48 +0200
commita85b9cd5eff54558733770665d96f40f9562856d (patch)
tree0acc61708397cebeefaa0027b09ad55a39606c8a /java/jni/direct_bt/DBTAdapter.cxx
parent94588c93be703c1e9ccf57b6c41c32b788c6f8a2 (diff)
JNI Callback listener issued from a native thread must not mute exceptions (forward to java exception)
All JNI Callback listener which are issued from a native thread don't return to the JVM, but its native caller thread. Catching C++ exceptions and forwarding them to the JVM simply mutes the whole exception, as it will never get checked and processed. Therefor remove this 'exception muting' in the JNI AdapterStatusListener and GATTCharacteristicListener instances. Instead we decorate all listener/callback invocations with exception handling to properly report this 'user exception' and allow the native thread to continue! On the native side this has been completed for AdapterStatusListener, GATTCharacteristicListener and MgmtAdapterEventCallback. Hence all potential user exceptions covered in the native implementation.
Diffstat (limited to 'java/jni/direct_bt/DBTAdapter.cxx')
-rw-r--r--java/jni/direct_bt/DBTAdapter.cxx167
1 files changed, 65 insertions, 102 deletions
diff --git a/java/jni/direct_bt/DBTAdapter.cxx b/java/jni/direct_bt/DBTAdapter.cxx
index decfbd41..1ca9effa 100644
--- a/java/jni/direct_bt/DBTAdapter.cxx
+++ b/java/jni/direct_bt/DBTAdapter.cxx
@@ -193,129 +193,89 @@ class JNIAdapterStatusListener : public AdapterStatusListener {
void adapterSettingsChanged(DBTAdapter const &a, const AdapterSetting oldmask, const AdapterSetting newmask,
const AdapterSetting changedmask, const uint64_t timestamp) override {
JNIEnv *env = *jni_env;
- try {
- #ifdef VERBOSE_ON
- fprintf(stderr, "****** Native Adapter SETTINGS_CHANGED: %s -> %s, changed %s\n",
- direct_bt::adapterSettingsToString(oldmask).c_str(),
- direct_bt::adapterSettingsToString(newmask).c_str(),
- direct_bt::adapterSettingsToString(changedmask).c_str());
- fprintf(stderr, "Status DBTAdapter:\n");
- fprintf(stderr, "%s\n", a.toString().c_str());
- #endif
- (void)a;
- jobject adapterSettingOld = env->NewObject(adapterSettingsClazzRef->getClass(), adapterSettingsClazzCtor, (jint)oldmask);
- java_exception_check_and_throw(env, E_FILE_LINE);
- JNIGlobalRef::check(adapterSettingOld, E_FILE_LINE);
+ DBG_PRINT("****** JNI Adapter SETTINGS_CHANGED: %s -> %s, changed %s\n",
+ direct_bt::adapterSettingsToString(oldmask).c_str(),
+ direct_bt::adapterSettingsToString(newmask).c_str(),
+ direct_bt::adapterSettingsToString(changedmask).c_str());
+ (void)a;
+ jobject adapterSettingOld = env->NewObject(adapterSettingsClazzRef->getClass(), adapterSettingsClazzCtor, (jint)oldmask);
+ java_exception_check_and_throw(env, E_FILE_LINE);
+ JNIGlobalRef::check(adapterSettingOld, E_FILE_LINE);
- jobject adapterSettingNew = env->NewObject(adapterSettingsClazzRef->getClass(), adapterSettingsClazzCtor, (jint)newmask);
- java_exception_check_and_throw(env, E_FILE_LINE);
- JNIGlobalRef::check(adapterSettingNew, E_FILE_LINE);
+ jobject adapterSettingNew = env->NewObject(adapterSettingsClazzRef->getClass(), adapterSettingsClazzCtor, (jint)newmask);
+ java_exception_check_and_throw(env, E_FILE_LINE);
+ JNIGlobalRef::check(adapterSettingNew, E_FILE_LINE);
- jobject adapterSettingChanged = env->NewObject(adapterSettingsClazzRef->getClass(), adapterSettingsClazzCtor, (jint)changedmask);
- java_exception_check_and_throw(env, E_FILE_LINE);
- JNIGlobalRef::check(adapterSettingChanged, E_FILE_LINE);
+ jobject adapterSettingChanged = env->NewObject(adapterSettingsClazzRef->getClass(), adapterSettingsClazzCtor, (jint)changedmask);
+ java_exception_check_and_throw(env, E_FILE_LINE);
+ JNIGlobalRef::check(adapterSettingChanged, E_FILE_LINE);
- env->CallVoidMethod(listenerObjRef->getObject(), mAdapterSettingsChanged,
- JavaGlobalObj::GetObject(adapterObjRef), adapterSettingOld, adapterSettingNew, adapterSettingChanged, (jlong)timestamp);
- java_exception_check_and_throw(env, E_FILE_LINE);
- } catch(...) {
- rethrow_and_raise_java_exception(env);
- }
+ env->CallVoidMethod(listenerObjRef->getObject(), mAdapterSettingsChanged,
+ JavaGlobalObj::GetObject(adapterObjRef), adapterSettingOld, adapterSettingNew, adapterSettingChanged, (jlong)timestamp);
+ java_exception_check_and_throw(env, E_FILE_LINE);
}
void discoveringChanged(DBTAdapter const &a, const bool enabled, const bool keepAlive, const uint64_t timestamp) override {
JNIEnv *env = *jni_env;
- try {
- #ifdef VERBOSE_ON
- fprintf(stderr, "****** DBTAdapter Device DISCOVERING: enabled %d, keepAlive %d: %s\n", enabled, keepAlive, a.toString().c_str());
- fprintf(stderr, "Status DBTAdapter:\n");
- fprintf(stderr, "%s\n", device->getAdapter().toString().c_str());
- #endif
- (void)a;
- env->CallVoidMethod(listenerObjRef->getObject(), mDiscoveringChanged, JavaGlobalObj::GetObject(adapterObjRef),
- (jboolean)enabled, (jboolean)keepAlive, (jlong)timestamp);
- java_exception_check_and_throw(env, E_FILE_LINE);
- } catch(...) {
- rethrow_and_raise_java_exception(env);
- }
+ DBG_PRINT("****** JNI Adapter Device DISCOVERING: enabled %d, keepAlive %d: %s\n", enabled, keepAlive, a.toString().c_str());
+ (void)a;
+ env->CallVoidMethod(listenerObjRef->getObject(), mDiscoveringChanged, JavaGlobalObj::GetObject(adapterObjRef),
+ (jboolean)enabled, (jboolean)keepAlive, (jlong)timestamp);
+ java_exception_check_and_throw(env, E_FILE_LINE);
}
void deviceFound(std::shared_ptr<DBTDevice> device, const uint64_t timestamp) override {
JNIEnv *env = *jni_env;
- try {
- #ifdef VERBOSE_ON
- fprintf(stderr, "****** Native Adapter Device FOUND__: %s\n", device->toString().c_str());
- fprintf(stderr, "Status DBTAdapter:\n");
- fprintf(stderr, "%s\n", device->getAdapter().toString().c_str());
- #endif
- jobject jdevice;
- std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject();
- if( JavaGlobalObj::isValid(jDeviceRef) ) {
- // Reuse Java instance
- jdevice = JavaGlobalObj::GetObject(jDeviceRef);
- } else {
- // New Java instance
- // Device(final long nativeInstance, final Adapter adptr, final String address, final String name)
- const jstring addr = from_string_to_jstring(env, device->getAddressString());
- const jstring name = from_string_to_jstring(env, device->getName());
- java_exception_check_and_throw(env, E_FILE_LINE);
- jobject jDevice = env->NewObject(deviceClazzRef->getClass(), deviceClazzCtor,
- (jlong)device.get(), JavaGlobalObj::GetObject(adapterObjRef), addr, device->getAddressType(), name, (jlong)timestamp);
- java_exception_check_and_throw(env, E_FILE_LINE);
- JNIGlobalRef::check(jDevice, E_FILE_LINE);
- std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject();
- JavaGlobalObj::check(jDeviceRef, E_FILE_LINE);
- jdevice = JavaGlobalObj::GetObject(jDeviceRef);
- }
- env->CallVoidMethod(listenerObjRef->getObject(), mDeviceFound, jdevice, (jlong)timestamp);
+ DBG_PRINT("****** JNI Adapter Device FOUND__: %s\n", device->toString(true).c_str());
+ jobject jdevice;
+ std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject();
+ if( JavaGlobalObj::isValid(jDeviceRef) ) {
+ // Reuse Java instance
+ jdevice = JavaGlobalObj::GetObject(jDeviceRef);
+ } else {
+ // New Java instance
+ // Device(final long nativeInstance, final Adapter adptr, final String address, final int intAddressType, final String name)
+ const jstring addr = from_string_to_jstring(env, device->getAddressString());
+ const jstring name = from_string_to_jstring(env, device->getName());
java_exception_check_and_throw(env, E_FILE_LINE);
- } catch(...) {
- rethrow_and_raise_java_exception(env);
+ jobject jDevice = env->NewObject(deviceClazzRef->getClass(), deviceClazzCtor,
+ (jlong)device.get(), JavaGlobalObj::GetObject(adapterObjRef), addr, device->getAddressType(), name, (jlong)timestamp);
+ java_exception_check_and_throw(env, E_FILE_LINE);
+ JNIGlobalRef::check(jDevice, E_FILE_LINE);
+ std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject();
+ JavaGlobalObj::check(jDeviceRef, E_FILE_LINE);
+ jdevice = JavaGlobalObj::GetObject(jDeviceRef);
}
+ env->CallVoidMethod(listenerObjRef->getObject(), mDeviceFound, jdevice, (jlong)timestamp);
+ java_exception_check_and_throw(env, E_FILE_LINE);
}
void deviceUpdated(std::shared_ptr<DBTDevice> device, const uint64_t timestamp, const EIRDataType updateMask) override {
JNIEnv *env = *jni_env;
- try {
- #ifdef VERBOSE_ON
- fprintf(stderr, "****** Native Adapter Device UPDATED: %s of %s\n", direct_bt::eirDataMaskToString(updateMask).c_str(), device->toString().c_str());
- fprintf(stderr, "Status DBTAdapter:\n");
- fprintf(stderr, "%s\n", device->getAdapter().toString().c_str());
- #endif
- std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject();
- JavaGlobalObj::check(jDeviceRef, E_FILE_LINE);
- env->SetLongField(JavaGlobalObj::GetObject(jDeviceRef), deviceClazzTSUpdateField, (jlong)timestamp);
- java_exception_check_and_throw(env, E_FILE_LINE);
+ DBG_PRINT("****** JNI Adapter Device UPDATED: %s of %s\n", direct_bt::eirDataMaskToString(updateMask).c_str(), device->toString(true).c_str());
+ std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject();
+ JavaGlobalObj::check(jDeviceRef, E_FILE_LINE);
+ env->SetLongField(JavaGlobalObj::GetObject(jDeviceRef), deviceClazzTSUpdateField, (jlong)timestamp);
+ java_exception_check_and_throw(env, E_FILE_LINE);
- jobject eirDataTypeSet = env->NewObject(eirDataTypeSetClazzRef->getClass(), eirDataTypeSetClazzCtor, (jint)updateMask);
- java_exception_check_and_throw(env, E_FILE_LINE);
- JNIGlobalRef::check(eirDataTypeSet, E_FILE_LINE);
+ jobject eirDataTypeSet = env->NewObject(eirDataTypeSetClazzRef->getClass(), eirDataTypeSetClazzCtor, (jint)updateMask);
+ java_exception_check_and_throw(env, E_FILE_LINE);
+ JNIGlobalRef::check(eirDataTypeSet, E_FILE_LINE);
- env->CallVoidMethod(listenerObjRef->getObject(), mDeviceUpdated, JavaGlobalObj::GetObject(jDeviceRef), (jlong)timestamp, eirDataTypeSet);
- java_exception_check_and_throw(env, E_FILE_LINE);
- } catch(...) {
- rethrow_and_raise_java_exception(env);
- }
+ env->CallVoidMethod(listenerObjRef->getObject(), mDeviceUpdated, JavaGlobalObj::GetObject(jDeviceRef), (jlong)timestamp, eirDataTypeSet);
+ java_exception_check_and_throw(env, E_FILE_LINE);
}
void deviceConnectionChanged(std::shared_ptr<DBTDevice> device, const bool connected, const uint64_t timestamp) override {
JNIEnv *env = *jni_env;
- try {
- #ifdef VERBOSE_ON
- fprintf(stderr, "****** DBTAdapter Device CONNECTION: connected %d: %s\n", connected, device->toString().c_str());
- fprintf(stderr, "Status DBTAdapter:\n");
- fprintf(stderr, "%s\n", device->getAdapter().toString().c_str());
- #endif
- std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject();
- JavaGlobalObj::check(jDeviceRef, E_FILE_LINE);
- env->SetLongField(JavaGlobalObj::GetObject(jDeviceRef), deviceClazzTSUpdateField, (jlong)timestamp);
- java_exception_check_and_throw(env, E_FILE_LINE);
- env->CallVoidMethod(listenerObjRef->getObject(), mDeviceConnectionChanged, JavaGlobalObj::GetObject(jDeviceRef),
- (jboolean)connected, (jlong)timestamp);
- java_exception_check_and_throw(env, E_FILE_LINE);
- } catch(...) {
- rethrow_and_raise_java_exception(env);
- }
+ DBG_PRINT("****** JNI Adapter Device CONNECTION: connected %d: %s\n", connected, device->toString(true).c_str());
+ std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject();
+ JavaGlobalObj::check(jDeviceRef, E_FILE_LINE);
+ env->SetLongField(JavaGlobalObj::GetObject(jDeviceRef), deviceClazzTSUpdateField, (jlong)timestamp);
+ java_exception_check_and_throw(env, E_FILE_LINE);
+ env->CallVoidMethod(listenerObjRef->getObject(), mDeviceConnectionChanged, JavaGlobalObj::GetObject(jDeviceRef),
+ (jboolean)connected, (jlong)timestamp);
+ java_exception_check_and_throw(env, E_FILE_LINE);
}
};
std::atomic<int> JNIAdapterStatusListener::iname_next(0);
@@ -324,13 +284,13 @@ jboolean Java_direct_1bt_tinyb_DBTAdapter_addStatusListener(JNIEnv *env, jobject
{
try {
if( nullptr == statusListener ) {
- throw IllegalArgumentException("statusListener is null", E_FILE_LINE);
+ throw IllegalArgumentException("JNIAdapterStatusListener::addStatusListener: statusListener is null", E_FILE_LINE);
}
{
JNIAdapterStatusListener * pre =
getObjectRef<JNIAdapterStatusListener>(env, statusListener, "nativeInstance");
if( nullptr != pre ) {
- WARN_PRINT("statusListener's nativeInstance not null, already in use");
+ WARN_PRINT("JNIAdapterStatusListener::addStatusListener: statusListener's nativeInstance not null, already in use");
return false;
}
}
@@ -348,11 +308,14 @@ jboolean Java_direct_1bt_tinyb_DBTAdapter_addStatusListener(JNIEnv *env, jobject
if( adapter->addStatusListener( l ) ) {
setInstance(env, statusListener, l.get());
+ DBG_PRINT("JNIAdapterStatusListener::addStatusListener: OK: %s", l->toString().c_str());
return JNI_TRUE;
}
+ ERR_PRINT("JNIAdapterStatusListener::addStatusListener: FAILED: %s", l->toString().c_str());
} catch(...) {
rethrow_and_raise_java_exception(env);
}
+ DBG_PRINT("JNIAdapterStatusListener::addStatusListener: FAILED XX");
return JNI_FALSE;
}