552
查看android log系统的源代码
android log系统
0
←
android log系统
跳转至:
导航
、
搜索
因为以下原因,你没有权限编辑本页:
你被禁止执行你刚才请求的操作。
您可以查看并复制此页面的源代码:
= 使用选项简介 = <pre> Controlling Log Output Format Log messages contain a number of metadata fields, in addition to the tag and priority. You can modify the output format for messages so that they display a specific metadata field. To do so, you use the -v option and specify one of the supported output formats listed below. brief — Display priority/tag and PID of the process issuing the message (the default format). process — Display PID only. tag — Display the priority/tag only. raw — Display the raw log message, with no other metadata fields. time — Display the date, invocation time, priority/tag, and PID of the process issuing the message. threadtime — Display the date, invocation time, priority, tag, and the PID and TID of the thread issuing the message. long — Display all metadata fields and separate messages with blank lines. </pre> 如:adb logcat -v threadtime,可同时打印时间、PID和TID,详见 http://developer.android.com/tools/debugging/debugging-log.html = 实现方式剖析 = == 一、java接口 == '''android.util.Log''' <pre class="prettyprint"> public final class Log { ... public static final int VERBOSE = 2; ... 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)); } ... } </pre> '''android.util.Slog''' <pre class="prettyprint"> public final class Slog { ... public static int v(String tag, String msg) { return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag, msg); } public static int v(String tag, String msg, Throwable tr) { return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag, msg + '\n' + Log.getStackTraceString(tr)); } ... public static int println(int priority, String tag, String msg) { return Log.println_native(Log.LOG_ID_SYSTEM, priority, tag, msg); } } </pre> '''com.mediatek.xlog.Xlog''' <pre class="prettyprint"> public final class Xlog { public static int v(String tag, String msg) { return Log.println_native(Log.LOG_ID_MAIN, Log.VERBOSE, tag, msg); } public static int v(String tag, String msg, Throwable tr) { return Log.println_native(Log.LOG_ID_MAIN, Log.VERBOSE, tag, msg + '\n' + Log.getStackTraceString(tr)); } ... } </pre> '''com.mediatek.xlog.SXlog''' <pre class="prettyprint"> public final class SXlog { public static int v(String tag, String msg) { return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag, msg); } public static int v(String tag, String msg, Throwable tr) { return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag, msg + '\n' + Log.getStackTraceString(tr)); } ... } </pre> == 二、jni接口 == '''/frameworks/base/core/jni/android_util_Log.cpp''' <pre class="prettyprint"> namespace android { ... static jint android_util_Log_println_native(JNIEnv* env, jobject clazz, jint bufID, jint priority, jstring tagObj, jstring msgObj) { const char* tag = NULL; const char* msg = NULL; if (msgObj == NULL) { jniThrowNullPointerException(env, "println needs a message"); return -1; } if (bufID < 0 || bufID >= LOG_ID_MAX) { jniThrowNullPointerException(env, "bad bufID"); return -1; } if (tagObj != NULL) tag = env->GetStringUTFChars(tagObj, NULL); msg = env->GetStringUTFChars(msgObj, NULL); int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg); if (tag != NULL) env->ReleaseStringUTFChars(tagObj, tag); env->ReleaseStringUTFChars(msgObj, msg); return res; } /* * JNI registration. */ static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "isLoggable", "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable }, { "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native }, }; ... }; // namespace android </pre> println_native 等同于 android_util_Log_println_native. == 三、hal == '''/system/core/liblog/logd_write.c''' 首先来看 jni中 android_util_Log_println_native所调用的函数 __android_log_buf_write: <pre class="prettyprint"> int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg) { struct iovec vec[3]; if (!tag) tag = ""; /* XXX: This needs to go! */ if (!strcmp(tag, "HTC_RIL") || !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ !strcmp(tag, "AT") || !strcmp(tag, "GSM") || !strcmp(tag, "STK") || !strcmp(tag, "CDMA") || !strcmp(tag, "PHONE") || !strcmp(tag, "SMS")) bufID = LOG_ID_RADIO; vec[0].iov_base = (unsigned char *) &prio; vec[0].iov_len = 1; vec[1].iov_base = (void *) tag; vec[1].iov_len = strlen(tag) + 1; vec[2].iov_base = (void *) msg; vec[2].iov_len = strlen(msg) + 1; return write_to_log(bufID, vec, 3); } </pre> 此函数只是进行了传入参数的检验,并将 msg和 tag相关信息转存到了 vec[3]这个数组中,接着调用了函数 write_to_log,很容易发现 write_to_log其实是一个函数指针: <pre class="prettyprint"> static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init; </pre> 但在运行过程中,其指向函数会发生变化: <pre class="prettyprint"> 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); } </pre> 即除了第一次调用Log系列函数时会通过 __write_to_log_init进行初始化外,后续的调用都会指向到 __write_to_log_kernel当中: <pre class = "prettyprint"> 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; } </pre> log_writev则是一个宏: <pre class = "prettyprint"> #if FAKE_LOG_DEVICE // This will be defined when building for the host. #define log_open(pathname, flags) fakeLogOpen(pathname, flags) #define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count) #define log_close(filedes) fakeLogClose(filedes) #else #define log_open(pathname, flags) open(pathname, flags) #define log_writev(filedes, vector, count) writev(filedes, vector, count) #define log_close(filedes) close(filedes) #endif </pre> 在android中指向 writev(filedes, vector, count): '''bionic/libc/arch-sh/syscalls/writev.S''' <pre class="prettyprint"> /* autogenerated by gensyscalls.py */ #include <sys/linux-syscalls.h> .text .type writev, @function .globl writev .align 4 writev: /* invoke trap */ mov.l 0f, r3 /* trap num */ trapa #(3 + 0x10) /* check return value */ cmp/pz r0 bt __NR_writev_end /* keep error number */ sts.l pr, @-r15 mov.l 1f, r1 jsr @r1 mov r0, r4 lds.l @r15+, pr __NR_writev_end: rts nop .align 2 0: .long __NR_writev 1: .long __set_syscall_errno </pre> 也就是说,log最终是写入到以下设备文件中的: '''/system/core/include/cutils/logger.h''' <pre class="prettyprint"> #define LOGGER_LOG_MAIN "log/main" #define LOGGER_LOG_RADIO "log/radio" #define LOGGER_LOG_EVENTS "log/events" #define LOGGER_LOG_SYSTEM "log/system" </pre> == 四、Log驱动 == '''kernel/drivers/staging/android/logger.h''' <pre class="prettyprint"> ... #define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */ #define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */ #define LOGGER_LOG_SYSTEM "log_system" /* system/framework messages */ #define LOGGER_LOG_MAIN "log_main" /* everything else */ ... </pre> '''kernel/drivers/staging/android/logger.c''' <pre class="prettyprint"> ... static int __init logger_init(void) { int ret; ret = init_log(&log_main); if (unlikely(ret)) goto out; ret = init_log(&log_events); if (unlikely(ret)) goto out; ret = init_log(&log_radio); if (unlikely(ret)) goto out; ret = init_log(&log_system); if (unlikely(ret)) goto out; init_log_proc(); out: return ret; } ... </pre> == 五、疑问 == 文件 kernel/drivers/staging/android/logger.h 中 <pre class="prettyprint"> ... #define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */ ... </pre> 名字为何与实际 dev/ 文件夹下的 log/radio 不一致???
返回
android log系统
。
导航菜单
个人工具
   
个人维基
注册
登录
名字空间
页面
变换
查看
阅读
查看源代码
统计
查看历史
操作
搜索
导航
首页
Ubuntu
Android
C&CPP
Java
Python
大杂烩
最近更改
工具箱
所有页面
文件列表
特殊页面