2012-02-08 37 views
13

Tôi đang chuyển một số mã C hiện có để chạy trên Android. Mã C này viết rất nhiều đầu ra cho stdout/stderr. Tôi cần phải nắm bắt đầu ra này, hoặc trong một bộ nhớ đệm hoặc một tập tin, vì vậy tôi có thể gửi nó qua email hoặc chia sẻ nó.Chụp stdout/stderr với NDK

Làm thế nào tôi có thể đạt được điều này, lý tưởng mà không sửa đổi mã C hiện có?

Lưu ý: câu hỏi này là NOT về việc chuyển hướng đầu ra sang adb hoặc logcat; Tôi cần phải đệm đầu ra cục bộ trên thiết bị. Tôi biết trong những câu hỏi sau đây, mà không xuất hiện để giải quyết các truy vấn của tôi:

+0

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

Trả lời

1

stdout là đường 1 và stderr là con đường 2. Biết được điều này, bạn có thể thiết lập (các) đường dẫn mới mà bạn muốn là điểm đến đầu ra, sau đó ép chúng vào vị trí đầu ra và/hoặc tiêu chuẩn. Có một ví dụ cho thấy cách thực hiện điều này tại practical examples use dup or dup2.

+0

Tôi muốn chỉ ra rằng không có gì đặc biệt về Android ở đây. Đây là cách bình thường để thực hiện mọi thứ trên hầu hết các hệ thống giống Unix. –

17

Sử dụng một cái gì đó như thế này để chuyển hướng stderr đến một đường ống. Có một người đọc ở phía bên kia của đường ống viết cho 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ạn sẽ muốn chạy điều này theo chủ đề riêng của nó. Tôi quay lên các chủ đề trong Java và sau đó có các chủ đề Java gọi mã NDK này như thế này:

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

Đoạn mã này làm rò rỉ một bộ mô tả tập tin - bạn nên 'đóng (các đường ống [1]') sau cuộc gọi đến 'dup2()'. Ngoài ra, bạn nên kiểm tra lỗi, mặc dù tôi không hoàn toàn chắc chắn những gì bạn sẽ làm nếu bất kỳ cuộc gọi hệ thống nào không thành công. –

1

Tôi đã sử dụng câu trả lời được gửi bởi James Moore, nhưng tôi muốn có thể bật và tắt đăng nhập. Với điều này tôi có thể thiết lập mKeepRunning thành false và nó sẽ tắt. Tôi cũng cần thêm cờ O_NONBLOCK vào tệp để nó không còn là cuộc gọi chặn nữa.

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