Android中LOG機制詳解(下)


2.2、類android.util.LogJNI實現

android.util.Log有兩個Native方法,它們通過JNIc/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中實現的。這兩個方法分別對應下列兩個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()的實現是比較<level>(來自參數)與當前property里設定的"log.tag.<tag>"<tag>來自參數)的level值,大於或等於都是可記錄的。程序實現片斷如下

    // 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 LOG機制流程圖》來看。

android_util.Log.cpp中,函數android_util_Log_println_native() 調用了Android_log_buf_write()函數,而Android_log_buf_write()又直接調用了system/core/liblog/logd_write.c中的__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;

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM