Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions core/src/jni/rac_hybrid_custom_filter_jni.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,15 @@ rac_bool_t custom_filter_predicate(const rac_hybrid_routing_context_t* ctx, void
}
const jboolean keep = scope.env->CallBooleanMethod(a->predicate, a->mid_evaluate, model_id);
scope.env->DeleteLocalRef(model_id);
// The predicate is app code. A throw leaves `keep` undefined and, worse,
// leaves the exception pending on this thread: the next JNI call made by
// whoever we return into aborts the process with "JNI called with pending
// exception". Clear it and keep the candidate, the same answer this
// function already gives when it cannot reach the JVM at all.
if (scope.env->ExceptionCheck() == JNI_TRUE) {
scope.env->ExceptionClear();
return RAC_TRUE;
}
return keep != JNI_FALSE ? RAC_TRUE : RAC_FALSE;
}

Expand Down
25 changes: 22 additions & 3 deletions core/src/jni/rac_hybrid_device_state_jni.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,16 @@ bool device_state_is_online(void* user_data) {
if (scope.env == nullptr) {
return true;
}
return scope.env->CallBooleanMethod(a->provider, a->mid_is_online) != JNI_FALSE;
const jboolean online = scope.env->CallBooleanMethod(a->provider, a->mid_is_online);
// The provider is app code. A throw leaves the exception pending on this
// thread, and the next JNI call aborts the process with "JNI called with
// pending exception", so clear it and fall back to the same answer used
// when the JVM is unreachable.
if (scope.env->ExceptionCheck() == JNI_TRUE) {
scope.env->ExceptionClear();
return true;
}
return online != JNI_FALSE;
}

int32_t device_state_battery_percent(void* user_data) {
Expand All @@ -93,7 +102,12 @@ int32_t device_state_battery_percent(void* user_data) {
if (scope.env == nullptr) {
return 100;
}
return static_cast<int32_t>(scope.env->CallIntMethod(a->provider, a->mid_battery_percent));
const jint percent = scope.env->CallIntMethod(a->provider, a->mid_battery_percent);
if (scope.env->ExceptionCheck() == JNI_TRUE) {
scope.env->ExceptionClear();
return 100;
}
return static_cast<int32_t>(percent);
}

bool device_state_is_thermal_throttled(void* user_data) {
Expand All @@ -105,7 +119,12 @@ bool device_state_is_thermal_throttled(void* user_data) {
if (scope.env == nullptr) {
return false;
}
return scope.env->CallBooleanMethod(a->provider, a->mid_is_thermal_throttled) != JNI_FALSE;
const jboolean throttled = scope.env->CallBooleanMethod(a->provider, a->mid_is_thermal_throttled);
if (scope.env->ExceptionCheck() == JNI_TRUE) {
scope.env->ExceptionClear();
return false;
}
return throttled != JNI_FALSE;
}

/** Detach commons from the current adapter and free its GlobalRef. */
Expand Down
Loading