Android - выполнение команд su программно не работает

Мне нужно, чтобы мое приложение выполняло некоторые команды su программно (телефон рутирован).

При использовании adb команды работают.

Например: su -c "mkdir /sdcard/testdir" создает каталог с именем «testdir» в /sdcard.

Когда я звоню:

    p = Runtime.getRuntime().exec("su -c \"mkdir /sdcard/testdir\"");
    p.waitFor();

Он просто движется вперед, и никаких изменений не происходит.

Я попытался прочитать ввод:

DataInputStream dis = new DataInputStream(p.getInputStream());
    while((temp = dis.readLine())!=null)
        Log.d(ctx.TAG,"shell:"+temp);

Но он ничего не сообщает (цикл делает 0 итераций).

Кто-нибудь когда-либо сталкивался с этой проблемой раньше? Как это решить? Само собой разумеется, что команды, отличные от su, программно работают с этим методом.

Примечание. В качестве примера я привел mkdir (я знаю, что для этого не обязательно требуется su). Мне нужно много разнообразных команд, которые будут выполняться под su

Благодарю вас!

РЕДАКТИРОВАТЬ: когда я вызываю su -c "id" программно, на выходе получается, что uid=0.


person LoneDuck    schedule 20.04.2015    source источник
comment
Вы решили эту проблему? столкнулся с той же проблемой здесь точно   -  person York Yang    schedule 12.04.2018


Ответы (4)


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

Исправление:

    p=Runtime.getRuntime().exec("su");
    DataOutputStream dos = new DataOutputStream(p.getOutputStream());
    dos.writeBytes("mkdir /sdcard/testdir\n");
    dos.writeBytes("exit\n");
    dos.flush();
    dos.close();
    p.waitFor();

Не забывайте \n в конце каждой команды, которую вы записываете в DataOutputStream, так как без него она работать не будет.

person LoneDuck    schedule 20.04.2015
comment
Если я таким образом запущу диалог суперпользователя, я не смогу его щелкнуть - person Elliptica; 14.09.2017
comment
он получает ошибку java.io.IOException: не удается запустить программу su: ошибка = 13, разрешение отклонено - person Mobile World; 23.09.2017
comment
Я получаю Вызвано: java.io.IOException: Невозможно запустить программу su: ошибка = 13, Отказано в доступе. Как я могу настроить свой эмулятор, чтобы получить это разрешение? - person sadat; 03.04.2020

Вы написали, что вам «нужны различные команды для выполнения под su». Обратите внимание, что использование «Runtime.exec()» не рекомендуется Chainfire, разработчиком самого известного корневого приложения SuperSU.

Заманчиво использовать Runtime.getRuntime().exec("su -c [команда]");, но вы должны знать, что [команда] должна быть одним параметром, и поэтому может потребоваться заключение в кавычки. К сожалению, как цитирование параметра [command], так и передача параметров в виде отдельных переменных либо в Runtime.exec(), либо в ProcessBuilder не работают последовательно во всех версиях Android, и поэтому этой конструкции следует полностью избегать. Сделать это правильно не невозможно, но велик риск возникновения проблем.

См. документ Как подать заявку. Так что вы можете следовать его рекомендации здесь:

3.2. Звонок

Обычный метод вызова su, позволяющий избежать известных проблем, перечисленных выше, заключается в создании интерактивной оболочки и передаче в нее команд. Это делается путем вызова Runtime.getRuntime().exec("su"); и получения входных и выходных потоков из возвращенного объекта Process. Выполнение этого является довольно простым фрагментом кода, но включая журналы отладки и проверки, это немного долго для воспроизведения здесь.

Основной код находится здесь: [libsuperuser :: Shell.java на GitHub]. Shell.run() — это общий вызов для запуска кода оболочки, следующие более конкретные (статические) служебные функции — это те, которые вы, вероятно, в конечном итоге будете использовать:

List<String> Shell.SH.run(String command)
List<String> Shell.SH.run(List<String> commands)
List<String> Shell.SH.run(String[] commands)

List<String> Shell.SU.run(String command)
List<String> Shell.SU.run(List<String> commands)
List<String> Shell.SU.run(String[] commands)

Варианты SH используются для оболочки без полномочий root, а варианты SU — для оболочки с полномочиями root. Эти вызовы возвращают список, содержащий вывод команд оболочки. Если вывода не было, список пустой, но не нулевой. Результат будет нулевым только в случае возникновения ошибки, включая пользователя, не предоставившего вашему приложению доступ su. Это блокировка звонков.

Обратите внимание, что при компиляции отладки все STDIN/STDOUT/STDERR оболочки будут регистрироваться в logcat, и эти вызовы (преднамеренно) приведут к сбою вашего приложения, если они вызываются из основного потока. Причина этого будет обсуждаться в разделе 4. Когда вызывать su.

person tony    schedule 20.04.2015

Если вы используете двойные кавычки, это будет работать:

su -c ""command with args""
person Bruce Bane    schedule 11.12.2017

Возможно, вы вызываете Runtime.getRuntime().exec() в основном потоке, а p.waitFor() заставляет ваш основной поток ждать, пока он не выполнится. Попробуйте позвонить в другой поток, например следующий фрагмент.

new Thread(){

     @override
     public void run(){
        p = Runtime.getRuntime().exec("su -c \"mkdir /sdcard/testdir\"");
        p.waitFor();

     }.start();

}
person Aswin    schedule 20.04.2015
comment
Спасибо, Асвин, но моя программа не застревает - p.waitFor() завершается и продолжается. Проблема в том, что команда не оказывает никакого влияния, и в /sdcard не создается testdir. - person LoneDuck; 20.04.2015
comment
Ваша SD-карта смонтирована? Проверьте путь /sdcard. - person Aswin; 20.04.2015
comment
Да, и su -c "mkdir /sdcard/testdir" работает, если выполняется в оболочке adb. - person LoneDuck; 20.04.2015