尝试从libart.so调用JNI_CreateJavaVM失败 我正在使用一个C++部分的XAMARIN。Android应用程序。现在我需要直接从C++库调用Android的java接口。 < >我复制了使用JNI调用从C++到java < /强>的代码。但是我不能像他那样获得指向JVM的指针

尝试从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

(顺便说一句,我主要是一名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;                      // 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]添加另一个选项
to
JavaVMOption 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]添加另一个选项
to
JavaVMOption 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加载可能是错误的,我现在正在阅读您链接的问题(这将花费我一段时间)