解讀Android LOG機制的實現:(3)JNI及c/c++域寫裝置檔案

來源:互聯網
上載者:User
 

解讀Android LOG機制的實現:(3)JNI及c/c++域寫裝置檔案

田海立@CSDN

2011/07/24

 

Android提供了使用者級輕量的LOG機制,它的實現貫穿了Java,JNI,本地c/c++實現以及LINUX核心驅動等Android的各個層次,而且還足夠簡單清晰,是一個相當不錯的解讀案例。本系列文章針對LOG機制的內部實現機理進行解讀,本文是系列之三,解讀android.util.Log的JNI實現,以及在c/c++的本地實現中如何操作裝置檔案寫Log資訊。

 

類Log的JNI實現

由前文知道,類android.util.Log有兩個Native方法,需要通過JNI在c/c++中實現。

public static native boolean isLoggable(String tag, int level);public static native int println_native(int bufID,            int priority, String tag, String msg);

這兩個方法是在frameworks/base/core/jni/android_util_log.cpp中實現的。如何?JNI的,在這裡不做表述。不過最終這兩個方法分別轉入了下列兩個c/c++函數的調用。

static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,        jint bufID, jint priority, jstring tagObj, jstring msgObj)

 

isLoggable()的實現

isLoggable的實現是比較<level>(來自參數)與當前property裡設定的“log.tag.<tag>”(<tag>來自參數)的值,大於或等於都是可記錄的。程式實現片斷如下:

    // LOG_NAMESPACE : “log.tag.”    // chars: convert from param<tag>    strncpy(key, LOG_NAMESPACE, sizeof(LOG_NAMESPACE)-1);    strcpy(key + sizeof(LOG_NAMESPACE) - 1, chars);      len = property_get(key, buf, "");    int logLevel = toLevel(buf);    return (logLevel >= 0 && level >= logLevel) ? true : false;

 

println_native()的實現

函數android_util_Log_println_native() [檔案android_util.Log.cpp中]調用了__android_log_buf_write()[檔案system/core/liblog/logd_write.c中]。__android_log_buf_write()組織了參數,又調用了write_to_log這個函數指標。

write_to_log這個函數指標是實現的關鍵。

看write_to_log的定義:

static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;

write_to_log初始是指向__write_to_log_init()這個函數的。所以第一次執行write_to_log的時候是執行了__write_to_log_init()。而如果write_to_log不是第一次被執行,它已經在__write_to_log_init()裡被修改指向了__write_to_log_kernel()。

先看__write_to_log_init()的實現:

static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr){#ifdef HAVE_PTHREADS    pthread_mutex_lock(&log_init_lock);#endif    if (write_to_log == __write_to_log_init) {        log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);        log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);        log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);        log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY);        write_to_log = __write_to_log_kernel;        if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||                log_fds[LOG_ID_EVENTS] < 0) {            log_close(log_fds[LOG_ID_MAIN]);            log_close(log_fds[LOG_ID_RADIO]);            log_close(log_fds[LOG_ID_EVENTS]);            log_fds[LOG_ID_MAIN] = -1;            log_fds[LOG_ID_RADIO] = -1;            log_fds[LOG_ID_EVENTS] = -1;            write_to_log = __write_to_log_null;        }        if (log_fds[LOG_ID_SYSTEM] < 0) {            log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN];        }    }#ifdef HAVE_PTHREADS    pthread_mutex_unlock(&log_init_lock);#endif    return write_to_log(log_id, vec, nr);}

基本上就是做互斥訪問的保護,然後如果是第一次調用(write_to_log還指向__write_to_log_init()),就開啟相應的裝置檔案,擷取描述符,並把write_to_log指向__write_to_log_kernel()。再在__write_to_log_kernel()中具體執行寫入檔案操作。

看__write_to_kernel()的實現,基本就是寫操作:

static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr){    ssize_t ret;    int log_fd;    if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {        log_fd = log_fds[(int)log_id];    } else {        return EBADF;    }    do {        ret = log_writev(log_fd, vec, nr);    } while (ret < 0 && errno == EINTR);    return ret;}

 

總結一下,println_native()的操作,就是開啟裝置檔案(如果還沒開啟),然後寫入資料。而具體怎麼寫入的,要看Log的裝置驅動Logger的實現。

 

【本系列文章】

解讀Android LOG機制的實現:(1)LOG的實現架構

        解讀LOG機制的實現架構。

解讀Android LOG機制的實現:(2)Java域輸出LOG

        解讀Android的Java程式中如何輸出LOG資訊到LOG的體系中。

解讀Android LOG機制的實現:(3)JNI及NATIVE域寫裝置檔案

        解讀android.util.Log的JNI實現,以及在c/c++的本地實現中如何操作裝置檔案寫Log資訊。

解讀Android LOG機制的實現:(4)LOG裝置驅動logger

        解讀LINUX核心中的裝置驅動Logger中實現。Logger是Android為Linux寫的一個MISC類型驅動,用迴圈隊列實現了讀者/寫者。Logger是整個LOG機制實現的核心。

解讀Android LOG機制的實現:(5)擷取LOG程式LogCat

        解讀應用程式LogCat如何通過對裝置檔案的open()/select()/read()來擷取LOG資訊。

解讀Android LOG機制的實現:(6)c/c++域使用LOG

        解讀Android的c/c++程式中如何使用LOG機制記錄LOG資訊。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.