Skip to content

Commit

Permalink
Add AndroidApp::vm_as_ptr() and ::activity_as_ptr() APIs
Browse files Browse the repository at this point in the history
This enables applications to make JNI calls without needing the
`ndk-context` crate - which we would like to deprecate.

Fixes: #60
  • Loading branch information
rib committed Feb 14, 2023
1 parent 6942637 commit dc9ca83
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 0 deletions.
3 changes: 3 additions & 0 deletions android-activity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Added `AndroidApp::vm_as_ptr()` to expose JNI `JavaVM` pointer ([#60](https://github.com/rust-mobile/android-activity/issues/60))
- Added `AndroidApp::activity_as_ptr()` to expose Android `Activity` JNI reference as pointer ([#60](https://github.com/rust-mobile/android-activity/issues/60))

## [0.4] - 2022-11-10
### Changed
Expand Down
11 changes: 11 additions & 0 deletions android-activity/src/game_activity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use std::sync::{Arc, RwLock};
use std::time::Duration;
use std::{ptr, thread};

use libc::c_void;
use log::{error, trace, Level};

use jni_sys::*;
Expand Down Expand Up @@ -155,6 +156,16 @@ pub struct AndroidAppInner {
}

impl AndroidAppInner {
pub fn vm_as_ptr(&self) -> *mut c_void {
let app_ptr = self.native_app.as_ptr();
unsafe { (*(*app_ptr).activity).vm as _ }
}

pub fn activity_as_ptr(&self) -> *mut c_void {
let app_ptr = self.native_app.as_ptr();
unsafe { (*(*app_ptr).activity).javaGameActivity as _ }
}

pub fn native_window(&self) -> Option<NativeWindow> {
self.native_window.read().unwrap().clone()
}
Expand Down
44 changes: 44 additions & 0 deletions android-activity/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ use std::sync::Arc;
use std::sync::RwLock;
use std::time::Duration;

use libc::c_void;
use ndk::asset::AssetManager;
use ndk::native_window::NativeWindow;

Expand Down Expand Up @@ -472,6 +473,49 @@ impl AndroidApp {
self.inner.read().unwrap().native_window()
}

/// Returns a pointer to the Java Virtual Machine, for making JNI calls
///
/// This returns a pointer to the Java Virtual Machine which can be used
/// with the [`jni`] crate (or similar crates) to make JNI calls that bridge
/// between native Rust code and Java/Kotlin code running within the JVM.
///
/// If you use the [`jni`] crate you can wrap this as a [`JavaVM`] via:
/// ```ignore
/// # use jni::JavaVM;
/// # let app: AndroidApp = todo!();
/// let vm = unsafe { JavaVM::from_raw(app.vm_as_ptr()) };
/// ```
///
/// [`jni`]: https://crates.io/crates/jni
/// [`JavaVM`]: https://docs.rs/jni/latest/jni/struct.JavaVM.html
pub fn vm_as_ptr(&self) -> *mut c_void {
self.inner.read().unwrap().vm_as_ptr()
}

/// Returns a JNI object reference for this application's JVM `Activity` as a pointer
///
/// If you use the [`jni`] crate you can wrap this as an object reference via:
/// ```ignore
/// # use jni::objects::JObject;
/// # let app: AndroidApp = todo!();
/// let activity = unsafe { JObject::from_raw(app.activity_as_ptr()) };
/// ```
///
/// # JNI Safety
///
/// Note that the object reference will be a JNI global reference, not a
/// local reference and it should not be deleted. Don't wrap the reference
/// in an [`AutoLocal`] which would try to explicitly delete the reference
/// when dropped. Similarly, don't wrap the reference as a [`GlobalRef`]
/// which would also try to explicitly delete the reference when dropped.
///
/// [`jni`]: https://crates.io/crates/jni
/// [`AutoLocal`]: https://docs.rs/jni/latest/jni/objects/struct.AutoLocal.html
/// [`GlobalRef`]: https://docs.rs/jni/latest/jni/objects/struct.GlobalRef.html
pub fn activity_as_ptr(&self) -> *mut c_void {
self.inner.read().unwrap().activity_as_ptr()
}

/// Polls for any events associated with this [AndroidApp] and processes those events
/// (such as lifecycle events) via the given `callback`.
///
Expand Down
10 changes: 10 additions & 0 deletions android-activity/src/native_activity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::ptr::NonNull;
use std::sync::{Arc, RwLock};
use std::time::Duration;

use libc::c_void;
use log::{error, trace};

use ndk_sys::ALooper_wake;
Expand Down Expand Up @@ -130,6 +131,15 @@ pub(crate) struct AndroidAppInner {
}

impl AndroidAppInner {
pub(crate) fn vm_as_ptr(&self) -> *mut c_void {
unsafe { (*self.native_activity.activity).vm as _ }
}

pub(crate) fn activity_as_ptr(&self) -> *mut c_void {
// "clazz" is a completely bogus name; this is the _instance_ not class pointer
unsafe { (*self.native_activity.activity).clazz as _ }
}

pub(crate) fn native_activity(&self) -> *const ndk_sys::ANativeActivity {
self.native_activity.activity
}
Expand Down

0 comments on commit dc9ca83

Please sign in to comment.