android log机制——输出log【转】
2016-08-23 16:17
267 查看
转自:http://blog.csdn.net/tdstds/article/details/19084327
目录(?)[-]
在androidJavacode中输出log
Logprintln_native方法
本地层代码Log输出
转自:http://my.oschina.net/wolfcs/blog/164624
Androidlog系统。
Java/android/util/Log.java中可以看到:
Java层可以通过三个class来输出其中三种类型的log,三种类型分别为MAIN、RADIO和SYSTEM,三个class分别为Log、Rlog和Slog,其package则分别为android.util、android.telephony和android.util。这些用于打印log的classes,其构造函数都为private,因而都不能创建其对象,但它们都提供了静态方法来给用户打印log。各个log打印class的实现都大同小异,可以看一下Log这个class中的一些:
最终都会是调用Log.println_native()静态native方法来打印log,各个类中各个方法的不同之处也仅在于参数的差异。
可以看到,干的都是转换参数的事情,最终再call到__android_log_buf_write()函数,这个函数的定义在system/core/liblog/logd_write.c,为:
做了三件事情,一是根据log的tag,转换bufID,二是用传进来的参数构造一个structiovec数组,三是将前一步构造的数组作为参数调用write_to_log()。write_to_log()是一个函数指针,在开始时,它指向了__write_to_log_init():
__write_to_log_init()的实现如下:
这个地方,会检查write_to_log是否指向了__write_to_log_init,也就是是否是第一次打印log,如果是,则打开几个用于输出log的设备文件,然后使write_to_log函数指针指向__write_to_log_kernel,或者在打开输出log设备文件出现异常时,使write_to_log指向__write_to_log_null,最后再次调用经过了重定向的write_to_log,也就是__write_to_log_kernel或者__write_to_log_null函数。我们可以看一下那几个设备文件究竟是什麽(在system/core/include/cutils/logger.h):
接着继续来看__write_to_log_kernel或者__write_to_log_null函数:
由log_id获取到对应的log_fd,然后调用log_writev()打印log。可以看一下log_writev()的定义,它是一个宏:
这些就都是标准的unix系统调用了。
使用这组宏,需要定义另外一个宏来作为所打印log的tag:
此外,还要include头文件<cutils/log.h>。来看一下这些宏中的一些的定义:
先来看一下,在native层中定义的priority(在system/core/include/android/log.h中):
另外,这些宏最终都会call到__android_log_print(),也是在system/core/liblog/logd_write.c中:
先是格式化参数,然后就是调用__android_log_write()函数。这个函数的code如下:
这个函数与我们前面看到的__android_log_buf_write()非常相似。所不同的就是这个函数没有log_id参数,因而它默认是输出MAINlog,当log的TAG为某些特殊字串时,则输出RADIOlog。最后同样是调用write_to_log这个函数指针来输出log。
我们再来看一个skia里面打log的SkDebugf()函数的实现:
call到了__android_log_vprint()来输出log,__android_log_vprint()的定义也在system/core/liblog/logd_write.c中:
一样是__android_log_write()函数。
Done.
目录
转自:
在androidJavacode中输出log
android系统有4种类型、6个优先级的log,有一些常量用于标识这些信息,相关的定义在frameworks/base/core/01 | /** |
02 | *Priorityconstantfortheprintlnmethod;useLog.v. |
03 | */ |
04 | public static final int VERBOSE= 2 ; |
05 |
06 | /** |
07 | *Priorityconstantfortheprintlnmethod;useLog.d. |
08 | */ |
09 | public static final int DEBUG= 3 ; |
10 |
11 | /** |
12 | *Priorityconstantfortheprintlnmethod;useLog.i. |
13 | */ |
14 | public static final int INFO= 4 ; |
15 |
16 | /** |
17 | *Priorityconstantfortheprintlnmethod;useLog.w. |
18 | */ |
19 | public static final int WARN= 5 ; |
20 |
21 | /** |
22 | *Priorityconstantfortheprintlnmethod;useLog.e. |
23 | */ |
24 | public static final int ERROR= 6 ; |
25 |
26 | /** |
27 | *Priorityconstantfortheprintlnmethod. |
28 | */ |
29 | public static final int ASSERT= 7 ; |
30 |
31 | /**@hide*/ public static final int LOG_ID_MAIN= 0 ; |
32 | /**@hide*/ public static final int LOG_ID_RADIO= 1 ; |
33 | /**@hide*/ public static final int LOG_ID_EVENTS= 2 ; |
34 | /**@hide*/ public static final int LOG_ID_SYSTEM= 3 ; |
01 | public static int v(Stringtag,Stringmsg,Throwabletr){ |
02 | return println_native(LOG_ID_MAIN,VERBOSE,tag,msg+ '\n' +getStackTraceString(tr)); |
03 | } |
04 |
05 | /** |
06 | *Senda{@link#DEBUG}logmessage. |
07 | *@paramtagUsedtoidentifythesourceofalogmessage.Itusuallyidentifies |
08 | *theclassoractivitywherethelogcalloccurs. |
09 | *@parammsgThemessageyouwouldlikelogged. |
10 | */ |
11 | public static int d(Stringtag,Stringmsg){ |
12 | return println_native(LOG_ID_MAIN,DEBUG,tag,msg); |
13 | } |
Log.println_native()方法
这个方法的code在/frameworks/base/core/jni/android_util_Log.cpp,为:01 | static jintandroid_util_Log_println_native(JNIEnv*env,jobjectclazz, |
02 | jintbufID,jintpriority,jstringtagObj,jstringmsgObj) |
03 | { |
04 | const char *tag=NULL; |
05 | const char *msg=NULL; |
06 |
07 | if (msgObj==NULL){ |
08 | jniThrowNullPointerException(env, "printlnneedsamessage" ); |
09 | return -1; |
10 | } |
11 |
12 | if (bufID<0||bufID>=LOG_ID_MAX){ |
13 | jniThrowNullPointerException(env, "badbufID" ); |
14 | return -1; |
15 | } |
16 |
17 | if (tagObj!=NULL) |
18 | tag=env->GetStringUTFChars(tagObj,NULL); |
19 | msg=env->GetStringUTFChars(msgObj,NULL); |
20 |
21 | int res=__android_log_buf_write(bufID,(android_LogPriority)priority,tag,msg); |
22 |
23 | if (tag!=NULL) |
24 | env->ReleaseStringUTFChars(tagObj,tag); |
25 | env->ReleaseStringUTFChars(msgObj,msg); |
26 |
27 | return res; |
28 | } |
29 |
30 | /* |
31 | *JNIregistration. |
32 | */ |
33 | static JNINativeMethodgMethods[]={ |
34 | /*name,signature,funcPtr*/ |
35 | { "isLoggable" , "(Ljava/lang/String;I)Z" ,( void *)android_util_Log_isLoggable}, |
36 | { "println_native" , "(IILjava/lang/String;Ljava/lang/String;)I" ,( void *)android_util_Log_println_native}, |
37 | }; |
01 | int __android_log_buf_write( int bufID, int prio, const char *tag, const char *msg) |
02 | { |
03 | struct iovecvec[3]; |
04 | char tmp_tag[32]; |
05 |
06 | if (!tag) |
07 | tag= "" ; |
08 |
09 | /*XXX:Thisneedstogo!*/ |
10 | if ((bufID!=LOG_ID_RADIO)&& |
11 | (! strcmp (tag, "HTC_RIL" )|| |
12 | ! strncmp (tag, "RIL" ,3)|| /*Anylogtagwith"RIL"astheprefix*/ |
13 | ! strncmp (tag, "IMS" ,3)|| /*Anylogtagwith"IMS"astheprefix*/ |
14 | ! strcmp (tag, "AT" )|| |
15 | ! strcmp (tag, "GSM" )|| |
16 | ! strcmp (tag, "STK" )|| |
17 | ! strcmp (tag, "CDMA" )|| |
18 | ! strcmp (tag, "PHONE" )|| |
19 | ! strcmp (tag, "SMS" ))){ |
20 | bufID=LOG_ID_RADIO; |
21 | //Informthirdpartyapps/ril/radio..touseRlogorRLOG |
22 | snprintf(tmp_tag, sizeof (tmp_tag), "use-Rlog/RLOG-%s" ,tag); |
23 | tag=tmp_tag; |
24 | } |
25 |
26 | vec[0].iov_base=(unsigned char *)&prio; |
27 | vec[0].iov_len=1; |
28 | vec[1].iov_base=( void *)tag; |
29 | vec[1].iov_len= strlen (tag)+1; |
30 | vec[2].iov_base=( void *)msg; |
31 | vec[2].iov_len= strlen (msg)+1; |
32 |
33 | return write_to_log(bufID,vec,3); |
34 | } |
1 | static int (*write_to_log)(log_id_t, struct iovec*vec, size_t nr)=__write_to_log_init; |
01 | static int __write_to_log_init(log_id_tlog_id, struct iovec*vec, size_t nr) |
02 | { |
03 | #ifdefHAVE_PTHREADS |
04 | pthread_mutex_lock(&log_init_lock); |
05 | #endif |
06 |
07 | if (write_to_log==__write_to_log_init){ |
08 | log_fds[LOG_ID_MAIN]=log_open( "/dev/" LOGGER_LOG_MAIN,O_WRONLY); |
09 | log_fds[LOG_ID_RADIO]=log_open( "/dev/" LOGGER_LOG_RADIO,O_WRONLY); |
10 | log_fds[LOG_ID_EVENTS]=log_open( "/dev/" LOGGER_LOG_EVENTS,O_WRONLY); |
11 | log_fds[LOG_ID_SYSTEM]=log_open( "/dev/" LOGGER_LOG_SYSTEM,O_WRONLY); |
12 |
13 | write_to_log=__write_to_log_kernel; |
14 |
15 | if (log_fds[LOG_ID_MAIN]<0||log_fds[LOG_ID_RADIO]<0|| |
16 | log_fds[LOG_ID_EVENTS]<0){ |
17 | log_close(log_fds[LOG_ID_MAIN]); |
18 | log_close(log_fds[LOG_ID_RADIO]); |
19 | log_close(log_fds[LOG_ID_EVENTS]); |
20 | log_fds[LOG_ID_MAIN]=-1; |
21 | log_fds[LOG_ID_RADIO]=-1; |
22 | log_fds[LOG_ID_EVENTS]=-1; |
23 | write_to_log=__write_to_log_null; |
24 | } |
25 |
26 | if (log_fds[LOG_ID_SYSTEM]<0){ |
27 | log_fds[LOG_ID_SYSTEM]=log_fds[LOG_ID_MAIN]; |
28 | } |
29 | } |
30 |
31 | #ifdefHAVE_PTHREADS |
32 | pthread_mutex_unlock(&log_init_lock); |
33 | #endif |
34 |
35 | return write_to_log(log_id,vec,nr); |
36 | } |
1 | #defineLOGGER_LOG_MAIN"log/main" |
2 | #defineLOGGER_LOG_RADIO"log/radio" |
3 | #defineLOGGER_LOG_EVENTS"log/events" |
4 | #defineLOGGER_LOG_SYSTEM"log/system" |
01 | static int __write_to_log_null(log_id_tlog_fd, struct iovec*vec, size_t nr) |
02 | { |
03 | return -1; |
04 | } |
05 |
06 | static int __write_to_log_kernel(log_id_tlog_id, struct iovec*vec, size_t nr) |
07 | { |
08 | ssize_tret; |
09 | int log_fd; |
10 |
11 | if ( /*(int)log_id>=0&&*/ ( int )log_id<( int )LOG_ID_MAX){ |
12 | log_fd=log_fds[( int )log_id]; |
13 | } else { |
14 | return EBADF; |
15 | } |
16 |
17 | do { |
18 | ret=log_writev(log_fd,vec,nr); |
19 | } while (ret<0&& errno ==EINTR); |
20 |
21 | return ret; |
22 | } |
01 | #ifFAKE_LOG_DEVICE |
02 | //Thiswillbedefinedwhenbuildingforthehost. |
03 | #definelog_open(pathname,flags)fakeLogOpen(pathname,flags) |
04 | #definelog_writev(filedes,vector,count)fakeLogWritev(filedes,vector,count) |
05 | #definelog_close(filedes)fakeLogClose(filedes) |
06 | #else |
07 | #definelog_open(pathname,flags)open(pathname,(flags)|O_CLOEXEC) |
08 | #definelog_writev(filedes,vector,count)writev(filedes,vector,count) |
09 | #definelog_close(filedes)close(filedes) |
10 | #endif |
本地层代码Log输出
以一些比较典型的native代码打印log的case为例。先来看一下,在JNI的code中打印log的方法。在JNI中,比较常见到用ALOGx这一组宏来打印log,比如在frameworks/base/core/jni/android/graphics/TextLayoutCache.cpp这个文件中的dumpCacheStats()函数:01 | void TextLayoutCache::dumpCacheStats(){ |
02 | float remainingPercent=100*((mMaxSize-mSize)/(( float )mMaxSize)); |
03 | float timeRunningInSec=(systemTime(SYSTEM_TIME_MONOTONIC)-mCacheStartTime)/1000000000; |
04 |
05 | size_t cacheSize=mCache.size(); |
06 |
07 | ALOGD( "------------------------------------------------" ); |
08 | ALOGD( "Cachestats" ); |
09 | ALOGD( "------------------------------------------------" ); |
10 | ALOGD( "pid:%d" ,getpid()); |
11 | ALOGD( "running:%.0fseconds" ,timeRunningInSec); |
12 | ALOGD( "entries:%d" ,cacheSize); |
13 | ALOGD( "maxsize:%dbytes" ,mMaxSize); |
14 | ALOGD( "used:%dbytesaccordingtomSize" ,mSize); |
15 | ALOGD( "remaining:%dbytesor%2.2fpercent" ,mMaxSize-mSize,remainingPercent); |
16 | ALOGD( "hits:%d" ,mCacheHitCount); |
17 | ALOGD( "saved:%0.6fms" ,mNanosecondsSaved*0.000001f); |
18 | ALOGD( "------------------------------------------------" ); |
19 | } |
1 | #defineLOG_TAG"TextLayoutCache" |
01 | /* |
02 | *SimplifiedmacrotosendadebuglogmessageusingthecurrentLOG_TAG. |
03 | */ |
04 | #ifndefALOGD |
05 | #defineALOGD(...)((void)ALOG(LOG_DEBUG,LOG_TAG,__VA_ARGS__)) |
06 | #endif |
07 |
08 | /* |
09 | *SimplifiedmacrotosendawarninglogmessageusingthecurrentLOG_TAG. |
10 | */ |
11 | #ifndefALOGW |
12 | #defineALOGW(...)((void)ALOG(LOG_WARN,LOG_TAG,__VA_ARGS__)) |
13 | #endif |
14 |
15 | /* |
16 | *Basiclogmessagemacro. |
17 | * |
18 | *Example: |
19 | *ALOG(LOG_WARN,NULL,"Failedwitherror%d",errno); |
20 | * |
21 | *ThesecondargumentmaybeNULLor""toindicatethe"global"tag. |
22 | */ |
23 | #ifndefALOG |
24 | #defineALOG(priority,tag,...)\ |
25 | LOG_PRI(ANDROID_##priority,tag,__VA_ARGS__) |
26 | #endif |
27 |
28 | /* |
29 | *Logmacrothatallowsyoutospecifyanumberforthepriority. |
30 | */ |
31 | #ifndefLOG_PRI |
32 | #defineLOG_PRI(priority,tag,...)\ |
33 | android_printLog(priority,tag,__VA_ARGS__) |
34 | #endif |
35 |
36 | #defineandroid_printLog(prio,tag,fmt...)\ |
37 | __android_log_print(prio,tag,fmt) |
01 | /* |
02 | *Androidlogpriorityvalues,inascendingpriorityorder. |
03 | */ |
04 | typedef enum android_LogPriority{ |
05 | ANDROID_LOG_UNKNOWN=0, |
06 | ANDROID_LOG_DEFAULT, /*onlyforSetMinPriority()*/ |
07 | ANDROID_LOG_VERBOSE, |
08 | ANDROID_LOG_DEBUG, |
09 | ANDROID_LOG_INFO, |
10 | ANDROID_LOG_WARN, |
11 | ANDROID_LOG_ERROR, |
12 | ANDROID_LOG_FATAL, |
13 | ANDROID_LOG_SILENT, /*onlyforSetMinPriority();mustbelast*/ |
14 | }android_LogPriority; |
01 | int __android_log_print( int prio, const char *tag, const char *fmt,...) |
02 | { |
03 | va_list ap; |
04 | char buf[LOG_BUF_SIZE]; |
05 |
06 | va_start (ap,fmt); |
07 | vsnprintf(buf,LOG_BUF_SIZE,fmt,ap); |
08 | va_end (ap); |
09 |
10 | return __android_log_write(prio,tag,buf); |
11 | } |
01 | int __android_log_write( int prio, const char *tag, const char *msg) |
02 | { |
03 | struct iovecvec[3]; |
04 | log_id_tlog_id=LOG_ID_MAIN; |
05 | char tmp_tag[32]; |
06 |
07 | if (!tag) |
08 | tag= "" ; |
09 |
10 | /*XXX:Thisneedstogo!*/ |
11 | if (! strcmp (tag, "HTC_RIL" )|| |
12 | ! strncmp (tag, "RIL" ,3)|| /*Anylogtagwith"RIL"astheprefix*/ |
13 | ! strncmp (tag, "IMS" ,3)|| /*Anylogtagwith"IMS"astheprefix*/ |
14 | ! strcmp (tag, "AT" )|| |
15 | ! strcmp (tag, "GSM" )|| |
16 | ! strcmp (tag, "STK" )|| |
17 | ! strcmp (tag, "CDMA" )|| |
18 | ! strcmp (tag, "PHONE" )|| |
19 | ! strcmp (tag, "SMS" )){ |
20 | log_id=LOG_ID_RADIO; |
21 | //Informthirdpartyapps/ril/radio..touseRlogorRLOG |
22 | snprintf(tmp_tag, sizeof (tmp_tag), "use-Rlog/RLOG-%s" ,tag); |
23 | tag=tmp_tag; |
24 | } |
25 |
26 | vec[0].iov_base=(unsigned char *)&prio; |
27 | vec[0].iov_len=1; |
28 | vec[1].iov_base=( void *)tag; |
29 | vec[1].iov_len= strlen (tag)+1; |
30 | vec[2].iov_base=( void *)msg; |
31 | vec[2].iov_len= strlen (msg)+1; |
32 |
33 | return write_to_log(log_id,vec,3); |
34 | } |
我们再来看一个skia里面打log的SkDebugf()函数的实现:
1 | #include<android/log.h> |
2 |
3 | void SkDebugf( const char format[],...){ |
4 | va_list args; |
5 | va_start (args,format); |
6 | __android_log_vprint(ANDROID_LOG_DEBUG,LOG_TAG,format,args); |
7 | va_end (args); |
8 | } |
1 | int __android_log_vprint( int prio, const char *tag, const char *fmt, va_list ap) |
2 | { |
3 | char buf[LOG_BUF_SIZE]; |
4 |
5 | vsnprintf(buf,LOG_BUF_SIZE,fmt,ap); |
6 |
7 | return __android_log_write(prio,tag,buf); |
8 | } |
Done.
相关文章推荐
- android log机制——输出log
- 解读Android LOG机制的实现:(2)JAVA域输出LOG
- android的Log输出
- Android JNI输出LOG
- 在android 输出log 信息 用于调试
- 在android 输出log 信息 用于调试
- Android中Log的输出
- Android中Log信息的输出方法
- 解读Android LOG机制的实现
- Android在JNI中输出输出LOG
- 解读Android LOG机制的实现:(6)c/c++域使用LOG
- android jni 输出log
- Android中Log机制详解
- android 监听应用程序异常,输出异常日志log
- Android中Log.d和Log.v如何实现在release版本不输出
- 把android平板USB上输出LOG方法
- Android中Log机制详解
- Android输出Log相关应用技巧剖析
- 解读Android LOG机制的实现
- 解读Android LOG机制的实现