现在的位置: 首页 > 综合 > 正文

Android logcat使用详解

2013年12月09日 ⁄ 综合 ⁄ 共 15484字 ⁄ 字号 评论关闭

android logcat命令

       1. logcat -c 清除已有log信息

  2.logcat -b main 显示主缓冲区的log

  logcat -b radio 显示无线缓冲区的log

  logcat -b events 显示事件缓冲区的log

  3.logcat -f [filename] 将log保存到指定的文件中,例如 logcat -b radio -f /data/radio.log

  4.logcat -v 设置logcat输出的格式

  主要有7种输出格式:

  1. brief — Display priority/tag and PID of originating process (the default format).

  2. process — Display PID only.

  3. tag — Display the priority/tag only.

  4. thread — Display process:thread and priority/tag only.

  5. raw — Display the raw log message, with no other metadata fields.

  6. time — Display the date, invocation time, priority/tag, and PID of the originating process.

  7. long — Display all metadata fields and separate messages with a blank lines.

  比较常用的是显示时间:logcat -v time &

  5.logcat -g 查看缓冲区的大小

  logcat -g main

  logcat -g radio

  logcat -g events

Log机制的一些理解:


1. 系统结构

应用程序调用应用程序框架层的Java接口(android.util.Log)来使用日志系统,这个Java接口通过JNI方法和系统运行库最终调用内核驱动程序Logger把Log写到内核空间中。


2. 关键代码及理解

一. 应用程序框架层日志系统Java接口的实现

代码位置:frameworks/base/core/java/android/util/Log.java文件中,实现日志系统的Java接口:

  1. public final class Log {  
  2.   
  3. /** 
  4.      * Priority constant for the println method; use Log.v. 
  5.      */  
  6.     public static final int VERBOSE = 2;  
  7.   
  8.     /** 
  9.      * Priority constant for the println method; use Log.d. 
  10.      */  
  11.     public static final int DEBUG = 3;  
  12.   
  13.     /** 
  14.      * Priority constant for the println method; use Log.i. 
  15.      */  
  16.     public static final int INFO = 4;  
  17.   
  18.     /** 
  19.      * Priority constant for the println method; use Log.w. 
  20.      */  
  21.     public static final int WARN = 5;  
  22.   
  23.     /** 
  24.      * Priority constant for the println method; use Log.e. 
  25.      */  
  26.     public static final int ERROR = 6;  
  27.   
  28.     /** 
  29.      * Priority constant for the println method. 
  30.      */  
  31.     public static final int ASSERT = 7;  
  32.   
  33.     ........................  
  34.     
  35.     public static int v(String tag, String msg) {  
  36.         return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);  
  37.     }  
  38.   
  39.     public static int d(String tag, String msg) {  
  40.         return println_native(LOG_ID_MAIN, DEBUG, tag, msg);  
  41.     }  
  42.   
  43.     public static int i(String tag, String msg) {  
  44.         return println_native(LOG_ID_MAIN, INFO, tag, msg);  
  45.     }  
  46.   
  47.     public static int w(String tag, String msg) {  
  48.         return println_native(LOG_ID_MAIN, WARN, tag, msg);  
  49.     }  
  50.   
  51.     public static int e(String tag, String msg) {  
  52.         return println_native(LOG_ID_MAIN, ERROR, tag, msg);  
  53.     }  
  54.   
  55.     public static int println(int priority, String tag, String msg) {  
  56.         return println_native(LOG_ID_MAIN, priority, tag, msg);  
  57.     }  
  58.   
  59.     ...................  
  60.   
  61.     /** @hide */ public static final int LOG_ID_MAIN = 0;  
  62.     /** @hide */ public static final int LOG_ID_RADIO = 1;  
  63.     /** @hide */ public static final int LOG_ID_EVENTS = 2;  
  64.     /** @hide */ public static final int LOG_ID_SYSTEM = 3;  
  65.   
  66.     /** @hide */ public static native int println_native(int bufID,  
  67.             int priority, String tag, String msg);  
  68. }  

其中 VERBOSE ,DEBUG, INFO,WARN,ERROR,ASSERT代表Log优先级,分别由对应的v,d,i,w,e,a方法实现写入。

在logcat中用 

logcat  ActivityManager:w
 

命令显示ActivityManager标签中等于或高于WARN级别的Log


其中

  1. <span style="font-size: 13px; line-height: 19px; "></span><pre name="code" class="java" style="margin-top: 4px; margin-right: 0px; margin-bottom: 4px; margin-left: 0px; background-color: rgb(240, 240, 240); ">LOG_ID_MAIN = 0  LOG_ID_RADIO = 1  LOG_ID_EVENTS = 2 LOG_ID_SYSTEM = 3;  


为日志缓冲区,在底层定义了3个设备文件分别为:/dev/log/main、/dev/log/events和/dev/log/radio(),第4个日志缓冲区LOG_ID_SYSTEM并没有对应的设备文件,在这种情况下,它和LOG_ID_MAIN对应同一个缓冲区ID(为什么这样下面会提到)。

在整个Log接口中,最关键的地方声明了println_native本地方法,所有的Log接口都是通过调用这个本地方法来实现Log的注入。下面我们就继续分析这个本地方法println_native。

二. 应用程序框架层日志系统JNI方法的实现。

在frameworks/base/core/jni/android_util_Log.cpp文件中,实现JNI方法println_native:

  1. #define LOG_NAMESPACE "log.tag."
      
  2. #define LOG_TAG "Log_println"
      
  3.    
  4. #include <assert.h>   
  5. #include <cutils/properties.h>
      
  6. #include <utils/Log.h>   
  7. #include <utils/String8.h>
      
  8.    
  9. #include "jni.h"   
  10. #include "utils/misc.h"   
  11. #include "android_runtime/AndroidRuntime.h"
      
  12.    
  13. #define MIN(a,b) ((a<b)?a:b)
      
  14.    
  15. namespace android {  
  16.    
  17. struct levels_t {  
  18.     jint verbose;  
  19.     jint debug;  
  20.     jint info;  
  21.     jint warn;  
  22.     jint error;  
  23.     jint assert;  
  24. };  
  25. static levels_t levels;  
  26.    
  27. static int toLevel(const char* value)   
  28. {  
  29.     switch (value[0]) {  
  30.         case 'V'return levels.verbose;  
  31.         case 'D'return levels.debug;  
  32.         case 'I'return levels.info;  
  33.         case 'W'return levels.warn;  
  34.         case 'E'return levels.error;  
  35.         case 'A'return levels.assert;  
  36.         case 'S'return -1; // SUPPRESS
      
  37.     }  
  38.     return levels.info;  
  39. }  
  40.    
  41. static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)  
  42. {  
  43. #ifndef HAVE_ANDROID_OS
      
  44.     return false;  
  45. #else /* HAVE_ANDROID_OS */
      
  46.     int len;  
  47.     char key[PROPERTY_KEY_MAX];  
  48.     char buf[PROPERTY_VALUE_MAX];  
  49.    
  50.     if (tag == NULL) {  
  51.         return false;  
  52.     }  
  53.    
  54.     jboolean result = false;  
  55.    
  56.     const char* chars = env->GetStringUTFChars(tag, NULL);  
  57.    
  58.     if ((strlen(chars)+sizeof(LOG_NAMESPACE)) > PROPERTY_KEY_MAX) {  
  59.         jclass clazz = env->FindClass("java/lang/IllegalArgumentException");  
  60.         char buf2[200];  
  61.         snprintf(buf2, sizeof(buf2), "Log tag \"%s\" exceeds limit of %d characters\n",  
  62.                 chars, PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE));  
  63.    
  64.         // release the chars!   
  65.         env->ReleaseStringUTFChars(tag, chars);  
  66.    
  67.         env->ThrowNew(clazz, buf2);  
  68.         return false;  
  69.     } else {  
  70.         strncpy(key, LOG_NAMESPACE, sizeof(LOG_NAMESPACE)-1);  
  71.         strcpy(key + sizeof(LOG_NAMESPACE) - 1, chars);  
  72.     }  
  73.    
  74.     env->ReleaseStringUTFChars(tag, chars);  
  75.    
  76.     len = property_get(key, buf, "");  
  77.     int logLevel = toLevel(buf);  
  78.     return (logLevel >= 0 && level >= logLevel) ? true : false;  
  79. #endif /* HAVE_ANDROID_OS */
      
  80. }  
  81.    
  82. /* 
  83.  * In class android.util.Log: 
  84.  *  public static native int println_native(int buffer, int priority, String tag, String msg) 
  85.  */  
  86. static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,  
  87.         jint bufID, jint priority, jstring tagObj, jstring msgObj)  
  88. {  
  89.     const char* tag = NULL;  
  90.     const char* msg = NULL;  
  91.    
  92.     if (msgObj == NULL) {  
  93.         jclass npeClazz;  
  94.    
  95.         npeClazz = env->FindClass("java/lang/NullPointerException");  
  96.         assert(npeClazz != NULL);  
  97.    
  98.         env->ThrowNew(npeClazz, "println needs a message");  
  99.         return -1;  
  100.     }  
  101.    
  102.     if (bufID < 0 || bufID >= LOG_ID_MAX) {  
  103.         jclass npeClazz;  
  104.    
  105.         npeClazz = env->FindClass("java/lang/NullPointerException");  
  106.         assert(npeClazz != NULL);  
  107.    
  108.         env->ThrowNew(npeClazz, "bad bufID");  
  109.         return -1;  
  110.     }  
  111.    
  112.     if (tagObj != NULL)  
  113.         tag = env->GetStringUTFChars(tagObj, NULL);  
  114.     msg = env->GetStringUTFChars(msgObj, NULL);  
  115.    
  116.     int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);  
  117.    
  118.     if (tag != NULL)  
  119.         env->ReleaseStringUTFChars(tagObj, tag);  
  120.     env->ReleaseStringUTFChars(msgObj, msg);  
  121.    
  122.     return res;  
  123. }  
  124.    
  125. /* 
  126.  * JNI registration. 
  127.  */  
  128. static JNINativeMethod gMethods[] = {  
  129.     /* name, signature, funcPtr */  
  130.     { "isLoggable",      "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },  
  131.     { "println_native",  "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },  
  132. };  
  133.    
  134. int register_android_util_Log(JNIEnv* env)  
  135. {  
  136.     jclass clazz = env->FindClass("android/util/Log");  
  137.    
  138.     if (clazz == NULL) {  
  139.         LOGE("Can't find android/util/Log");  
  140.         return -1;  
  141.     }  
  142.    
  143.     levels.verbose = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "VERBOSE""I"));  
  144.     levels.debug = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "DEBUG""I"));  
  145.     levels.info = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "INFO""I"));  
  146.     levels.warn = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "WARN""I"));  
  147.     levels.error = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ERROR""I"));  
  148.     levels.assert = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ASSERT""I"));  
  149.    
  150.     return AndroidRuntime::registerNativeMethods(env, "android/util/Log", gMethods, NELEM(gMethods));  
  151. }  
  152.    
  153. }; // namespace android  

在gMethods变量中,定义了println_native本地方法对应的函数调用是android_util_Log_println_native。在android_util_Log_println_native函数中,通过了各项参数验证正确后,就调用运行时库函数__android_log_buf_write来实现Log的写入操作。__android_log_buf_write函实实现在liblog库中,它有4个参数,分别缓冲区ID、优先级别ID、Tag字符串和Msg字符串。下面运行时库liblog中的__android_log_buf_write的实现。

三. 系统运行库层日志系统的实现。

在system/core/liblog/logd_write.c中,关注写入函数__android_log_buf_write的实现

  1. int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)  
  2. {  
  3.     struct iovec vec[3];  
  4.     if (!tag)  
  5.         tag = "";  
  6.     /* XXX: This needs to go! */  
  7.     if (!strcmp(tag, "HTC_RIL") ||  
  8.         !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */  
  9.         !strcmp(tag, "AT") ||  
  10.         !strcmp(tag, "GSM") ||  
  11.         !strcmp(tag, "STK") ||  
  12.         !strcmp(tag, "CDMA") ||  
  13.         !strcmp(tag, "PHONE") ||  
  14.         !strcmp(tag, "SMS"))  
  15.             bufID = LOG_ID_RADIO;  
  16.    
  17.     vec[0].iov_base   = (unsigned char *) &prio;  
  18.     vec[0].iov_len    = 1;  
  19.     vec[1].iov_base   = (void *) tag;  
  20.     vec[1].iov_len    = strlen(tag) + 1;  
  21.     vec[2].iov_base   = (void *) msg;  
  22.     vec[2].iov_len    = strlen(msg) + 1;  
  23.    
  24.     return write_to_log(bufID, vec, 3);  
  25. }  

函数进来后,首先把以HTC_RIL,RIL,AT,GSM,STK,CDMA,PHONE,SMS开头的标签的Log缓存区设为LOG_ID_RADIO,表示无线缓冲区。其他的就基本是写入LOG_ID_MAIN(主分区)中了。

就先写道这里吧,这主要是我想知道Log是怎么写入radio日志分区中看到的一些东西。大部分来自:

http://disanji.net/2011/08/18/android%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E6%A1%86%E6%9E%B6%E5%B1%82%E5%92%8C%E7%B3%BB%E7%BB%9F%E8%BF%90%E8%A1%8C%E5%BA%93%E5%B1%82%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F%E6%BA%90%E4%BB%A3%E7%A0%81/

非常感谢

抱歉!评论已关闭.