Android Lib层打印log之------bionic库打印log

来源:互联网 发布:java中main函数 编辑:程序博客网 时间:2024/04/19 07:28

1. 前提:

    android系统把标准输出stdout从定向到/dev/null 中,所以logcat无法查看printf()打印的log信息。

2. 实际操作:

  1. 使用头文件: # include<private/logc_logging.h>
  2. 需要打印log使用: __libc_format_log()
  3. 例子:
# 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是在<errno.h>中定义, 在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库的。
初来乍到,欢迎拍砖。

0 0
原创粉丝点击