2012-02-08 19 views
13

Przenoszę część istniejącego kodu C, aby działał na systemie Android. Ten kod C zapisuje wiele danych wyjściowych na stdout/stderr. Muszę przechwycić to wyjście, albo w buforze pamięci, albo pliku, więc mogę wysłać go pocztą e-mail lub w inny sposób udostępnić.Przechwytywanie stdout/stderr z NDK

Jak mogę to osiągnąć, najlepiej bez modyfikowania istniejącego kodu C?

Uwaga: to pytanie to NOT o przekierowaniu wyjścia do adb lub logcat; Muszę buforować dane wyjściowe lokalnie na urządzeniu. Zdaję sobie sprawę z poniższych pytań, które nie wydają się rozwiązać moje zapytanie:

+0

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

Odpowiedz

1

stdout jest ścieżka 1 i stderr jest ścieżka 2. Wiedząc to, można ustanowić nowa ścieżka (ścieżki), która ma być miejscem docelowym, a następnie przymusić je do standardowego wyjścia i/lub stderr. Oto przykład pokazujący, jak to zrobić w practical examples use dup or dup2.

+0

Chciałbym podkreślić, że nie ma nic szczególnego w Androidzie tutaj. Jest to normalny sposób wykonywania czynności w większości systemów podobnych do systemu uniksowego. –

17

Użyj czegoś takiego, aby przekierować stderr do potoku. Czy czytnik po drugiej stronie rury napisz do 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); 
    } 
} 

Będziesz chciał uruchomić to we własnym wątku. I rozpędzają wątku w Javie, a następnie mieć połączenie wątków Java ten kod NDK tak:

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

Ten kod wycieka z deskryptora pliku - powinieneś "zamknąć (pipe [1]') po wywołaniu 'dup2()'. Powinieneś także sprawdzić błędy, ale nie jestem pewien, co byś zrobił, gdyby któreś z tych połączeń systemowych nie powiodło się. –

1

użyłem odpowiedź złożonej przez Jamesa Moore'a, ale chciałem, aby móc włączyć rejestrowanie i wyłączać. Dzięki temu mogę ustawić mKeepRunning na false i to się wyłączy. Musiałem również dodać do pliku flagę O_NONBLOCK, aby nie była to już blokada.

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