02/21
2014

Android Java执行Shell命令

主要介绍Android或Java应用中如何以默认用户或root用户执行Shell命令,ShellUtils的API介绍、使用及使用场景(如静默安装和卸载、修改hosts文件、拷贝文件)。使用纯Java实现,所以对Java程序同样适用。

 

很多朋友在使用TrineaAndroidCommon@Github中的ShellUtils工具类了,那就大致介绍下他的功能吧。

 

1、API介绍

以下是ShellUtils中最终执行命令的方法execCommand
public CommandResult execCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg)

其中commands表示依次执行的shell命令数组

isRoot表示是否以su用户执行(需要手机已经root)

isNeedResultMsg表示是否存储命令执行成功及失败后的信息。

/**
 * result of command
 * 
 * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-16
 */
public static class CommandResult {

	/** result of command **/
	public int    result;
	/** success message of command result **/
	public String successMsg;
	/** error message of command result **/
	public String errorMsg;

	public CommandResult(int result){
		this.result = result;
	}

	public CommandResult(int result, String successMsg, String errorMsg){
		this.result = result;
		this.successMsg = successMsg;
		this.errorMsg = errorMsg;
	}
}

CommandResult 为返回的数据结构,如下其中result表示执行的结果,根据linux命令执行规则,0表示成功,其他为相应错误码。

successMsg存储执行成功后的输出信息,errorMsg存储执行失败后的输出信息。

如果isNeedResultMsg为false,successMsg和errorMsg会始终为空,而result依然为正常结果。

 

其他接口,Shell命令支持执行String(单个命令), List(多个命令),String[](多个命令)

见:ShellUtils.java#Api Guide

 

2、使用

(1)引入公共库
引入TrineaAndroidCommon@Github(欢迎star和fork^_^)作为你项目的library(如何拉取代码及添加公共库)。

 

(2) 调用上面介绍的execCommand函数,

注意有些命令可能运行时间较长,所以最好在线程中执行execCommand

 

3、使用场景

以目前自己的几个场景举下例子

(1) 静默安装和卸载

这个很多朋友已经用过了Android root权限静默安装或卸载应用,原理是执行命令:pm install apkFilePath及pm uninstall packageName

具体代码可见:PackageUtils installSilent(Context context, String filePath, String pmParams)

 

(2) 获取系统设置->存储->首选安装位置

原理是执行命令:pm get-install-location

具体代码可见:PackageUtils getInstallLocation()

 

(3) Android修改hosts文件

原理是执行命令:

mount -o rw,remount /system
echo “127.0.0.1 localhost” > /etc/hosts
echo “185.31.17.184 github.global.ssl.fastly.net” >> /etc/hosts
chmod 644 /etc/hosts

代码如下:

List<String> commnandList = new ArrayList<String>();
commnandList.add("mount -o rw,remount /system");
commnandList.add("echo \"127.0.0.1 localhost\" > /etc/hosts");
commnandList.add("echo \"185.31.17.184 github.global.ssl.fastly.net\" >> /etc/hosts");
commnandList.add("chmod 644 /etc/hosts");
CommandResult result = ShellUtils.execCommand(commnandList, true);

用echo命令改hosts文件很牛逼哦,不用重启可以直接生效的哦。

 

(4) 拷贝文件

原理是执行命令:

mount -o rw,remount /system

cp /mnt/sdcard/xx.apk /system/app/

代码如下:

String[] commands = new String[] { "mount -o rw,remount /system", "cp /mnt/sdcard/xx.apk /system/app/" };
CommandResult result = ShellUtils.execCommand(commands, true);

注意一般拷贝文件是不需要root的,上面用root是因为需要拷贝到/system/app/下面

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

31 thoughts on “Android Java执行Shell命令

  1. 请教楼主,我的手机是eng版本,有root权限,执行ShellUtils.execCommand(new String[]{” cat /sys/kernel/debug/tcore/tee_version”}, true);报错如下:

    07-12 09:11:00.585: W/System.err(8408): java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null
    07-12 09:11:00.591: W/System.err(8408): at java.lang.ProcessManager.exec(ProcessManager.java:211)
    07-12 09:11:00.602: W/System.err(8408): at java.lang.Runtime.exec(Runtime.java:174)
    07-12 09:11:00.611: W/System.err(8408): at java.lang.Runtime.exec(Runtime.java:247)
    07-12 09:11:00.615: W/System.err(8408): at java.lang.Runtime.exec(Runtime.java:190)
    07-12 09:11:00.617: W/System.err(8408): at com.example.cmdtest.ShellUtils.execCommand(ShellUtils.java:135)
    07-12 09:11:00.619: W/System.err(8408): at com.example.cmdtest.ShellUtils.execCommand(ShellUtils.java:80)
    07-12 09:11:00.621: W/System.err(8408): at com.example.cmdtest.MainActivity.onCreate(MainActivity.java:33)
    07-12 09:11:00.624: W/System.err(8408): at android.app.Activity.performCreate(Activity.java:6286)
    07-12 09:11:00.626: W/System.err(8408): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1113)
    07-12 09:11:00.628: W/System.err(8408): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2500)
    07-12 09:11:00.630: W/System.err(8408): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2613)
    07-12 09:11:00.631: W/System.err(8408): at android.app.ActivityThread.-wrap11(ActivityThread.java)
    07-12 09:11:00.634: W/System.err(8408): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1469)
    07-12 09:11:00.636: W/System.err(8408): at android.os.Handler.dispatchMessage(Handler.java:111)
    07-12 09:11:00.637: W/System.err(8408): at android.os.Looper.loop(Looper.java:207)
    07-12 09:11:00.640: W/System.err(8408): at android.app.ActivityThread.main(ActivityThread.java:5695)
    07-12 09:11:00.641: W/System.err(8408): at java.lang.reflect.Method.invoke(Native Method)
    07-12 09:11:00.644: W/System.err(8408): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
    07-12 09:11:00.645: W/System.err(8408): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:749)
    07-12 09:11:00.647: W/System.err(8408): Caused by: java.io.IOException: Permission denied
    07-12 09:11:00.652: W/System.err(8408): at java.lang.ProcessManager.exec(Native Method)
    07-12 09:11:00.654: W/System.err(8408): at java.lang.ProcessManager.exec(ProcessManager.java:209)
    07-12 09:11:00.655: W/System.err(8408): … 18 more

    怎么解决啊,跪求指教

  2. 请教楼主,执行你上面的第4种,拷贝文件命令。报下面错误,是什么情况呢?
    01-02 11:39:09.875: W/System.err(29417): java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null

  3. 我的程序 List commandList = new ArrayList(); commandList.add(“mount -o rw,remount /system”); commandList.add(“ping 9.9.9.9 -n 1 -w 5000″); //commandList.add(“echo “185.31.17.184 github.global.ssl.fastly.net” >> /etc/hosts”); commandList.add(“chmod 777 /data/data/nand_test”); CommandResult result = ShellUtils.execCommand(commandList, true); 第一个命令,运行到下面语句的时候报错 os.write(command.getBytes());01-06 16:31:42.792: W/System.err(12280): java.io.IOException: write failed: EPIPE (Broken pipe)01-06 16:31:42.792: W/System.err(12280): at libcore.io.IoBridge.write(IoBridge.java:470)01-06 16:31:42.792: W/System.err(12280): at java.io.FileOutputStream.write(FileOutputStream.java:187)01-06 16:31:42.792: W/System.err(12280): at java.io.DataOutputStream.write(DataOutputStream.java:98)01-06 16:31:42.802: W/System.err(12280): at java.io.OutputStream.write(OutputStream.java:82)01-06 16:31:42.802: W/System.err(12280): at com.spreadtrum.test.util.ShellUtils.execCommand(ShellUtils.java:143)01-06 16:31:42.802: W/System.err(12280): at com.spreadtrum.test.util.ShellUtils.execCommand(ShellUtils.java:68)01-06 16:31:42.802: W/System.err(12280): at com.spreadtrum.test.iprecondition.ComPublicFunction.runShellCommand2(ComPublicFunction.java:605)01-06 16:31:42.802: W/System.err(12280): at com.spreadtrum.test.task.RomOperationTask.doInBackground(RomOperationTask.java:87)01-06 16:31:42.812: W/System.err(12280): at com.spreadtrum.test.task.RomOperationTask.doInBackground(RomOperationTask.java:1)01-06 16:31:42.812: W/System.err(12280): at android.os.AsyncTask$2.call(AsyncTask.java:288)01-06 16:31:42.812: W/System.err(12280): at java.util.concurrent.FutureTask.run(FutureTask.java:237)01-06 16:31:42.812: W/System.err(12280): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)01-06 16:31:42.812: W/System.err(12280): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)01-06 16:31:42.822: W/System.err(12280): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)01-06 16:31:42.822: W/System.err(12280): at java.lang.Thread.run(Thread.java:841)01-06 16:31:42.822: W/System.err(12280): Caused by: libcore.io.ErrnoException: write failed: EPIPE (Broken pipe)01-06 16:31:42.822: W/System.err(12280): at libcore.io.Posix.writeBytes(Native Method)01-06 16:31:42.832: W/System.err(12280): at libcore.io.Posix.write(Posix.java:202)01-06 16:31:42.832: W/System.err(12280): at libcore.io.BlockGuardOs.write(BlockGuardOs.java:197)01-06 16:31:42.832: W/System.err(12280): at libcore.io.IoBridge.write(IoBridge.java:465)01-06 16:31:42.832: W/System.err(12280): … 14 more

  4. Pingback: 如何在Android中执行monkey命令 | XiXi的博客

  5. 请问LZ,假如我需要执行某一个运行的命令,直到发出停止的信号才结束的这个命令,然后才返回执行结果。就像运行某个监控指令,然后一直运行着,直到手动去关闭它才停止。这个发出的停止信号貌似不能放在同一个execCommand啊,而且我需要模拟这个键盘上按下的ctrl+c的终止信号,这个怎么弄呢?