Android提供了两种执行shell命令的方法。
1.Runtime.getRuntime().exec(cmds)
2.ProcessBuilder(cmds)
两种方法背后的逻辑相同。都是创建一个新的进程,执行shell命令。本文以第一种方法为例。代码如下:
public class RuntimeExcUtil {
public static int run(String[] fCmds){
int tCode=0;
mLogger.i("APP_SHELL", "start run");
try {
Process tProcess = Runtime.getRuntime().exec(fCmds);
printError(tProcess);
tCode = tProcess.waitFor();
mLogger.i("APP_SHELL", "Code Result= "+tCode);
} catch (Exception e) {
mLogger.e("APP_SHELL", "run Failed, Error Message :"+e.getMessage());
}
return tCode;
}
public static int runWithSu(String[] fCmds){
int tCode=0;
mLogger.i("APP_SHELL", "start run");
try {
Process tProcess = Runtime.getRuntime().exec("su");
runShellScript(tProcess,fCmds);
printError(tProcess);
tCode = tProcess.waitFor();
mLogger.i("APP_SHELL", "Code Result= "+tCode);
} catch (Exception e) {
mLogger.e("APP_SHELL", "runWithSu Failed, Error Message :"+e.getMessage());
}
return tCode;
}
private static void printError(Process fProcess){
StringBuilder output = new StringBuilder();
String line;
try(BufferedReader tReader = new BufferedReader(
new InputStreamReader(fProcess.getErrorStream()))) {
while ((line = tReader.readLine()) != null) {
output.append(line).append("\n");
}
if (output.toString().length()>0){
mLogger.e("APP_SHELL", "Error Output = "+output);
}
}catch (Exception e){
mLogger.e("APP_SHELL", "Print Error Output Failed, Error Message :"+e.getMessage());
}
}
private static void runShellScript(Process fProcess, String[] fCmds){
try(DataOutputStream outputStream = new DataOutputStream(fProcess.getOutputStream())) {
for (String tCmd :
fCmds) {
Log.i("APP_SHELL", "Cmd :" + tCmd);
outputStream.writeBytes(tCmd + "\n");
}
outputStream.flush();
outputStream.writeBytes("exit\n");
outputStream.flush();
} catch (Exception e) {
Log.e("APP_SHELL", "Run Shell Script Failed, Error Message :"+e.getMessage());
}
}
}
测试代码如下:
//case 1
RuntimeExcUtil.runWithSu(new String[]{"cp -a -p "+tJavaCrashLogFolderPath+" "+ tCollectFolder});
//case 2
RuntimeExcUtil.runWithSu(new String[]{"cd "+tJavaCrashLogFolderPath,"rm -f crash*"});
//case 3
RuntimeExcUtil.run(new String[]{"cd /sdcard/Download"});
//case 4
RuntimeExcUtil.run(new String[]{"cd", "/sdcard/Download"});
//case 5
RuntimeExcUtil.run(new String[]{"cp -a -p "+tJavaCrashLogFolderPath+" "+ tCollectFolder});
//case 6
RuntimeExcUtil.run(new String[]{"cp", "-a", "-p", tJavaCrashLogFolderPath,tCollectFolder});
//case 7
RuntimeExcUtil.run(new String[]{"rm -f /sdcard/crash/crash*"});
//case 8
RuntimeExcUtil.run(new String[]{"rm", "-f", "/sdcard/crash/crash*"});
Case | 结果分析 |
1 | 结果:执行成功。 原因:创建su窗口,并获取上下文,将后续指令写入 DataOutputStream。不会有权限问题,不会有指令解析问题。 |
2 | 结果:同1 原因:同1 |
3 | 结果:执行失败。返回Cannot run program "cd /sdcard/Download": error=2, No such file or directory。 原因:将整个命令字符串作为一个参数传递给 |
4 | 结果:执行失败。返回Cannot run program "cd": error=13, Permission denied。 原因:“cd”是用来改变当前工作目录的 shell 命令,并不是一个可执行程序。所以会得到 "Permission denied" 的错误,这是因为 Android 不允许直接执行这种命令。 |
5 | 结果:同3 原因:同3 |
6 | 结果:执行成功 原因:将指令与参数分开,方便解析。 |
7 | 结果:同3 原因:同3 |
8 | 结果:执行成功 原因:将指令与参数分开,方便解析。 |