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

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.

你可能感兴趣的:(android,function,socket,Stream,Signal,credentials)