Захват stdout/stderr с помощью NDK
Я переношу некоторый существующий код C для запуска на Android. Этот C-код записывает много вывода в stdout/stderr. Мне нужно записать этот вывод либо в буфер памяти, либо в файл, поэтому я могу отправить его по электронной почте или иным образом поделиться им.
Как я могу достичь этого, в идеале без изменения существующего кода C?
Примечание: этот вопрос НЕ о перенаправлении вывода на adb или logcat; Мне нужно буферизовать вывод локально на устройстве. Я знаю следующие вопросы, которые, как представляется, не затрагивают мой запрос:
Ответы
Ответ 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);