util.rs 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use miniquad::native::android::{self, ndk_sys};
  19. use std::cell::RefCell;
  20. thread_local! {
  21. static JNI_ENV: RefCell<JniEnvHolder> = RefCell::new(JniEnvHolder {
  22. env: std::ptr::null_mut(),
  23. vm: std::ptr::null_mut(),
  24. });
  25. }
  26. struct JniEnvHolder {
  27. env: *mut ndk_sys::JNIEnv,
  28. vm: *mut ndk_sys::JavaVM,
  29. }
  30. impl Drop for JniEnvHolder {
  31. fn drop(&mut self) {
  32. assert!(!self.env.is_null());
  33. unsafe {
  34. let detach_current_thread = (**self.vm).DetachCurrentThread.unwrap();
  35. let _ = detach_current_thread(self.vm);
  36. }
  37. }
  38. }
  39. /// Get the JNIEnv for the current thread, attaching if necessary.
  40. /// The returned pointer is cached per-thread and automatically detached
  41. /// when the thread exits.
  42. pub unsafe fn get_jni_env() -> *mut ndk_sys::JNIEnv {
  43. JNI_ENV.with(|holder| {
  44. let mut holder = holder.borrow_mut();
  45. if !holder.env.is_null() {
  46. return holder.env;
  47. }
  48. // Call miniquad's attach_jni_env to get the env
  49. let env = android::attach_jni_env();
  50. assert!(!env.is_null());
  51. // Retrieve the JavaVM from the JNIEnv
  52. let get_java_vm = (**env).GetJavaVM.unwrap();
  53. let mut vm: *mut ndk_sys::JavaVM = std::ptr::null_mut();
  54. let res = get_java_vm(env, &mut vm);
  55. assert!(res == 0);
  56. assert!(!vm.is_null());
  57. holder.env = env;
  58. holder.vm = vm;
  59. env
  60. })
  61. }
  62. /// Check for pending Java exceptions and log them
  63. ///
  64. /// This function should be called after any JNI call that might throw an exception.
  65. /// It will use ExceptionDescribe to print the exception to logcat, then clear it.
  66. unsafe fn check_except(env: *mut ndk_sys::JNIEnv, context: &str) {
  67. let exception_check = (**env).ExceptionCheck.unwrap();
  68. if exception_check(env) != 0 {
  69. // Use ExceptionDescribe to print the exception stack trace to logcat
  70. // This is safe to call even with a pending exception and handles StackOverflowError gracefully
  71. let exception_describe = (**env).ExceptionDescribe.unwrap();
  72. exception_describe(env);
  73. let exception_clear = (**env).ExceptionClear.unwrap();
  74. exception_clear(env);
  75. panic!("Java exception detected in {context}");
  76. }
  77. }