log_native stdout.log.tey 是什么东西?

android log机制——输出log
android log机制——输出log
android log机制——输出log
发表于5个月前( 15:27)&&
阅读(412)&|&评论()
0人收藏此文章,
android log系统。
在android Java code中输出log
android系统有4种类型、6个优先级的log,有一些常量用于标识这些信息,相关的定义在frameworks/base/core/java/android/util/Log.java中可以看到:
01/**02&* Priority constant fo use Log.v.03&*/04public static final int VERBOSE = 2;05&06/**07&* Priority constant fo use Log.d.08&*/09public static final int DEBUG = 3;10&11/**12&* Priority constant fo use Log.i.13&*/14public static final int INFO = 4;15&16/**17&* Priority constant fo use Log.w.18&*/19public static final int WARN = 5;20&21/**22&* Priority constant fo use Log.e.23&*/24public static final int ERROR = 6;25&26/**27&* Priority constant for the println method.28&*/29public static final int ASSERT = 7;30&31/** @hide */ public static final int LOG_ID_MAIN = 0;32/** @hide */ public static final int LOG_ID_RADIO = 1;33/** @hide */ public static final int LOG_ID_EVENTS = 2;34/** @hide */ public static final int LOG_ID_SYSTEM = 3;
Java层可以通过三个class来输出其中三种类型的log,三种类型分别为MAIN、RADIO和SYSTEM,三个class分别为Log、Rlog和Slog,其package则分别为android.util、android.telephony和 android.util。这些用于打印log的classes,其构造函数都为private,因而都不能创建其对象,但它们都提供了静态方法来给用户打印log。各个log打印class的实现都大同小异,可以看一下Log这个class中的一些:
01public static int v(String tag, String msg, Throwable tr) {02&&&&return println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr));03}04&05/**06&* Send a {@link #DEBUG} log message.07&* @param tag Used to identify the source of a log message.& It usually identifies08&*&&&&&&& the class or activity where the log call occurs.09&* @param msg The message you would like logged.10&*/11public static int d(String tag, String msg) {12&&&&return println_native(LOG_ID_MAIN, DEBUG, tag, msg);13}
最终都会是调用Log.println_native()静态native方法来打印log,各个类中各个方法的不同之处也仅在于参数的差异。
Log.println_native()方法
这个方法的code在/frameworks/base/core/jni/android_util_Log.cpp,为:
01static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,02&&&&&&&&jint bufID, jint priority, jstring tagObj, jstring msgObj)03{04&&&&const char* tag = NULL;05&&&&const char* msg = NULL;06&07&&&&if (msgObj == NULL) {08&&&&&&&&jniThrowNullPointerException(env, "println needs a message");09&&&&&&&&return -1;10&&&&}11&12&&&&if (bufID & 0 || bufID &= LOG_ID_MAX) {13&&&&&&&&jniThrowNullPointerException(env, "bad bufID");14&&&&&&&&return -1;15&&&&}16&17&&&&if (tagObj != NULL)18&&&&&&&&tag = env-&GetStringUTFChars(tagObj, NULL);19&&&&msg = env-&GetStringUTFChars(msgObj, NULL);20&21&&&&int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);22&23&&&&if (tag != NULL)24&&&&&&&&env-&ReleaseStringUTFChars(tagObj, tag);25&&&&env-&ReleaseStringUTFChars(msgObj, msg);26&27&&&&return 28}29&30/*31&* JNI registration.32&*/33static JNINativeMethod gMethods[] = {34&&&&/* name, signature, funcPtr */35&&&&{ "isLoggable",&&&&& "(Ljava/lang/SI)Z", (void*) android_util_Log_isLoggable },36&&&&{ "println_native",& "(IILjava/lang/SLjava/lang/S)I", (void*) android_util_Log_println_native },37};
可以看到,干的都是转换参数的事情,最终再call到__android_log_buf_write()函数,这个函数的定义在system/core/liblog/logd_write.c,为:
01int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)02{03&&&&struct iovec vec[3];04&&&&char tmp_tag[32];05&06&&&&if (!tag)07&&&&&&&&tag = "";08&09&&&&/* XXX: This needs to go! */10&&&&if ((bufID != LOG_ID_RADIO) &&11&&&&&&&&&(!strcmp(tag, "HTC_RIL") ||12&&&&&&&&!strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */13&&&&&&&&!strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */14&&&&&&&&!strcmp(tag, "AT") ||15&&&&&&&&!strcmp(tag, "GSM") ||16&&&&&&&&!strcmp(tag, "STK") ||17&&&&&&&&!strcmp(tag, "CDMA") ||18&&&&&&&&!strcmp(tag, "PHONE") ||19&&&&&&&&!strcmp(tag, "SMS"))) {20&&&&&&&&&&&&bufID = LOG_ID_RADIO;21&&&&&&&&&&&&// Inform third party apps/ril/radio.. to use Rlog or RLOG22&&&&&&&&&&&&snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);23&&&&&&&&&&&&tag = tmp_24&&&&}25&26&&&&vec[0].iov_base&& = (unsigned char *) &27&&&&vec[0].iov_len&&& = 1;28&&&&vec[1].iov_base&& = (void *)29&&&&vec[1].iov_len&&& = strlen(tag) + 1;30&&&&vec[2].iov_base&& = (void *)31&&&&vec[2].iov_len&&& = strlen(msg) + 1;32&33&&&&return write_to_log(bufID, vec, 3);34}
做了三件事情,一是根据log的tag,转换bufID,二是用传进来的参数构造一个struct iovec数组,三是将前一步构造的数组作为参数调用write_to_log()。write_to_log()是一个函数指针,在开始时,它指向了__write_to_log_init():
1static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_
__write_to_log_init()的实现如下:
01static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)02{03#ifdef HAVE_PTHREADS04&&&&pthread_mutex_lock(&log_init_lock);05#endif06&07&&&&if (write_to_log == __write_to_log_init) {08&&&&&&&&log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);09&&&&&&&&log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);10&&&&&&&&log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);11&&&&&&&&log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY);12&13&&&&&&&&write_to_log = __write_to_log_14&15&&&&&&&&if (log_fds[LOG_ID_MAIN] & 0 || log_fds[LOG_ID_RADIO] & 0 ||16&&&&&&&&&&&&&&&&log_fds[LOG_ID_EVENTS] & 0) {17&&&&&&&&&&&&log_close(log_fds[LOG_ID_MAIN]);18&&&&&&&&&&&&log_close(log_fds[LOG_ID_RADIO]);19&&&&&&&&&&&&log_close(log_fds[LOG_ID_EVENTS]);20&&&&&&&&&&&&log_fds[LOG_ID_MAIN] = -1;21&&&&&&&&&&&&log_fds[LOG_ID_RADIO] = -1;22&&&&&&&&&&&&log_fds[LOG_ID_EVENTS] = -1;23&&&&&&&&&&&&write_to_log = __write_to_log_24&&&&&&&&}25&26&&&&&&&&if (log_fds[LOG_ID_SYSTEM] & 0) {27&&&&&&&&&&&&log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN];28&&&&&&&&}29&&&&}30&31#ifdef HAVE_PTHREADS32&&&&pthread_mutex_unlock(&log_init_lock);33#endif34&35&&&&return write_to_log(log_id, vec, nr);36}
这个地方,会检查write_to_log是否指向了__write_to_log_init,也就是是否是第一次打印log,如果是,则打开几个用于输出log的设备文件,然后使write_to_log函数指针指向__write_to_log_kernel,或者在打开输出log设备文件出现异常时,使write_to_log指向__write_to_log_null,最后再次调用经过了重定向的write_to_log,也就是__write_to_log_kernel或者__write_to_log_null函数。我们可以看一下那几个设备文件究竟是什麽(在system/core/include/cutils/logger.h):
1#define LOGGER_LOG_MAIN&&&& "log/main"2#define LOGGER_LOG_RADIO&&& "log/radio"3#define LOGGER_LOG_EVENTS&& "log/events"4#define LOGGER_LOG_SYSTEM&& "log/system"
接着继续来看__write_to_log_kernel或者__write_to_log_null函数:
01static int __write_to_log_null(log_id_t log_fd, struct iovec *vec, size_t nr)02{03&&&&return -1;04}05&06static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)07{08&&&&ssize_09&&&&int log_10&11&&&&if (/*(int)log_id &= 0 &&*/ (int)log_id & (int)LOG_ID_MAX) {12&&&&&&&&log_fd = log_fds[(int)log_id];13&&&&} else {14&&&&&&&&return EBADF;15&&&&}16&17&&&&do {18&&&&&&&&ret = log_writev(log_fd, vec, nr);19&&&&} while (ret & 0 && errno == EINTR);20&21&&&&return 22}
由log_id获取到对应的log_fd,然后调用log_writev()打印log。可以看一下log_writev()的定义,它是一个宏:
01#if FAKE_LOG_DEVICE02// This will be defined when building for the host.03#define log_open(pathname, flags) fakeLogOpen(pathname, flags)04#define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count)05#define log_close(filedes) fakeLogClose(filedes)06#else07#define log_open(pathname, flags) open(pathname, (flags) | O_CLOEXEC)08#define log_writev(filedes, vector, count) writev(filedes, vector, count)09#define log_close(filedes) close(filedes)10#endif
这些就都是标准的unix系统调用了。
本地层代码Log输出
以一些比较典型的native代码打印log的case为例。先来看一下,在JNI的code中打印log的方法。在JNI中,比较常见到用ALOGx这一组宏来打印log,比如在frameworks/base/core/jni/android/graphics/TextLayoutCache.cpp这个文件中的dumpCacheStats()函数:
01void TextLayoutCache::dumpCacheStats() {02&&&&float remainingPercent = 100 * ((mMaxSize - mSize) / ((float)mMaxSize));03&&&&float timeRunningInSec = (systemTime(SYSTEM_TIME_MONOTONIC) - mCacheStartTime) / ;04&05&&&&size_t cacheSize = mCache.size();06&07&&&&ALOGD("------------------------------------------------");08&&&&ALOGD("Cache stats");09&&&&ALOGD("------------------------------------------------");10&&&&ALOGD("pid&&&&&& : %d", getpid());11&&&&ALOGD("running&& : %.0f seconds", timeRunningInSec);12&&&&ALOGD("entries&& : %d", cacheSize);13&&&&ALOGD("max size& : %d bytes", mMaxSize);14&&&&ALOGD("used&&&&& : %d bytes according to mSize", mSize);15&&&&ALOGD("remaining : %d bytes or %2.2f percent", mMaxSize - mSize, remainingPercent);16&&&&ALOGD("hits&&&&& : %d", mCacheHitCount);17&&&&ALOGD("saved&&&& : %0.6f ms", mNanosecondsSaved * 0.000001f);18&&&&ALOGD("------------------------------------------------");19}
使用这组宏,需要定义另外一个宏来作为所打印log的tag:
1#define LOG_TAG "TextLayoutCache"
此外,还要include头文件&cutils/log.h&。来看一下这些宏中的一些的定义:
01/*02&* Simplified macro to send a debug log message using the current LOG_TAG.03&*/04#ifndef ALOGD05#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))06#endif07&08/*09&* Simplified macro to send a warning log message using the current LOG_TAG.10&*/11#ifndef ALOGW12#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))13#endif14&15/*16&* Basic log message macro.17&*18&* Example:19&*& ALOG(LOG_WARN, NULL, "Failed with error %d", errno);20&*21&* The second argument may be NULL or "" to indicate the "global" tag.22&*/23#ifndef ALOG24#define ALOG(priority, tag, ...) \25&&&&LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)26#endif27&28/*29&* Log macro that allows you to specify a number for the priority.30&*/31#ifndef LOG_PRI32#define LOG_PRI(priority, tag, ...) \33&&&&android_printLog(priority, tag, __VA_ARGS__)34#endif35&36#define android_printLog(prio, tag, fmt...) \37&&&&__android_log_print(prio, tag, fmt)
先来看一下,在native层中定义的priority(在system/core/include/android/log.h中):
01/*02&* Android log priority values, in ascending priority order.03&*/04typedef enum android_LogPriority {05&&&&ANDROID_LOG_UNKNOWN = 0,06&&&&ANDROID_LOG_DEFAULT,&&& /* only for SetMinPriority() */07&&&&ANDROID_LOG_VERBOSE,08&&&&ANDROID_LOG_DEBUG,09&&&&ANDROID_LOG_INFO,10&&&&ANDROID_LOG_WARN,11&&&&ANDROID_LOG_ERROR,12&&&&ANDROID_LOG_FATAL,13&&&&ANDROID_LOG_SILENT,&&&& /* only for SetMinPriority(); must be last */14} android_LogP
另外,这些宏最终都会call到__android_log_print(),也是在system/core/liblog/logd_write.c中:
01int __android_log_print(int prio, const char *tag, const char *fmt, ...)02{03&&&&va_list 04&&&&char buf[LOG_BUF_SIZE];05&06&&&&va_start(ap, fmt);07&&&&vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);08&&&&va_end(ap);09&10&&&&return __android_log_write(prio, tag, buf);11}
先是格式化参数,然后就是调用__android_log_write()函数。这个函数的code如下:
01int __android_log_write(int prio, const char *tag, const char *msg)02{03&&&&struct iovec vec[3];04&&&&log_id_t log_id = LOG_ID_MAIN;05&&&&char tmp_tag[32];06&07&&&&if (!tag)08&&&&&&&&tag = "";09&10&&&&/* XXX: This needs to go! */11&&&&if (!strcmp(tag, "HTC_RIL") ||12&&&&&&&&!strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */13&&&&&&&&!strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */14&&&&&&&&!strcmp(tag, "AT") ||15&&&&&&&&!strcmp(tag, "GSM") ||16&&&&&&&&!strcmp(tag, "STK") ||17&&&&&&&&!strcmp(tag, "CDMA") ||18&&&&&&&&!strcmp(tag, "PHONE") ||19&&&&&&&&!strcmp(tag, "SMS")) {20&&&&&&&&&&&&log_id = LOG_ID_RADIO;21&&&&&&&&&&&&// Inform third party apps/ril/radio.. to use Rlog or RLOG22&&&&&&&&&&&&snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);23&&&&&&&&&&&&tag = tmp_24&&&&}25&26&&&&vec[0].iov_base&& = (unsigned char *) &27&&&&vec[0].iov_len&&& = 1;28&&&&vec[1].iov_base&& = (void *)29&&&&vec[1].iov_len&&& = strlen(tag) + 1;30&&&&vec[2].iov_base&& = (void *)31&&&&vec[2].iov_len&&& = strlen(msg) + 1;32&33&&&&return write_to_log(log_id, vec, 3);34}
这个函数与我们前面看到的__android_log_buf_write()非常相似。所不同的就是这个函数没有log_id参数,因而它默认是输出MAIN log,当log的TAG为某些特殊字串时,则输出RADIO log。最后同样是调用write_to_log这个函数指针来输出log。
我们再来看一个skia里面打log的SkDebugf()函数的实现:
1#include &android/log.h&2&3void SkDebugf(const char format[], ...) {4&&&&va_list 5&&&&va_start(args, format);6&&&&__android_log_vprint(ANDROID_LOG_DEBUG, LOG_TAG, format, args);7&&&&va_end(args);8}
call到了__android_log_vprint()来输出log,__android_log_vprint()的定义也在system/core/liblog/logd_write.c中:
1int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap)2{3&&&&char buf[LOG_BUF_SIZE];4&5&&&&vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);6&7&&&&return __android_log_write(prio, tag, buf);8}
一样是__android_log_write()函数。
发表评论:
TA的最新馆藏[转]&java - What is in android.util.Log#println_native()? - Stack Overflow
to customize your list.
Announcing Stack Overflow Documentation
We started with Q&A. Technical documentation is next, and we need your help.
Whether you're a beginner or an experienced developer, you can contribute.
is the android.util.Log source code.
At the very bottom (line 340), what is in the method:
public static native int println_native(int bufID,
int priority, String tag, String msg);
i guess println_native() is more or less like its println(), just with an int bufID different.
But even i got the codes of println_native(), i still lack com.android.internal.os.RuntimeInit (line 19, the import) to simulate android.util.Log in old Android version.
2,14351747
Just did some digging in the android source code. This function maps to
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);
Basically this then passes the arguments to the driver in the system which goes and writes to the Log buffer. Log buffer is pointed by /dev/log in the Linux kernel.
5,23621639
Once you have downloaded the sdk, you can use find to dig files.
Java code is linked to cpp code through jni.
In your case, you can use this command to find the related files:
find framework -type f -name "*.cpp" -exec grep "println_native" {} \; -ls
then you'll see that your java function is linked to this file : framework/base/core/jni/android_util_Log.cpp
Your Answer
Sign up or
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Post as a guest
By posting your answer, you agree to the
Not the answer you're looking for?
Browse other questions tagged
Stack Overflow works best with JavaScript enabled9465人阅读
Android(102)
转自: http://my.oschina.net/wolfcs/blog/164624
android log系统。
在android Java code中输出log
android系统有4种类型、6个优先级的log,有一些常量用于标识这些信息,相关的定义在frameworks/base/core/java/android/util/Log.java中可以看到:
&* Priority constant fo use Log.v.
public static
VERBOSE = 2;
&* Priority constant fo use Log.d.
public static
DEBUG = 3;
&* Priority constant fo use Log.i.
public static
&* Priority constant fo use Log.w.
public static
&* Priority constant fo use Log.e.
public static
ERROR = 6;
&* Priority constant for the println method.
public static
ASSERT = 7;
/** @hide */
public static final
int LOG_ID_MAIN = 0;
/** @hide */
public static final
int LOG_ID_RADIO = 1;
/** @hide */
public static final
int LOG_ID_EVENTS = 2;
/** @hide */
public static final
int LOG_ID_SYSTEM = 3;
Java层可以通过三个class来输出其中三种类型的log,三种类型分别为MAIN、RADIO和SYSTEM,三个class分别为Log、Rlog和Slog,其package则分别为android.util、android.telephony和
android.util。这些用于打印log的classes,其构造函数都为private,因而都不能创建其对象,但它们都提供了静态方法来给用户打印log。各个log打印class的实现都大同小异,可以看一下Log这个class中的一些:
public static
int v(String tag, String msg, Throwable tr) {
&&&&return
println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n'
+ getStackTraceString(tr));
&* Send a {@link #DEBUG} log message.
&* @param tag Used to identify the source of a log message.& It usually identifies
&*&&&&&&& the class or activity where the log call occurs.
&* @param msg The message you would like logged.
public static
int d(String tag, String msg) {
&&&&return
println_native(LOG_ID_MAIN, DEBUG, tag, msg);
最终都会是调用Log.println_native()静态native方法来打印log,各个类中各个方法的不同之处也仅在于参数的差异。
Log.println_native()方法
这个方法的code在/frameworks/base/core/jni/android_util_Log.cpp,为:
jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
&&&&&&&&jint bufID, jint priority, jstring tagObj, jstring msgObj)
char* tag = NULL;
char* msg = NULL;
(msgObj == NULL) {
&&&&&&&&jniThrowNullPointerException(env,
&println needs a message&);
&&&&&&&&return
(bufID & 0 || bufID &= LOG_ID_MAX) {
&&&&&&&&jniThrowNullPointerException(env,
&bad bufID&);
&&&&&&&&return
(tagObj != NULL)
&&&&&&&&tag = env-&GetStringUTFChars(tagObj, NULL);
&&&&msg = env-&GetStringUTFChars(msgObj, NULL);
res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
(tag != NULL)
&&&&&&&&env-&ReleaseStringUTFChars(tagObj, tag);
&&&&env-&ReleaseStringUTFChars(msgObj, msg);
&&&&return
JNINativeMethod gMethods[] = {
&isLoggable&,&&&&& &(Ljava/lang/SI)Z&, (void*) android_util_Log_isLoggable },
&println_native&,& &(IILjava/lang/SLjava/lang/S)I&, (void*) android_util_Log_println_native
可以看到,干的都是转换参数的事情,最终再call到__android_log_buf_write()函数,这个函数的定义在system/core/liblog/logd_write.c,为:
int __android_log_buf_write(int
bufID, int
prio, const char
*tag, const
char *msg)
&&&&struct
iovec vec[3];
tmp_tag[32];
&&&&&&&&tag =
((bufID != LOG_ID_RADIO) &&
&&&&&&&&&(!strcmp(tag,
&HTC_RIL&) ||
&&&&&&&&!strncmp(tag,
&RIL&, 3) ||
&&&&&&&&!strncmp(tag,
&IMS&, 3) ||
&&&&&&&&!strcmp(tag,
&&&&&&&&!strcmp(tag,
&&&&&&&&!strcmp(tag,
&&&&&&&&!strcmp(tag,
&CDMA&) ||
&&&&&&&&!strcmp(tag,
&PHONE&) ||
&&&&&&&&!strcmp(tag,
&SMS&))) {
&&&&&&&&&&&&bufID = LOG_ID_RADIO;
&&&&&&&&&&&&
&&&&&&&&&&&&snprintf(tmp_tag,
sizeof(tmp_tag),
&use-Rlog/RLOG-%s&, tag);
&&&&&&&&&&&&tag = tmp_
&&&&vec[0].iov_base&& = (unsigned
&&&&vec[0].iov_len&&& = 1;
&&&&vec[1].iov_base&& = (void
&&&&vec[1].iov_len&&& =
strlen(tag) + 1;
&&&&vec[2].iov_base&& = (void
&&&&vec[2].iov_len&&& =
strlen(msg) + 1;
&&&&return
write_to_log(bufID, vec, 3);
做了三件事情,一是根据log的tag,转换bufID,二是用传进来的参数构造一个struct iovec数组,三是将前一步构造的数组作为参数调用write_to_log()。write_to_log()是一个函数指针,在开始时,它指向了__write_to_log_init():
int (*write_to_log)(log_id_t, struct
iovec *vec, size_t
nr) = __write_to_log_
__write_to_log_init()的实现如下:
int __write_to_log_init(log_id_t log_id, struct
iovec *vec, size_t
#ifdef HAVE_PTHREADS
&&&&pthread_mutex_lock(&log_init_lock);
(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_
&&&&&&&&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_
&&&&&&&&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);
&&&&return
write_to_log(log_id, vec, nr);
这个地方,会检查write_to_log是否指向了__write_to_log_init,也就是是否是第一次打印log,如果是,则打开几个用于输出log的设备文件,然后使write_to_log函数指针指向__write_to_log_kernel,或者在打开输出log设备文件出现异常时,使write_to_log指向__write_to_log_null,最后再次调用经过了重定向的write_to_log,也就是__write_to_log_kernel或者__write_to_log_null函数。我们可以看一下那几个设备文件究竟是什麽(在system/core/include/cutils/logger.h):
#define LOGGER_LOG_MAIN&&&& &log/main&
#define LOGGER_LOG_RADIO&&& &log/radio&
#define LOGGER_LOG_EVENTS&& &log/events&
#define LOGGER_LOG_SYSTEM&& &log/system&
接着继续来看__write_to_log_kernel或者__write_to_log_null函数:
int __write_to_log_null(log_id_t log_fd, struct
iovec *vec, size_t
&&&&return
int __write_to_log_kernel(log_id_t log_id, struct
iovec *vec, size_t
&&&&ssize_
(int)log_id & (int)LOG_ID_MAX) {
&&&&&&&&log_fd = log_fds[(int)log_id];
&&&&&&&&return
&&&&&&&&ret = log_writev(log_fd, vec, nr);
while (ret & 0 && errno
== EINTR);
&&&&return
由log_id获取到对应的log_fd,然后调用log_writev()打印log。可以看一下log_writev()的定义,它是一个宏:
#if FAKE_LOG_DEVICE
#define log_open(pathname, flags) fakeLogOpen(pathname, flags)
#define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count)
#define log_close(filedes) fakeLogClose(filedes)
#define log_open(pathname, flags) open(pathname, (flags) | O_CLOEXEC)
#define log_writev(filedes, vector, count) writev(filedes, vector, count)
#define log_close(filedes) close(filedes)
这些就都是标准的unix系统调用了。
本地层代码Log输出
以一些比较典型的native代码打印log的case为例。先来看一下,在JNI的code中打印log的方法。在JNI中,比较常见到用ALOGx这一组宏来打印log,比如在frameworks/base/core/jni/android/graphics/TextLayoutCache.cpp这个文件中的dumpCacheStats()函数:
void TextLayoutCache::dumpCacheStats() {
remainingPercent = 100 * ((mMaxSize - mSize) / ((float)mMaxSize));
timeRunningInSec = (systemTime(SYSTEM_TIME_MONOTONIC) - mCacheStartTime) / ;
&&&&size_t
cacheSize = mCache.size();
&&&&ALOGD(&------------------------------------------------&);
&&&&ALOGD(&Cache stats&);
&&&&ALOGD(&------------------------------------------------&);
&&&&ALOGD(&pid&&&&&& : %d&, getpid());
&&&&ALOGD(&running&& : %.0f seconds&, timeRunningInSec);
&&&&ALOGD(&entries&& : %d&, cacheSize);
&&&&ALOGD(&max size& : %d bytes&, mMaxSize);
&&&&ALOGD(&used&&&&& : %d bytes according to mSize&, mSize);
&&&&ALOGD(&remaining : %d bytes or %2.2f percent&, mMaxSize - mSize, remainingPercent);
&&&&ALOGD(&hits&&&&& : %d&, mCacheHitCount);
&&&&ALOGD(&saved&&&& : %0.6f ms&, mNanosecondsSaved * 0.000001f);
&&&&ALOGD(&------------------------------------------------&);
使用这组宏,需要定义另外一个宏来作为所打印log的tag:
#define LOG_TAG &TextLayoutCache&
此外,还要include头文件&cutils/log.h&。来看一下这些宏中的一些的定义:
#ifndef ALOGD
#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#ifndef ALOGW
#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
#ifndef ALOG
#define ALOG(priority, tag, ...) \
&&&&LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
#ifndef LOG_PRI
#define LOG_PRI(priority, tag, ...) \
&&&&android_printLog(priority, tag, __VA_ARGS__)
#define android_printLog(prio, tag, fmt...) \
&&&&__android_log_print(prio, tag, fmt)
先来看一下,在native层中定义的priority(在system/core/include/android/log.h中):
enum android_LogPriority {
&&&&ANDROID_LOG_UNKNOWN = 0,
&&&&ANDROID_LOG_DEFAULT,&&&
&&&&ANDROID_LOG_VERBOSE,
&&&&ANDROID_LOG_DEBUG,
&&&&ANDROID_LOG_INFO,
&&&&ANDROID_LOG_WARN,
&&&&ANDROID_LOG_ERROR,
&&&&ANDROID_LOG_FATAL,
&&&&ANDROID_LOG_SILENT,&&&&
} android_LogP
另外,这些宏最终都会call到__android_log_print(),也是在system/core/liblog/logd_write.c中:
int __android_log_print(int
prio, const
char *tag, const
char *fmt, ...)
&&&&va_list
buf[LOG_BUF_SIZE];
&&&&va_start(ap, fmt);
&&&&vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
&&&&va_end(ap);
&&&&return
__android_log_write(prio, tag, buf);
先是格式化参数,然后就是调用__android_log_write()函数。这个函数的code如下:
int __android_log_write(int
prio, const
char *tag, const
char *msg)
&&&&struct
iovec vec[3];
&&&&log_id_t log_id = LOG_ID_MAIN;
tmp_tag[32];
&&&&&&&&tag =
(!strcmp(tag,
&HTC_RIL&) ||
&&&&&&&&!strncmp(tag,
&RIL&, 3) ||
&&&&&&&&!strncmp(tag,
&IMS&, 3) ||
&&&&&&&&!strcmp(tag,
&&&&&&&&!strcmp(tag,
&&&&&&&&!strcmp(tag,
&&&&&&&&!strcmp(tag,
&CDMA&) ||
&&&&&&&&!strcmp(tag,
&PHONE&) ||
&&&&&&&&!strcmp(tag,
&&&&&&&&&&&&log_id = LOG_ID_RADIO;
&&&&&&&&&&&&
&&&&&&&&&&&&snprintf(tmp_tag,
sizeof(tmp_tag),
&use-Rlog/RLOG-%s&, tag);
&&&&&&&&&&&&tag = tmp_
&&&&vec[0].iov_base&& = (unsigned
&&&&vec[0].iov_len&&& = 1;
&&&&vec[1].iov_base&& = (void
&&&&vec[1].iov_len&&& =
strlen(tag) + 1;
&&&&vec[2].iov_base&& = (void
&&&&vec[2].iov_len&&& =
strlen(msg) + 1;
&&&&return
write_to_log(log_id, vec, 3);
这个函数与我们前面看到的__android_log_buf_write()非常相似。所不同的就是这个函数没有log_id参数,因而它默认是输出MAIN log,当log的TAG为某些特殊字串时,则输出RADIO log。最后同样是调用write_to_log这个函数指针来输出log。
我们再来看一个skia里面打log的SkDebugf()函数的实现:
#include &android/log.h&
void SkDebugf(const
char format[], ...) {
&&&&va_list
&&&&va_start(args, format);
&&&&__android_log_vprint(ANDROID_LOG_DEBUG, LOG_TAG, format, args);
&&&&va_end(args);
call到了__android_log_vprint()来输出log,__android_log_vprint()的定义也在system/core/liblog/logd_write.c中:
int __android_log_vprint(int
prio, const
char *tag, const
char *fmt, va_list
buf[LOG_BUF_SIZE];
&&&&vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
&&&&return
__android_log_write(prio, tag, buf);
一样是__android_log_write()函数。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:181641次
积分:2171
积分:2171
排名:第12517名
原创:37篇
转载:106篇
(1)(1)(4)(4)(3)(2)(2)(4)(1)(1)(1)(2)(7)(3)(1)(32)(38)(9)(17)(13)

我要回帖

更多关于 我的世界 nativelog 的文章

 

随机推荐