Android(安卓)Lib层打印log之------bionic库打印log
16lz
2021-01-26
1. 前提:
android系统把标准输出stdout从定向到/dev/null 中,所以logcat无法查看printf()打印的log信息。
2. 实际操作:
- 使用头文件:
# include
- 需要打印log使用:
__libc_format_log()
- 例子:
# include<private/logc_logging.h> //也可以是 #include "private/libc_logging.h"xxx_func() { /** * int __libc_format_log(int priority, const char* tag, const char* format, ...) * * priority : int, 是在private/libc_logging.h定义的log的level,与java层的类似。 * 参考"/bionic/libc/bionic/private/libc_logging.h" 定义的ANDROID_LOG_DEBUG。 * tag : char* , log的Tag信息。 * format : char* , 格式化的字符串, */ char * tag = "DroidMage"; char * format = "%s"; char * msg = "This is for test!"; __libc_format_log(ANDROID_LOG_DEBUG, tag, format, msg);}
Note: Google好久都没什么好的发现,有一天浏览bionic源码,发现android底层有打印log的方法。(以android源码为根目录): /bionic/libc/private/logc_logging.cpp
3. 跟踪源码:libc_logging.cpp
int __libc_format_log(int priority, const char* tag, const char* format, ...) { va_list args; // 用来获得可变参数存入args,可变参数的标准用法。 va_start(args, format); int result = __libc_format_log_va_list(priority, tag, format, args); va_end(args); return result;}
Note:点击参看va_start说明。
- 继续跟踪 __libc_format_log_va_list():
int __libc_format_log_va_list(int priority, const char* tag, const char* format, va_list args) { char buffer[1024]; // BufferOutputStream 是一个c++类,也在libc_logging.cpp中的。可以自行查看。 BufferOutputStream os(buffer, sizeof(buffer)); // 下面对参数的操作,将参数格式化保存在buffer中。 out_vformat(os, format, args); // 关键: 返回 __libc_write_log()的调用 ,下面继续跟踪。 return __libc_write_log(priority, tag, buffer);}
- 继续跟踪 __libc_write_log():
static int __libc_write_log(int priority, const char* tag, const char* msg) {#ifdef TARGET_USES_LOGD ... // 由于TARGET_USES_LOGD未定义,跳过这里。#else // 这里打开了/dev/log/main文件,也是logcat查看log的地方。 // TEMP_FAILURE_RETRY不断尝试操作。操作成功返回,或则发生错误返回-1,错误类型保存'errno' int main_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/main", O_CLOEXEC | O_WRONLY)); // main_log_fd 等于-1表示打开文件失败 if (main_log_fd == -1) { // 判断出错类型是不是文件夹不存在的错误,errno是在中定义, 在TEMP_FAILURE_RETRY中使用。 if (errno == ENOTDIR) { // /dev/log isn't a directory? Maybe we're running on the host? Try stderr instead. // __libc_write_stderr()与__libc_write_log()类似,打开/dev/stderr并写入。请自行查看源码。 return __libc_write_stderr(tag, msg); } return -1; } iovec vec[3]; vec[0].iov_base = &priority; vec[0].iov_len = 1; vec[1].iov_base = const_cast<char*>(tag); vec[1].iov_len = strlen(tag) + 1; vec[2].iov_base = const_cast<char*>(msg); vec[2].iov_len = strlen(msg) + 1;#endif // 这里就把log信息写入文件了 int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0]))); close(main_log_fd); return result;}
- 在 unistd.h 定义了TEMP_FAILURE_RETRY 的宏:
/* Evaluate EXPRESSION, and repeat as long as it returns -1 with 'errno' set to EINTR. *//* 这里的说明:不断尝试进行操作。 结果:操作成功。或则发生错误返回-1,并把错误类型保存'errno' */// 具体可以参看博客:http://blog.csdn.net/zhangwu416826/article/details/17438591# define TEMP_FAILURE_RETRY(expression) \ (__extension__ \ ({ long int __result; \ do __result = (long int) (expression); \ while (__result == -1L && errno == EINTR); \ __result; }))#endif
4. 后记:
最初是抱着“Google的工程师是如何调试lib层代码的呢?”的疑问浏览bionic库的。
初来乍到,欢迎拍砖。
更多相关文章
- 使用ViewPager时,如何对view进行更新
- 你真的了解AsyncTask吗?AsyncTask源码分析
- Android(安卓)Fragment 体系源码跟踪笔记(1)
- View绘制流程源码解析-第一篇
- 关于 android Intent 传对象和对象数组的一些操作
- 编译源码生成的SDK,创建android project 没有proguard.cfg问题
- 导入android源码有错,R.java文件不能自动生成解决方法[转]
- Android(安卓)无法查看外部依赖jar的源码的问题
- Android(安卓)(Android(安卓)studio3.0.1)一篇可以实现app多语言的