首页 > 运维 > linux运维 > 正文

Android开发日常:使用JNI执行任何二进制文件

絕刀狂花
发布: 2025-07-12 08:40:14
原创
863人浏览过

android开发日常:使用jni执行任何二进制文件

什么是 JNI?

JNI,即 Java Native Interface 的缩写,通过使用 Java 本地接口编写程序,可以确保代码在不同平台上方便移植。从 Java 1.1 开始,JNI 标准成为 Java 平台的一部分,它允许 Java 代码与其他语言编写的代码进行交互。JNI 最初是为了本地已编译的语言,尤其是 C 和 C++ 设计的,但它并不妨碍你使用其他编程语言,只要调用约定受支持即可。使用 Java 与本地已编译的代码交互,通常会丧失平台的可移植性。然而,在某些情况下,这样做是可以接受的,甚至是必要的。例如,使用一些旧的库,与硬件或操作系统进行交互,或者为了提高程序的性能。JNI 标准至少保证本地代码能在任何 Java 虚拟机环境中工作。

在哪里见过?native 关键字。一个 native 方法就是一个 Java 调用非 Java 代码的接口。一个 native 方法是指该方法的实现由非 Java 语言实现,比如用 C 或 C++ 实现。在定义一个 native 方法时,不提供实现体(类似于定义一个 Java Interface),因为其实现体是由非 Java 语言在外部实现的。这主要是因为 Java 无法对操作系统底层进行操作,但可以通过 JNI(Java Native Interface)调用其他语言来实现底层的访问。

提出问题

很多时候使用 Kotlin 或 Java 开发 Android 时都离不开访问 /data/data/com.xxx.xxx/ 下的文件,由于 Linux 的不可控因素,在高版本 Android 系统中 Runtime.exec("su") 已经失效。那么该如何使用 root 权限去执行应用包下的二进制文件呢?

一些前提条件

使用 native 是少不了 NDK 包的,通过 Preferences(Settings) > Appearence & Behavior > System Settings > Android SDK 中的 SDK Tools 下载 NDK 与 CMake,具体如下图:

android开发日常:使用jni执行任何二进制文件

解决方案架构

在创建项目时使用 native C++ 模板进行创建;在 /src/main/ 包下会出现 cpp 与 java 两种语言的核心包;进入 /src/main/cpp/native-lib.cpp 中,可以看到系统已自动生成了一个 C++ 函数;

System Fork

现在使用我们二年级学过的 C++ 知识来写一个 Linux 操作,让 system() 函数去执行:

#include <jni.h>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
<p>void<em> Shell(){
char shell[64];
sprintf(shell,"sh /data/data/com.example.jni/start.sh");
system(shell);
return nullptr;
}
登录后复制

这样我们就创建了一个 Shell() 方法。

JNI调用

将 Shell() 方法挂载到 JNI 实例中:

extern "C"
JNIEXPORT void JNICALL
Java_com_example_jni_utils_shellUtil_execShell(JNIEnv </em>env, jobject thiz) {
Shell();
}
登录后复制

回到需要调用的工具类(utils.shellUtil)中,写入调用:

static {
System.loadLibrary("native_lib");
}
private static native void shell(); //使用native关键字调取
登录后复制

这里的 System.loadLibrary("native_lib") 的意思为:调用你 build 之后生成的 libnative_lib.so SO库。

so库在哪里

编写完 C++ native lib 之后进行 build 操作可以在文件目录 /build/intermediates/merged_native_libs/debug/out/lib 下找到对应不同操作系统的 so 库文件。将它们复制到你的 libs(与 src 同级目录) 下后再 run 你的项目即可完成调用。

android开发日常:使用jni执行任何二进制文件

多线程

至此,已经完成了 native 库的编写与运行,你应该对 JNI 也有了一定的了解。但很多情况下我们不希望 被运行的二进制文件 阻碍 安卓主线程,这时候,需要使用到多线程对二进制文件的运行进行处理。我们可以在 native-lib.cpp 中这样处理:

#include <jni.h></p><h1>include <string></h1><h1>include <cstdio></h1><h1>include <cstdlib></h1><h1>include <unistd.h></h1><h1>include <pthread.h></h1><p>void* Shell(){
char shell[64];
//fork拷贝
sprintf(shell,"sh /data/data/com.example.jni/start.sh");
system(shell);
return nullptr;
}</p><p>extern "C"
JNIEXPORT void JNICALL
Java_com_example_jni_utils_shellUtil_execShell(JNIEnv <em>env, jobject thiz) {
//创建线程id
pthread_t tid;
//启动线程
pthread_create(
&tid,
nullptr,
reinterpret_cast<void</em>>(Shell),
nullptr
);
}
登录后复制

通过 pthread 函数库进行线程处理,这样就保障了安卓应用主线程的线程安全,与并行的效率。

如何停止线程?管道通信

我们在小学三年级的 Linux操作系统 课程中已经知道了 system() 命令的执行过程是 fork子进程 执行二进制,这样就带来一个问题:我的二进制文件需要指定一个配置来启动的话就读取不到被设定为 read only 的文件夹内的资源。

如何解决?我也不会,希望有大佬能指点江山。

以上就是Android开发日常:使用JNI执行任何二进制文件的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号