android系统把标准输出stdout从定向到/dev/null 中,所以logcat无法查看printf()打印的log信息。
# include
__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
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说明。
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);
}
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;
}
/* 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
最初是抱着“Google的工程师是如何调试lib层代码的呢?”的疑问浏览bionic库的。
初来乍到,欢迎拍砖。