将jni :: sys :: JNIEnv转换为ffi中定义的JNINativeInterface [英] Converting jni::sys::JNIEnv to JNINativeInterface defined in ffi

查看:97
本文介绍了将jni :: sys :: JNIEnv转换为ffi中定义的JNINativeInterface的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在跟踪

I am following up on Casting a borrowed reference with a lifetime to a raw pointer in Rust, which solved the wrong problem.

请考虑以下代码:

extern crate jni;
extern crate ffi;

use jni::JNIEnv;
use jni::objects::JClass;
use jni::sys::{jint, jlong, jobject};

struct CameraAppEngine {
    _env: *mut jni::sys::JNIEnv,
    _width: i32,
    _height: i32
}

impl CameraAppEngine {
    pub fn new(_env: *mut jni::sys::JNIEnv, _width: i32, _height: i32) -> CameraAppEngine {
        CameraAppEngine { _env, _width, _height }
    }

    pub fn create_camera_session(&mut self, surface: jobject) {
        // error!
        let window = ffi::ANativeWindow_fromSurface(self._env, surface);
    }
}

fn app_engine_create(env: &JNIEnv, width: i32, height: i32) -> *mut CameraAppEngine {
    let engine = CameraAppEngine::new(env.get_native_interface(), width, height);
    Box::into_raw(Box::new(engine))
}

#[no_mangle]
pub extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_createCamera(env: JNIEnv<'static>, _: JClass, width:jint, height:jint) -> jlong {
    app_engine_create(&env, width, height) as jlong
}

#[no_mangle]
pub extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_onPreviewSurfaceCreated(_: JNIEnv, _: JClass, engine_ptr:jlong, surface:jobject) {
    let mut app = unsafe { Box::from_raw(engine_ptr as *mut CameraAppEngine) };
    app.create_camera_session(surface);
}

ffi板条箱中,我们有:

extern "C" {
    pub fn ANativeWindow_fromSurface(env: *mut JNIEnv, surface: jobject) -> *mut ANativeWindow;
}

结果是:

error[E0308]: mismatched types
--> native_app/src/lib.rs:24:53
|
|         let window = ffi::ANativeWindow_fromSurface(self._env, surface);
|                                                     ^^^^^^^^^ expected struct `ffi::JNINativeInterface`, found struct `jni::sys::JNINativeInterface_`
|
= note: expected raw pointer `*mut *const ffi::JNINativeInterface`
            found raw pointer `*mut *const jni::sys::JNINativeInterface_`

error[E0308]: mismatched types
--> native_app/src/lib.rs:24:64
|
|         let window = ffi::ANativeWindow_fromSurface(self._env, surface);
|                                                                ^^^^^^^ expected enum `std::ffi::c_void`, found enum `jni::sys::_jobject`
|
= note: expected raw pointer `*mut std::ffi::c_void`
            found raw pointer `*mut jni::sys::_jobject`

问题在于,ANativeWindow_fromSurface期望的JNIEnv类型实际上与jni::sys::JNIEnv完全无关.

The problem is that the JNIEnv type expected by ANativeWindow_fromSurface is actually unrelated to jni::sys::JNIEnv entirely.

它是在ffi中定义的,如下所示:

It's defined in ffi like so:

pub type JNIEnv = *const JNINativeInterface;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct JNINativeInterface {
    pub reserved0: *mut ::std::os::raw::c_void,
    pub reserved1: *mut ::std::os::raw::c_void,
    pub reserved2: *mut ::std::os::raw::c_void,
    pub reserved3: *mut ::std::os::raw::c_void,
    pub GetVersion: ::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv) -> jint>,
    pub DefineClass: ::std::option::Option<
        unsafe extern "C" fn(
            arg1: *mut JNIEnv,
            arg2: *const ::std::os::raw::c_char,
            arg3: jobject,
            arg4: *const jbyte,
            arg5: jsize,
        ) -> jclass,
    >,
    pub FindClass: ::std::option::Option<
        unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: *const ::std::os::raw::c_char) -> jclass,
    >,
    pub FromReflectedMethod:
        ::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: jobject) -> jmethodID>,
    pub FromReflectedField:
        ::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: jobject) -> jfieldID>,
    pub ToReflectedMethod: ::std::option::Option<
        unsafe extern "C" fn(
            arg1: *mut JNIEnv,
            arg2: jclass,
            arg3: jmethodID,
            arg4: jboolean,
        ) -> jobject,
    >
    // etc...
}

给出示例中显示的粘合代码,如何获得对ffi::JNIEnv的有效引用,以便可以将其传递给ANativeWindow_fromSurface方法.如果您提供有关将jni::sys::jobject转换为*mut std::os::raw::c_void的建议(生命周期问题,空指针等),将获得加分.

Given the glue code shown in the example, how do I get a valid reference to ffi::JNIEnv so that I may pass it to the ANativeWindow_fromSurface method. Bonus points if you give advice on converting jni::sys::jobject to *mut std::os::raw::c_void (lifetime concerns, null pointers, etc.).

完整的ffi定义来源

这是我用来在公认的答案中证明这一概念的基本helloworld实现:

Here is the basic helloworld implementation I used to prove the concept in the accepted answer:

use std::ffi::{CString, CStr};
use std::os::raw::{c_char};

/// Expose the JNI interface for android below
#[cfg(target_os="android")]
#[allow(non_snake_case)]
pub mod android {
    extern crate ffi;

    use super::*;
    use self::ffi::{JNIEnv, jclass, jstring, jlong};


    #[derive(Debug)]
    struct AppEngine {
        greeting: *mut c_char
    }

    unsafe fn rust_greeting(app: *mut AppEngine) -> *mut c_char {
        let app = Box::from_raw(app);
        app.greeting
    }

    /// Constructs an AppEngine object.
    fn rust_engine_create(to: *const c_char) -> *mut AppEngine {
        let c_str = unsafe { CStr::from_ptr(to) };
        let recipient = match c_str.to_str() {
            Err(_) => "there",
            Ok(string) => string,
        };

        let greeting = CString::new("Hello ".to_owned() + recipient).unwrap().into_raw();

        let app = AppEngine{greeting: greeting};
        Box::into_raw(Box::new(app))
    }

    /// Destroys an AppEngine object previously constructed using `rust_engine_create()`.
    unsafe fn rust_engine_destroy(app: *mut AppEngine) {
        drop(Box::from_raw(app))
    }

    #[no_mangle]
    pub unsafe extern fn Java_io_waweb_cartoonifyit_MainActivity_greeting(env: &mut JNIEnv, _: jclass, app_ptr: jlong) -> jstring {
        let app = app_ptr as *mut AppEngine;
        let new_string = env.as_ref().unwrap().NewStringUTF.unwrap();
        new_string(env, rust_greeting(app))
    }

    #[no_mangle]
    pub unsafe extern fn Java_io_waweb_cartoonifyit_MainActivity_createNativeApp(env: &mut JNIEnv, _: jclass, java_pattern: jstring) -> jlong {
        let get_string_chars = env.as_ref().unwrap().GetStringChars.unwrap();
        let is_copy = 0 as *mut u8;
        rust_engine_create(get_string_chars(env, java_pattern, is_copy) as *const c_char ) as jlong
    }

    #[no_mangle]
    pub unsafe extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_destroyNativeApp(_: JNIEnv, _: jclass, app_ptr: jlong) {
        let app = app_ptr as *mut AppEngine;
        rust_engine_destroy(app)
    }
}

这仅仅是概念的证明.转换原始指针时应多加注意.另请参阅已接受答案中有关Box::leak的注释.

This is just a proof of concept. More care should be taken when casting raw pointers about. Also see notes about Box::leak in the accepted answer.

推荐答案

JNIEnv是指向用于Java与本机代码之间通信的结构的指针.几乎每个JVM(和android)都实现了这种通信ABI.上述结构有多个版本,这就是GetVersion字段的作用.

A JNIEnv is a pointer to a struct used for communication between Java and native code. This communication ABI is implemented by pretty much every JVM(and android). There are multiple versions of the aforementioned structs, which is what the GetVersion field is for.

在我看来,您正在使用外部jni条板箱以及从此ffi条板箱/wrapper.h"rel =" nofollow noreferrer>包装器.我希望您的ffi条板箱是最正确的,因为它使用的是android标头,而不是标准的JVM标头,而JVM标头很可能由jni条板箱使用.

It seems to me that you are using an external jni crate along with your own ffi crate generated from this wrapper. I would expect your ffi crate to be the most correct since it is using android headers, instead of the standard JVM headers which a most likely being used by the jni crate.

最后一个音符Box::from_raw(engine_ptr as *mut CameraAppEngine)创建一个框,该框将释放位于engine_ptr的内存.这可能不是您想要的.考虑使用Box::leak泄漏创建的Box,并避免释放后使用.

One last note Box::from_raw(engine_ptr as *mut CameraAppEngine), creates a box which will free the memory located at engine_ptr. This is likely not what you want. Consider using Box::leak to leak the created Box and avoid use after frees.

这篇关于将jni :: sys :: JNIEnv转换为ffi中定义的JNINativeInterface的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆