[转]NDK中log输出方法
生活随笔
收集整理的這篇文章主要介紹了
[转]NDK中log输出方法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1:在編譯so文件的c或cpp文件之前中加入以下代碼,就可以在android中的log顯示日志內容
? ? ? #include <android/log.h>
? ? ? #define LOG_TAG "show infomation"
? ? ? #define LOGW(a ) ?__android_log_write(ANDROID_LOG_WARN,LOG_TAG,a)
2:就可以在c或cpp中加入LOWG(str) 就可以在android中的log中顯示打印的內容
3.這樣寫完以后,如果直接編譯,就會報 __android_log_write 方法undefined.
怎么回事呢?關鍵是在設置編譯選項上面。
在Android.mk文件里,可以指定一個LOCAL_LDLIBS的參數。如果不指定,那么編譯的時候,只會引入默認的幾個重要的lib,比如libc之類的。
如果要用log,那就要把 liblog給引進來。
網上很多的寫法是 LOCAL_LDLIBS := -llog ,這在build static lib的時候沒什么問題。如果是build shared lib,就會報個 cannot find -llog的錯誤。意思是找不到liblog.so這個庫文件。
因此需要改成 LOCAL_LDLIBS := ?-L$(SYSROOT)/usr/lib -llog 才可以正常編譯。
其中-L參數是指定了搜索lib的路徑。
下面是一個android.mk的內容的例子:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE ? ?:= TestNdkNetwork
LOCAL_SRC_FILES := HttpConnection.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
include $(BUILD_SHARED_LIBRARY)
?Android中Log信息的輸出方法 收藏?
共兩篇文章,第一篇講述了如何在程序中輸出Log信息,第二篇詳細的分析了Log信息的輸出機制。
下面是第一篇(轉自:http://blog.163.com/binghaitao@126/blog/static/3383532520099309366435/)?
1:在編譯so文件的c或cpp文件之前中加入以下代碼,就可以在android中的log顯示日志內容
? ? ? #include <android/log.h>
? ? ? #define LOG_TAG "show infomation"
? ? ? #define LOGW(a ) ?__android_log_write(ANDROID_LOG_WARN,LOG_TAG,a)
2:就可以在c或cpp中加入LOWG(str) 就可以在android中的log中顯示打印的內容
3.這樣寫完以后,如果直接編譯,就會報 __android_log_write 方法undefined.
怎么回事呢?關鍵是在設置編譯選項上面。
在Android.mk文件里,可以指定一個LOCAL_LDLIBS的參數。如果不指定,那么編譯的時候,只會引入默認的幾個重要的lib,比如libc之類的。
如果要用log,那就要把 liblog給引進來。
網上很多的寫法是 LOCAL_LDLIBS := -llog ,這在build static lib的時候沒什么問題。如果是build shared lib,就會報個 cannot find -llog的錯誤。意思是找不到liblog.so這個庫文件。
因此需要改成 LOCAL_LDLIBS := ?-L$(SYSROOT)/usr/lib -llog 才可以正常編譯。
其中-L參數是指定了搜索lib的路徑。
下面是一個android.mk的內容的例子:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE ? ?:= TestNdkNetwork
LOCAL_SRC_FILES := HttpConnection.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
include $(BUILD_SHARED_LIBRARY)
下面是第二篇(轉自http://blog.csdn.net/knock/archive/2010/04/21/5511255.aspx)?
為了調試,必須要將log怎么打印的搞清楚,于是有了以下的分析。
我們通常在程序中插入LOGD(..),LOGE(..)之類的語句,但什么情況下可以查看這些打印消息呢?
首先,來到定義處:system/core/include/cutils/log.h,在開頭就可以看到
#ifndef LOG_TAG
#define LOG_TAG NULL
#endif
所以程序中#include "log.h"之前要定義LOG_TAG,不然就為空.
再看LOGD的定義
#ifndef LOGD
#define LOGD(...) ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif
跟進
#ifndef LOG
#define LOG(priority, tag, ...) \
? ?LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
#endif
繼續
#ifndef LOG_PRI
#define LOG_PRI(priority, tag, ...) \
? ?android_printLog(priority, tag, __VA_ARGS__)
#endif
再跟進
#define android_printLog(prio, tag, fmt...) \
? ?__android_log_print(prio, tag, fmt)
__android_log_print()是位于system/core/liblog/logd_write.c內
int __android_log_print(int prio, const char *tag, const char *fmt, ...)
{
? ?va_list ap;
? ?char buf[LOG_BUF_SIZE]; ? ?
? ?va_start(ap, fmt);
? ?vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
? ?va_end(ap);
? ?return __android_log_write(prio, tag, buf);
}
看__android_log_write()
int __android_log_write(int prio, const char *tag, const char *msg)
{
? ?......
? ?return write_to_log(log_id, vec, 3);
}
write_to_log定義如下
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)
{
#ifdef HAVE_PTHREADS
? ?pthread_mutex_lock(&log_init_lock);
#endif
? ?if (write_to_log == __write_to_log_init) {
? ? ? ?log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
? ? ? ?log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
? ? ? ?log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);
? ? ? ?write_to_log = __write_to_log_kernel;
? ? ? ?if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||
? ? ? ? ? ? ? ?log_fds[LOG_ID_EVENTS] < 0) {
? ? ? ? ? ?log_close(log_fds[LOG_ID_MAIN]);
? ? ? ? ? ?log_close(log_fds[LOG_ID_RADIO]);
? ? ? ? ? ?log_close(log_fds[LOG_ID_EVENTS]);
? ? ? ? ? ?log_fds[LOG_ID_MAIN] = -1;
? ? ? ? ? ?log_fds[LOG_ID_RADIO] = -1;
? ? ? ? ? ?log_fds[LOG_ID_EVENTS] = -1;
? ? ? ? ? ?write_to_log = __write_to_log_null;
? ? ? ?}
? ?}
#ifdef HAVE_PTHREADS
? ?pthread_mutex_unlock(&log_init_lock);
#endif
? ?return write_to_log(log_id, vec, nr);
}
這段的主要意思是打開/dev/log/main,/dev/log/radio,/dev/log/events三個設備都成功則將
write_to_log指向__write_to_log_kernel,否則指向__write_to_log_null。
下面就分別看看這兩個
static int __write_to_log_null(log_id_t log_fd, struct iovec *vec, size_t nr)
{
? ?return -1;
}
static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
{
? ?ssize_t ret;
? ?int log_fd;
? ?if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
? ? ? ?log_fd = log_fds[(int)log_id];
? ?} else {
? ? ? ?return EBADF;
? ?}
? ?do {
? ? ? ?ret = log_writev(log_fd, vec, nr);
? ?} while (ret < 0 && errno == EINTR);
? ?return ret;
}
__write_to_log_null()什么也不做,表示丟棄log信息。__write_to_log_kernel會調用log_writev()
將log寫進對應的設備(/dev/log/*).
為什么寫進init.rc里由init來執行的程序不能輸出log呢?下面再來探究一番。。
system/core/init/init.c中,
void service_start(struct service *svc)函數啟動服務,有這么一句
? ? ? ?if (needs_console) {
? ? ? ? ? ?setsid();
? ? ? ? ? ?open_console();
? ? ? ?} else {
? ? ? ? ? ?zap_stdio();
? ? ? ?}
而這兩個函數為:
static void zap_stdio(void)
{
? ?int fd;
? ?fd = open("/dev/null", O_RDWR);
? ?dup2(fd, 0);
? ?dup2(fd, 1);
? ?dup2(fd, 2);
? ?close(fd);
}
static void open_console()
{
? ?int fd;
? ?if ((fd = open(console_name, O_RDWR)) < 0) {
? ? ? ?fd = open("/dev/null", O_RDWR);
? ?}
? ?dup2(fd, 0);
? ?dup2(fd, 1);
? ?dup2(fd, 2);
? ?close(fd);
}
zap_stdio()比較狠,直接將STDIN,STDOUT,STDERR都干掉了,而open_console()則只是在/dev/console
不存在的情況下才干掉STDIN,STDOUT,STDERR,如果/dev/console存在,則將所有輸入輸出重定向到它
。
調用哪個取決于needs_console,
needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;
而svc->flags關于SVC_CONSOLE的部分來自于system/core/init/parser.c
static void parse_line_service(struct parse_state *state, int nargs, char **args)
{
? ? ? case K_console:
? ? ? ?svc->flags |= SVC_CONSOLE;
? ? ? ?break;
}
這也就是說如果init.rc中service部分有請求console,則可以打印到console。
但怎么樣才能打印到系統的log中,可以使用logcat來查看呢?這就需要用到logwrapper。
system/core/logwrapper/logwrapper.c中,logwrapper先打開/dev/ptmx,查詢到設備名后
fork()一個子進程并將STDOUT,STDERR定向到查詢到的設備。
? ? ? ?// redirect stdout and stderr
? ? ? ?close(parent_ptty);
? ? ? ?dup2(child_ptty, 1);
? ? ? ?dup2(child_ptty, 2);
? ? ? ?close(child_ptty);
然后開始執行要運行的程序
child(argc - 1, &argv[1]);
總結:
系統中的程序中輸出log一般是到/dev/log/下的三個設備中,可以用logcat查看。
對于init運行的程序則有兩種方法查看到log信息:
1.添加/system/bin/logwrapper,可以用logcat查看,例如
service /system/bin/logwrapper /system/bin/rild
2.添加console,像sh一樣直接輸出到console
service console /system/bin/sh
? ? ?console
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/guopeixin/archive/2010/06/09/5659279.aspx
? ? ? #include <android/log.h>
? ? ? #define LOG_TAG "show infomation"
? ? ? #define LOGW(a ) ?__android_log_write(ANDROID_LOG_WARN,LOG_TAG,a)
2:就可以在c或cpp中加入LOWG(str) 就可以在android中的log中顯示打印的內容
3.這樣寫完以后,如果直接編譯,就會報 __android_log_write 方法undefined.
怎么回事呢?關鍵是在設置編譯選項上面。
在Android.mk文件里,可以指定一個LOCAL_LDLIBS的參數。如果不指定,那么編譯的時候,只會引入默認的幾個重要的lib,比如libc之類的。
如果要用log,那就要把 liblog給引進來。
網上很多的寫法是 LOCAL_LDLIBS := -llog ,這在build static lib的時候沒什么問題。如果是build shared lib,就會報個 cannot find -llog的錯誤。意思是找不到liblog.so這個庫文件。
因此需要改成 LOCAL_LDLIBS := ?-L$(SYSROOT)/usr/lib -llog 才可以正常編譯。
其中-L參數是指定了搜索lib的路徑。
下面是一個android.mk的內容的例子:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE ? ?:= TestNdkNetwork
LOCAL_SRC_FILES := HttpConnection.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
include $(BUILD_SHARED_LIBRARY)
?Android中Log信息的輸出方法 收藏?
共兩篇文章,第一篇講述了如何在程序中輸出Log信息,第二篇詳細的分析了Log信息的輸出機制。
下面是第一篇(轉自:http://blog.163.com/binghaitao@126/blog/static/3383532520099309366435/)?
1:在編譯so文件的c或cpp文件之前中加入以下代碼,就可以在android中的log顯示日志內容
? ? ? #include <android/log.h>
? ? ? #define LOG_TAG "show infomation"
? ? ? #define LOGW(a ) ?__android_log_write(ANDROID_LOG_WARN,LOG_TAG,a)
2:就可以在c或cpp中加入LOWG(str) 就可以在android中的log中顯示打印的內容
3.這樣寫完以后,如果直接編譯,就會報 __android_log_write 方法undefined.
怎么回事呢?關鍵是在設置編譯選項上面。
在Android.mk文件里,可以指定一個LOCAL_LDLIBS的參數。如果不指定,那么編譯的時候,只會引入默認的幾個重要的lib,比如libc之類的。
如果要用log,那就要把 liblog給引進來。
網上很多的寫法是 LOCAL_LDLIBS := -llog ,這在build static lib的時候沒什么問題。如果是build shared lib,就會報個 cannot find -llog的錯誤。意思是找不到liblog.so這個庫文件。
因此需要改成 LOCAL_LDLIBS := ?-L$(SYSROOT)/usr/lib -llog 才可以正常編譯。
其中-L參數是指定了搜索lib的路徑。
下面是一個android.mk的內容的例子:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE ? ?:= TestNdkNetwork
LOCAL_SRC_FILES := HttpConnection.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
include $(BUILD_SHARED_LIBRARY)
下面是第二篇(轉自http://blog.csdn.net/knock/archive/2010/04/21/5511255.aspx)?
為了調試,必須要將log怎么打印的搞清楚,于是有了以下的分析。
我們通常在程序中插入LOGD(..),LOGE(..)之類的語句,但什么情況下可以查看這些打印消息呢?
首先,來到定義處:system/core/include/cutils/log.h,在開頭就可以看到
#ifndef LOG_TAG
#define LOG_TAG NULL
#endif
所以程序中#include "log.h"之前要定義LOG_TAG,不然就為空.
再看LOGD的定義
#ifndef LOGD
#define LOGD(...) ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif
跟進
#ifndef LOG
#define LOG(priority, tag, ...) \
? ?LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
#endif
繼續
#ifndef LOG_PRI
#define LOG_PRI(priority, tag, ...) \
? ?android_printLog(priority, tag, __VA_ARGS__)
#endif
再跟進
#define android_printLog(prio, tag, fmt...) \
? ?__android_log_print(prio, tag, fmt)
__android_log_print()是位于system/core/liblog/logd_write.c內
int __android_log_print(int prio, const char *tag, const char *fmt, ...)
{
? ?va_list ap;
? ?char buf[LOG_BUF_SIZE]; ? ?
? ?va_start(ap, fmt);
? ?vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
? ?va_end(ap);
? ?return __android_log_write(prio, tag, buf);
}
看__android_log_write()
int __android_log_write(int prio, const char *tag, const char *msg)
{
? ?......
? ?return write_to_log(log_id, vec, 3);
}
write_to_log定義如下
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)
{
#ifdef HAVE_PTHREADS
? ?pthread_mutex_lock(&log_init_lock);
#endif
? ?if (write_to_log == __write_to_log_init) {
? ? ? ?log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
? ? ? ?log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
? ? ? ?log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);
? ? ? ?write_to_log = __write_to_log_kernel;
? ? ? ?if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||
? ? ? ? ? ? ? ?log_fds[LOG_ID_EVENTS] < 0) {
? ? ? ? ? ?log_close(log_fds[LOG_ID_MAIN]);
? ? ? ? ? ?log_close(log_fds[LOG_ID_RADIO]);
? ? ? ? ? ?log_close(log_fds[LOG_ID_EVENTS]);
? ? ? ? ? ?log_fds[LOG_ID_MAIN] = -1;
? ? ? ? ? ?log_fds[LOG_ID_RADIO] = -1;
? ? ? ? ? ?log_fds[LOG_ID_EVENTS] = -1;
? ? ? ? ? ?write_to_log = __write_to_log_null;
? ? ? ?}
? ?}
#ifdef HAVE_PTHREADS
? ?pthread_mutex_unlock(&log_init_lock);
#endif
? ?return write_to_log(log_id, vec, nr);
}
這段的主要意思是打開/dev/log/main,/dev/log/radio,/dev/log/events三個設備都成功則將
write_to_log指向__write_to_log_kernel,否則指向__write_to_log_null。
下面就分別看看這兩個
static int __write_to_log_null(log_id_t log_fd, struct iovec *vec, size_t nr)
{
? ?return -1;
}
static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
{
? ?ssize_t ret;
? ?int log_fd;
? ?if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
? ? ? ?log_fd = log_fds[(int)log_id];
? ?} else {
? ? ? ?return EBADF;
? ?}
? ?do {
? ? ? ?ret = log_writev(log_fd, vec, nr);
? ?} while (ret < 0 && errno == EINTR);
? ?return ret;
}
__write_to_log_null()什么也不做,表示丟棄log信息。__write_to_log_kernel會調用log_writev()
將log寫進對應的設備(/dev/log/*).
為什么寫進init.rc里由init來執行的程序不能輸出log呢?下面再來探究一番。。
system/core/init/init.c中,
void service_start(struct service *svc)函數啟動服務,有這么一句
? ? ? ?if (needs_console) {
? ? ? ? ? ?setsid();
? ? ? ? ? ?open_console();
? ? ? ?} else {
? ? ? ? ? ?zap_stdio();
? ? ? ?}
而這兩個函數為:
static void zap_stdio(void)
{
? ?int fd;
? ?fd = open("/dev/null", O_RDWR);
? ?dup2(fd, 0);
? ?dup2(fd, 1);
? ?dup2(fd, 2);
? ?close(fd);
}
static void open_console()
{
? ?int fd;
? ?if ((fd = open(console_name, O_RDWR)) < 0) {
? ? ? ?fd = open("/dev/null", O_RDWR);
? ?}
? ?dup2(fd, 0);
? ?dup2(fd, 1);
? ?dup2(fd, 2);
? ?close(fd);
}
zap_stdio()比較狠,直接將STDIN,STDOUT,STDERR都干掉了,而open_console()則只是在/dev/console
不存在的情況下才干掉STDIN,STDOUT,STDERR,如果/dev/console存在,則將所有輸入輸出重定向到它
。
調用哪個取決于needs_console,
needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;
而svc->flags關于SVC_CONSOLE的部分來自于system/core/init/parser.c
static void parse_line_service(struct parse_state *state, int nargs, char **args)
{
? ? ? case K_console:
? ? ? ?svc->flags |= SVC_CONSOLE;
? ? ? ?break;
}
這也就是說如果init.rc中service部分有請求console,則可以打印到console。
但怎么樣才能打印到系統的log中,可以使用logcat來查看呢?這就需要用到logwrapper。
system/core/logwrapper/logwrapper.c中,logwrapper先打開/dev/ptmx,查詢到設備名后
fork()一個子進程并將STDOUT,STDERR定向到查詢到的設備。
? ? ? ?// redirect stdout and stderr
? ? ? ?close(parent_ptty);
? ? ? ?dup2(child_ptty, 1);
? ? ? ?dup2(child_ptty, 2);
? ? ? ?close(child_ptty);
然后開始執行要運行的程序
child(argc - 1, &argv[1]);
總結:
系統中的程序中輸出log一般是到/dev/log/下的三個設備中,可以用logcat查看。
對于init運行的程序則有兩種方法查看到log信息:
1.添加/system/bin/logwrapper,可以用logcat查看,例如
service /system/bin/logwrapper /system/bin/rild
2.添加console,像sh一樣直接輸出到console
service console /system/bin/sh
? ? ?console
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/guopeixin/archive/2010/06/09/5659279.aspx
總結
以上是生活随笔為你收集整理的[转]NDK中log输出方法的全部內容,希望文章能夠幫你解決所遇到的問題。