Выполнение нескольких исполнений в Runtime exec

Я пытаюсь сделать этот простой unix ls в Android:

cd /data

тогда

ls

Он должен вернуть все содержимое папки /data.

Я это закодировал:

try {
       String line;
       Process p = Runtime.getRuntime().exec(new String[] { "ls /data"});
       BufferedReader in = new BufferedReader(
               new InputStreamReader(p.getInputStream()) );
       while ((line = in.readLine()) != null) {
         Log.d("debugging", line);
       }
       in.close();
     }
     catch (Exception e) {
       e.printStackTrace();
     }

Проблема, с которой я сталкиваюсь в данный момент, заключается в том, что я не могу выполнять более одной команды одновременно. Например, если я напишу ls /data, ничего не вернется. Кажется, он не любит пространства.

Все работает, если я просто напишу одно слово, например «ls», которое возвращает список корневого каталога:

03-19 22:51:59.241: D/debugging(16274): acct
03-19 22:51:59.241: D/debugging(16274): cache
03-19 22:51:59.241: D/debugging(16274): config
03-19 22:51:59.241: D/debugging(16274): crashtag
03-19 22:51:59.241: D/debugging(16274): d
03-19 22:51:59.241: D/debugging(16274): data
03-19 22:51:59.241: D/debugging(16274): default.prop
03-19 22:51:59.241: D/debugging(16274): dev
03-19 22:51:59.241: D/debugging(16274): etc
03-19 22:51:59.241: D/debugging(16274): fstab
03-19 22:51:59.241: D/debugging(16274): init
03-19 22:51:59.241: D/debugging(16274): init.clrdex.sh
03-19 22:51:59.241: D/debugging(16274): init.goldfish.rc
03-19 22:51:59.241: D/debugging(16274): init.hostapd.sh
03-19 22:51:59.241: D/debugging(16274): init.rc
03-19 22:51:59.241: D/debugging(16274): init.semc.rc
03-19 22:51:59.241: D/debugging(16274): init.usbmode.sh
03-19 22:51:59.241: D/debugging(16274): logo.rle
03-19 22:51:59.241: D/debugging(16274): mnt
03-19 22:51:59.241: D/debugging(16274): mr.log
03-19 22:51:59.241: D/debugging(16274): proc
03-19 22:51:59.241: D/debugging(16274): root
03-19 22:51:59.241: D/debugging(16274): sbin
03-19 22:51:59.241: D/debugging(16274): sdcard
03-19 22:51:59.241: D/debugging(16274): sys
03-19 22:51:59.241: D/debugging(16274): system
03-19 22:51:59.241: D/debugging(16274): ueventd.goldfish.rc
03-19 22:51:59.241: D/debugging(16274): ueventd.rc
03-19 22:51:59.241: D/debugging(16274): ueventd.semc.rc
03-19 22:51:59.241: D/debugging(16274): vendor

Я пытался, как кто-то упомянул, заполнить этот массив несколькими командами, но он ничего не возвращает. Пустой.

{"ls","ls"} //this should return twice ls result.

Есть идеи, как я могу "объединить" команду в Android Runtime?


person Reinherd    schedule 19.03.2013    source источник
comment
Вам действительно нужен System.exec? Рассматривали ли вы возможность использования метода listFiles() из файла (docs.oracle .com/javase/6/docs/api/java/io/File.html)   -  person gerrytan    schedule 20.03.2013
comment
Вместо этого я бы использовал ProcessBuilder. из Runtime.getRuntime.exec().   -  person syb0rg    schedule 20.03.2013
comment
Да, потому что это не то, что я пытаюсь сделать в конце. Я хочу вызвать системную программу, но если я не справлюсь с выполнением двух разных команд одновременно, я не смогу запустить эти программы   -  person Reinherd    schedule 20.03.2013
comment
@SergiCastellsaguéMillán Может быть, вы можете создать файл сценария .sh с необходимыми командами и запустить этот файл с помощью java. Я думаю, что это та же концепция файла .bat в Windows. ---› выполнить .bat-файл с Android   -  person Smit    schedule 20.03.2013


Ответы (3)


Я думаю, вам нужен root-доступ для выполнения команды ls /data, поэтому вы должны сначала получить оболочку su, а затем выполнять команды, например:

// run command with su rights and return output of that command(inside su
// shell)
// command = "ls /data"
public static void suOutputExecute(String command) {
    try {
        int BUFF_LEN = 1024;
        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(command + "\n"); // \n executes the command
        InputStream stdout = p.getInputStream();
        byte[] buffer = new byte[BUFF_LEN];
        int read;
        String out = new String();
        // while((read=stdout.read(buffer))>0) won't work here
        while (true) {
            read = stdout.read(buffer);
            out += new String(buffer, 0, read);
            if (read < BUFF_LEN) {
                // we have read everything
                break;
            }
        }
        stdout.close();
        Log.e("ROOT", out);
        p.waitFor();
    } catch (Exception e) {
        Log.e("ROOT", "Error", e);
    }
}

Вам нужно рутированное устройство. Для эмулятора вам все равно придется установить суперпользователя.

Для команд, которые не требуют su, должен работать следующий код (я не могу его проверить прямо сейчас):

public static void shExecute(String[] commands) {
    Process shell = null;
    DataOutputStream out = null;
    BufferedReader in = null;

    try {
        // Acquire sh
        Log.i(LOG_TAG, "Starting exec of sh");
        shell = Runtime.getRuntime().exec("sh");//su if needed
        out = new DataOutputStream(shell.getOutputStream());

        in = new BufferedReader(new InputStreamReader(shell.getInputStream()));

        // Executing commands without root rights
        Log.i(LOG_TAG, "Executing commands...");
        for (String command : commands) {
            Log.i(LOG_TAG, "Executing: " + command);
            out.writeBytes(command + "\n");
            out.flush();
        }

        out.writeBytes("exit\n");
        out.flush();
        String line;
        StringBuilder sb = new StringBuilder();
        while ((line = in.readLine()) != null) {
            sb.append(line).append("\n");
        }
        Log.i(LOG_TAG, sb.toString());
        shell.waitFor();

    } catch (Exception e) {
        Log.e(LOG_TAG, "ShellRoot#shExecute() finished with error", e);
    } finally {
        try {
            if (out != null) {
                out.close();
            }
            if(in != null){
                in.close();
            }
            // shell.destroy();
        } catch (Exception e) {
            // hopeless
        }
    }
}
person Leszek    schedule 19.03.2013
comment
С помощью этого кода я могу прочитать вывод, созданный командами? - person Reinherd; 20.03.2013
comment
Да по крайней мере с первым примером, насчет второго не совсем уверен. - person Leszek; 20.03.2013

Я думаю, что ваша проблема с

Process p = Runtime.getRuntime().exec(new String[] { "ls /data"});

Вы должны либо использовать exec (команда String), либо разбить «ls/data» на две строки.

Runtime.getRuntime().exec(new String[] { "ls", "/data"});
person creechy    schedule 19.03.2013
comment
Runtime.getRuntime().exec(new String[] { "ls", "/data"});, по-видимому, не возвращает данных. - person Reinherd; 20.03.2013
comment
Это вообще исключение? - person creechy; 20.03.2013
comment
Ничего. catch (Exception e) { Log.d("debugging","Exception"); e.printStackTrace(); } ничего не напечатано. - person Reinherd; 20.03.2013
comment
Если вы введете явно фиктивную команду вместо ls, вы получите какую-либо ошибку? Он должен генерировать исключение IOException, если по какой-либо причине не может выполнить команду. - person creechy; 20.03.2013
comment
неа, я тоже хотя бы так. Если я наберу dsadasofpasnfas, он также ничего не вернет. Может быть, потому что BufferedReader in = new BufferedReader( new InputStreamReader(p.getInputStream()) ); просто слушает stdout, а не stderr? я не уверен в этом... - person Reinherd; 20.03.2013
comment
Подождите, сейчас выбрасывается исключение. Например, для pwd -> ExceptionError running exec(). Command: [pwd] Working Directory: null Environment: null - person Reinherd; 20.03.2013
comment
Похоже, что @Lecho накладывает некоторые тонкие ограничения на Android в том смысле, что вам нужно рутированное устройство. - person creechy; 20.03.2013

Изучили ли вы эту команду exec для среды выполнения java. Создайте файловый объект с путем, по которому вы хотите «cd», а затем введите его в качестве третьего параметра для метода exec.

public Process exec(String command,
                String[] envp,
                File dir)
         throws IOException

Выполняет указанную строковую команду в отдельном процессе с указанной средой и рабочим каталогом.

Это метод удобства. Вызов формы exec(command, envp, dir) ведет себя точно так же, как вызов exec(cmdarray, envp, dir), где cmdarray — это массив всех токенов в команде.

Точнее, командная строка разбивается на токены с помощью StringTokenizer, созданного вызовом new StringTokenizer(command) без дальнейшего изменения категорий символов. Маркеры, созданные токенизатором, затем помещаются в новый массив строк cmdarray в том же порядке.

Parameters:
    command - a specified system command.
    envp - array of strings, each element of which has environment variable settings in the format name=value, or null if the subprocess should inherit the environment of the current process.
    dir - the working directory of the subprocess, or null if the subprocess should inherit the working directory of the current process. 
Returns:
    A new Process object for managing the subprocess 
Throws:
    SecurityException - If a security manager exists and its checkExec method doesn't allow creation of the subprocess 
    IOException - If an I/O error occurs 
    NullPointerException - If command is null, or one of the elements of envp is null 
    IllegalArgumentException - If command is empty
person deepak.prathapani    schedule 18.07.2014