2011-08-01 16 views
11

en primer lugar voy a presentar mi situación. Necesito ejecutar el comando "su" en mi aplicación de Android y funciona bien. Entonces necesito ejecutar el comando "ls" y leer el resultado. Lo hago obteniendo el flujo de salida del proceso "su" y escribiendo mi comando en él.Lea la salida del comando dentro de su proceso

Y aquí va la pregunta. ¿Cómo leer el resultado del proceso "ls"? Todo lo que tengo es el objeto de proceso "su". Obtener el flujo de entrada de él no da nada, porque "su" no escribe nada. Pero "ls" sí y no sé cómo acceder a sus mensajes de salida.

He buscado en muchos sitios pero no he encontrado ninguna solución. Tal vez alguien me va a ayudar :)

Saludos

Respuesta

23

Ok, he encontrado una solución. Se debe tener este aspecto:

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 

Esperamos que sea útil para alguien

+4

La llamada a read() se detiene si la llamada al sistema no devuelve nada. En este caso particular, "ls" siempre debería devolver algo, pero solo tenga en cuenta que podría quedarse bloqueado con otros comandos. – pmont

+1

@glodos ¿Hay alguna manera de hacerlo sin especificar BUFF_LEN? Es decir, ¿leer una línea a la vez hasta que no haya más líneas? –

+0

Hola, he estado usando tu ejemplo con éxito pero estoy luchando para que esto funcione en Android Nougat. Alguien tiene alguna idea para esto? – 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; 
} 

Comprobar el código mencionado aquí:

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); 
} 

Referencias

this code GScript

+0

Este código no va a funcionar. No existe una clase como "android.os.Exec". He leído que ya no funciona en Froyo y más. – glodos

+0

mmm verifique el otro/ –

+0

Intenté algo así, pero con "su" antes del comando, pero luego el sistema solicita permiso para cada ejecución que de alguna manera difiere de la anterior (por ejemplo, listando otro directorio). Todo lo que necesito hacer es obtener permiso para el comando "su" solo una vez (el usuario hace clic en "recordar" y el sistema nunca vuelve a preguntar) y luego ejecutar mis comandos dentro de este proceso y leer su salida.Para ser claro: 1. Cree su proceso. 2. Escriba el comando "ls" en la secuencia de salida (ls ejecuta con su permiso). 3. Lea la salida "ls". No puedo alcanzar el punto 3 – glodos

0

he modificado respuesta aceptada por @glodos de los problemas siguientes:

  1. las corrientes están cerrados, de lo contrario el proceso ejecutivo se cuelga para siempre, en la transmisión abierta. Si ejecuta ps en shell (es decir, adb shell) después de varias ejecuciones, verá varios procesos de vivos. Necesitan ser terminados apropiadamente.
  2. agregó waitFor() para asegurarse de que el proceso finaliza.
  3. Manejo adicional para read=-1, ahora se pueden ejecutar comandos con stdout vacío. Anteriormente se bloquearon en new String(buffer, 0, read)
  4. Utilizando StringBuffer para un manejo de cadenas más eficiente.

    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(); 
    } 
    

Algunos créditos van a @Sherif Elkhatib))

Cuestiones relacionadas