Android Runtime.getRuntime().exec() 使用方法
苍痕 2015-04-08 15:05:01 26143 收藏 5 版权 Android 可以通过Runtime.getRuntime().exec()方法来执行命令或者创建进程。
1. Runtime.getRuntime().exec共有六个重载方法:
public Process exec(String command)
在单独的进程中执行指定的字符串命令。
public Process exec(String [] cmdArray)
在单独的进程中执行指定命令和变量
public Process exec(String command, String [] envp)
在指定环境的独立进程中执行指定命令和变量
public Process exec(String [] cmdArray, String [] envp)
在指定环境的独立进程中执行指定的命令和变量
public Process exec(String command,String[] envp,File dir)
在有指定环境和工作目录的独立进程中执行指定的字符串命令
public Process exec(String[] cmdarray,String[] envp,File dir)
在指定环境和工作目录的独立进程中执行指定的命令和变量
我们先来比较exec(String command)与exec(String[] cmdArray)的区别,其实他们是等价的,最终都会调用:
exec(String[] cmdarray,String[] envp,File dir),我们看看方法exec(String cmdarray,String[] envp,File dir) throws IOException的实现代码:
public Process exec(String command, String[] envp, File dir) throws IOException { if (command.length() == 0) throw new IllegalArgumentException("Empty command"); StringTokenizer st = new StringTokenizer(command); String[] cmdarray = new String[st.countTokens()]; for (int i = 0; st.hasMoreTokens(); i++) { cmdarray[i] = st.nextToken(); } return exec(cmdarray, envp, dir); } 从上面的代码,我们可以看出最终调用的代码都是:exec(String[] cmdArray,String envp,File dir)。exec(String command)相当于exec(command,null,null),exec(String[] cmdArray)相当于exec(cmdArray,null,null)。 2. 参数说明:
cmdarray- 包含所调用命令及其参数的数组
envp- 字符串数组,其中每个元素的环境变量的设置格式为 name=value,如果子进程应该继承当前进程的环境,或该参数为 null
dir- 子进程的工作目录;如果子进程应该继承当前进程的工作目录,则该参数为 null
3. 关于返回结果类型:Process,它有几个方法:
(1).destroy():杀掉子进程
(2).exitValue():返回子进程的出口值,值0表示正常终止
(3).getErrorStream():获取子进程的错误流
(4).getInputStream():获取子进程的输入流
(5).getOutputStream():获取子进程的输出流
(6).waitFor():导致当前线程等待,如有必要,一直要等到由该Process对象表示的进程已经终止。如果已终止该子进程,此方法立即返回。如果没有终止该子进程,调用的线程将被阻塞,直到退出子进程,根据惯例, 0表示正常终止
4. 如何获取command 最终执行的结果? (1) 执行command命令,将命令行输出重定向到一个文件,再读取文件判断执行结果。
比如命令:javap -l xxx > output.txt , 调用exec(String[] cmdArray)如下:
Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c", "javap -l xxx > output.txt"}); (2) 也可以通过InputStream/OutputStream, 获取命令执行的结果。
下面例子是先利用“su”提权,然后执行command,完整代码:
private static boolean exeCommand(String command) { boolean ret = false; try { VirtualTerminal vt; vt = new VirtualTerminal("su"); VTCommandResult r = vt.runCommand(command); ret = r.success(); vt.shutdown(); } catch (Exception e) { e.printStackTrace(); } return ret; } VirtualTerminal.java
package com.test.mytest; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import android.util.Log; public class VirtualTerminal { private static final String TAG = "VirtualTerminal"; private final Object mReadLock = new Object(); private final Object mWriteLock = new Object(); private Process mProcess = null; private DataOutputStream mOutputStream; private ByteArrayOutputStream mInputBuffer = new ByteArrayOutputStream(); private ByteArrayOutputStream mErrBuffer = new ByteArrayOutputStream(); private InputReaderThread mInputReaderThread; private InputReaderThread mErrReaderThread; public VirtualTerminal(String shell) throws IOException, InterruptedException { mProcess = Runtime.getRuntime().exec(shell); mOutputStream = new DataOutputStream(mProcess.getOutputStream()); mInputReaderThread = new InputReaderThread(mProcess.getInputStream(), mInputBuffer); mErrReaderThread = new InputReaderThread(mProcess.getErrorStream(), mErrBuffer); Thread.sleep(50); mInputReaderThread.start(); mErrReaderThread.start(); } public VTCommandResult runCommand(String command) throws Exception { synchronized (mWriteLock) { mInputBuffer.reset(); mErrBuffer.reset(); } // $? 表示最后运行的命令的结束代码(返回值) mOutputStream.writeBytes(command + "\necho :RET=$?\n"); mOutputStream.flush(); while (true) { synchronized (mReadLock) { boolean doWait = false; synchronized (mWriteLock) { byte[] inpbyte = mInputBuffer.toByteArray(); String inp = new String(inpbyte); doWait = !inp.contains(":RET="); } if (doWait) { mReadLock.wait(); } } synchronized (mWriteLock) { byte[] inpbyte = mInputBuffer.toByteArray(); byte[] errbyte = mErrBuffer.toByteArray(); String inp = new String(inpbyte); String err = new String(errbyte); //Please keep log statement or else it will dead loop if (inp.contains(":RET=")) { if (inp.contains(":RET=EOF") || err.contains(":RET=EOF")) { Log.w(TAG, "exec:[eof]" + inp); } if (inp.contains(":RET=0")) { Log.w(TAG, "exec:[ok]" + inp); return new VTCommandResult(0, inp, err); } else { Log.w(TAG, "exec:[err]" + inp); return new VTCommandResult(1, inp, err); } } } } } public void shutdown() { mInputReaderThread.interrupt(); mErrReaderThread.interrupt(); mProcess.destroy(); } /** * A thread class helps to read/write data */ public class InputReaderThread extends Thread { private InputStream mInputStream; private ByteArrayOutputStream mByteArrayOutputStream; public InputReaderThread(InputStream in, ByteArrayOutputStream out) { mInputStream = in; mByteArrayOutputStream = out; } @Override public void run() { if (mInputStream != null) { try { byte[] buffer = new byte[1024]; while (true) { int read = mInputStream.read(buffer); if (read < 0) { synchronized(mWriteLock) { String eof = ":RET=EOF"; mByteArrayOutputStream.write(eof.getBytes()); } synchronized (mReadLock) { mReadLock.notifyAll(); } break; } else if (read > 0) { synchronized(mWriteLock) { mByteArrayOutputStream.write(buffer, 0, read); } synchronized (mReadLock) { mReadLock.notifyAll(); } } } } catch (Exception ex) { ex.printStackTrace(); } } } } /** * A result wrapper for exec() */ public class VTCommandResult { public final String mStdout; public final String mStderr; public final Integer mExitValue; VTCommandResult(Integer exit_value_in, String stdout_in, String stderr_in) { mExitValue = exit_value_in; mStdout = stdout_in; mStderr = stderr_in; } VTCommandResult(Integer exit_value_in) { this(exit_value_in, null, null); } public boolean success() { return mExitValue != null && mExitValue == 0; } } } 5. 如何用Worker thread 实现 exec() 的等待超时机制?
/** * 运行一个外部命令,返回状态, 可以设置超时时间 * @param command * @param timeout, in milliseconds * @return */ private int execCommand(final String[] commandArray, final long timeout) { Worker worker = null; try { worker = new Worker(commandArray); worker.start(); worker.join(timeout); } catch (Throwable t) { t.printStackTrace(); } finally { if (worker.exit != Integer.MAX_VALUE) { return worker.exit; } else { worker.interrupt(); } } return ErrorCodeDefine.DOROOT_FAIL; } /** * 用Worker thread 可以实现超时机制 */ private static class Worker extends Thread { private final String[] commandArray; private int exit = Integer.MAX_VALUE; private Worker(String[] commandArray) { this.commandArray = commandArray; } public void run() { Process process = null; try { process = Runtime.getRuntime().exec(commandArray); if (process != null) { exit = process.waitFor(); } } catch (InterruptedException e) { e.printStackTrace(); } catch (Throwable t) { t.printStackTrace(); } finally { if (process != null) { killProcess(process); } } } } /** * 通过Android底层实现进程关闭 */ private static void killProcess(Process process) { int pid = getProcessId(process.toString()); if (pid != 0) { try { closeAllStream(process); android.os.Process.killProcess(pid); } catch (Exception e) { try { process.destroy(); } catch (Exception ex) { ex.printStackTrace(); } } } } /** * 获取当前进程的ID */ private static int getProcessId(String str) { try { int i = str.indexOf("=") + 1; int j = str.indexOf("]"); String cStr = str.substring(i, j).trim(); return Integer.parseInt(cStr); } catch (Exception e) { return 0; } } /** * 关闭进程的所有流 * * @param process */ public static void closeAllStream(Process process) { try { InputStream in = process.getInputStream(); if (in != null) in.close(); } catch (Exception e) { e.printStackTrace(); } try { InputStream in = process.getErrorStream(); if (in != null) in.close(); } catch (Exception e) { e.printStackTrace(); } try { OutputStream out = process.getOutputStream(); if (out != null) out.close(); } catch (Exception e) { e.printStackTrace(); }
———————————————— 版权声明:本文为博主「苍痕」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/wangbaochu/article/details/44941045