2011-12-31 9 views
18

Si yo uso esto:Runtime.exec() ERROR: cuelga sin proporcionar un objeto de proceso

process = Runtime.getRuntime().exec("logcat -d time"); 

o que:

process = new ProcessBuilder() 
       .command("logcat", "-d", "time") 
       .redirectErrorStream(true) 
       .start(); 

consigo los mismos resultados: a menudo se cuelga en el ejecutivo() o start() llamada, sin importar lo que intenté hacer! ¡El hilo que se ejecuta no se puede interrumpir con Thread.interrupt()! El proceso hijo definitivamente se inicia y si se cancela los comandos anteriores regresan.

Estas llamadas pueden fallar en el primer intento, por lo que NO HAY MANERA DE LEER SU SALIDA! También puedo usar una simple línea de comando "su -c kill xxx", ¡el mismo resultado!

EDIT: ¡Comenzó a depurar el archivo java_lang_ProcessManager.cpp en un proyecto NDK con algunos registros de depuración! Así que aquí es lo que he encontrado hasta el momento, después de que el tenedor() el padre hace esto:

int result; 
int count = read(statusIn, &result, sizeof(int));   <- hangs there 
close(statusIn); 

Aunque el proceso hijo no se supone que bloquear en él: Eso es lo que el niño (si se inicia en absoluto !):

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

el niño puede fallar por 2 razones reproducibles: 1- código niño no se está ejecutando, pero el padre cree que es! 2- bloques secundarios en closeNonStandardFds (statusOut, androidSystemPropertiesFd);

En cualquier caso, la lectura (estadoEn ...) en el elemento primario termina en interbloqueo. y un proceso secundario se deja muerto (y no se puede acceder, pid desconocido, ¡no hay objeto de proceso)!

+0

http://developer.android.com/reference/java/lang/Process.html – Selvin

+0

¿Estás seguro de que leíste * todo * el resultado de tu proceso? Lo lees en un bucle, ¿verdad? – JimmyB

+0

Sí, iniciando inmediatamente un hilo para leer la salida de forma continua. A veces, la primera llamada a exec() solo se cuelga, por lo que no hay nada que leer, ya que el objeto de proceso no se ha devuelto todavía, por lo tanto, no se puede retener en las transmisiones. ¡Entonces nada que ver con leer la salida! Actualmente estoy reproduciendo el problema con el código fuente NDK y agregando información de depuración para rastrear esto. Curiosamente, descubrió que agregar algunos registros hace que el problema sea más difícil de reproducir. Es el exec() seguro para subprocesos? – 3c71

Respuesta

0

Tengo el mismo problema en ICS (parece que funciona bien en Android < 4). ¿Encontraste una solución?

Una solución sencilla podría ser la de llamar al método "ejecutivo" en un hilo dedicado con un tiempo de espera-se unen para que esta situación podría ser "detectado" (sí, sé que no es muy elegante ...)

+0

Lo intenté, aunque resultó que el hilo dedicado no podía ser agotado ni interrumpido. ¡Simplemente está atorado! De hecho, puedo reproducir esto en Android 4 todo el tiempo, mientras que en Android <4, el problema se muestra solo con poca frecuencia en kernels personalizados. – 3c71

+0

Sí, encontré una solución confiable real, simplemente mire abajo;) – 3c71

4

¡La solución anterior no demostró ser confiable de ninguna manera, causando más problemas en algunos dispositivos!

Así que volvió de nuevo a la .exec estándar() y se mantiene la excavación ...

Si examina el código niño que cuelga, me di cuenta el proceso niño va a colgar al intentar cerrar todos los descriptores de archivos heredados de el padre (excepto el creado dentro de la llamada exec())!

Así que busco el código de la aplicación completa para cualquier BufferedReader/Writer y clases similares para asegurarme de que se cerrarían al llamar a exec()!

La frecuencia del problema se redujo considerablemente, y en realidad nunca volvió a ocurrir cuando eliminé el último descriptor de archivo abierto antes de llamar a exec().

NB: Asegúrate de que SU binary esté actualizado, ¡de hecho puede causar este problema!

Disfrute de su búsqueda;)

+0

Me enfrento a este problema por el momento en una aplicación muy grande que hace muchas cosas simultáneas (con archivos, conectores y varias cosas que podrían estar causando descriptores de archivos abiertos) .) Me gustaría preguntarle a 3c71, cuando dices "NB: asegúrate de que el binary SU esté actualizado, ¡de hecho también puede causar este problema!" - ¿Qué quieres decir exactamente? ¿Es posible que la actualización de SU lo haga funcionar sin tener que asegurarse de que todos los descriptores de archivos estén cerrados? – tristan2468

+1

En ese momento también había problemas con SU, pero esos se han ido hace tiempo. – 3c71

3

Corrección de error en la biónica fue hace commited meses, pero todavía no se ha incluido en Android 4.0.4.

6

Este problema se corrigió en Jelly Bean (Android 4.1) pero no en ICS (4.0.4) y supongo que nunca se solucionará en ICS.

+0

¿Hay más información de contexto para mostrar cómo se relaciona este problema con el colgado del hijo y del padre como se describe en la pregunta editada de 3C71 más arriba? ¿Es porque el proceso hijo llama a closeNonStandardFds que llama a cpuacct_add que se bloquea mientras usa el mismo fd (statusOut anterior desde el punto de vista del niño) que el proceso principal está esperando en la función de lectura (statusIn desde el punto de vista de los padres)? Estoy tratando de entender si hay una manera confiable de evitar esto en las versiones anteriores a la 4.1: cerrar todas las fd abiertas es complicado en una gran aplicación para desarrolladores múltiples. – Mick

+0

Tener un vistazo a la confirmación: https://github.com/android/platform_bionic/commit/177ba8cb42ed6d232e7c8bcad5e6ee21fc51a0e8 – chrulri

+0

Dice: Cuando se bifurcan de un nuevo proceso en el biónica, es fundamental que no asigna ninguna memoria de acuerdo al comentario en java_lang_ProcessManager.c: "Nota: No podemos malloc() o libre() después de este punto! Un hilo que ya no se ejecuta puede estar reteniendo el bloqueo de montón, y un intento de malloc () o libre() daría lugar a un punto muerto ". Sin embargo, como fork usa las llamadas de lib estándar al rastrearlo un poco, pueden asignar memoria y causar el punto muerto. Esto es una reescritura de modo que la función cpuacct_add, que llama la horquilla, utilizará las llamadas del sistema en lugar de las llamadas de lib estándar. – chrulri

Cuestiones relacionadas