在Android开发中,调用命令行(也称为执行Shell命令)是一个常见的需求,尤其是在需要系统级操作、性能优化或与底层组件交互的场景中,Android基于Linux内核,因此其命令行环境与Linux类似,开发者可以通过Java代码或NDK(Native Development Kit)来执行Shell命令,本文将详细介绍Android调用命令行的多种方法、注意事项及实际应用场景。

调用命令行的方法
Android中执行Shell命令主要通过Runtime类或ProcessBuilder类实现,两者均属于Java标准库,无需额外依赖,以下是具体实现方式:
使用Runtime类
Runtime类提供了exec()方法来执行命令,该方法支持传入命令字符串或字符串数组,字符串数组形式更推荐,因为它能避免命令注入风险(通过参数分割自动处理空格和特殊字符)。
try {
// 执行简单命令(如获取设备型号)
Process process = Runtime.getRuntime().exec("getprop ro.product.model");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
Log.d("ShellCommand", line);
}
process.waitFor(); // 等待命令执行完成
} catch (Exception e) {
e.printStackTrace();
}
使用ProcessBuilder类
ProcessBuilder提供了更灵活的进程管理功能,如设置工作目录、环境变量等,它通过链式调用配置参数,代码可读性更高。
try {
// 执行复杂命令(如同时执行多个命令)
ProcessBuilder processBuilder = new ProcessBuilder("ls", "-l", "/sdcard");
processBuilder.redirectErrorStream(true); // 合并错误流和输出流
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
Log.d("ShellCommand", line);
}
int exitCode = process.waitFor();
Log.d("ShellCommand", "Exit code: " + exitCode);
} catch (Exception e) {
e.printStackTrace();
}
通过NDK执行命令
对于需要高性能或直接调用C库的场景,可通过NDK使用system()函数或popen()执行命令,在C代码中:

#include <stdlib.h>
int main() {
system("ls /data/data"); // 执行Shell命令
return 0;
}
编译为SO库后,在Java层通过System.loadLibrary()加载并调用 native 方法。
命令执行的关键参数与流程
| 参数/流程 | 说明 |
|---|---|
| 命令输入 | 通过exec()或ProcessBuilder传入命令字符串或数组,数组形式更安全。 |
| 输入流管理 | 通过Process.getInputStream()获取命令输出,getErrorStream()获取错误信息。 |
| 线程阻塞 | 主线程调用waitFor()会导致ANR,建议在子线程中执行命令。 |
| 权限处理 | 普通应用只能执行shell用户权限的命令,需root权限才能执行高危操作。 |
| 超时控制 | 可通过Process.destroy()强制终止超时进程,或使用Handler实现超时逻辑。 |
实际应用场景
-
系统信息获取
通过执行getprop、dumpsys等命令获取设备参数、系统状态。Process process = Runtime.getRuntime().exec("dumpsys battery"); -
文件操作
使用cp、rm等命令管理文件,但需注意Android的文件系统权限限制。 -
性能监控
执行top、ps命令获取CPU、内存使用情况,结合BufferedReader解析输出。
(图片来源网络,侵删) -
Root权限操作
在已Root设备上,通过su命令提升权限执行系统级操作(如修改系统文件)。
注意事项
-
权限限制
Android 10及以上版本对非应用私有目录的访问限制严格,部分命令可能因权限不足失败。 -
安全性问题
避免直接拼接用户输入到命令中,防止命令注入攻击。// 错误示例:直接拼接用户输入 Runtime.getRuntime().exec("rm " + userInput); // 正确做法:使用参数数组 Runtime.getRuntime().exec(new String[]{"rm", userInput}); -
ANR风险
长时间运行的命令(如ping)应在AsyncTask或IntentService中执行,避免阻塞主线程。 -
输出缓冲区
命令输出量大时需及时读取输入流,否则可能导致进程阻塞(缓冲区满)。
相关问答FAQs
Q1: 为什么在Android中执行某些Shell命令时提示“Permission denied”?
A1: 这是由于Android的权限机制限制,普通应用只能执行shell用户权限的命令,且无法访问受保护的系统目录(如/system),若需执行高危操作,需满足以下条件之一:
- 设备已Root,并通过
su命令提升权限; - 使用系统应用签名(如Android系统应用);
- 通过
adb shell调试时授予临时权限。
Q2: 如何在Android中执行需要持续输出的命令(如logcat)并实时处理结果?
A2: 对于持续输出的命令,需在子线程中循环读取输入流,避免阻塞,示例代码如下:
new Thread(() -> {
try {
Process process = Runtime.getRuntime().exec("logcat -d");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
// 实时处理每一行输出
Log.d("Logcat", line);
}
} catch (Exception e) {
e.printStackTrace();
}
}).start();
可通过Process.destroy()终止命令,或使用logcat -c清空缓冲区。
