Подтвердить что ты не робот

Захват stdout/stderr с помощью NDK

Я переношу некоторый существующий код C для запуска на Android. Этот C-код записывает много вывода в stdout/stderr. Мне нужно записать этот вывод либо в буфер памяти, либо в файл, поэтому я могу отправить его по электронной почте или иным образом поделиться им.

Как я могу достичь этого, в идеале без изменения существующего кода C?

Примечание: этот вопрос НЕ о перенаправлении вывода на adb или logcat; Мне нужно буферизовать вывод локально на устройстве. Я знаю следующие вопросы, которые, как представляется, не затрагивают мой запрос:

4b9b3361

Ответ 1

stdout - это путь 1, а stderr - путь 2. Зная это, вы можете установить новые пути, которые вы хотите быть выходным пунктом назначения, а затем принудительно вставлять их в stdout и/или stderr. Там пример, демонстрирующий, как это сделать на практических примерах использовать dup или dup2.

Ответ 2

Используйте что-то вроде этого, чтобы перенаправить stderr в трубу. Попросите читателя на другой стороне трубы записать 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);
    }
}

Вы хотите запустить это в своем потоке. Я разворачиваю поток в Java, а затем поток Java вызывает этот код NDK следующим образом:

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

Ответ 3

Я использовал ответ, представленный Джеймсом Муром, но я хотел иметь возможность включить и выключить ведение журнала. С этим я могу установить mKeepRunning в false, и он отключится. Мне также нужно было добавить флаг O_NONBLOCK в файл, чтобы он больше не был блокирующим вызовом.

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