Android2.x中Logger日志系统采用了字符设备驱动来支持,到了Android6.0已经找不到kernel/goldfish/drivers/staging/android/logger.c这一层的驱动程序了。不过上层接口还是没变的,所以顺着最顶层接口,可以一路找到6.0下Logger的实现机制。

从最上层frameworks/base/core/java/android/util/Log.java找到:

public final class Log {……    public static int d(String tag, String msg) {        return println_native(LOG_ID_MAIN, DEBUG, tag, msg);    }……}
再从frameworks/base/core/jni/android_utilLog.cpp中找到:

static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,        jint bufID, jint priority, jstring tagObj, jstring msgObj){    const char* tag = NULL;    const char* msg = NULL;    if (msgObj == NULL) {        jniThrowNullPointerException(env, "println needs a message");        return -1;    }    if (bufID < 0 || bufID >= LOG_ID_MAX) {        jniThrowNullPointerException(env, "bad bufID");        return -1;    }    if (tagObj != NULL)        tag = env->GetStringUTFChars(tagObj, NULL);    msg = env->GetStringUTFChars(msgObj, NULL);    int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);    if (tag != NULL)        env->ReleaseStringUTFChars(tagObj, tag);    env->ReleaseStringUTFChars(msgObj, msg);    return res;}
接下来就要去Runtime层找__android_log_buf_write了:system/core/liblog/logd_write.c:

int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg){    struct iovec vec[3];   ……   // 将日志优先级、tag、内容赋给vec的三段    return write_to_log(bufID, vec, 3);}
在文件system/core/liblog/logd_write.c的头部可以看到write_to_log是个函数指针,初始值指向__write_to_log_init:

static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;……static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr){    ……    if (write_to_log == __write_to_log_init) {        int ret;        ret = __write_to_log_initialize();    ……        write_to_log = __write_to_log_daemon;    }    ……    return write_to_log(log_id, vec, nr);}

屏蔽掉不关键的信息,__write_to_log_init首次被执行时调用__write_to_log_initialize,之后把write_to_log指针指向了__write_to_log_daemon,之后再执行write_to_log。以后__android_log_buf_write也将通过write_to_log调用__write_to_log_daemon。

再来看__write_to_log_initialize:

static int __write_to_log_initialize(){    int i, ret = 0;#if FAKE_LOG_DEVICE    for (i = 0; i < LOG_ID_MAX; i++) {        char buf[sizeof("/dev/log_system")];        snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));        log_fds[i] = fakeLogOpen(buf, O_WRONLY);    }#else    if (pstore_fd < 0) {        pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));    }    if (logd_fd < 0) {        i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));        if (i < 0) {            ret = -errno;        } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) {            ret = -errno;            close(i);        } else {            struct sockaddr_un un;            memset(&un, 0, sizeof(struct sockaddr_un));            un.sun_family = AF_UNIX;            strcpy(un.sun_path, "/dev/socket/logdw");            if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un,                                           sizeof(struct sockaddr_un))) < 0) {                ret = -errno;                close(i);            } else {                logd_fd = i;            }        }    }#endif    return ret;}

用gdb把断点设在函数首行发现直接进入了#else的部分,说明FAKE_LOG_DEVICE或者没定义,或者定义为0,以后都可以忽略。接下来创建scoket并连接/dev/socket/logdw,并将套接字赋给logd_fd。以后的日志都写到了logd_fd中。

所以研究Android6.0的日志系统在内核层应该去找/dev/socket/logdw的驱动。


写了个简单的程序从Runtime层由上往下跟进:

#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <android/log.h>#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "keymatch", __VA_ARGS___)int main(int argc, const char** argv){    __android_log_write(ANDROID_LOG_INFO, "LOG", "ABCDEF");    printf("123456");    return 0;}
Android.mk文件需要注意,加上链接libs:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optionalLOCAL_LDLIBS := -llogLOCAL_MODULE := testlog LOCAL_SRC_FILES := $(call all-subdir-c-files)include $(BUILD_EXECUTABLE)

__android_log_write这个函数定义在logd_write.c中:

int __android_log_write(int prio, const char *tag, const char *msg){    return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);}
当我用gdb step in 到__android_log_buf_write时,却怎么也进不去:

(gdb) b mainBreakpoint 1 at 0x614: file external/testlog/testlog.c, line 10.(gdb) cThe program is not being run.(gdb) target remote :1234Remote debugging using :1234warning: Unable to find dynamic linker breakpoint function.GDB will be unable to debug shared library initializersand track explicitly loaded dynamic code.Cannot access memory at address 0x00xb6ef6658 in ?? ()(gdb) cContinuing.warning: Could not load shared library symbols for 6 libraries, e.g. /system/bin/linker.Use the "info sharedlibrary" command to see the complete listing.Do you need "set solib-search-path" or "set sysroot"?Breakpoint 1, main (argc=1, argv=0xbee3dba4) at external/testlog/testlog.c:1010        __android_log_write(ANDROID_LOG_INFO, "LOG", "ABCDEF");(gdb) set solib-absolute-prefix out/target/product/generic/symbwarning: Unable to find dynamic linker breakpoint function.GDB will be unable to debug shared library initializersand track explicitly loaded dynamic code.(gdb) set solib-absolute-prefix out/target/product/generic/symbols/Reading symbols from out/target/product/generic/symbols/system/bin/linker...done.Loaded symbols for out/target/product/generic/symbols/system/bin/linkerReading symbols from out/target/product/generic/symbols/system/lib/libc++.so...done.Loaded symbols for out/target/product/generic/symbols/system/lib/libc++.soReading symbols from out/target/product/generic/symbols/system/lib/libc.so...done.Loaded symbols for out/target/product/generic/symbols/system/lib/libc.soReading symbols from out/target/product/generic/symbols/system/lib/libm.so...done.Loaded symbols for out/target/product/generic/symbols/system/lib/libm.soReading symbols from out/target/product/generic/symbols/system/lib/liblog.so...done.Loaded symbols for out/target/product/generic/symbols/system/lib/liblog.soReading symbols from out/target/product/generic/symbols/system/lib/libnetd_client.so...done.Loaded symbols for out/target/product/generic/symbols/system/lib/libnetd_client.so(gdb) n9    {(gdb) n10        __android_log_write(ANDROID_LOG_INFO, "LOG", "ABCDEF");(gdb) s__android_log_write (prio=4, tag=0xb6f18070 "LOG", msg=0xb6f18074 "ABCDEF") at system/core/liblog/logd_write.c:359359    {(gdb) s360        return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);(gdb) si0xb6d8bcd2    360        return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);(gdb)0xb6d8bcd4    360        return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);(gdb)361    }(gdb)
无论使用s或者si都不行,我判断应该是因为__android_log_buf_write被调用的次数不多,因此被编译器内联了。不过没关系,这只是个过路函数,它内部调用了write_to_log,这是个函数指针, 凡是被函数指针指过的函数,应该都不会被内联 。因为被内联的函数相当于代码展开,函数不存在了,也就无法被函数指针指向。因此,可以把断点端到write_to_log所指向的__write_to_log_initialize和__write_to_log_daemon。






更多相关文章

  1. 使用Kotlin开发Android 扩展函数(Extensions)
  2. android调用高版本api函数的兼容性问题
  3. Android O system函数执行reboot命令失败
  4. Android下使用dlopen函数动态调用.so链接库 [转]
  5. sp 强指针类的用法
  6. Android Studio如何使用快捷键生成get,set,tostring,构造函数
  7. Android Apk反编译函数对应法则

随机推荐

  1. AutoCompleteTextView与MultiAutoComplet
  2. android中webView JS调用Android的方法、
  3. Android获取屏幕的宽和高
  4. Android 中文API (37) —— AbsoluteLayout
  5. android超快模拟器Ggenymotion的安装和配
  6. android复制数据库到SD卡
  7. Android热插拔事件处理流程--Vold
  8. Android installation problem on Ubuntu
  9. Android getText(int resId)和getString(
  10. 获取Android设备的方向