从android执行shell命令

Posted

技术标签:

【中文标题】从android执行shell命令【英文标题】:execute shell command from android 【发布时间】:2014-01-22 19:15:28 【问题描述】:

我正在尝试从应用程序模拟器终端执行此命令(您可以在 google play 中找到它)在这个应用程序中我写 su 并按 enter,所以写:

screenrecord --time-limit 10 /sdcard/MyVideo.mp4

再按一次enter,使用android kitkat的新功能开始录屏。

所以,我尝试使用这个从 java 执行相同的代码:

Process su = Runtime.getRuntime().exec("su");
Process execute = Runtime.getRuntime().exec("screenrecord --time-limit 10 /sdcard/MyVideo.mp4");

但不工作,因为文件没有创建。显然我在安装了 android kitkat 的 root 设备上运行。问题出在哪里?我该如何解决?因为终端模拟器可以工作,而 Java 不行?

【问题讨论】:

【参考方案1】:

您应该获取刚刚启动的su 进程的标准输入并在那里写下命令,否则您正在使用当前UID 运行命令。

试试这样的:

try
    Process su = Runtime.getRuntime().exec("su");
    DataOutputStream outputStream = new DataOutputStream(su.getOutputStream());

    outputStream.writeBytes("screenrecord --time-limit 10 /sdcard/MyVideo.mp4\n");
    outputStream.flush();

    outputStream.writeBytes("exit\n");
    outputStream.flush();
    su.waitFor();
catch(IOException e)
    throw new Exception(e);
catch(InterruptedException e)
    throw new Exception(e);

【讨论】:

su 的某些版本将在命令行上使用参数,因此您可以例如exec("su -c screenrecord /sdcard/foo.mp4"). 是否可以在没有root权限的情况下进行录制? 非常感谢您提供的这个 sn-p,并且只是补充一下我在这篇文章中错过的是 在命令末尾必须有一个 \n字符串 它返回了以下错误。运行 exec() 时出错。命令:Super User 工作目录:null 环境:null 我运行这些代码得到su error=13, permission denied,它需要root权限吗?【参考方案2】:

@CarloCannas 对代码的修改:

public static void sudo(String...strings) 
    try
        Process su = Runtime.getRuntime().exec("su");
        DataOutputStream outputStream = new DataOutputStream(su.getOutputStream());

        for (String s : strings) 
            outputStream.writeBytes(s+"\n");
            outputStream.flush();
        

        outputStream.writeBytes("exit\n");
        outputStream.flush();
        try 
            su.waitFor();
         catch (InterruptedException e) 
            e.printStackTrace();
        
        outputStream.close();
    catch(IOException e)
        e.printStackTrace();
    

(欢迎大家为outputStream.close()寻找更好的地方)

使用示例:

private static void suMkdirs(String path) 
    if (!new File(path).isDirectory()) 
        sudo("mkdir -p "+path);
    

更新: 要获得结果(输出到标准输出),请使用:

public static String sudoForResult(String...strings) 
    String res = "";
    DataOutputStream outputStream = null;
    InputStream response = null;
    try
        Process su = Runtime.getRuntime().exec("su");
        outputStream = new DataOutputStream(su.getOutputStream());
        response = su.getInputStream();

        for (String s : strings) 
            outputStream.writeBytes(s+"\n");
            outputStream.flush();
        

        outputStream.writeBytes("exit\n");
        outputStream.flush();
        try 
            su.waitFor();
         catch (InterruptedException e) 
            e.printStackTrace();
        
        res = readFully(response);
     catch (IOException e)
        e.printStackTrace();
     finally 
        Closer.closeSilently(outputStream, response);
    
    return res;

public static String readFully(InputStream is) throws IOException 
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int length = 0;
    while ((length = is.read(buffer)) != -1) 
        baos.write(buffer, 0, length);
    
    return baos.toString("UTF-8");

静默关闭多个 Closeables (Soсket may be no Closeable) 的实用程序是:

public class Closer 
// closeAll()
public static void closeSilently(Object... xs) 
    // Note: on Android API levels prior to 19 Socket does not implement Closeable
    for (Object x : xs) 
        if (x != null) 
            try 
                Log.d("closing: "+x);
                if (x instanceof Closeable) 
                    ((Closeable)x).close();
                 else if (x instanceof Socket) 
                    ((Socket)x).close();
                 else if (x instanceof DatagramSocket) 
                    ((DatagramSocket)x).close();
                 else 
                    Log.d("cannot close: "+x);
                    throw new RuntimeException("cannot close "+x);
                
             catch (Throwable e) 
                Log.x(e);
            
        
    


【讨论】:

你先生,摇滚。是的。【参考方案3】:
Process p;
StringBuffer output = new StringBuffer();
try 
    p = Runtime.getRuntime().exec(params[0]);
    BufferedReader reader = new BufferedReader(
            new InputStreamReader(p.getInputStream()));
    String line = "";
    while ((line = reader.readLine()) != null) 
        output.append(line + "\n");
        p.waitFor();
    
 
catch (IOException e) 
    e.printStackTrace();
 catch (InterruptedException e) 
    e.printStackTrace();

String response = output.toString();
return response;

【讨论】:

我无法使用上述命令执行器am start -n com.qop.tabletApp.activity.ConfigurationAndSetup启动应用程序

以上是关于从android执行shell命令的主要内容,如果未能解决你的问题,请参考以下文章

如何在android程序中执行adb shell命令

在 Android 上通过 java 代码运行 Shell 命令?

如何在android程序中执行adb shell命令

如何以编程方式在android中使用blktrace命令执行shell脚本?

利用shell命令实现Eeclipse对Android的远程调试

Android 代码中执行adb shell命令