1. 前提:

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

2. 实际操作:

  1. 使用头文件: # include
  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是在中定义, 在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库的。
初来乍到,欢迎拍砖。

更多相关文章

  1. 使用ViewPager时,如何对view进行更新
  2. 你真的了解AsyncTask吗?AsyncTask源码分析
  3. Android(安卓)Fragment 体系源码跟踪笔记(1)
  4. View绘制流程源码解析-第一篇
  5. 关于 android Intent 传对象和对象数组的一些操作
  6. 编译源码生成的SDK,创建android project 没有proguard.cfg问题
  7. 导入android源码有错,R.java文件不能自动生成解决方法[转]
  8. Android(安卓)无法查看外部依赖jar的源码的问题
  9. Android(安卓)(Android(安卓)studio3.0.1)一篇可以实现app多语言的

随机推荐

  1. Android(安卓)StepView物流进度
  2. 安卓不知道怎么学?看十年码农如何回答这个
  3. Android实现系统关机和重启
  4. MVC架构设计与三层模型 & MVP思想精髓与
  5. Android mediaplayer 播放本地音乐文件
  6. Unity3D for Android 纹理压缩支持
  7. Android 版本兼容适配
  8. Android Studio中获取sha1证书指纹数据的
  9. [置顶] Android原生(Native)C(JNI/NDK)开
  10. Android中ViewPager+Fragment懒加载问题