2011-08-01 81 views
11

首先我将介绍我的情况。 我需要在我的android应用程序中执行“su”命令,它运行良好。然后我需要执行“ls”命令并读取输出。我通过从“su”进程获取输出流并将其写入其中来执行此操作。su过程中读取命令输出

这里是个问题。如何读取“ls”过程的输出?我所拥有的就是“su”过程对象。从中获取输入流不会产生任何效果,因为“su”不会写入任何内容。但是“ls”确实存在,我不知道如何访问它的输出消息。

我搜查了很多网站,但我没有找到任何解决方案。也许有人会帮我:)这里提到

问候

回答

23

好吧,我已经找到了解决办法。它应该是这样的:

Process p = Runtime.getRuntime().exec(new String[]{"su", "-c", "system/bin/sh"}); 
DataOutputStream stdin = new DataOutputStream(p.getOutputStream()); 
//from here all commands are executed with su permissions 
stdin.writeBytes("ls /data\n"); // \n executes the command 
InputStream stdout = p.getInputStream(); 
byte[] buffer = new byte[BUFF_LEN]; 
int read; 
String out = new String(); 
//read method will wait forever if there is nothing in the stream 
//so we need to read it in another way than while((read=stdout.read(buffer))>0) 
while(true){ 
    read = stdout.read(buffer); 
    out += new String(buffer, 0, read); 
    if(read<BUFF_LEN){ 
     //we have read everything 
     break; 
    } 
} 
//do something with the output 

希望这将是有益的人

+4

如果系统调用不返回任何内容,则read()函数会挂起。在这个特殊情况下,“ls”应该总是返回一些东西,但是请记住它可能会与其他命令一起停止。 – pmont

+1

@glodos有没有办法做到这一点,而不指定BUFF_LEN?也就是说,一次读一行,直到没有更多的行? –

+0

嗨,我一直在成功地使用你的例子,但我努力让这个工作在Android Nougat上。任何人有任何想法呢? – zeroprobe

4
public String ls() { 
    Class<?> execClass = Class.forName("android.os.Exec"); 
    Method createSubprocess = execClass.getMethod("createSubprocess", String.class, String.class, String.class, int[].class); 
    int[] pid = new int[1]; 
    FileDescriptor fd = (FileDescriptor)createSubprocess.invoke(null, "/system/bin/ls", "/", null, pid); 

    BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(fd))); 
    String output = ""; 
    try { 
     String line; 
     while ((line = reader.readLine()) != null) { 
      output += line + "\n"; 
     } 
    } 
    catch (IOException e) {} 
    return output; 
} 

检查这个代码:

How to run terminal command in Android application?


try { 
// Executes the command. 
Process process = Runtime.getRuntime().exec("/system/bin/ls /sdcard"); 

// Reads stdout. 
// NOTE: You can write to stdin of the command using 
//  process.getOutputStream(). 
BufferedReader reader = new BufferedReader(
     new InputStreamReader(process.getInputStream())); 
int read; 
char[] buffer = new char[4096]; 
StringBuffer output = new StringBuffer(); 
while ((read = reader.read(buffer)) > 0) { 
    output.append(buffer, 0, read); 
} 
reader.close(); 

// Waits for the command to finish. 
process.waitFor(); 

return output.toString(); 
} catch (IOException e) { 
throw new RuntimeException(e); 
} catch (InterruptedException e) { 
throw new RuntimeException(e); 
} 

参考

this code GScript

+0

此代码不会去上班。没有像“android.os.Exec”这样的类。我读过它在Froyo和更高版本上不再工作。 – glodos

+0

mmm检查另一个/ –

+0

我尝试过类似的命令,但在命令前加上了“su”,但是然后系统要求每次执行的权限与以前不同(例如列出另一个目录)。我所需要做的只是获得“su”命令的许可(用户单击记住并且系统不会再次请求),然后在此进程中执行我的命令并读取它们的输出。要清楚:1.创建su进程。 2.将“ls”命令写入输出流(ls使用su许可执行)。 3.阅读“ls”输出。我无法实现第3点 – glodos

0

我修改接受的答案被@glodos对以下问题:

  1. 流被关闭,否则EXEC过程在打开的流中永远挂起。如果在执行多次执行后在shell中执行ps(即adb shell) ,则会看到多个su进程 处于活动状态。他们需要妥善终止。
  2. 添加了waitFor()以确保过程终止。
  3. 增加了对read=-1的处理,现在可以执行空指令stdout。以前他们坠毁在new String(buffer, 0, read)
  4. 使用StringBuffer更有效的字符串处理。

    private String execCommand(String cmd) throws IOException, InterruptedException { 
        Process p = Runtime.getRuntime().exec(new String[]{"su", "-c", "system/bin/sh"}); 
        DataOutputStream stdout = new DataOutputStream(p.getOutputStream()); 
    
        stdout.writeBytes(cmd); 
        stdout.writeByte('\n'); 
        stdout.flush(); 
        stdout.close(); 
    
        BufferedReader stdin = new BufferedReader(new InputStreamReader(p.getInputStream())); 
        char[] buffer = new char[1024]; 
        int read; 
        StringBuffer out = new StringBuffer(); 
    
        while((read = stdin.read(buffer)) > 0) { 
         out.append(buffer, 0, read); 
        } 
        stdin.close(); 
        p.waitFor(); 
        return out.toString(); 
    } 
    

一些学分去@Sherif elKhatib))