2012-05-10 28 views
29

Tôi không thể mua Nexus S của mình (chạy Android 4.0) để chuyển hướng thông báo xuất bản gốc sang logcat. Tôi đã đọc rằng tôi cần phải làm điều này:Chuyển hướng stdout sang logcat trong Android NDK

$ adb shell stop 
$ adb shell setprop log.redirect-stdio true 
$ adb shell start 

Tuy nhiên, điều này dường như không hiệu quả. (Nó phá vỡ JUnit tuy nhiên, như đã đề cập here, do đó, nó không phải không có hiệu lực.)

Để tham khảo, đây là mã của tôi:

package com.mayastudios; 

import android.util.Log; 

public class JniTester { 

    public static void test() { 
    Log.e("---------", "Start of test"); 
    System.err.println("This message comes from Java.");  
    void printCMessage(); 
    Log.e("---------", "End of test"); 
    } 

    private static native int printCMessage(); 

    static { 
    System.loadLibrary("jni_test"); 
    } 
} 

Và file .c JNI:

JNIEXPORT void JNICALL 
Java_com_mayastudios_JniTester_printCMessage(JNIEnv *env, jclass cls) { 
    setvbuf(stdout, NULL, _IONBF, 0); 
    printf("This message comes from C (JNI).\n"); 
    fflush(stdout); 

    //setvbuf(stderr, NULL, _IONBF, 0); 
    //fprintf(stderr, "This message comes from C (JNI).\n"); 
    //fflush(stderr); 
} 

Và Android.mk:

LOCAL_PATH := $(call my-dir) 

include $(CLEAR_VARS) 
LOCAL_MODULE := jni_test 
LOCAL_SRC_FILES := test_jni.c 
include $(BUILD_SHARED_LIBRARY) 

Tôi đang biên soạn điều này chỉ bằng cách gọi ndk-build. Phương thức nguyên gốc được gọi chính xác nhưng tôi không nhận được bất kỳ đầu ra bản ghi nào từ nó (ngay cả trên tiết). Tôi nhận được đầu ra đăng nhập từ Java mặc dù ("Thông báo này đến từ Java.").

Bất kỳ gợi ý nào về những gì tôi có thể đang làm sai?

PS: Tôi đã thiết lập một kho Mercurial nhỏ mà chứng tỏ vấn đề: https://bitbucket.org/skrysmanski/android-ndk-log-output/

+0

Kiểm tra câu trả lời của tôi trong questino này - http : //stackoverflow.com/questions/10274920/how-to-get-printf-messgaes-written-in-ndk-application/10275209#10275209 – Shaiful

+1

Tôi biết về giải pháp này (và đó là những gì tôi đã sử dụng). Tuy nhiên, câu hỏi ban đầu vẫn còn. Có lẽ nó chỉ là một lỗi. –

+0

Bạn đã thử xóa cuộc gọi setvbuf chưa? Tôi có printf follwed bởi fflush hiển thị trong nhật ký một cách chính xác trong mã mà không sử dụng setvbuf. –

Trả lời

-1

Hãy thử đặt fflush(stdout); sau printf của bạn. Hoặc cách khác sử dụng fprintf(stderr, "This message comes from C (JNI).\n");

giá trị mặc định theo mặc định là bộ đệm. stderr - không phải. Và bạn đang sử dụng System.err, không phải System.out từ Java.

Ngoài ra, bạn có thể tắt chế độ đệm theo chuẩn với điều này: setvbuf(stdout, NULL, _IONBF, 0); Chỉ cần đảm bảo bạn gọi nó trước cuộc gọi printf đầu tiên.

+0

Thật không may, không phải "fflush()" cũng không "setvbuf()" có bất kỳ hiệu ứng nào - bất kể tôi sử dụng stdout hay stderr. Tôi đã thử nghiệm nó với "fflush()" trước đây nhưng tôi chỉ quên thêm nó vào ví dụ của tôi. Tôi có bây giờ. –

7

stdout/stderr được chuyển hướng đến /dev/null trong các ứng dụng Android. Cách giải quyết setprop là một hack cho các thiết bị bắt nguồn sao chép stdout/stderr vào nhật ký. Xem Android Native Code Debugging.

15

Điều này không rõ ràng đối với tôi từ các câu trả lời trước. Ngay cả trên các thiết bị bắt nguồn bạn cần phải chạy:

adb root 
adb shell stop 
adb shell setprop log.redirect-stdio true 
adb shell start 
+2

Điều này làm việc để có được đầu ra nhưng nó chỉ làm tôi phát điên - mọi bản dựng ứng dụng mới sẽ không cài đặt chính xác! – hooby3dfx

+1

Điều này không hiệu quả đối với tôi. Tôi đã phải thay đổi nó trở lại sai trước khi tôi có thể khởi động lại ứng dụng –

+0

Hoạt động tốt trên Samsung S3 –

9

Bạn cũng sẽ có thể quấn mã đăng nhập của bạn để phát hiện nếu nó Android và nếu như vậy sử dụng khai thác gỗ của Android. Điều này có thể hoặc có thể không thực tế đối với tất cả mọi người.

Bao gồm các tập tin tiêu đề ghi:

#include <android/log.h>

Sử dụng được xây dựng trong chức năng logging:

__android_log_print(ANDROID_LOG_INFO, "foo", "Error: %s", foobar);

+0

Điều này hoạt động giống như một sự quyến rũ! – Sharm

4

setprop log.redirect-stdio true chuyển hướng chỉ sản lượng tạo ra bởi mã java, nhưng không phải là mã nguồn gốc. Thực tế này là described on developer.android.com theo cách sau:

Theo mặc định, hệ thống Android sẽ gửi đầu ra stdout và stderr (System.out và System.err) tới/dev/null.Trong các quá trình chạy VM Dalvik, bạn có thể có hệ thống ghi một bản sao của đầu ra vào tệp nhật ký.

Để có được sản lượng từ mã gốc, tôi thực sự thích this solution

+1

Giải pháp được liên kết ở đây phải được đánh dấu là giải pháp vì nó không yêu cầu root hoặc bất kỳ đặc quyền đặc biệt nào khác. Chỉ cần gọi một "init" chức năng lên phía trước và tất cả các cuộc gọi cout kết thúc trong LogCat ... ngọt ngào. – gnichola

0

Dưới đây là đoạn code tôi sử dụng để cho stdout đầu ra và stderr Android log

#include <android/log.h> 
#include <pthread.h> 
#include <unistd.h> 

static int pfd[2]; 
static pthread_t loggingThread; 
static const char *LOG_TAG = "YOU APP LOG TAG"; 

static void *loggingFunction(void*) { 
    ssize_t readSize; 
    char buf[128]; 

    while((readSize = read(pfd[0], buf, sizeof buf - 1)) > 0) { 
     if(buf[readSize - 1] == '\n') { 
      --readSize; 
     } 

     buf[readSize] = 0; // add null-terminator 

     __android_log_write(ANDROID_LOG_DEBUG, LOG_TAG, buf); // Set any log level you want 
    } 

    return 0; 
} 

static int runLoggingThread() { // run this function to redirect your output to android log 
    setvbuf(stdout, 0, _IOLBF, 0); // make stdout line-buffered 
    setvbuf(stderr, 0, _IONBF, 0); // make stderr unbuffered 

    /* create the pipe and redirect stdout and stderr */ 
    pipe(pfd); 
    dup2(pfd[1], 1); 
    dup2(pfd[1], 2); 

    /* spawn the logging thread */ 
    if(pthread_create(&loggingThread, 0, loggingFunction, 0) == -1) { 
     return -1; 
    } 

    pthread_detach(loggingThread); 

    return 0; 
} 
+0

Chúng ta cần một cách tiêu chuẩn không phải là cách giải quyết. –

Các vấn đề liên quan