2016-05-27 2 views
3

в моей программе C вызывается из Java, функции C могут вызываться вне контекста Java, но иногда нужны некоторые Java-ресурсы. Я должен объяснить, что такое программа ... Итак, C-библиотека - это плагиновая система, которая может загружать плагины C, плагинам иногда нужен доступ к ресурсам Java, например, для получения идентификатора String.JNI конвертировать String в char *, возвращенный методом экземпляра

Поэтому, когда система плагина загружается, функция инициализации вызывается JNI, поэтому JNIEnv * и jobject могут быть сохранены для дальнейшего доступа плагинами.

В классе Java я предоставил метод экземпляра, чтобы получить доступ к этим RESSOURCES, например, у меня есть метод

private String getId() { 
    return "Bryan"; 
} 

Система С плагин есть функция

char *get_id(char *id) { 
    jobject jobj = (*jvm.env)->CallObjectMethod(jvm.env, jvm.this, jvm.getId); 
    jstring jid = jobj; 
    if (jid == NULL) 
    debug("get_id", RED "jid NULL"); 
    else 
    debug("get_id", RED "jid not null"); */ 
    debug("get_id", RED "in get_id, method called"); 
    const char *cid = (*jvm.env)->GetStringUTFChars(jvm.env, jid, NULL); 
    debug("get_id", RED "converted to c string: %s", cid); 
    strcpy(id, cid); 
    debug("get_id", RED "string copied"); 
    (*jvm.env)->ReleaseStringUTFChars(jvm.env, jid, cid); 
    debug("get_id", RED "string released"); 
    return id; 
} 

Где JVM представляет собой структуру, содержащие поле env и obj, соответствующие JNIEnv * и jobject, сохраненные при инициализации, и jvm.getId, который является methodID of getId Метод экземпляра Java, инициализированный одновременно. Отладочный макрос - это всего лишь звонок printf с flush, которые помогают мне отлаживать программу.

И это выход после вызова get_id:

DEBUG IN plugin_system.c LINE 339: 
In get_id 
in get_id, calling method... 
DEBUG IN plugin_system.c LINE 343: 
In get_id 
jid NULL 
DEBUG IN plugin_system.c LINE 346: 
In get_id 
in get_id, method called 
# 
# A fatal error has been detected by the Java Runtime Environment: 
# 
# SIGSEGV (0xb) at pc=0x00007fb6bcb6cd70, pid=25254, tid=0x00007fb6974be700 
# 
# JRE version: OpenJDK Runtime Environment (8.0_92-b14) (build 1.8.0_92-b14) 
# Java VM: OpenJDK 64-Bit Server VM (25.92-b14 mixed mode linux-amd64 compressed oops) 
# Problematic frame: 
# V [libjvm.so+0x675d70] 
# 
# Core dump written. Default location: /home/kowa/code/reseaux/projet/ringo/java/bin/core or core.25254 
# 
# An error report file with more information is saved as: 
# /home/kowa/code/reseaux/projet/ringo/java/bin/hs_err_pid25254.log 
# 
# If you would like to submit a bug report, please visit: 
# http://bugreport.java.com/bugreport/crash.jsp 
# The crash happened outside the Java Virtual Machine in native code. 
# See problematic frame for where to report the bug. 
# 
[4] 25254 abort (core dumped) java Jring Nick 9999 8888 1 

Как вы можете видеть вызов Java getId есть (внешний вид) преуспевающий, но дамп запускается GetStringUTFChars.

Что случилось?

+1

Каков ваш объект 'jvm'? Структура? Класс? Как вы его заполняете? В общем случае вы не можете кэшировать значения, такие как значение JVM 'env'. Также вы не можете кэшировать объекты или идентификаторы методов, если вы не создадите [глобальную ссылку] (http://stackoverflow.com/questions/112603/what-is-jni-global-reference). –

+0

Это 'struct jvm {JNIEnv * env; jobject this; jclass thisClass; methodID getId; }; ', поле заполняется после загрузки библиотеки после вызова java для собственной функции init. –

+0

Прежде всего, какой набор символов и кодирование вы используете для строк C, системного или определенного? –

ответ

1

Вы не можете кэшировать JVM env. См Keeping a global reference to the JNIEnv environment, особенно this answer:

The JNI interface pointer (JNIEnv) is valid only in the current thread. Should another thread need to access the Java VM, it must first call AttachCurrentThread() to attach itself to the VM and obtain a JNI interface pointer. Once attached to the VM, a native thread works just like an ordinary Java thread running inside a native method. The native thread remains attached to the VM until it calls DetachCurrentThread() to detach itself.

Updated link. Ссылка в другом ответе устарела.

Что касается объекта Java, класса и метода Java, вам необходимо указать obtain a global reference, если вы собираетесь их кэшировать. См. What is 'JNI Global reference' и Caching JNI objects and thread-safety (in Android)

+0

Спасибо, я не знал об этом. Я изменил код, поэтому теперь структура содержит только указатель на JVM и глобальную ссылку на объект. Каждый раз, когда я вызываю JNI из «чистого C-контекста», я называю «AttachCurrentThread» раньше. Я все еще получаю сообщение об ошибке: 'JNIEnv * env; jint rs = (* jvm.jvm) -> AttachCurrentThread (jvm.jvm, & env, NULL); assert (rs == JNI_OK); rs = (* jvm.jvm) -> DetachCurrentThread (jvm.jvm); assert (rs == JNI_OK); ', утверждение инициируется вызовом' DetachCurrentThread' ... –

+0

Что вы подразумеваете под «чистым контекстом C»? По [документации Java API] (http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html): «Собственный поток, подключенный к виртуальной машине, должен вызвать DetachCurrentThread(), чтобы отсоединиться до выхода. Нить не может отсоединиться, если есть Java-методы в стек вызовов. " Возможно, вам не нужно называть 'DetachCurrentThread()'. Распечатайте значение 'env' в вашей начальной функции JNI, которая запускает загрузку вашего плагина, а затем снова, когда вы вызываете' DetachCurrentThread() '. Это может быть одно и то же, потому что это тот же поток. –

Смежные вопросы