版权声明:本文为博主原创文章,未经博主允许不得转载。

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 -;
} if (bufID < || bufID >= LOG_ID_MAX) {
jniThrowNullPointerException(env, "bad bufID");
return -;
} 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[]; …… // 将日志优先级、tag、内容赋给vec的三段 return write_to_log(bufID, vec, );
}

在文件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 = ; #if FAKE_LOG_DEVICE
for (i = ; 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 < ) {
pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
} if (logd_fd < ) {
i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, ));
if (i < ) {
ret = -errno;
} else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < ) {
ret = -errno;
close(i);
} else {
struct sockaddr_un un;
memset(&un, , 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))) < ) {
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("");
return ;
}

Android.mk文件需要注意,加上链接libs:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_LDLIBS := -llog
LOCAL_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 main
Breakpoint at 0x614: file external/testlog/testlog.c, line .
(gdb) c
The program is not being run.
(gdb) target remote :
Remote debugging using :
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
Cannot access memory at address 0x0
0xb6ef6658 in ?? ()
(gdb) c
Continuing.
warning: Could not load shared library symbols for 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 , main (argc=, argv=0xbee3dba4) at external/testlog/testlog.c:
__android_log_write(ANDROID_LOG_INFO, "LOG", "ABCDEF");
(gdb) set solib-absolute-prefix out/target/product/generic/symb
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and 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/linker
Reading symbols from out/target/product/generic/symbols/system/lib/libc++.so...done.
Loaded symbols for out/target/product/generic/symbols/system/lib/libc++.so
Reading symbols from out/target/product/generic/symbols/system/lib/libc.so...done.
Loaded symbols for out/target/product/generic/symbols/system/lib/libc.so
Reading symbols from out/target/product/generic/symbols/system/lib/libm.so...done.
Loaded symbols for out/target/product/generic/symbols/system/lib/libm.so
Reading symbols from out/target/product/generic/symbols/system/lib/liblog.so...done.
Loaded symbols for out/target/product/generic/symbols/system/lib/liblog.so
Reading 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) n
{
(gdb) n
__android_log_write(ANDROID_LOG_INFO, "LOG", "ABCDEF");
(gdb) s
__android_log_write (prio=, tag=0xb6f18070 "LOG", msg=0xb6f18074 "ABCDEF") at system/core/liblog/logd_write.c:
{
(gdb) s
return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
(gdb) si
0xb6d8bcd2 return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
(gdb)
0xb6d8bcd4 return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
(gdb)
}
(gdb)

无论使用s或者si都不行,我判断应该是因为__android_log_buf_write被调用的次数不多,因此被编译器内联了。不过没关系,这只是个过路函数,它内部调用了write_to_log,这是个函数指针,凡是被函数指针指过的函数,应该都不会被内联。因为被内联的函数相当于代码展开,函数不存在了,也就无法被函数指针指向。因此,可以把断点端到write_to_log所指向的__write_to_log_initialize和__write_to_log_daemon。

Android6的Logger日志系统的更多相关文章

  1. Android源码——Logger日志系统

    Android的Logger日志系统是基于内核中的Logger日志驱动程序实现的. 日志保存在内核空间中 缓冲区保存日志   分类方法:日志的类型  +   日志的输出量   日志类型:   main ...

  2. Android Logger日志系统

    文件夹 文件夹 前言 执行时库层日志库liblog 源代码分析 CC日志写入接口 Java日志写入接口 logcat工具分析 基础数据结构 初始化过程 日志记录的读取过程 前言 该篇文章是我的读书和实 ...

  3. Android日志系统驱动程序Logger源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6595744 我们知道,在Android系统中, ...

  4. Java日志系统---Logger之简单入门

    Java 中自带的日志系统,今天抽空了解了一点,算是入了门,所以将自己的一些心得记录下来,以备日后查看,有兴趣的朋友,看到此文章,觉得有错误或需要添加的地方,请在下方评论留言,大家可以共同进步,谢谢: ...

  5. Atitit.日志系统slf4j的使用

    Atitit.日志系统slf4j的使用 SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar ...

  6. 使用Slf4j集成Log4j2构建项目日志系统的完美解决方案

    一.背景 最近因为公司项目性能需要,我们考虑把以前基于的log4j的日志系统重构成基于Slf4j和log4j2的日志系统,因为,使用slf4j可以很好的保证我们的日志系统具有良好的兼容性,兼容当前常见 ...

  7. [Asp.net 5] Logging-其他日志系统的实现

    Microsoft.Framework.Logging.NLog 使用Nlog扩展日志系统:按照我们上节说的,对于扩展的日志系统都要实现俩个接口ILogger.ILoggerProvider.所以在当 ...

  8. Java日志系统框架的设计与实现

    推荐一篇好的文章介绍java日志系统框架的设计的文章:http://soft.chinabyte.com/database/438/11321938.shtml 文章内容总结: 日志系统对跟踪调试.程 ...

  9. paip.log4j 日志系统 参数以及最佳实践

    paip.log4j 日志系统 参数以及最佳实践   %d{yyyy-MM-dd HH:mm:ss} [thrd:%t] %5p   loger:%c   (%C.%M.%L)  - %m%n 201 ...

随机推荐

  1. Nunit 2.6 无法调试.Net Framework 4.0

    <configuration> <!-- The GUI only runs under .NET 2.0 or higher. The useLegacyV2RuntimeActi ...

  2. 天梯L2-001. 紧急救援(25分)

    L2-001. 紧急救援 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 作为一个城市的应急救援队伍的负责人,你有一张特殊的全国 ...

  3. DCloud:目录

    ylbtech-DCloud:目录 1.返回顶部 1.5+ App开发入门指南 http://ask.dcloud.net.cn/article/89 2.   3. 2.返回顶部   3.返回顶部 ...

  4. Linux打包下载命令

    语法:tar [主选项+辅选项] 文件或者目录使用该命令时,主选项是必须要有的,它告诉tar要做什么事情,辅选项是辅助使用的,可以选用. 主选项: c 创建新的档案文件.如果用户想备份一个目录或是一些 ...

  5. centos软件安装目录(amp目录)

    entos安装软件的目录 1. 如果是rpm安装的可以:rpm -ql package-name 2. 可以在根目录上直接find . -name 软件中的某个文件名 不过安装软件一般都在/usr/l ...

  6. HotSpotVM创建过程(JNI_CreateJavaVM)详解

    来自:<Java Performance>第3章 JVM Overview The HotSpot VM's implementation of the JNI_CreateJavaVM ...

  7. javascript——对象的概念——创建对象与销毁对象

    一.创建对象 1.创建空对象 方式一: var o ={};o; //Object {} typeof(o); //"object" 方式二: var o=new Object() ...

  8. DAY7-面向对象之封装

    一.引子 从封装本身的意思去理解,封装就好像是拿来一个麻袋,把小猫,小狗,小王八,还有alex一起装进麻袋,然后把麻袋封上口子.照这种逻辑看,封装=‘隐藏’,这种理解是相当片面的 二.先看如何隐藏 在 ...

  9. C#操作JSON专题

    第一章:C#如何拿到从http上返回JSON数据? 第二章:C#如何解析JSON数据?(反序列化对象) 第三章:C#如何生成JSON字符串?(序列化对象) 第四章:C#如何生成JSON字符串提交给接口 ...

  10. python爬虫框架(3)--Scrapy框架安装配置

    1.安装python并将scripts配置进环境变量中 2.安装pywin32 在windows下,必须安装pywin32,安装地址:http://sourceforge.net/projects/p ...