Android應用程式架構層和系統運行庫層日誌系統原始碼分析

來源:互聯網
上載者:User

在開發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 {

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.