注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

民主与科学

独立之人格,自由之思想

 
 
 

日志

 
 

Android中LOG机制详解(下)  

2011-10-07 21:05:15|  分类: 深入研究 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
2.2、类android.util.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中实现的。这两个方法分别对应下列两个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;
}
  评论这张
 
阅读(1999)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017