2012-06-25 29 views
10

Hầu hết các lỗi xảy ra trong mã C++ của tôi khiến ứng dụng đơn giản thoát ra, không có đầu ra LogCat nào, và không có thông báo trên thiết bị. Null con trỏ và sử dụng không chính xác của JNI thường sản xuất kết quả này, và không cần phải nói, nó làm cho gỡ lỗi rất khó. Hiện tại tôi có thể nhận được một dấu vết ngăn xếp với lệnh 'bt' trong ndk-gdb, nhưng không phải nếu sự cố xảy ra trong vòng 2 giây đầu tiên của khởi động, bởi vì ndk-gdb bắt đầu quá trình và gắn vào nó sau khi nó có đã bắt đầu. Ngoài ra, ndk-gdb là không đáng tin cậy, thường nói rằng nó không thể tìm thấy bất kỳ ký hiệu nào, hoặc phàn nàn về các lỗi "SIGILL" phi vật thể, chẳng hạn.Tôi có thể nhận được dấu vết ngăn xếp C++ khi ứng dụng Android gặp sự cố không?

Có cách nào để bẫy lỗi và in dấu vết ngăn xếp hoặc thông tin khác khi ứng dụng gặp sự cố không? Ví dụ: nếu có SIGSEGV, tôi muốn biết địa chỉ ứng dụng đang cố gắng truy cập.

+1

kiểm tra câu trả lời này. điều này dành riêng cho android http://stackoverflow.com/a/28858941/365229 –

Trả lời

4

trace.txt tệp cấp gì đó? Tôi không nhớ nếu vị trí của anh ấy là: /data/anr/trace.txt hoặc /data/data/{pkg}/trace.txt

1

Bạn cần bắt đầu bằng cách bẫy SIGSEGV để thực thi mã khi bạn nhận được segv. Đây là mã posix, vì vậy một cái gì đó tương tự nên hoạt động trên android:

void abortHandler(int signum, siginfo_t* si, void* unused) 
{ 
    const char* name = NULL; 
    switch(signum) 
    { 
    case SIGABRT: name = "SIGABRT"; break; 
    case SIGSEGV: name = "SIGSEGV"; break; 
    case SIGBUS: name = "SIGBUS"; break; 
    case SIGILL: name = "SIGILL"; break; 
    case SIGFPE: name = "SIGFPE"; break; 
    case SIGPIPE: name = "SIGPIPE"; break; 
    } 

    if (name) 
     printf(stderr, "Caught signal %d (%s)\n", signum, name); 
    else 
     printf(stderr, "Caught signal %d\n", signum); 

    printStackTrace(stderr); 

    exit(signum); 
} 

void handleCrashes() 
{ 
    struct sigaction sa; 
    sa.sa_flags = SA_SIGINFO; 
    sa.sa_sigaction = abortHandler; 
    sigemptyset(&sa.sa_mask); 

    sigaction(SIGABRT, &sa, NULL); 
    sigaction(SIGSEGV, &sa, NULL); 
    sigaction(SIGBUS, &sa, NULL); 
    sigaction(SIGILL, &sa, NULL); 
    sigaction(SIGFPE, &sa, NULL); 
    sigaction(SIGPIPE, &sa, NULL); 
} 

Điều tiếp theo là gọi hàm đó để đăng ký trình xử lý tín hiệu. Bạn có thể làm điều đó như là điều đầu tiên trong chính, nhưng sau đó bạn sẽ không nhận được dấu vết ngăn xếp cho đến khi chính. Nếu bạn muốn chúng trước, bạn có thể gọi hàm này từ hàm tạo của một đối tượng chung. Nhưng không có gì đảm bảo rằng nó sẽ được gọi là constructor đầu tiên. Có nhiều cách để đảm bảo nó được gọi sớm. Ví dụ, toán tử quá tải mới - trong quá trình xây dựng gỡ lỗi - để khởi tạo lần đầu tiên các dấu vết ngăn xếp trên phân bổ đầu tiên, và sau đó gọi vào toán tử thực mới. Điều này sẽ cung cấp cho bạn các dấu vết ngăn xếp bắt đầu từ phân bổ đầu tiên.

Để in một stack trace:

void printStackTrace(unsigned int max_frames = 63) 
{ 
    void* addrlist[max_frames+1]; 

    // retrieve current stack addresses 
    u32 addrlen = backtrace(addrlist, sizeof(addrlist)/sizeof(void*)); 

    if (addrlen == 0) 
    { 
     printf(stderr, " <empty, possibly corrupt>\n"); 
     return; 
    } 

    char** symbollist = backtrace_symbols(addrlist, addrlen); 

    for (u32 i = 3; i < addrlen; i++) 
     printf(stderr, "%s\n", symbollist[i]): 
} 

Bạn sẽ cần phải làm việc nhiều hơn để demangle những biểu tượng để làm cho họ có thể đọc được. thử abi :: __ cxa_demangle. Tất nhiên xây dựng với -g và liên kết với -rdynamic.

+0

Cảm ơn bạn. Tôi đã sửa lỗi mà tôi đang tìm nhưng tôi chắc chắn sẽ cung cấp cho lần phát hành này lần sau. Tôi không chắc tôi hiểu '-rdynamic', mặc dù tôi đã tra cứu tài liệu:" Vượt qua cờ-động-động tới liên kết ELF, trên các mục tiêu hỗ trợ nó. Điều này chỉ thị cho trình liên kết thêm tất cả các ký hiệu, không chỉ được sử dụng những cái, đến bảng ký hiệu động. Tùy chọn này là cần thiết cho một số ứng dụng của dlopen hoặc để cho phép lấy backtraces từ bên trong một chương trình. " ('-g', trong khi đó," bật thông tin gỡ lỗi ở định dạng ưa thích cho mục tiêu ".) – Qwertie

+9

Crap! backtrace được cho là trong execinfo.h, nhưng nó không tồn tại trên Android! (execinfo.h: Không có tập tin hoặc thư mục như vậy) – Qwertie

+3

Vâng, không có 'backtrace'on Android. –

-2

Vâng, 'execinfo.h' không tồn tại ở đó, nhưng callstack không:

#include <utils/CallStack.h> 
.. 
CallStack cs; 
cs.dump(); 

Hy vọng nó có thể giúp đỡ trong việc xử lý tín hiệu như vậy.

+0

Tôi phải bỏ sót điều gì đó: lỗi nghiêm trọng: utils/CallStack.h: Không có tệp hoặc thư mục nào như vậy #include --- Có lẽ có thứ gì đó khác cần phải chuyển sang Android.mk hoặc gì đó? –

+3

Không có tập tin 'CallStack.h' trong thư mục NDK! –

+0

https://android.googlesource.com/platform/system/core.git/+/master/include/utils/CallStack.h https://android.googlesource.com/platform/frameworks/native/+/jb- dev/include/utils/CallStack.h –

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