亦余心之所善兮,虽九死其犹未悔。这篇文章主要讲述Android 在Android代码中执行命令行相关的知识,希望能为你提供帮助。
1.路径最好不要是自己拼写的路径/mnt/shell/emulated/0/wifidog.conf
最好是通过方法获取的路径,不然可能导致命令无效
(挂载点的原因)
public static final String SDCARD_ROOT=Environment.getExternalStorageDirectory().getAbsolutePath();
public static final String AAA_PATH=SDCARD_ROOT+"/wifidog.conf";
Android 命令行执行工具类
package com.example.videotest.utils; import android.os.Environment; import android.util.Log; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.InputStreamReader; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import static java.lang.Runtime.getRuntime; /** * 执行命令的类 * Created by Kappa */ public class ExeCommand { //shell进程 private Process process; //对应进程的3个流 private BufferedReader successResult; private BufferedReader errorResult; private DataOutputStream os; //是否同步,true:run会一直阻塞至完成或超时。false:run会立刻返回 private boolean bSynchronous; //表示shell进程是否还在运行 private boolean bRunning = false; //同步锁 ReadWriteLock lock = new ReentrantReadWriteLock(); //保存执行结果 private StringBuffer result = new StringBuffer(); /** * 构造函数 * * @param synchronous true:同步,false:异步 */ public ExeCommand(boolean synchronous) { bSynchronous = synchronous; }/** * 默认构造函数,默认是同步执行 */ public ExeCommand() { bSynchronous = true; }/** * 还没开始执行,和已经执行完成 这两种情况都返回false * * @return 是否正在执行 */ public boolean isRunning() { return bRunning; }/** * @return 返回执行结果 */ public String getResult() { Lock readLock = lock.readLock(); readLock.lock(); try { Log.i("auto", "getResult"); return new String(result); } finally { readLock.unlock(); } }/** * 执行命令 * * @param command eg: cat /sdcard/test.txt * 路径最好不要是自己拼写的路径,最好是通过方法获取的路径 * example:Environment.getExternalStorageDirectory() * @param maxTime 最大等待时间 (ms) * @return this */ public ExeCommand run(String command, final int maxTime) { Log.i("auto", "run command:" + command + ",maxtime:" + maxTime); if (command == null || command.length() == 0) { return this; }try { process = getRuntime().exec("sh"); //看情况可能是su } catch (Exception e) { return this; } bRunning = true; successResult = new BufferedReader(new InputStreamReader(process.getInputStream())); errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream())); os = new DataOutputStream(process.getOutputStream()); try { //向sh写入要执行的命令 os.write(command.getBytes()); os.writeBytes("\\n"); os.flush(); os.writeBytes("exit\\n"); os.flush(); os.close(); //如果等待时间设置为非正,就不开启超时关闭功能 if (maxTime > 0) { //超时就关闭进程 new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(maxTime); } catch (Exception e) { } try { int ret = process.exitValue(); Log.i("auto", "exitValue Stream over"+ret); } catch (IllegalThreadStateException e) { Log.i("auto", "take maxTime,forced to destroy process"); process.destroy(); } } }).start(); }//开一个线程来处理input流 final Thread t1 = new Thread(new Runnable() { @Override public void run() { String line; Lock writeLock = lock.writeLock(); try { while ((line = successResult.readLine()) != null) { line += "\\n"; writeLock.lock(); result.append(line); writeLock.unlock(); } } catch (Exception e) { Log.i("auto", "read InputStream exception:" + e.toString()); } finally { try { successResult.close(); Log.i("auto", "read InputStream over"); } catch (Exception e) { Log.i("auto", "close InputStream exception:" + e.toString()); } } } }); t1.start(); //开一个线程来处理error流 final Thread t2 = new Thread(new Runnable() { @Override public void run() { String line; Lock writeLock = lock.writeLock(); try { while ((line = errorResult.readLine()) != null) { line += "\\n"; writeLock.lock(); result.append(line); writeLock.unlock(); } } catch (Exception e) { Log.i("auto", "read ErrorStream exception:" + e.toString()); } finally { try { errorResult.close(); Log.i("auto", "read ErrorStream over"); } catch (Exception e) { Log.i("auto", "read ErrorStream exception:" + e.toString()); } } } }); t2.start(); Thread t3 = new Thread(new Runnable() { @Override public void run() { try { //等待执行完毕 t1.join(); t2.join(); process.waitFor(); } catch (Exception e) {} finally { bRunning = false; Log.i("auto", "run command process end"); } } }); t3.start(); if (bSynchronous) { Log.i("auto", "run is go to end"); t3.join(); Log.i("auto", "run is end"); } } catch (Exception e) { Log.i("auto", "run command process exception:" + e.toString()); } return this; }}
讲解一下关键点,首先是启动一个sh进程,当然如果你用的是root的设备,可以使用su。
这个进程包含 input、output、error 三个流,这三个流要处理好,否则可能不能正常结束进程,
另外也存在执行的命令已经结束,但是依然还有input流的情况,也需要处理。
其他请参考代码
使用方式为2种。首先是阻塞方式,这种调用方式会一直阻塞至命令执行完成,返回命令行的输出结果
public static final String SDCARD_ROOT=Environment.getExternalStorageDirectory().getAbsolutePath(); public static final String AAA_PATH=SDCARD_ROOT+"/wifidog.conf"; //读取目标文件(绝对路径)指定内容“#TrustedMACList ”的那一行 String cmd3="sed -n \'/#TrustedMACList /,//p\' "+AAA_PATH; String str3 = new ExeCommand().run(cmd3, 10000).getResult(); Log.i("auto", str3+"button3"); Toast.makeText(MainActivity.this, str3,Toast.LENGTH_SHORT).show();
LOG 程序执行的顺序
I/auto( 5542): run command:sed -n \'/#TrustedMACList /,//p\' /storage/emulated/0/wifidog.conf,maxtime:10000 I/auto( 5542): run is go to end I/auto( 5542): read ErrorStream over I/auto( 5542): read InputStream over I/auto( 5542): run command process end I/auto( 5542): run is end I/auto( 5542): getResult I/auto( 5542): #TrustedMACList 00:00:C0:1D:F0:0D,00:00:C0:1D:F0:0D,00:00:C0:1D:F0:0D,00:00:C0:1D:F0:0D,00:00:C0:1D:F0:0D,00:00:DE:AD:BE:AF,00:00:C0:1D:F0:0D I/auto( 5542): I/auto( 5542): button3
还有一种是异步方式,这种调用方式会直接返回,之后可以使用 getResult() 获取结果,使用 isRunning() 来判断是否完成,比如
ExeCommand cmd = new ExeCommand(false).run("your cmd", 60000); while(cmd.isRunning()) { try { sleep(1000); } catch (Exception e) {} String buf = cmd.getResult(); //do something }
【Android 在Android代码中执行命令行】
//修改目标文件指定内容“#TrustedMACList ”
String cmd="sed -i \'s/#TrustedMACList /#TrustedMACList 00:00:C0:1D:F0:0D,/g\' "+AAA_PATH; String str = new ExeCommand().run(cmd, 10000).getResult(); Log.i("auto", str+"button4"); Toast.makeText(MainActivity.this, str,Toast.LENGTH_SHORT).show();
推荐阅读
- 不得不知的的那些Windows进程
- 使用新版Android Studio检测内存泄露和性能
- Android ActivityThread(主线程或UI线程)简介
- AndroidLinker与SO加壳技术之下篇
- Android Studio第二十期 - 识别Recorder声纹显示水波泡泡效果
- 2016这些Android技术会很火
- Android_ADB 常用 shell命令 和 sqlite3 简单增删改查
- Your content must have a ListView whose id attribute is 'android.R.id.list'
- Android开发7(简单的数据存储(使?SharedPreferences)和文件操作)