Android 11执行OpenJDK二进制文件遇「Permission Denied」问题求助
我正在开发一款Android应用,需要执行从OpenJDK 22包中提取的java二进制文件。该文件位于应用的外部文件目录(/storage/emulated/0/Android/data/com.my.newproject31/files/jdk-22.0.2/bin/java)和内部文件目录(/data/data/com.newproject31/files/jdk-22.0.2/bin/java)。但我使用Runtime.getRuntime().exec()执行java -version命令检查版本时,遭遇「Permission Denied」错误。
我已将OpenJDK包提取至应用外部文件目录,尝试执行上述两个路径下的java命令均失败,报错信息为:
java.io.IOException: Cannot run program "/storage/emulated/0/Android/data/com.my.newproject31/files/jdk-22.0.2/bin/java": error=13,Permission denied
我已获取该目录的读写权限,但Android 11引入的作用域存储限制似乎禁止从外部存储执行二进制文件。请问在Android 11上是否有办法执行这类OpenJDK的java二进制文件?
环境信息:
- Android版本:11
- Target SDK:30
1. 放弃外部存储路径,改用应用内部私有目录
Android 11的作用域存储机制明确禁止从外部存储(包括应用专属外部目录/storage/emulated/0/Android/data/...)执行二进制文件,这是系统沙箱的强制限制,没有绕过方法。因此必须将OpenJDK文件放在应用内部私有目录(即/data/data/[你的包名]/files/...,可通过getFilesDir()获取),这个目录是应用完全可控的,不受作用域存储的执行限制。
2. 给二进制文件添加可执行权限
提取OpenJDK文件后,默认的文件权限不包含执行权限,这是导致「Permission Denied」的核心原因之一。你需要通过以下方式为java二进制文件添加可执行权限:
方式一:使用chmod命令
String javaPath = getFilesDir() + "/jdk-22.0.2/bin/java"; // 执行chmod 755赋予所有用户可执行权限 Runtime.getRuntime().exec(new String[]{"chmod", "755", javaPath});
方式二:使用File类的API
File javaFile = new File(getFilesDir(), "jdk-22.0.2/bin/java"); // setExecutable(true, false) 表示允许所有用户执行该文件 javaFile.setExecutable(true, false);
3. 正确执行java命令并配置环境
执行java命令时,需要确保依赖的库和工具可以被正确找到,建议使用ProcessBuilder来配置环境变量,将OpenJDK的bin目录加入PATH:
try { String javaBinDir = getFilesDir() + "/jdk-22.0.2/bin"; String javaPath = javaBinDir + "/java"; // 先确保权限已设置 new File(javaPath).setExecutable(true, false); ProcessBuilder pb = new ProcessBuilder(javaPath, "-version"); Map<String, String> env = pb.environment(); // 将OpenJDK的bin目录加入环境变量PATH,确保依赖的工具能被找到 env.put("PATH", javaBinDir + ":" + env.getOrDefault("PATH", "")); // 合并标准输出和错误输出,方便读取结果 pb.redirectErrorStream(true); Process process = pb.start(); // 读取执行结果 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { // 处理输出,比如打印到日志 Log.d("JavaExec", line); } // 等待命令执行完成 int exitCode = process.waitFor(); Log.d("JavaExec", "Exit code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); }
4. 验证OpenJDK的架构兼容性
确保你下载的OpenJDK二进制文件是针对Android设备架构编译的(比如arm64-v8a、armeabi-v7a)。如果下载的是x86架构的文件,在ARM设备上会执行失败,也可能触发类似权限错误的提示。
内容的提问来源于stack exchange,提问作者safin hoque

