Android应用程序框架层和系统运行库层日志系统源代码分析

时间:2021-11-20 03:39:15

        在开发Android应用程序时,少不了使用Log来监控和调试程序的执行。在上一篇文章Android日志系统驱动程序Logger源代码分析中,我们分析了驱动程序Logger的源代码,在前面的文章浅谈Android系统开发中Log的使用一文,我们也简单介绍在应用程序中使Log的方法,在这篇文章中,我们将详细介绍android应用程序框架层和系统运行库存层日志系统的源代码,使得我们可以更好地理解Android的日志系统的实现。

《Android系统源代码情景分析》一书正在进击的程序员网(http://0xcc0xcd.com)中连载,点击进入!

        我们在Android应用程序,一般是调用应用程序框架层的Java接口(android.util.Log)来使用日志系统,这个Java接口通过JNI方法和系统运行库最终调用内核驱动程序Logger把Log写到内核空间中。按照这个调用过程,我们一步步介绍Android应用程序框架层日志系统的源代码。学习完这个过程之后,我们可以很好地理解Android系统的架构,即应用程序层(Application)的接口是如何一步一步地调用到内核空间的。

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

        在浅谈Android系统开发中Log的使用一文中,我们曾经介绍过Android应用程序框架层日志系统的源代码接口。这里,为了描述方便和文章的完整性,我们重新贴一下这部份的代码,在frameworks/base/core/java/android/util/Log.java文件中,实现日志系统的Java接口:

[java]  view plain  copy
  1. ................................................  
  2.   
  3. public final class Log {  
  4.   
  5. ................................................  
  6.   
  7.     /** 
  8.      * Priority constant for the println method; use Log.v. 
  9.          */  
  10.     public static final int VERBOSE = 2;  
  11.   
  12.     /** 
  13.      * Priority constant for the println method; use Log.d. 
  14.          */  
  15.     public static final int DEBUG = 3;  
  16.   
  17.     /** 
  18.      * Priority constant for the println method; use Log.i. 
  19.          */  
  20.     public static final int INFO = 4;  
  21.   
  22.     /** 
  23.      * Priority constant for the println method; use Log.w. 
  24.          */  
  25.     public static final int WARN = 5;  
  26.   
  27.     /** 
  28.      * Priority constant for the println method; use Log.e. 
  29.          */  
  30.     public static final int ERROR = 6;  
  31.   
  32.     /** 
  33.      * Priority constant for the println method. 
  34.          */  
  35.     public static final int ASSERT = 7;  
  36.   
  37. .....................................................  
  38.   
  39.     public static int v(String tag, String msg) {  
  40.         return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);  
  41.     }  
  42.   
  43.     public static int v(String tag, String msg, Throwable tr) {  
  44.         return println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr));  
  45.     }  
  46.   
  47.     public static int d(String tag, String msg) {  
  48.         return println_native(LOG_ID_MAIN, DEBUG, tag, msg);  
  49.     }  
  50.   
  51.     public static int d(String tag, String msg, Throwable tr) {  
  52.         return println_native(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr));  
  53.     }  
  54.   
  55.     public static int i(String tag, String msg) {  
  56.         return println_native(LOG_ID_MAIN, INFO, tag, msg);  
  57.     }  
  58.   
  59.     public static int i(String tag, String msg, Throwable tr) {  
  60.         return println_native(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr));  
  61.     }  
  62.   
  63.     public static int w(String tag, String msg) {  
  64.         return println_native(LOG_ID_MAIN, WARN, tag, msg);  
  65.     }  
  66.   
  67.     public static int w(String tag, String msg, Throwable tr) {  
  68.         return println_native(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr));  
  69.     }  
  70.   
  71.     public static int w(String tag, Throwable tr) {  
  72.         return println_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));  
  73.     }  
  74.       
  75.     public static int e(String tag, String msg) {  
  76.         return println_native(LOG_ID_MAIN, ERROR, tag, msg);  
  77.     }  
  78.   
  79.     public static int e(String tag, String msg, Throwable tr) {  
  80.         return println_native(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr));  
  81.     }  
  82.   
  83. ..................................................................  
  84.     /** @hide */ public static native int LOG_ID_MAIN = 0;  
  85.     /** @hide */ public static native int LOG_ID_RADIO = 1;  
  86.     /** @hide */ public static native int LOG_ID_EVENTS = 2;  
  87.     /** @hide */ public static native int LOG_ID_SYSTEM = 3;  
  88.   
  89.     /** @hide */ public static native int println_native(int bufID,  
  90.         int priority, String tag, String msg);  
  91. }  
         定义了2~7一共6个日志优先级别ID和4个日志缓冲区ID。回忆一下 Android日志系统驱动程序Logger源代码分析一文,在Logger驱动程序模块中,定义了log_main、log_events和log_radio三个日志缓冲区,分别对应三个设备文件/dev/log/main、/dev/log/events和/dev/log/radio。这里的4个日志缓冲区的前面3个ID就是对应这三个设备文件的文件描述符了,在下面的章节中,我们将看到这三个文件描述符是如何创建的。在下载下来的Android内核源代码中,第4个日志缓冲区LOG_ID_SYSTEM并没有对应的设备文件,在这种情况下,它和LOG_ID_MAIN对应同一个缓冲区ID,在下面的章节中,我们同样可以看到这两个ID是如何对应到同一个设备文件的。

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

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

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

[cpp]  view plain  copy
  1. /* //device/libs/android_runtime/android_util_Log.cpp 
  2. ** 
  3. ** Copyright 2006, The Android Open Source Project 
  4. ** 
  5. ** Licensed under the Apache License, Version 2.0 (the "License");  
  6. ** you may not use this file except in compliance with the License.  
  7. ** You may obtain a copy of the License at  
  8. ** 
  9. **     http://www.apache.org/licenses/LICENSE-2.0  
  10. ** 
  11. ** Unless required by applicable law or agreed to in writing, software  
  12. ** distributed under the License is distributed on an "AS IS" BASIS,  
  13. ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  14. ** See the License for the specific language governing permissions and  
  15. ** limitations under the License. 
  16. */  
  17.   
  18. #define LOG_NAMESPACE "log.tag."  
  19. #define LOG_TAG "Log_println"  
  20.   
  21. #include <assert.h>  
  22. #include <cutils/properties.h>  
  23. #include <utils/Log.h>  
  24. #include <utils/String8.h>  
  25.   
  26. #include "jni.h"  
  27. #include "utils/misc.h"  
  28. #include "android_runtime/AndroidRuntime.h"  
  29.   
  30. #define MIN(a,b) ((a<b)?a:b)  
  31.   
  32. namespace android {  
  33.   
  34. struct levels_t {  
  35.     jint verbose;  
  36.     jint debug;  
  37.     jint info;  
  38.     jint warn;  
  39.     jint error;  
  40.     jint assert;  
  41. };  
  42. static levels_t levels;  
  43.   
  44. static int toLevel(const char* value)   
  45. {  
  46.     switch (value[0]) {  
  47.         case 'V'return levels.verbose;  
  48.         case 'D'return levels.debug;  
  49.         case 'I'return levels.info;  
  50.         case 'W'return levels.warn;  
  51.         case 'E'return levels.error;  
  52.         case 'A'return levels.assert;  
  53.         case 'S'return -1; // SUPPRESS  
  54.     }  
  55.     return levels.info;  
  56. }  
  57.   
  58. static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)  
  59. {  
  60. #ifndef HAVE_ANDROID_OS  
  61.     return false;  
  62. #else /* HAVE_ANDROID_OS */  
  63.     int len;  
  64.     char key[PROPERTY_KEY_MAX];  
  65.     char buf[PROPERTY_VALUE_MAX];  
  66.   
  67.     if (tag == NULL) {  
  68.         return false;  
  69.     }  
  70.       
  71.     jboolean result = false;  
  72.       
  73.     const char* chars = env->GetStringUTFChars(tag, NULL);  
  74.   
  75.     if ((strlen(chars)+sizeof(LOG_NAMESPACE)) > PROPERTY_KEY_MAX) {  
  76.         jclass clazz = env->FindClass("java/lang/IllegalArgumentException");  
  77.         char buf2[200];  
  78.         snprintf(buf2, sizeof(buf2), "Log tag \"%s\" exceeds limit of %d characters\n",  
  79.                 chars, PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE));  
  80.   
  81.         // release the chars!  
  82.         env->ReleaseStringUTFChars(tag, chars);  
  83.   
  84.         env->ThrowNew(clazz, buf2);  
  85.         return false;  
  86.     } else {  
  87.         strncpy(key, LOG_NAMESPACE, sizeof(LOG_NAMESPACE)-1);  
  88.         strcpy(key + sizeof(LOG_NAMESPACE) - 1, chars);  
  89.     }  
  90.       
  91.     env->ReleaseStringUTFChars(tag, chars);  
  92.   
  93.     len = property_get(key, buf, "");  
  94.     int logLevel = toLevel(buf);  
  95.     return (logLevel >= 0 && level >= logLevel) ? true : false;  
  96. #endif /* HAVE_ANDROID_OS */  
  97. }  
  98.   
  99. /* 
  100.  * In class android.util.Log: 
  101.  *  public static native int println_native(int buffer, int priority, String tag, String msg) 
  102.  */  
  103. static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,  
  104.         jint bufID, jint priority, jstring tagObj, jstring msgObj)  <li class="alt" style="border-top: none; border-right: none; border-bottom: none; border-left: 3px solid rgb(108, 226, 108); border-image: initial; list-style-type: decimal-leading-zero; list-style-image