尝试从libart.so调用JNI_CreateJavaVM失败 我正在使用一个C++部分的XAMARIN。Android应用程序。现在我需要直接从C++库调用Android的java接口。 < >我复制了使用JNI调用从C++到java < /强>的代码。但是我不能像他那样获得指向JVM的指针
(顺便说一句,我主要是一名C#程序员,所以完全有可能我在C++中犯了一个基本错误) 在头文件中:尝试从libart.so调用JNI_CreateJavaVM失败 我正在使用一个C++部分的XAMARIN。Android应用程序。现在我需要直接从C++库调用Android的java接口。 < >我复制了使用JNI调用从C++到java < /强>的代码。但是我不能像他那样获得指向JVM的指针,android,c++,xamarin.android,java-native-interface,dlsym,Android,C++,Xamarin.android,Java Native Interface,Dlsym,(顺便说一句,我主要是一名C#程序员,所以完全有可能我在C++中犯了一个基本错误) 在头文件中: #pragma once class MyJniClass { //Create this once and cache it. JavaVM *m_jvm; // Pointer to the JVM (Java Virtual Machine) JNIEnv *m_env; // Poi
#pragma once
class MyJniClass
{
//Create this once and cache it.
JavaVM *m_jvm; // Pointer to the JVM (Java Virtual Machine)
JNIEnv *m_env; // Pointer to native interface
bool init_jvm();
}
在.cpp文件中:
#include <jni.h>
#include <dlfcn.h>
#include "MyJniClass.h"
typedef int(*JNI_CreateJavaVM_t)(void *, void *, void *);
/**Code is based on https://github.com/rednaga/native-shim/blob/master/vm.c
*/
bool MyJniClass::init_jvm()
{
// https://android.googlesource.com/platform/frameworks/native/+/ce3a0a5/services/surfaceflinger/DdmConnection.cpp
JavaVMOption opt[1];
opt[0].optionString = "-Djava.class.path=."; // I added a small java class to the dll to which this C++ class is linked,
//so that there would be a java class in the current directory.
//opt/*[1]*/.optionString = "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
JavaVMInitArgs args;
args.version = JNI_VERSION_1_6;
args.options = opt;
args.nOptions = 1;
args.ignoreUnrecognized = JNI_FALSE;
void *libart_dso = dlopen("libart.so", RTLD_NOW); //libdvm.so is outdated, libnativehelper.so doesn't work
if (!libart_dso )
{
//Execution doesn't pass through here
return false;
}
//Try to get the JNI_CreateJavaVM function pointer
JNI_CreateJavaVM_t JNI_CreateJavaVM;
JNI_CreateJavaVM = (JNI_CreateJavaVM_t)dlsym(libart_dso, "JNI_CreateJavaVM");
if (!JNI_CreateJavaVM)
{
//Execution doesn't pass through here
return false;
}
signed int result = JNI_CreateJavaVM(&(m_jvm), &(m_env), &args);
if ( result != 0)
{
ostringstream os;
os << "Call to JNI_CreateJavaVM returned ";
os << result;
m_logger->writeEntry(Loglevel::debug, os.str()); // ===> Here, I can see that result is always -1
return false;
}
return true;
}
#包括
#包括
#包括“MyJniClass.h”
typedef int(*JNI_CreateJavaVM_t)(void*,void*,void*);
/**代码基于https://github.com/rednaga/native-shim/blob/master/vm.c
*/
bool MyJniClass::init_jvm()
{
// https://android.googlesource.com/platform/frameworks/native/+/ce3a0a5/services/surfaceflinger/DdmConnection.cpp
JavaVMOption选项[1];
opt(0)opopStist= =“Djava .class .PATH=”;//i向该C++类链接的DLL添加了一个小java类,
//这样在当前目录中就会有一个java类。
//opt/*[1]*/.optionString=“-agentlib:jdwp=transport=dt\u android\u adb,suspend=n,server=y”;
JavaVMInitArgs args;
args.version=JNI_version_1_6;
args.options=opt;
args.nOptions=1;
args.ignoreunrecogned=JNI_FALSE;
void*libart_dso=dlopen(“libart.so”,RTLD_NOW);//libdvm.so已过时,libnativehelper.so不起作用
如果(!libart_dso)
{
//这里没有死刑
返回false;
}
//尝试获取JNI_CreateJavaVM函数指针
JNI_CreateJavaVM_t JNI_CreateJavaVM;
JNI_CreateJavaVM=(JNI_CreateJavaVM_t)dlsym(libart_dso,“JNI_CreateJavaVM”);
如果(!JNI_CreateJavaVM)
{
//这里没有死刑
返回false;
}
signed int result=JNI_CreateJavaVM(&(m_jvm),&(m_env),&args);
如果(结果!=0)
{
ostringstream os;
在这里,我可以看到结果总是-1
返回false;
}
返回true;
}
我试图在ART源代码中找到函数JNI_CreateJavaVM,但找不到它。但它肯定应该在那里,这样dlsym就可以找到函数了?我想我必须进一步查找libart.so的源代码
我做错了什么,无法获得对JNI_CreateJavaVM的有效调用?这里的第一个修改是添加诊断选项
Xcheck:JNI
。
这将在出现错误时提供详细信息。
通过修改JavaVMOption opt[1]添加另一个选项
toJavaVMOption opt[2]代码>
然后,添加以下选项:
opt[1]。optionString=“-Xcheck:jni”
此外,dll必须从其原始位置加载(因为涉及其他dll),而不是从项目目录加载。
Mor详情见以下帖子:
最后,您应该通过修改以下内容将指针强制转换为本机接口JNIEnv:
signed int result = JNI_CreateJavaVM(&(m_jvm), &(m_env), &args);
到
这应该可以解决问题。这里的第一个修改是添加诊断选项Xcheck:jni
。
这将在出现错误时提供详细信息。
通过修改JavaVMOption opt[1]添加另一个选项
toJavaVMOption opt[2]代码>
然后,添加以下选项:
opt[1]。optionString=“-Xcheck:jni”
此外,dll必须从其原始位置加载(因为涉及其他dll),而不是从项目目录加载。
Mor详情见以下帖子:
最后,您应该通过修改以下内容将指针强制转换为本机接口JNIEnv:
signed int result = JNI_CreateJavaVM(&(m_jvm), &(m_env), &args);
到
这应该可以解决问题。看起来问题与提供JNI\u CreateJavaVM
的库有关。我指的是这一行
void *libart_dso = dlopen("libart.so", RTLD_NOW);
如果我把你的代码从所有与JVM无关的东西中去掉,如果我使用基于macOS的JDK,它就可以正常工作
--- 8< CUT HERE 8< ----
#include <jni.h>
#include <dlfcn.h>
#include <iostream>
#include "MyJniClass.h"
using namespace std;
bool MyJniClass::init_jvm()
{
JavaVM *jvm;
JNIEnv *env = NULL;
JavaVMOption opt[1];
opt[0].optionString = "-Djava.class.path=.";
JavaVMInitArgs args;
args.version = JNI_VERSION_1_6;
args.options = opt;
args.nOptions = 1;
args.ignoreUnrecognized = JNI_FALSE;
int status = JNI_CreateJavaVM (&jvm, (void **) &env, &args);
cout << status << endl;
return true;
}
int main(int argc, char **argv) {
MyJniClass jni;
jni.init_jvm();
}
--- 8< CUT HERE 8< ----
(基于此处的recipeNo027:)
我可以毫无问题地运行它
> lib/recipeNo027_main
0
您的JNI\u CreateJavaVM
实现中似乎有可疑的事情发生。问题似乎与提供JNI\u CreateJavaVM
的库有关。我指的是这一行
void *libart_dso = dlopen("libart.so", RTLD_NOW);
如果我把你的代码从所有与JVM无关的东西中去掉,如果我使用基于macOS的JDK,它就可以正常工作
--- 8< CUT HERE 8< ----
#include <jni.h>
#include <dlfcn.h>
#include <iostream>
#include "MyJniClass.h"
using namespace std;
bool MyJniClass::init_jvm()
{
JavaVM *jvm;
JNIEnv *env = NULL;
JavaVMOption opt[1];
opt[0].optionString = "-Djava.class.path=.";
JavaVMInitArgs args;
args.version = JNI_VERSION_1_6;
args.options = opt;
args.nOptions = 1;
args.ignoreUnrecognized = JNI_FALSE;
int status = JNI_CreateJavaVM (&jvm, (void **) &env, &args);
cout << status << endl;
return true;
}
int main(int argc, char **argv) {
MyJniClass jni;
jni.init_jvm();
}
--- 8< CUT HERE 8< ----
(基于此处的recipeNo027:)
我可以毫无问题地运行它
> lib/recipeNo027_main
0
您的JNI\u CreateJavaVM
实现中似乎发生了一些可疑的事情。谢谢您的回答!dll加载可能是错误的,我现在正在阅读您链接的问题(这将花费我一点时间)。我确实尝试过将指针指向void**(正如CP文章中建议的那样),但没有任何效果。你知道为什么有必要这样做吗?将指针强制转换为void**确实可能不是问题的根源,但这在JNI规范中得到了建议,它将阻止编译警告从void**隐式转换为JNIEnv**
,请注意-Xcheck:jni
对于调试很有用,但出于性能原因,必须删除生产代码。老实说,我无法将此答案与问题中描述的问题联系起来。我没有从我的项目目录加载dll,而且在任何情况下,dlopen都会找到Android库并返回一个指针。jni没有给我任何额外的adb日志记录。好的,如果没有帮助,很抱歉。关于-Xcheck:jni
,这不会在所有情况下都找到所有无效参数或诊断所有错误,但它对一些检查很有帮助。对于dll加载,这通常是问题的根源,这就是我建议您检查的原因。您使用哪种开发环境?您是否也在CP文章中提到的路径中添加了/bin/server?谢谢您的回答!dll加载可能是错误的,我现在正在阅读您链接的问题(这将花费我一段时间)