ejecutar comando shell desde Android


Estoy tratando de ejecutar este comando desde el terminal del emulador de la aplicación (lo puedes encontrar en google play) en esta aplicación escribo su y presiono enter , así que escribe:

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

Y pulse de nuevo enter e inicie la grabación de la pantalla utilizando la nueva función de android kitkat.

Así que intento ejecutar el mismo código desde Java usando esto:

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

Pero no funciona porque el archivo no se crea. obviamente me estoy ejecutando en un dispositivo rooteado con android kitkat instalado. ¿dónde está el problema? cómo puedo solucionar? porque desde el emulador de terminal funciona y en Java no?

Author: Scott Ritchie, 2014-01-05

4 answers

Debe tomar la entrada estándar del proceso su que acaba de iniciarse y escribir el comando allí, de lo contrario, está ejecutando los comandos con el UID actual.

Intenta algo como esto:

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);
}
 61
Author: Carlo Cannas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-05 09:56:57

Una modificación del código por @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();
    }
}

(Le invitamos a encontrar un lugar mejor para OutputStream.cerrar())

Ejemplo de uso:

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

Actualización: Para obtener el resultado (la salida a stdout), utilice:

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

La utilidad para cerrar silenciosamente un número de Closeables (Socket puede no ser Closeable) es:

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);
            }
        }
    }
}
}
 24
Author: 18446744073709551615,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-10 16:45:37
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;
 5
Author: Mr.Vicky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-04 22:35:12

Ejemplo para copiar el archivo:

void copyFile_dd(){
    try {           
        Process su;

        su = Runtime.getRuntime().exec("su");

        String cmd = "dd if=/mnt/sdcard/test.dat of=/mnt/sdcard/test1.dat \n"+ "exit\n";
        su.getOutputStream().write(cmd.getBytes());

        if ((su.waitFor() != 0)) {
            throw new SecurityException();
        }

    } catch (Exception e) {
        e.printStackTrace();
        //throw new SecurityException();
    }
}
 1
Author: ShivBuyya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-07 10:22:45