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 | 结果:执行成功 原因:将指令与参数分开,方便解析。 |