Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android應用程序框架層和系統運行庫層日志系統源代碼分析

Android應用程序框架層和系統運行庫層日志系統源代碼分析

編輯:關於Android編程

在開發Android應用程序時,少不了使用Log來監控和調試程序的執行。在上一篇文章Android日志系統驅動程序Logger源代碼分析中,我們分析了驅動程序Logger的源代碼,在前面的文章淺談Android系統開發中Log的使用一文,我們也簡單介紹在應用程序中使Log的方法,在這篇文章中,我們將詳細介紹Android應用程序框架層和系統運行庫存層日志系統的源代碼,使得我們可以更好地理解Android的日志系統的實現。
           我們在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接口:
  
 [color=amily:Consolas,'Courier]
 
[java] view plaincopy
 

 

................................................ 
  
 public final class Log { 
  
 ................................................ 
  
     /**
     * Priority constant for the println method; use Log.v.
         */ 
     public static final int VERBOSE = 2; 
  
     /**
     * Priority constant for the println method; use Log.d.
         */ 
     public static final int DEBUG = 3; 
  
     /**
     * Priority constant for the println method; use Log.i.
         */ 
     public static final int INFO = 4; 
  
     /**
     * Priority constant for the println method; use Log.w.
         */ 
     public static final int WARN = 5; 
  
     /**
     * Priority constant for the println method; use Log.e.
         */ 
     public static final int ERROR = 6; 
  
     /**
     * Priority constant for the println method.
         */ 
     public static final int ASSERT = 7; 
  
 ..................................................... 
  
     public static int v(String tag, String msg) { 
         return println_native(LOG_ID_MAIN, VERBOSE, tag, msg); 
     } 
  
     public static int v(String tag, String msg, Throwable tr) { 
         return println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr)); 
     } 
  
     public static int d(String tag, String msg) { 
         return println_native(LOG_ID_MAIN, DEBUG, tag, msg); 
     } 
  
     public static int d(String tag, String msg, Throwable tr) { 
         return println_native(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr)); 
     } 
  
     public static int i(String tag, String msg) { 
         return println_native(LOG_ID_MAIN, INFO, tag, msg); 
     } 
  
     public static int i(String tag, String msg, Throwable tr) { 
         return println_native(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr)); 
     } 
  
     public static int w(String tag, String msg) { 
         return println_native(LOG_ID_MAIN, WARN, tag, msg); 
     } 
  
     public static int w(String tag, String msg, Throwable tr) { 
         return println_native(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr)); 
     } 
  
     public static int w(String tag, Throwable tr) { 
         return println_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr)); 
     } 
      
     public static int e(String tag, String msg) { 
         return println_native(LOG_ID_MAIN, ERROR, tag, msg); 
     } 
  
     public static int e(String tag, String msg, Throwable tr) { 
         return println_native(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr)); 
     } 
  
 .................................................................. 
     /** @hide */ public static native int LOG_ID_MAIN = 0; 
     /** @hide */ public static native int LOG_ID_RADIO = 1; 
     /** @hide */ public static native int LOG_ID_EVENTS = 2; 
     /** @hide */ public static native int LOG_ID_SYSTEM = 3; 
  
     /** @hide */ public static native int println_native(int bufID, 
         int priority, String tag, String msg); 
 } 
          定義了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:
  
 [color=amily:Consolas,'Courier]
 
[cpp] view plaincopy
 

 

/* //device/libs/android_runtime/android_util_Log.cpp
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License"); 
 ** you may not use this file except in compliance with the License. 
 ** You may obtain a copy of the License at 
 **
**     http://www.apache.org/licenses/LICENSE-2.0 
 **
** Unless required by applicable law or agreed to in writing, software 
 ** distributed under the License is distributed on an "AS IS" BASIS, 
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 ** See the License for the specific language governing permissions and 
 ** limitations under the License.
*/ 
  
 #define LOG_NAMESPACE "log.tag." 
 #define LOG_TAG "Log_println" 
  
 #include <assert.h> 
 #include <cutils/properties.h> 
 #include <utils/Log.h> 
 #include <utils/String8.h> 
  
 #include "jni.h" 
 #include "utils/misc.h" 
 #include "android_runtime/AndroidRuntime.h" 
  
 #define MIN(a,b) ((a<b)?a:b) 
  
 namespace android { 
  
 struct levels_t { 
     jint verbose; 
     jint debug; 
     jint info; 
     jint warn; 
     jint error; 
     jint assert; 
 }; 
 static levels_t levels; 
  
 static int toLevel(const char* value)  
 { 
     switch (value[0]) { 
         case 'V': return levels.verbose; 
         case 'D': return levels.debug; 
         case 'I': return levels.info; 
         case 'W': return levels.warn; 
         case 'E': return levels.error; 
         case 'A': return levels.assert; 
         case 'S': return -1; // SUPPRESS 
     } 
     return levels.info; 
 } 
  
 static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level) 
 { 
 #ifndef HAVE_ANDROID_OS 
     return false; 
 #else /* HAVE_ANDROID_OS */ 
     int len; 
     char key[PROPERTY_KEY_MAX]; 
     char buf[PROPERTY_VALUE_MAX]; 
  
     if (tag == NULL) { 
         return false; 
     } 
      
     jboolean result = false; 
      
     const char* chars = env->GetStringUTFChars(tag, NULL); 
  
     if ((strlen(chars)+sizeof(LOG_NAMESPACE)) > PROPERTY_KEY_MAX) { 
         jclass clazz = env->FindClass("java/lang/IllegalArgumentException"); 
         char buf2[200]; 
         snprintf(buf2, sizeof(buf2), "Log tag \"%s\" exceeds limit of %d characters\n", 
                 chars, PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE)); 
  
         // release the chars! 
         env->ReleaseStringUTFChars(tag, chars); 
  
         env->ThrowNew(clazz, buf2); 
         return false; 
     } else {

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved