You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android API31/32执行可执行文件报error=13权限拒绝如何解决

问题原因

你遇到的error=13, Permission denied和Android清单权限、运行时权限申请没有关系,核心是Android 12(API 31)开始强制落地的W^X(写时不可执行)安全策略:

  • API 24/25等低版本Android系统中,应用私有目录下的getFilesDir()、getCacheDir()路径默认带执行权限,你放在该路径下的Rust交叉编译二进制可以正常启动
  • 从API 31开始,上述应用私有可写目录会被系统以noexec标记挂载,哪怕你手动给二进制文件设置777权限,内核也会直接拦截执行请求,直接抛出权限拒绝错误。
解决方法

方案1(最稳定,官方兼容):将二进制放入应用原生库目录

这是官方支持的可执行文件存放路径,不会触发noexec限制,操作步骤:

  1. 重命名你编译好的Rust可执行文件,要求以lib开头、后缀为.so,比如原文件名plugintest改为libplugintest.so
  2. 根据CPU架构将文件放入Android工程对应jniLibs目录,比如ARM64架构放到src/main/jniLibs/arm64-v8a/,32位ARM放到src/main/jniLibs/armeabi-v7a/,随APK打包
  3. 替换原有代码中二进制文件的获取逻辑,不要从files目录读取,直接从nativeLibraryDir获取:
// 替换原有pluginFilePath的初始化逻辑
File pluginFilePath = new File(getApplicationInfo().nativeLibraryDir, "libplugintest.so");

// 后续ProcessBuilder逻辑保持不变即可
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command(pluginFilePath.getCanonicalPath(), "-c", pingPath.getCanonicalPath(), "-lp"
        , binFilePath1.getCanonicalPath(), "-o", resultPath.getCanonicalPath());
Process process = processBuilder.start();

注意:不要把lib目录下的so文件拷贝到files/cache目录再执行,拷贝后依然会触发noexec限制。

方案2(适合动态下发插件场景):改造为原生库通过JNI调用

如果你需要动态下发Rust编译的程序、不能随APK打包,可以把Rust代码的编译目标改为cdylib,编译成标准的Android原生共享库,下发后通过System.load()加载,再通过JNI定义的接口调用对应逻辑,完全绕开文件执行的权限限制,全版本兼容。

避坑说明
  • 不需要浪费时间申请READ_EXTERNAL_STORAGE、MANAGE_EXTERNAL_STORAGE等存储权限,Android 10以后公共存储目录同样默认带noexec标记,即使有权限访问文件也无法执行
  • 不需要尝试通过chmod命令修改文件权限,目录挂载的noexec标记优先级高于文件本身的权限位,修改权限无法解决问题
  • 不要尝试将二进制放到/data/local/tmp等系统临时目录,普通第三方应用无权限操作该路径下的可执行文件

内容的提问来源于stack exchange,提问作者HiteshGs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 08:15:51