zoukankan      html  css  js  c++  java
  • 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;

    }

  • 相关阅读:
    java并发5-volatile关键字解析
    java并发4-单例设计方法
    Java并发3-多线程面试题
    JAVA并发2
    JAVA并发
    2015第27周三Java内存模型
    同一时候使用windows和linux系统
    深入浅出Windows BATCH
    DrawText的使用
    redmine忘记username和password
  • 原文地址:https://www.cnblogs.com/xiwix/p/2450489.html
Copyright © 2011-2022 走看看