Android6的Logger日志系统
16lz
2021-01-23
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。
更多相关文章
- 使用Kotlin开发Android 扩展函数(Extensions)
- android调用高版本api函数的兼容性问题
- Android O system函数执行reboot命令失败
- Android下使用dlopen函数动态调用.so链接库 [转]
- sp 强指针类的用法
- Android Studio如何使用快捷键生成get,set,tostring,构造函数
- Android Apk反编译函数对应法则