2012-02-08 20 views
13

Estoy portando algún código C existente para ejecutar en Android. Este código C escribe muchos resultados en stdout/stderr. Necesito capturar esta salida, ya sea en un búfer de memoria o en un archivo, para poder enviarlo por correo electrónico o compartirlo.Capturando stdout/stderr con NDK

¿Cómo puedo lograr esto, idealmente sin modificar el código C existente?

Nota: esta pregunta es NOT sobre la redirección de la salida a adb o logcat; Necesito almacenar la salida localmente en el dispositivo. Soy consciente de las siguientes preguntas, que no aparecen para hacer frente a mi consulta:

+0

C++ http://stackoverflow.com/questions/8870174/is-stdcout-usable-in-android-ndkl –

Respuesta

1

stdoutes ruta 1 y ruta stderres 2. Sabiendo esto, se puede establecer nuevas rutas que desea que sean el destino de salida, luego forzarlas a stdout y/o stderr. Hay un ejemplo que muestra cómo hacer esto en practical examples use dup or dup2.

+0

me gustaría señalar que no hay nada especial acerca de Android aquí. Esta es la forma normal de hacer las cosas en la mayoría de los sistemas tipo Unix. –

17

Use algo como esto para redirigir stderr a una tubería. Tener un lector en el otro lado de la tubería escriba a logcat:

extern "C" void Java_com_test_yourApp_yourJavaClass_nativePipeSTDERRToLogcat(JNIEnv* env, jclass cls, jobject obj) 
{ 
    int pipes[2]; 
    pipe(pipes); 
    dup2(pipes[1], STDERR_FILENO); 
    FILE *inputFile = fdopen(pipes[0], "r"); 
    char readBuffer[256]; 
    while (1) { 
     fgets(readBuffer, sizeof(readBuffer), inputFile); 
     __android_log_write(2, "stderr", readBuffer); 
    } 
} 

Querrá ejecutar esto en su propio hilo. Yo girar el hilo en Java y luego tener la llamada hebra Java el código NDK así:

new Thread() { 
    public void run() { 
     nativePipeSTDERRToLogcat(); 
    } 
}.start(); 
+2

Este código filtra un descriptor de archivo: debe 'cerrar (pipes [1]') después de la llamada a 'dup2()'. Además, debe verificar si hay errores, aunque no estoy muy seguro de qué haría si fallara alguna de esas llamadas al sistema. –

1

utilicé la respuesta presentada por James Moore, pero quería ser capaz de convertir el registro de encendido y apagado. Con esto puedo establecer el mKeepRunning en falso y se apagará. También necesitaba agregar el indicador O_NONBLOCK al archivo para que ya no fuera una llamada de bloqueo.

int lWriteFD = dup(STDERR_FILENO); 

if (lWriteFD < 0) 
{ 
    // WE failed to get our file descriptor 
    LOGE("Unable to get STDERR file descriptor."); 
    return; 
} 

int pipes[2]; 
pipe(pipes); 
dup2(pipes[1], STDERR_FILENO); 
FILE *inputFile = fdopen(pipes[0], "r"); 

close(pipes[1]); 

int fd = fileno(inputFile); 
int flags = fcntl(fd, F_GETFL, 0); 
flags |= O_NONBLOCK; 
fcntl(fd, F_SETFL, flags); 

if (nullptr == inputFile) 
{ 
    LOGE("Unable to get read pipe for STDERR"); 
    return; 
} 

char readBuffer[256]; 

while (true == mKeepRunning) 
{ 
    fgets(readBuffer, sizeof(readBuffer), inputFile); 

    if (strlen(readBuffer) == 0) 
    { 
     sleep(1); 
     continue; 
    } 

    __android_log_write(ANDROID_LOG_ERROR, "stderr", readBuffer); 
} 

close(pipes[0]); 
fclose(inputFile);