我目前正在开发一个具有C ++集成的小型演示Android应用程序。我正在使用Android Studio 3.1.4,并且我的项目具有NDK支持(开发环境为 Windows 10 )。
该应用程序的目的是从存储(sdcard)加载共享库(.so)文件,然后动态链接该库。
这是我创建此应用程序要经历的步骤:
1。在Cygwin上使用GCC生成共享库
这些是我用来编译库的文件
“ sumLib.h”:
#define _MYLIB_H_
#define MAX_INPUT 25
extern double sum(double x, double y);
“ sumLib.c”:
#include <stdlib.h>
#include "sumLib.h"
double sum(double x, double y) {
return x + y;
}
然后我使用以下这些命令来生成库文件:
gcc -shared -o sumLib.o -c sumLib.c
gcc -shared -o sumLib.so sumLib.o
2。在Android客户端上加载库文件
我已将文件传输到Android模拟器的sd卡中(使用设备文件浏览器)(/ storage / emulated / 0 / Download / sumLib.so)
这是读取库并将其与符号“ sum” 链接的c ++代码:
extern "C" {
JNIEXPORT jdouble JNICALL
Java_com_example_user_demo_MainActivity_sum(JNIEnv *env, jobject obj, jdouble n1, jdouble n2) {
void *handle;
double (*sum)(double, double);
char *error;
char fname[PATH_MAX];
strcpy(fname, internalPath); //internal path is a predefined string that points to the Download folder in the SD card
strcat(fname, "/sumLib.so");
handle = dlopen(fname, RTLD_LAZY);
if (!handle) {
__android_log_write(ANDROID_LOG_ERROR, "Creating handle", "Error creating handle");
exit(EXIT_FAILURE);
}
dlerror();
*(void **) (&sum) = dlsym(handle, "sum");
if ((error = dlerror()) != NULL) {
__android_log_write(ANDROID_LOG_ERROR, "Error linking symbol", error);
exit(EXIT_FAILURE);
}
double result = (*sum)(n1, n2);
dlclose(handle);
return result;
}
}
这是调用c ++函数的Java代码:
public native double sum(double n1, double n2);
// function was called after the click of a button
public void onClickTestBtn(View v) {
// set up the text view to display the result
TextView tv = findViewById(R.id.sample_text);
double result = sum(134.3, 11.3);
tv.setText(String.format("Result is %f", result));
}
理论上,这应该调用c ++定义的“ sum”函数,并使用该库查找符号“ sum” 并执行操作,但是 dlopen 无法从文件创建句柄,它不断抛出错误。
这是错误消息:
"dlopen failed: library \"/storage/emulated/0/Download/sumLib.so\" needed or dlopened by \"/data/app/com.example.user.demo-fzNLN7tBu86LCNun1yLQlg==/lib/x86_64/libnative-lib.so\" is not accessible for the namespace \"classloader-namespace\""
我在错误消息中的文件地址末尾注意到,他们添加了一个正斜杠而不是反斜杠,这有什么影响吗?另外,我不确定错误消息的后半部分是什么意思。
我认为Cygwin上的GCC可能在与运行Android模拟器的架构不同的体系结构上进行编译,但是我检查了文件后,发现它是针对 x64 进行编译的(根据{{3}},通过读取文件,我发现 PE d + 。对于仿真器,我正在运行x86_64图像(API 27),并在调用后将其打印出 x86_64 :
String arch = System.getProperty("os.arch");
Log.d("Debug", String.format("system arch is %s", arch));
我还检查了是否可以从c ++环境访问该文件,所以我使用了
FILE *f = fopen(fname, "r");
并且在调试器中,它没有指向null,而是指向 0x00007227dd414018 ,是可以安全地假定它已找到文件并可以正确读取文件的假设?
我不确定如何解决 dlopen 给我的错误,至于库文件的完整性和正确性,我已使用以下C代码对其进行了测试:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int agrc, char **agrv) {
void *handle;
double (*sum)(double, double);
char *error;
handle = dlopen("./sumLib.so", RTLD_LAZY);
if (!handle) {
printf("error opening file");
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror();
*(void **) (&sum) = dlsym(handle, "sum");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
printf("Sum is %f\n", (*sum)(13.3, 113.4));
dlclose(handle);
exit(EXIT_SUCCESS);
return 0;
}
它能够正确打开库,链接符号并返回正确的结果。
我在做什么导致 dlopen 抛出该错误?
答案 0 :(得分:0)
尝试为目标SDK 23或更低版本构建您的应用,并在模拟器API 24或更低版本上运行它。我相信您看到的故障是最近安全措施的体现。参见 Android 7.0 Behavior Changes :
从Android 7.0开始,系统会阻止应用动态链接非NDK库。
使用主机 gcc 编译器构建 sumLib.so 也无济于事。即使生成的库针对相同的 x86_64 ABI,Android上的运行时环境也完全不同。请使用NDK工具链。如果愿意,可以使用独立工具链代替 ndk-build 或 CMake 脚本。