Android C/CPP log

来源:互联网 发布:linux重新挂载分区 编辑:程序博客网 时间:2024/05/17 13:39

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

int main(){    int s;    struct sigaction act;    int logsocket = -1;    logsocket = socket_local_client("logd",            ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);    if(logsocket < 0) {        logsocket = -1;    } else {        fcntl(logsocket, F_SETFD, FD_CLOEXEC);    }    act.sa_handler = SIG_DFL;    sigemptyset(&act.sa_mask);    sigaddset(&act.sa_mask,SIGCHLD);    act.sa_flags = SA_NOCLDWAIT;    sigaction(SIGCHLD, &act, 0);    s = socket_local_server("android:debuggerd",            ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);    if(s < 0) return -1;    fcntl(s, F_SETFD, FD_CLOEXEC);    LOG("debuggerd: " __DATE__ " " __TIME__ "\n");    for(;;) {        struct sockaddr addr;        socklen_t alen;        int fd;        alen = sizeof(addr);        fd = accept(s, &addr, &alen);        if(fd < 0) continue;        fcntl(fd, F_SETFD, FD_CLOEXEC);        handle_crashing_process(fd);    }    return 0;}

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"

void debugger_init(){    signal(SIGILL, debugger_signal_handler);    signal(SIGABRT, debugger_signal_handler);    signal(SIGBUS, debugger_signal_handler);    signal(SIGFPE, debugger_signal_handler);    signal(SIGSEGV, debugger_signal_handler);    signal(SIGSTKFLT, debugger_signal_handler);    signal(SIGPIPE, debugger_signal_handler);}

and in the "debugger_signal_handler" , we will send our pid to the server

void debugger_signal_handler(int n){    unsigned tid;    int s;    /* avoid picking up GC interrupts */    signal(SIGUSR1, SIG_IGN);    tid = gettid();    s = socket_abstract_client("android:debuggerd", SOCK_STREAM);    if(s >= 0) {        /* debugger knows our pid from the credentials on the         * local socket but we need to tell it our tid.  It         * is paranoid and will verify that we are giving a tid         * that's actually in our process         */        int  ret;        RETRY_ON_EINTR(ret, write(s, &tid, sizeof(unsigned)));        if (ret == sizeof(unsigned)) {            /* if the write failed, there is no point to read on             * the file descriptor. */            RETRY_ON_EINTR(ret, read(s, &tid, 1));            notify_gdb_of_libraries();        }        close(s);    }    /* remove our net so we fault for real when we return */    signal(n, SIG_IGN);}


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.

static void handle_crashing_process(int fd){..... for(;;) {        n = waitpid(tid, &status, __WALL);        if(n < 0) {            if(errno == EAGAIN) continue;            LOG("waitpid failed: %s\n", strerror(errno));            goto done;        }        LOG("waitpid: n=%d status=%08x\n", n, status);        if(WIFSTOPPED(status)){            n = WSTOPSIG(status);            switch(n) {            case SIGSTOP:                LOG("stopped -- continuing\n");                n = ptrace(PTRACE_CONT, tid, 0, 0);                if(n) {                    LOG("ptrace failed: %s\n", strerror(errno));                    goto done;                }                continue;            case SIGILL:            case SIGABRT:            case SIGBUS:            case SIGFPE:            case SIGSEGV:            case SIGSTKFLT: {                LOG("stopped -- fatal signal\n");                need_cleanup = engrave_tombstone(cr.pid, tid, debug_uid, n);                kill(tid, SIGSTOP);                goto done;            }            default:                LOG("stopped -- unexpected signal\n");                goto done;            }        } else {            LOG("unexpected waitpid response\n");            goto done;        }    }...}

it was done int the "engrave_tombstone"

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