Android C/CPP log

Android use UNIX Domain Socket for get debug log.

usually name "tombstone_0X" and so on in /data/log/logcat/

 

1. Server

 First , it has a socket server. it's a executable program.

The code was in "system/core/debuggerd/debuggerd.c" 

in the main, it open a IPC socket

  1. int main()  
  2. {  
  3.     int s;  
  4.     struct sigaction act;  
  5.     int logsocket = -1;  
  6.   
  7.     logsocket = socket_local_client("logd",  
  8.             ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);  
  9.     if(logsocket < 0) {  
  10.         logsocket = -1;  
  11.     } else {  
  12.         fcntl(logsocket, F_SETFD, FD_CLOEXEC);  
  13.     }  
  14.   
  15.     act.sa_handler = SIG_DFL;  
  16.     sigemptyset(&act.sa_mask);  
  17.     sigaddset(&act.sa_mask,SIGCHLD);  
  18.     act.sa_flags = SA_NOCLDWAIT;  
  19.     sigaction(SIGCHLD, &act, 0);  
  20.   
  21.     s = socket_local_server("android:debuggerd",  
  22.             ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);  
  23.     if(s < 0) return -1;  
  24.     fcntl(s, F_SETFD, FD_CLOEXEC);  
  25.   
  26.     LOG("debuggerd: " __DATE__ " " __TIME__ "\n");  
  27.   
  28.     for(;;) {  
  29.         struct sockaddr addr;  
  30.         socklen_t alen;  
  31.         int fd;  
  32.   
  33.         alen = sizeof(addr);  
  34.         fd = accept(s, &addr, &alen);  
  35.         if(fd < 0) continue;  
  36.   
  37.         fcntl(fd, F_SETFD, FD_CLOEXEC);  
  38.   
  39.         handle_crashing_process(fd);  
  40.     }  
  41.     return 0;  
  42. }  

when a program crashed, the socket will be connected and the function handle_crashing_process(fd) will be called.

and the log is generated in this function.

 

2. Client

how could a crashed program connect to the server?

Since every crashed program will receive a signal from the system, so we use "signal" register a signal handle function to the client.

So we can do something before the program die.

the code is "boinic/linker/Debugger.c"

  1. void debugger_init()  
  2. {  
  3.     signal(SIGILL, debugger_signal_handler);  
  4.     signal(SIGABRT, debugger_signal_handler);  
  5.     signal(SIGBUS, debugger_signal_handler);  
  6.     signal(SIGFPE, debugger_signal_handler);  
  7.     signal(SIGSEGV, debugger_signal_handler);  
  8.     signal(SIGSTKFLT, debugger_signal_handler);  
  9.     signal(SIGPIPE, debugger_signal_handler);  
  10. }  

and in the "debugger_signal_handler" , we will send our pid to the server
  1. void debugger_signal_handler(int n)  
  2. {  
  3.     unsigned tid;  
  4.     int s;  
  5.   
  6.     /* avoid picking up GC interrupts */  
  7.     signal(SIGUSR1, SIG_IGN);  
  8.   
  9.     tid = gettid();  
  10.     s = socket_abstract_client("android:debuggerd", SOCK_STREAM);  
  11.   
  12.     if(s >= 0) {  
  13.         /* debugger knows our pid from the credentials on the 
  14.          * local socket but we need to tell it our tid.  It 
  15.          * is paranoid and will verify that we are giving a tid 
  16.          * that's actually in our process 
  17.          */  
  18.         int  ret;  
  19.   
  20.         RETRY_ON_EINTR(ret, write(s, &tid, sizeof(unsigned)));  
  21.         if (ret == sizeof(unsigned)) {  
  22.             /* if the write failed, there is no point to read on 
  23.              * the file descriptor. */  
  24.             RETRY_ON_EINTR(ret, read(s, &tid, 1));  
  25.             notify_gdb_of_libraries();  
  26.         }  
  27.         close(s);  
  28.     }  
  29.   
  30.     /* remove our net so we fault for real when we return */  
  31.     signal(n, SIG_IGN);  
  32. }  


3. how is the log file produced

in the client, we just write out tid to the server, of course the log is generated by the server.

in it's "handle_crashing_process" function.

  1. static void handle_crashing_process(int fd)  
  2. {  
  3. .....  
  4.  for(;;) {  
  5.         n = waitpid(tid, &status, __WALL);  
  6.   
  7.   
  8.         if(n < 0) {  
  9.             if(errno == EAGAIN) continue;  
  10.             LOG("waitpid failed: %s\n", strerror(errno));  
  11.             goto done;  
  12.         }  
  13.   
  14.   
  15.         LOG("waitpid: n=%d status=%08x\n", n, status);  
  16.   
  17.   
  18.         if(WIFSTOPPED(status)){  
  19.             n = WSTOPSIG(status);  
  20.             switch(n) {  
  21.             case SIGSTOP:  
  22.                 LOG("stopped -- continuing\n");  
  23.                 n = ptrace(PTRACE_CONT, tid, 0, 0);  
  24.                 if(n) {  
  25.                     LOG("ptrace failed: %s\n", strerror(errno));  
  26.                     goto done;  
  27.                 }  
  28.                 continue;  
  29.   
  30.   
  31.             case SIGILL:  
  32.             case SIGABRT:  
  33.             case SIGBUS:  
  34.             case SIGFPE:  
  35.             case SIGSEGV:  
  36.             case SIGSTKFLT: {  
  37.                 LOG("stopped -- fatal signal\n");  
  38.                 need_cleanup = engrave_tombstone(cr.pid, tid, debug_uid, n);  
  39.                 kill(tid, SIGSTOP);  
  40.                 goto done;  
  41.             }  
  42.   
  43.   
  44.             default:  
  45.                 LOG("stopped -- unexpected signal\n");  
  46.                 goto done;  
  47.             }  
  48.         } else {  
  49.             LOG("unexpected waitpid response\n");  
  50.             goto done;  
  51.         }  
  52.     }  
  53. ...  
  54. }  

it was done int the "engrave_tombstone"

the function did a lot of things, and we will discuss the detail later.

posted @ 2012-04-02 19:59  cascais  阅读(967)  评论(0编辑  收藏  举报