Ответ 1
Эта проблема исправлена в желе Bean (Android 4.1), но не в ICS (4.0.4), и я думаю, он никогда не будет исправлен в ICS.
Использую ли я это:
process = Runtime.getRuntime().exec("logcat -d time");
или что:
process = new ProcessBuilder()
.command("logcat", "-d", "time")
.redirectErrorStream(true)
.start();
Я получаю те же результаты: он часто зависает в вызове exec() или start(), независимо от того, что я пытался сделать! Нить с этим не может быть прервана с помощью Thread.interrupt()! Детский процесс определенно запущен, и если его убили, вернутся эти команды.
Эти вызовы могут потерпеть неудачу при первой попытке, поэтому НЕ МОЖЕТ ПРОЧИТАТЬ ИХ ВЫХОД! Я также могу использовать простую командную строку "su -c kill xxx", тот же результат!
EDIT: начата отладка файла java_lang_ProcessManager.cpp в проекте NDK с некоторыми журналами отладки! Итак, вот что я нашел до сих пор, после fork() родитель делает это:
int result;
int count = read(statusIn, &result, sizeof(int)); <- hangs there
close(statusIn);
Хотя дочерний процесс не должен блокироваться на нем: это то, что делает ребенок (, если он вообще запущен!):
// Make statusOut automatically close if execvp() succeeds.
fcntl(statusOut, F_SETFD, FD_CLOEXEC); <- make the parent will not block
// Close remaining unwanted open fds.
closeNonStandardFds(statusOut, androidSystemPropertiesFd); <- hangs here sometimes
...
execvp(commands[0], commands);
// If we got here, execvp() failed or the working dir was invalid.
execFailed:
int error = errno;
write(statusOut, &error, sizeof(int));
close(statusOut);
exit(error);
Ребенок может потерпеть неудачу по двум воспроизводимым причинам: 1- дочерний код не работает, но родитель полагает, что это так! 2- дочерние блоки на closeNonStandardFds (statusOut, androidSystemPropertiesFd);
В любом случае чтение (statusIn...) в родительском завершается в тупике! и дочерний процесс остается мертвым (и к нему нельзя получить доступ, pid неизвестно, нет объекта процесса)!
Эта проблема исправлена в желе Bean (Android 4.1), но не в ICS (4.0.4), и я думаю, он никогда не будет исправлен в ICS.
Выше решение не оказалось надежным в любом случае, вызывая больше проблем на некоторых устройствах!
Итак, я вернулся к стандартному .exec() и продолжал копать...
Посмотрев на дочерний код, который висит, я заметил, что дочерний процесс зависает, пытаясь закрыть все дескрипторы файлов, унаследованные от родительского (кроме того, что создано в вызове exec())!
Итак, я просматриваю весь код приложения для любого BufferedReader/Writer и подобных классов, чтобы убедиться, что они будут закрыты при вызове exec()!
Частота проблемы была значительно уменьшена и фактически никогда не возникала снова, когда я удалял последний открытый файловый дескриптор перед вызовом exec().
NB: Убедитесь, что SU-бинарный файл обновлен, он также может вызвать эту проблему!
Наслаждайтесь поиском;)
Исправление ошибок в Bionic было зарегистрировано месяц назад, но оно по-прежнему не включено в Android 4.0.4.
У меня такая же проблема на ICS (похоже, отлично работает на Android < 4). Вы нашли решение?
Простым обходным решением может быть вызов метода "exec" в выделенном потоке с тайм-соединением, чтобы эта ситуация могла быть "обнаружена" (да, я знаю, что это не очень элегантно...)