Android8.0.0-r4的log系统

时间:2024-04-05 12:31:24

Android提供的Logger日志系统是基于内核中的Logger日志驱动程序实现的。日志的类型一共分为四种:main,system,radio和events。在驱动中分别通过/dev/log/main、/dev/log/system、/dev/log/radio、/dev/log/events四个设备来访问的。

类型为main的日志是应用级别的,在应用框架层提供了android.util.Log接口通过liblog库来往Logger日志驱动程序中写入日志,在运行时库提供了宏LOGV、LOGD、LOGI、LOGW、LOGE用来写入main类型的日志。

类型为system的日志是系统级别的,在应用框架层提供了android.util.SLog接口通过liblog库来往Logger日志驱动程序中写入日志,在运行时库提供了宏SLOGV、SLOGD、SLOGI、SLOGW、SLOGE用来写入system类型的日志。

类型为events的日志是用来诊断系统问题的,在应用框架层提供了android.util.EventLog接口通过liblog库来往Logger日志驱动程序中写入日志,在运行时库提供了宏LOG_EVENT_INT、LOG_EVENT_LONG、LOG_STRING用来写入event类型的日志。

类型为radio类型的日志是与无线设备相关的,数量庞大,所以单独记录。

Android8.0.0-r4的log系统

                                                                                    Logger日志框架系统


Logger日志驱动程序的实现在内核空间中,从谷歌下载的Android源码未携带kernel源码.

log驱动程序在kernel的地方:
MTK:/drivers/misc/mediatek/mlog/mediatek
huawei:/drivers/staging/android/hwlogger
在驱动中主要完成日志设备的初始化,打开,读取,写入这四个过程。由于log驱动本身未开源,无法对比源码。而且这一部分会由芯片厂商提供,差异较大,需要具体代码具体分析。所以暂不做讲解

1.运行时库层日志库     

Android系统在运行时库层提供了一个用来和Logger日志驱动程序进行交互的日志库liblog。通过 日志库liblog提供的接口, 应用程序就可以方便地往Logger日志驱动程序中写人日志记录。 位于运行时库层的C/C++日志写人接口和位于应用程序框架层的Java日志写入接口都是通过liblog库提供的日志写人接口来往Logger日志驱动程序中写人日志记录的, 因此, 在分析这些C/C++或者Java日志写人接口之前, 我们首先介绍Iiblog库的日志记录写入接口。


日志库liblog提供的日志记录写人接口实现在logd_write.c文件

    代码路径: /system/core/liblog/logger_write.c

    (http://androidxref.com/8.0.0_r4/xref/ /system/core/liblog/logger_write.c)

根据写入的日志记录的类型不同,这些函数可以划分为三个类别,其中:

    1.函数__android_log_assert、__android_log_vprint和__android_log_print用来写人类型为main的日志记录;
    2. 函数__android_log_btwrite和__android_log_bwrite用来写人类型为events的日志记录;
    3.函数_android_log_buf_print可以写入任意一种类型的日志记录。

无论写入的是什么类型的日志记录,它们最终都是通过调用函数write_to_log写入到Logger日志驱动程序中的。write_to_log是一个函数指针,它开始时指向函数__write_to_log_init。因此,当函数write_to_log第一次被调用时,实际上执行的是函数__write_to_log_init。函数__write_to_log_init主要是进行一些日志库初始化操作,接着函数指针write_to_log重定向到函数__write_to_log_kernel或者__write_to_log_null中,这取决于能否成功地将日志设备文件打开。

函数指针write_to_log在开始的时候被设置为函数__write_to_log_init。当它第一次被调用时,便会执行函数__write_to_log_daemon来初始化日志库liblog

39static int __write_to_log_init(log_id_t, struct iovec* vec, size_t nr);
40static int (*write_to_log)(log_id_t, struct iovec* vec,
41                           size_t nr) = __write_to_log_init;


在__write_to_log_init中会__write_to_log_initialize调用初始化日志写入设备,并__write_to_log_daemon初始化log写入的守护进程,常驻内存中

377static int __write_to_log_init(log_id_t log_id, struct iovec* vec, size_t nr) {
378  __android_log_lock();
379
380  if (write_to_log == __write_to_log_init) {
381    int ret;
382
383    ret = __write_to_log_initialize();
384    if (ret < 0) {
385      __android_log_unlock();//解锁log写入进程,避免死锁
386      if (!list_empty(&__android_log_persist_write)) {
387        __write_to_log_daemon(log_id, vec, nr);
388      }
389      return ret;
390    }
391
392    write_to_log = __write_to_log_daemon;
393  }
394
395  __android_log_unlock();
396
397  return write_to_log(log_id, vec, nr);
398}


   通过调用__write_to_log_initialize()进行android的log属性设置和log的安全状态

193/* log_init_lock assumed */
194static int __write_to_log_initialize() {
195  struct android_log_transport_write* transport;
196  struct listnode* n;
197  int i = 0, ret = 0;
198
199  __android_log_config_write();
200  write_transport_for_each_safe(transport, n, &__android_log_transport_write) {
201    __android_log_cache_available(transport);
202    if (!transport->logMask) {
203      list_remove(&transport->node);
204      continue;
205    }
206    if (!transport->open || ((*transport->open)() < 0)) {
207      if (transport->close) {
208        (*transport->close)();
209      }
210      list_remove(&transport->node);
211      continue;
212    }
213    ++ret;
214  }
215  write_transport_for_each_safe(transport, n, &__android_log_persist_write) {
216    __android_log_cache_available(transport);//设置log缓存状态
217    if (!transport->logMask) {
218      list_remove(&transport->node);
219      continue;
220    }
221    if (!transport->open || ((*transport->open)() < 0)) {
222      if (transport->close) {
223        (*transport->close)();
224      }
225      list_remove(&transport->node);
226      continue;
227    }
228    ++i;
229  }
230  if (!ret && !i) {
231    return -ENODEV;
232  }
233
234  return ret;
235}

通过__write_to_log_daemon来真正执行初始化log设备的工作
244static int __write_to_log_daemon(log_id_t log_id, struct iovec* vec, size_t nr) {
245  struct android_log_transport_write* node;
246  int ret;
247  struct timespec ts;
248  size_t len, i;
249
250  for (len = i = 0; i < nr; ++i) {
251    len += vec[i].iov_len;
252  }
253  if (!len) {
254    return -EINVAL;
255  }
256
257#if defined(__ANDROID__)
258  clock_gettime(android_log_clockid(), &ts);
259
260  if (log_id == LOG_ID_SECURITY) {
261    if (vec[0].iov_len < 4) {
262      return -EINVAL;
263    }
264
265    ret = check_log_uid_permissions();
266    if (ret < 0) {
267      return ret;
268    }
269    if (!__android_log_security()) {
270      /* If only we could reset downstream logd counter */
271      return -EPERM;
272    }
273  } else if (log_id == LOG_ID_EVENTS) {
274    const char* tag;
275    size_t len;
276    EventTagMap *m, *f;
277
278    if (vec[0].iov_len < 4) {
279      return -EINVAL;
280    }
281
282    tag = NULL;
283    len = 0;
284    f = NULL;
285    m = (EventTagMap*)atomic_load(&tagMap);
286
287    if (!m) {
288      ret = __android_log_trylock();
289      m = (EventTagMap*)atomic_load(&tagMap); /* trylock flush cache */
290      if (!m) {
291        m = android_openEventTagMap(NULL);
292        if (ret) { /* trylock failed, use local copy, mark for close */
293          f = m;
294        } else {
295          if (!m) { /* One chance to open map file */
296            m = (EventTagMap*)(uintptr_t)-1LL;
297          }
298          atomic_store(&tagMap, (uintptr_t)m);
299        }
300      }
301      if (!ret) { /* trylock succeeded, unlock */
302        __android_log_unlock();
303      }
304    }
305    if (m && (m != (EventTagMap*)(uintptr_t)-1LL)) {
306      tag = android_lookupEventTag_len(m, &len, get4LE(vec[0].iov_base));
307    }
308    ret = __android_log_is_loggable_len(ANDROID_LOG_INFO, tag, len,
309                                        ANDROID_LOG_VERBOSE);
310    if (f) { /* local copy marked for close */
311      android_closeEventTagMap(f);
312    }
313    if (!ret) {
314      return -EPERM;
315    }
316  } else {
317    /* Validate the incoming tag, tag content can not split across iovec */
318    char prio = ANDROID_LOG_VERBOSE;
319    const char* tag = vec[0].iov_base;
320    size_t len = vec[0].iov_len;
321    if (!tag) {
322      len = 0;
323    }
324    if (len > 0) {
325      prio = *tag;
326      if (len > 1) {
327        --len;
328        ++tag;
329      } else {
330        len = vec[1].iov_len;
331        tag = ((const char*)vec[1].iov_base);
332        if (!tag) {
333          len = 0;
334        }
335      }
336    }
337    /* tag must be nul terminated */
338    if (tag && strnlen(tag, len) >= len) {
339      tag = NULL;
340    }
341
342    if (!__android_log_is_loggable_len(prio, tag, len - 1, ANDROID_LOG_VERBOSE)) {
343      return -EPERM;
344    }
345  }
346#else
347  /* simulate clock_gettime(CLOCK_REALTIME, &ts); */
348  {
349    struct timeval tv;
350    gettimeofday(&tv, NULL);
351    ts.tv_sec = tv.tv_sec;
352    ts.tv_nsec = tv.tv_usec * 1000;
353  }
354#endif
355
356  ret = 0;
357  i = 1 << log_id;
358  write_transport_for_each(node, &__android_log_transport_write) {
359    if (node->logMask & i) {
360      ssize_t retval;
361      retval = (*node->write)(log_id, &ts, vec, nr);
362      if (ret >= 0) {
363        ret = retval;
364      }
365    }
366  }
367
368  write_transport_for_each(node, &__android_log_persist_write) {
369    if (node->logMask & i) {
370      (void)(*node->write)(log_id, &ts, vec, nr);
371    }
372  }
373
374  return ret;
375}

在打开日志设备初始化失败后会调用 __write_to_log_null函数
594static int __write_to_log_null(log_id_t log_id, struct iovec* vec, size_t nr) {
595  size_t len, i;
596
597  if ((log_id < LOG_ID_MIN) || (log_id >= LOG_ID_MAX)) {
598    return -EINVAL;
599  }
600
601  for (len = i = 0; i < nr; ++i) {
602    len += vec[i].iov_len;
603  }
604  if (!len) {
605    return -EINVAL;
606  }
607  return len;
608}


函数

__android_log_bwrite,__android_log_security_bwrite,__android_log_btwrite,__android_log_bswrite,__android_log_security_bswrite都是调用函数android_log_write向Logger日志驱动程序中写入日志记录的, 它们都可以使用格式化字符串来描述要写人的日志记录内容

507LIBLOG_ABI_PUBLIC int __android_log_bwrite(int32_t tag, const void* payload,
508                                           size_t len) {
515  .............
516  return write_to_log(LOG_ID_EVENTS, vec, 2);
517}
518
519LIBLOG_ABI_PUBLIC int __android_log_security_bwrite(int32_t tag,
520                                                    const void* payload,
521                                                    size_t len) {
       ..............
529  return write_to_log(LOG_ID_SECURITY, vec, 2);
530}
531

537LIBLOG_ABI_PUBLIC int __android_log_btwrite(int32_t tag, char type,
538                                            const void* payload, size_t len) {
       .......................
547
548  return write_to_log(LOG_ID_EVENTS, vec, 3);
549}
550

555LIBLOG_ABI_PUBLIC int __android_log_bswrite(int32_t tag, const char* payload) {

568
569  return write_to_log(LOG_ID_EVENTS, vec, 4);
570}

576LIBLOG_ABI_PUBLIC int __android_log_security_bswrite(int32_t tag,
577                                                     const char* payload) {
591  return write_to_log(LOG_ID_SECURITY, vec, 4);
592}


函数__android_log_buf_print是调用函数 __android_log_buf_write向Logger日志驱动程序中写入日志记录的,它可以指定要写人的日志记录的类型,以及使用格式化字符串来描述要写人的日志记录内容

462LIBLOG_ABI_PUBLIC int __android_log_buf_print(int bufID, int prio,
463                                              const char* tag, const char* fmt,
464                                              ...) {
465  va_list ap;
466  char buf[LOG_BUF_SIZE];
467
468  va_start(ap, fmt);
469  vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
470  va_end(ap);
471
472  return __android_log_buf_write(bufID, prio, tag, buf);
473}


这里详细介绍了log的写入lib库,其实还有读取logger_read.c等其他文件。

2.C/C++层的日志写入接口

Android系统就提供了三组常用的C/C++宏来封装日志写入接口, 这些宏有的在程序的非调试版本中只是一个空定义, 因此, 可以避免在程序的发布版本中输出日志。

第一组宏是LOGV 、LOGD 、LOGI 、LOGW和LOGE,  它们用来写入类型为main的日志记录;
第二组宏是SLOGV 、SLOGD 、SLOGI 、SLOGW和SLOGE,它们用来写人类型为system的日志记录;
第三组宏是LOG_EVENT_INT、LOG_EVENT_LONG和LOG_EVENT_STRING,它们用来写人类型为events的日志记录。

 这些宏定义在Android 系统运行时库层的/system/core/include/log/下面

在log.h的文件中,定义了一个宏LOG_NDEBUG, 用来区分程序是调试版本还是发布版本

源码路径:/system/core/include/log/log.h

(http://androidxref.com/8.0.0_r4/xref/system/core/include/log/log.h)


在程序的发布版本中,  宏LOG_NDEBUG定义为 1 ,而在调试版本中定义为0。 通过这个宏,我们 就可以将某些日志宏在程序的发布版本中定义为空, 从而限制它们在程序的发布版本中输出。

61#ifndef LOG_NDEBUG
62#ifdef NDEBUG
63#define LOG_NDEBUG 1
64#else
65#define LOG_NDEBUG 0
66#endif
67#endif

这个头文件还定义了宏LOG_TAG,   用作当前编译单元的默认日志记录标签

48
49#ifndef LOG_TAG
50#define LOG_TAG NULL
51#endif
52

它默认定义为NULL ,即没有日志记录标签 。如果一个模块想要定义自己的默认日志记录标签 , 那么就需要使用#define指令来自定义宏LOG_TAG 的值

 第一组宏是LOGV 、LOGD 、LOGI 、LOGW和LOGE,  它们用来写入类型为main的日志记录

代码路径:/system/core/include/log/log_main.h

(http://androidxref.com/8.0.0_r4/xref/system/core/include/log/log_main.h)

这五个宏是用来写入类型为main的日志记录的,它们写入的日志记录的优先级分别为VERBOSE、DEBUG、INFO、WARN和ERROR。其中,宏LOGV只有在宏LOG_NDEBUG定义为0时,即在程序的调试版本中,才是有效的;否则,它只是一个空定义。这五个宏是通过使用宏LOG来实现日志写入功能的 ,它的定义如下所示
170
171/*
172 * Simplified macro to send a verbose log message using the current LOG_TAG.
173 */
174#ifndef ALOGV
175#define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
176#if LOG_NDEBUG
177#define ALOGV(...)          \
178  do {                      \
179    if (0) {                \
180      __ALOGV(__VA_ARGS__); \
181    }                       \
182  } while (0)
183#else
184#define ALOGV(...) __ALOGV(__VA_ARGS__)
185#endif
186#endif
187
188#ifndef ALOGV_IF
189#if LOG_NDEBUG
190#define ALOGV_IF(cond, ...) ((void)0)
191#else
192#define ALOGV_IF(cond, ...)                                                  \
193  ((__predict_false(cond)) ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
194                           : (void)0)
195#endif
196#endif
197
198/*
199 * Simplified macro to send a debug log message using the current LOG_TAG.
200 */
201#ifndef ALOGD
202#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
203#endif
204
205#ifndef ALOGD_IF
206#define ALOGD_IF(cond, ...)                                                \
207  ((__predict_false(cond)) ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
208                           : (void)0)
209#endif
210
211/*
212 * Simplified macro to send an info log message using the current LOG_TAG.
213 */
214#ifndef ALOGI
215#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
216#endif
217
218#ifndef ALOGI_IF
219#define ALOGI_IF(cond, ...)                                               \
220  ((__predict_false(cond)) ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
221                           : (void)0)
222#endif
223
224/*
225 * Simplified macro to send a warning log message using the current LOG_TAG.
226 */
227#ifndef ALOGW
228#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
229#endif
230
231#ifndef ALOGW_IF
232#define ALOGW_IF(cond, ...)                                               \
233  ((__predict_false(cond)) ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
234                           : (void)0)
235#endif
236
237/*
238 * Simplified macro to send an error log message using the current LOG_TAG.
239 */
240#ifndef ALOGE
241#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
242#endif
243
244#ifndef ALOGE_IF
245#define ALOGE_IF(cond, ...)                                                \
246  ((__predict_false(cond)) ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
247                           : (void)0)
248#endif
249
250/* --------------------------------------------------------------------- */
251
252/*
253 * Conditional based on whether the current LOG_TAG is enabled at
254 * verbose priority.
255 */
256#ifndef IF_ALOGV
257#if LOG_NDEBUG
258#define IF_ALOGV() if (false)
259#else
260#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG)
261#endif
262#endif
263
264/*
265 * Conditional based on whether the current LOG_TAG is enabled at
266 * debug priority.
267 */
268#ifndef IF_ALOGD
269#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG)
270#endif
271
272/*
273 * Conditional based on whether the current LOG_TAG is enabled at
274 * info priority.
275 */
276#ifndef IF_ALOGI
277#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG)
278#endif
279
280/*
281 * Conditional based on whether the current LOG_TAG is enabled at
282 * warn priority.
283 */
284#ifndef IF_ALOGW
285#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
286#endif
287
288/*
289 * Conditional based on whether the current LOG_TAG is enabled at
290 * error priority.
291 */
292#ifndef IF_ALOGE
293#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
294#endif
295   


这五个宏是通过使用宏LOG_PRI来实现日志写入功能的

296/* --------------------------------------------------------------------- */
297
298/*
299 * Basic log message macro.
300 *
301 * Example:
302 *  ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
303 *
304 * The second argument may be NULL or "" to indicate the "global" tag.
305 */
306#ifndef ALOG
307#define ALOG(priority, tag, ...) LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
308#endif
309
310/*
311 * Conditional given a desired logging priority and tag.
312 */
313#ifndef IF_ALOG
314#define IF_ALOG(priority, tag) if (android_testLog(ANDROID_##priority, tag))
315#endif
316

最终是通过调用日志库liblog提供的函数android_printLog向Logger日志驱动程序中写入日志记录的
67/*
68 * Log macro that allows you to specify a number for the priority.
69 */
70#ifndef LOG_PRI
71#define LOG_PRI(priority, tag, ...) android_printLog(priority, tag, __VA_ARGS__)
72#endif
73
74/*
75 * Log macro that allows you to pass in a varargs ("args" is a va_list).
76 */
77#ifndef LOG_PRI_VA
78#define LOG_PRI_VA(priority, tag, fmt, args) \
79  android_vprintLog(priority, NULL, tag, fmt, args)
80#endif

其他两组类似第一组组宏的提供的接口

第二组宏是SLOGV 、SLOGD 、SLOGI 、SLOGW和SLOGE,它们用来写人类型为system的日志记录;

代码路径:/system/core/include/log/log_system.h

(http://androidxref.com/8.0.0_r4/xref/system/core/include/log/log_system.h)

第三组宏是LOG_EVENT_INT、LOG_EVENT_LONG和LOG_EVENT_STRING,它们用来写人类型为events的日志记录

代码路径:/system/core/include/log/log_event_list.h

(http://androidxref.com/8.0.0_r4/xref/system/core/include/log/log_event_list.h)

3.Java层的日志写入接口

Android系统在应用程序框架层中定义了三个Java日志写入接口,它们分别是android.util.Log、android.util.Slog和android.util.EventLog,写入的日志记录类型分别为main、system和events。这三个Java日志写入接口是通过JNI方法来调用日志库liblog提供的函数来实现日志记录的写入功能的

接口android .util.Log提供的日志记录写入成员函数比较多 ,不过我们只关注常用的成员函数v、d、1、w和e 。这些成员函数写人的日志记录的类型都是 main ,而对应的日志记录的优先级分别为 VERBOSE 、DEBUG 、INFO 、WARN 、ERROR和ASSERT 。它们是通过调用JNI方法println_native来实现日志记录写入功能的

代码路径:/frameworks/base/core/java/android/util/Log.java

(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/android/util/Log.java)

58public final class Log {
59
60    /**
61     * Priority constant for the println method; use Log.v.
62     */
63    public static final int VERBOSE = 2;
64
65    /**
66     * Priority constant for the println method; use Log.d.
67     */
68    public static final int DEBUG = 3;
69
70    /**
71     * Priority constant for the println method; use Log.i.
72     */
73    public static final int INFO = 4;
74
75    /**
76     * Priority constant for the println method; use Log.w.
77     */
78    public static final int WARN = 5;
79
80    /**
81     * Priority constant for the println method; use Log.e.
82     */
83    public static final int ERROR = 6;
84
85    /**
86     * Priority constant for the println method.
87     */
88    public static final int ASSERT = 7;
89
90    /**
91     * Exception class used to capture a stack trace in {@link #wtf}.
92     */
93    private static class TerribleFailure extends Exception {
94        TerribleFailure(String msg, Throwable cause) { super(msg, cause); }
95    }
96
97    /**
98     * Interface to handle terrible failures from {@link #wtf}.
99     *
100     * @hide
101     */
102    public interface TerribleFailureHandler {
103        void onTerribleFailure(String tag, TerribleFailure what, boolean system);
104    }
105
106    private static TerribleFailureHandler sWtfHandler = new TerribleFailureHandler() {
107            public void onTerribleFailure(String tag, TerribleFailure what, boolean system) {
108                RuntimeInit.wtf(tag, what, system);
109            }
110        };
111
112    private Log() {
113    }
114
115    /**
116     * Send a {@link #VERBOSE} log message.
117     * @param tag Used to identify the source of a log message.  It usually identifies
118     *        the class or activity where the log call occurs.
119     * @param msg The message you would like logged.
120     */
121    public static int v(String tag, String msg) {
122        return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
123    }
124
125    /**
126     * Send a {@link #VERBOSE} log message and log the exception.
127     * @param tag Used to identify the source of a log message.  It usually identifies
128     *        the class or activity where the log call occurs.
129     * @param msg The message you would like logged.
130     * @param tr An exception to log
131     */
132    public static int v(String tag, String msg, Throwable tr) {
133        return printlns(LOG_ID_MAIN, VERBOSE, tag, msg, tr);
134    }
135
136    /**
137     * Send a {@link #DEBUG} log message.
138     * @param tag Used to identify the source of a log message.  It usually identifies
139     *        the class or activity where the log call occurs.
140     * @param msg The message you would like logged.
141     */
142    public static int d(String tag, String msg) {
143        return println_native(LOG_ID_MAIN, DEBUG, tag, msg);
144    }
145
146    /**
147     * Send a {@link #DEBUG} log message and log the exception.
148     * @param tag Used to identify the source of a log message.  It usually identifies
149     *        the class or activity where the log call occurs.
150     * @param msg The message you would like logged.
151     * @param tr An exception to log
152     */
153    public static int d(String tag, String msg, Throwable tr) {
154        return printlns(LOG_ID_MAIN, DEBUG, tag, msg, tr);
155    }
156
157    /**
158     * Send an {@link #INFO} log message.
159     * @param tag Used to identify the source of a log message.  It usually identifies
160     *        the class or activity where the log call occurs.
161     * @param msg The message you would like logged.
162     */
163    public static int i(String tag, String msg) {
164        return println_native(LOG_ID_MAIN, INFO, tag, msg);
165    }
166
167    /**
168     * Send a {@link #INFO} log message and log the exception.
169     * @param tag Used to identify the source of a log message.  It usually identifies
170     *        the class or activity where the log call occurs.
171     * @param msg The message you would like logged.
172     * @param tr An exception to log
173     */
174    public static int i(String tag, String msg, Throwable tr) {
175        return printlns(LOG_ID_MAIN, INFO, tag, msg, tr);
176    }
177
178    /**
179     * Send a {@link #WARN} log message.
180     * @param tag Used to identify the source of a log message.  It usually identifies
181     *        the class or activity where the log call occurs.
182     * @param msg The message you would like logged.
183     */
184    public static int w(String tag, String msg) {
185        return println_native(LOG_ID_MAIN, WARN, tag, msg);
186    }
187
188    /**
189     * Send a {@link #WARN} log message and log the exception.
190     * @param tag Used to identify the source of a log message.  It usually identifies
191     *        the class or activity where the log call occurs.
192     * @param msg The message you would like logged.
193     * @param tr An exception to log
194     */
195    public static int w(String tag, String msg, Throwable tr) {
196        return printlns(LOG_ID_MAIN, WARN, tag, msg, tr);
197    }
198
199    /**
200     * Checks to see whether or not a log for the specified tag is loggable at the specified level.
201     *
202     *  The default level of any tag is set to INFO. This means that any level above and including
203     *  INFO will be logged. Before you make any calls to a logging method you should check to see
204     *  if your tag should be logged. You can change the default level by setting a system property:
205     *      'setprop log.tag.&lt;YOUR_LOG_TAG> &lt;LEVEL>'
206     *  Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. SUPPRESS will
207     *  turn off all logging for your tag. You can also create a local.prop file that with the
208     *  following in it:
209     *      'log.tag.&lt;YOUR_LOG_TAG>=&lt;LEVEL>'
210     *  and place that in /data/local.prop.
211     *
212     * @param tag The tag to check.
213     * @param level The level to check.
214     * @return Whether or not that this is allowed to be logged.
215     * @throws IllegalArgumentException is thrown if the tag.length() > 23
216     *         for Nougat (7.0) releases (API <= 23) and prior, there is no
217     *         tag limit of concern after this API level.
218     */
219    public static native boolean isLoggable(String tag, int level);
220
221    /*
222     * Send a {@link #WARN} log message and log the exception.
223     * @param tag Used to identify the source of a log message.  It usually identifies
224     *        the class or activity where the log call occurs.
225     * @param tr An exception to log
226     */
227    public static int w(String tag, Throwable tr) {
228        return printlns(LOG_ID_MAIN, WARN, tag, "", tr);
229    }
230
231    /**
232     * Send an {@link #ERROR} log message.
233     * @param tag Used to identify the source of a log message.  It usually identifies
234     *        the class or activity where the log call occurs.
235     * @param msg The message you would like logged.
236     */
237    public static int e(String tag, String msg) {
238        return println_native(LOG_ID_MAIN, ERROR, tag, msg);
239    }
240
241    /**
242     * Send a {@link #ERROR} log message and log the exception.
243     * @param tag Used to identify the source of a log message.  It usually identifies
244     *        the class or activity where the log call occurs.
245     * @param msg The message you would like logged.
246     * @param tr An exception to log
247     */
248    public static int e(String tag, String msg, Throwable tr) {
249        return printlns(LOG_ID_MAIN, ERROR, tag, msg, tr);
250    }
251
252    /**
253     * What a Terrible Failure: Report a condition that should never happen.
254     * The error will always be logged at level ASSERT with the call stack.
255     * Depending on system configuration, a report may be added to the
256     * {@link android.os.DropBoxManager} and/or the process may be terminated
257     * immediately with an error dialog.
258     * @param tag Used to identify the source of a log message.
259     * @param msg The message you would like logged.
260     */
261    public static int wtf(String tag, String msg) {
262        return wtf(LOG_ID_MAIN, tag, msg, null, false, false);
263    }
264
265    /**
266     * Like {@link #wtf(String, String)}, but also writes to the log the full
267     * call stack.
268     * @hide
269     */
270    public static int wtfStack(String tag, String msg) {
271        return wtf(LOG_ID_MAIN, tag, msg, null, true, false);
272    }
273
274    /**
275     * What a Terrible Failure: Report an exception that should never happen.
276     * Similar to {@link #wtf(String, String)}, with an exception to log.
277     * @param tag Used to identify the source of a log message.
278     * @param tr An exception to log.
279     */
280    public static int wtf(String tag, Throwable tr) {
281        return wtf(LOG_ID_MAIN, tag, tr.getMessage(), tr, false, false);
282    }
283
284    /**
285     * What a Terrible Failure: Report an exception that should never happen.
286     * Similar to {@link #wtf(String, Throwable)}, with a message as well.
287     * @param tag Used to identify the source of a log message.
288     * @param msg The message you would like logged.
289     * @param tr An exception to log.  May be null.
290     */
291    public static int wtf(String tag, String msg, Throwable tr) {
292        return wtf(LOG_ID_MAIN, tag, msg, tr, false, false);
293    }
294
295    static int wtf(int logId, String tag, String msg, Throwable tr, boolean localStack,
296            boolean system) {
297        TerribleFailure what = new TerribleFailure(msg, tr);
298        // Only mark this as ERROR, do not use ASSERT since that should be
299        // reserved for cases where the system is guaranteed to abort.
300        // The onTerribleFailure call does not always cause a crash.
301        int bytes = printlns(logId, ERROR, tag, msg, localStack ? what : tr);
302        sWtfHandler.onTerribleFailure(tag, what, system);
303        return bytes;
304    }
305
306    static void wtfQuiet(int logId, String tag, String msg, boolean system) {
307        TerribleFailure what = new TerribleFailure(msg, null);
308        sWtfHandler.onTerribleFailure(tag, what, system);
309    }
310
311    /**
312     * Sets the terrible failure handler, for testing.
313     *
314     * @return the old handler
315     *
316     * @hide
317     */
318    public static TerribleFailureHandler setWtfHandler(TerribleFailureHandler handler) {
319        if (handler == null) {
320            throw new NullPointerException("handler == null");
321        }
322        TerribleFailureHandler oldHandler = sWtfHandler;
323        sWtfHandler = handler;
324        return oldHandler;
325    }
326
327    /**
328     * Handy function to get a loggable stack trace from a Throwable
329     * @param tr An exception to log
330     */
331    public static String getStackTraceString(Throwable tr) {
332        if (tr == null) {
333            return "";
334        }
335
336        // This is to reduce the amount of log spew that apps do in the non-error
337        // condition of the network being unavailable.
338        Throwable t = tr;
339        while (t != null) {
340            if (t instanceof UnknownHostException) {
341                return "";
342            }
343            t = t.getCause();
344        }
345
346        StringWriter sw = new StringWriter();
347        PrintWriter pw = new FastPrintWriter(sw, false, 256);
348        tr.printStackTrace(pw);
349        pw.flush();
350        return sw.toString();
351    }
352
353    /**
354     * Low-level logging call.
355     * @param priority The priority/type of this log message
356     * @param tag Used to identify the source of a log message.  It usually identifies
357     *        the class or activity where the log call occurs.
358     * @param msg The message you would like logged.
359     * @return The number of bytes written.
360     */
361    public static int println(int priority, String tag, String msg) {
362        return println_native(LOG_ID_MAIN, priority, tag, msg);
363    }
364
365    /** @hide */ public static final int LOG_ID_MAIN = 0;
366    /** @hide */ public static final int LOG_ID_RADIO = 1;
367    /** @hide */ public static final int LOG_ID_EVENTS = 2;
368    /** @hide */ public static final int LOG_ID_SYSTEM = 3;
369    /** @hide */ public static final int LOG_ID_CRASH = 4;
370
371    /** @hide */ public static native int println_native(int bufID,
372            int priority, String tag, String msg);
373
374    /**
375     * Return the maximum payload the log daemon accepts without truncation.
376     * @return LOGGER_ENTRY_MAX_PAYLOAD.
377     */
378    private static native int logger_entry_max_payload_native();
379
380    /**
381     * Helper function for long messages. Uses the LineBreakBufferedWriter to break
382     * up long messages and stacktraces along newlines, but tries to write in large
383     * chunks. This is to avoid truncation.
384     * @hide
385     */
386    public static int printlns(int bufID, int priority, String tag, String msg,
387            Throwable tr) {
388        ImmediateLogWriter logWriter = new ImmediateLogWriter(bufID, priority, tag);
389        // Acceptable buffer size. Get the native buffer size, subtract two zero terminators,
390        // and the length of the tag.
391        // Note: we implicitly accept possible truncation for Modified-UTF8 differences. It
392        //       is too expensive to compute that ahead of time.
393        int bufferSize = NoPreloadHolder.LOGGER_ENTRY_MAX_PAYLOAD  // Base.
394                - 2                                                // Two terminators.
395                - (tag != null ? tag.length() : 0)                 // Tag length.
396                - 32;                                              // Some slack.
397        // At least assume you can print *some* characters (tag is not too large).
398        bufferSize = Math.max(bufferSize, 100);
399
400        LineBreakBufferedWriter lbbw = new LineBreakBufferedWriter(logWriter, bufferSize);
401
402        lbbw.println(msg);
403
404        if (tr != null) {
405            // This is to reduce the amount of log spew that apps do in the non-error
406            // condition of the network being unavailable.
407            Throwable t = tr;
408            while (t != null) {
409                if (t instanceof UnknownHostException) {
410                    break;
411                }
412                if (t instanceof DeadSystemException) {
413                    lbbw.println("DeadSystemException: The system died; "
414                            + "earlier logs will point to the root cause");
415                    break;
416                }
417                t = t.getCause();
418            }
419            if (t == null) {
420                tr.printStackTrace(lbbw);
421            }
422        }
423
424        lbbw.flush();
425
426        return logWriter.getWritten();
427    }
428
429    /**
430     * NoPreloadHelper class. Caches the LOGGER_ENTRY_MAX_PAYLOAD value to avoid
431     * a JNI call during logging.
432     */
433    static class NoPreloadHolder {
434        public final static int LOGGER_ENTRY_MAX_PAYLOAD =
435                logger_entry_max_payload_native();
436    }
437
438    /**
439     * Helper class to write to the logcat. Different from LogWriter, this writes
440     * the whole given buffer and does not break along newlines.
441     */
442    private static class ImmediateLogWriter extends Writer {
443
444        private int bufID;
445        private int priority;
446        private String tag;
447
448        private int written = 0;
449
450        /**
451         * Create a writer that immediately writes to the log, using the given
452         * parameters.
453         */
454        public ImmediateLogWriter(int bufID, int priority, String tag) {
455            this.bufID = bufID;
456            this.priority = priority;
457            this.tag = tag;
458        }
459
460        public int getWritten() {
461            return written;
462        }
463
464        @Override
465        public void write(char[] cbuf, int off, int len) {
466            // Note: using String here has a bit of overhead as a Java object is created,
467            //       but using the char[] directly is not easier, as it needs to be translated
468            //       to a C char[] for logging.
469            written += println_native(bufID, priority, tag, new String(cbuf, off, len));
470        }
471
472        @Override
473        public void flush() {
474            // Ignored.
475        }
476
477        @Override
478        public void close() {
479            // Ignored.
480        }
481    }
482}


在JNI函数android_util_Log_println_native中,第检查写入的日志记录的内容msgObj是否为null ,接着检查写ru的日志记录的类型值是否位于0和LOG_ID_MAX 之间,其中 0、l 、2和3四个值表示的日志记录的类型分别为main 、radio 、events 和system 。通过这两个合法性检查之后 ,最后就调用日志库 liblog提供的函数__android_log_buf_write来往Logger日志驱动程序中写入日志记录。

代码路径:/frameworks/base/core/jni/android_util_Log.cpp

(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/jni/android_util_Log.cpp)

18#define LOG_NAMESPACE "log.tag."
19#define LOG_TAG "Log_println"
20
21#include <android-base/macros.h>
22#include <assert.h>
23#include <cutils/properties.h>
24#include <log/log.h>               // For LOGGER_ENTRY_MAX_PAYLOAD.
25#include <utils/Log.h>
26#include <utils/String8.h>
27
28#include "jni.h"
29#include "JNIHelp.h"
30#include "utils/misc.h"
31#include "core_jni_helpers.h"
32#include "android_util_Log.h"
33
34namespace android {
35
36struct levels_t {
37    jint verbose;
38    jint debug;
39    jint info;
40    jint warn;
41    jint error;
42    jint assert;
43};
44static levels_t levels;
45
46static jboolean isLoggable(const char* tag, jint level) {
47    return __android_log_is_loggable(level, tag, ANDROID_LOG_INFO);
48}
49
50static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)
51{
52    if (tag == NULL) {
53        return false;
54    }
55
56    const char* chars = env->GetStringUTFChars(tag, NULL);
57    if (!chars) {
58        return false;
59    }
60
61    jboolean result = isLoggable(chars, level);
62
63    env->ReleaseStringUTFChars(tag, chars);
64    return result;
65}
66
67bool android_util_Log_isVerboseLogEnabled(const char* tag) {
68    return isLoggable(tag, levels.verbose);
69}
70
71/*
72 * In class android.util.Log:
73 *  public static native int println_native(int buffer, int priority, String tag, String msg)
74 */
75static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
76        jint bufID, jint priority, jstring tagObj, jstring msgObj)
77{
78    const char* tag = NULL;
79    const char* msg = NULL;
80
81    if (msgObj == NULL) {
82        jniThrowNullPointerException(env, "println needs a message");
83        return -1;
84    }
85
86    if (bufID < 0 || bufID >= LOG_ID_MAX) {
87        jniThrowNullPointerException(env, "bad bufID");
88        return -1;
89    }
90
91    if (tagObj != NULL)
92        tag = env->GetStringUTFChars(tagObj, NULL);
93    msg = env->GetStringUTFChars(msgObj, NULL);
94
95    int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
96
97    if (tag != NULL)
98        env->ReleaseStringUTFChars(tagObj, tag);
99    env->ReleaseStringUTFChars(msgObj, msg);
100
101    return res;
102}
103
104/*
105 * In class android.util.Log:
106 *  private static native int logger_entry_max_payload_native()
107 */
108static jint android_util_Log_logger_entry_max_payload_native(JNIEnv* env ATTRIBUTE_UNUSED,
109                                                             jobject clazz ATTRIBUTE_UNUSED)
110{
111    return static_cast<jint>(LOGGER_ENTRY_MAX_PAYLOAD);
112}
113
114/*
115 * JNI registration.
116 */
117static const JNINativeMethod gMethods[] = {
118    /* name, signature, funcPtr */
119    { "isLoggable",      "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
120    { "println_native",  "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
121    { "logger_entry_max_payload_native",  "()I", (void*) android_util_Log_logger_entry_max_payload_native },
122};
123
124int register_android_util_Log(JNIEnv* env)
125{
126    jclass clazz = FindClassOrDie(env, "android/util/Log");
127
128    levels.verbose = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "VERBOSE", "I"));
129    levels.debug = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "DEBUG", "I"));
130    levels.info = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "INFO", "I"));
131    levels.warn = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "WARN", "I"));
132    levels.error = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ERROR", "I"));
133    levels.assert = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ASSERT", "I"));
134
135    return RegisterMethodsOrDie(env, "android/util/Log", gMethods, NELEM(gMethods));
136}
137
138}; // namespace android


在接口android.ut让Slog定义前面的注释中有一个“@hide”关键字,表示这是一个隐藏接口,只在系统内部使用 ,应用程序一般不应该使用该接口来写入日志记录 。接口android.util.Slog写人的日志记录的类型为 system ,它常用的成员函数有v 、d 、i 、w和e ,对应 的日志记录的优先级分别为 VERBOSE 、DEB UG 、INFO 、WARN 和ERROR ,并且它们都是通过调用接口android.util.Log的JNI方法println_native来实现的 

代码路径:frameworks/base/core/java/android/util/Slog.java

(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/android/util/Slog.java)

17package android.util;
18
19/**
20 * @hide
21 */
22public final class Slog {
23
24    private Slog() {
25    }
26
27    public static int v(String tag, String msg) {
28        return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag, msg);
29    }
30
31    public static int v(String tag, String msg, Throwable tr) {
32        return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag,
33                msg + '\n' + Log.getStackTraceString(tr));
34    }
35
36    public static int d(String tag, String msg) {
37        return Log.println_native(Log.LOG_ID_SYSTEM, Log.DEBUG, tag, msg);
38    }
39
40    public static int d(String tag, String msg, Throwable tr) {
41        return Log.println_native(Log.LOG_ID_SYSTEM, Log.DEBUG, tag,
42                msg + '\n' + Log.getStackTraceString(tr));
43    }
44
45    public static int i(String tag, String msg) {
46        return Log.println_native(Log.LOG_ID_SYSTEM, Log.INFO, tag, msg);
47    }
48
49    public static int i(String tag, String msg, Throwable tr) {
50        return Log.println_native(Log.LOG_ID_SYSTEM, Log.INFO, tag,
51                msg + '\n' + Log.getStackTraceString(tr));
52    }
53
54    public static int w(String tag, String msg) {
55        return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, msg);
56    }
57
58    public static int w(String tag, String msg, Throwable tr) {
59        return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag,
60                msg + '\n' + Log.getStackTraceString(tr));
61    }
62
63    public static int w(String tag, Throwable tr) {
64        return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, Log.getStackTraceString(tr));
65    }
66
67    public static int e(String tag, String msg) {
68        return Log.println_native(Log.LOG_ID_SYSTEM, Log.ERROR, tag, msg);
69    }
70
71    public static int e(String tag, String msg, Throwable tr) {
72        return Log.println_native(Log.LOG_ID_SYSTEM, Log.ERROR, tag,
73                msg + '\n' + Log.getStackTraceString(tr));
74    }
75
76    /**
77     * Like {@link Log#wtf(String, String)}, but will never cause the caller to crash, and
78     * will always be handled asynchronously.  Primarily for use by coding running within
79     * the system process.
80     */
81    public static int wtf(String tag, String msg) {
82        return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, false, true);
83    }
84
85    /**
86     * Like {@link #wtf(String, String)}, but does not output anything to the log.
87     */
88    public static void wtfQuiet(String tag, String msg) {
89        Log.wtfQuiet(Log.LOG_ID_SYSTEM, tag, msg, true);
90    }
91
92    /**
93     * Like {@link Log#wtfStack(String, String)}, but will never cause the caller to crash, and
94     * will always be handled asynchronously.  Primarily for use by coding running within
95     * the system process.
96     */
97    public static int wtfStack(String tag, String msg) {
98        return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, true, true);
99    }
100
101    /**
102     * Like {@link Log#wtf(String, Throwable)}, but will never cause the caller to crash,
103     * and will always be handled asynchronously.  Primarily for use by coding running within
104     * the system process.
105     */
106    public static int wtf(String tag, Throwable tr) {
107        return Log.wtf(Log.LOG_ID_SYSTEM, tag, tr.getMessage(), tr, false, true);
108    }
109
110    /**
111     * Like {@link Log#wtf(String, String, Throwable)}, but will never cause the caller to crash,
112     * and will always be handled asynchronously.  Primarily for use by coding running within
113     * the system process.
114     */
115    public static int wtf(String tag, String msg, Throwable tr) {
116        return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, tr, false, true);
117    }
118
119    public static int println(int priority, String tag, String msg) {
120        return Log.println_native(Log.LOG_ID_SYSTEM, priority, tag, msg);
121    }
122}


接口android.util.EventLog 提供了四个重载版本的 JNI方法writeEvent 向Logger 日志驱动程序中写入类型为events的日志记录 ,这些日志记录的内 容分别为整数 、长整数 、字符串和列表

代码路径:frameworks/base/core/java/android/util/EventLog.java

(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/android/util/EventLog.java)

47public class EventLog {
48    /** @hide */ public EventLog() {}
49
50    private static final String TAG = "EventLog";
51
52    private static final String TAGS_FILE = "/system/etc/event-log-tags";
53    private static final String COMMENT_PATTERN = "^\\s*(#.*)?$";
54    private static final String TAG_PATTERN = "^\\s*(\\d+)\\s+(\\w+)\\s*(\\(.*\\))?\\s*$";
55    private static HashMap<String, Integer> sTagCodes = null;
56    private static HashMap<Integer, String> sTagNames = null;
57
58    /** A previously logged event read from the logs. Instances are thread safe. */
59    public static final class Event {
60        private final ByteBuffer mBuffer;
61        private Exception mLastWtf;
62
63        // Layout of event log entry received from Android logger.
64        //  see system/core/include/log/log.h
65        private static final int LENGTH_OFFSET = 0;
66        private static final int HEADER_SIZE_OFFSET = 2;
67        private static final int PROCESS_OFFSET = 4;
68        private static final int THREAD_OFFSET = 8;
69        private static final int SECONDS_OFFSET = 12;
70        private static final int NANOSECONDS_OFFSET = 16;
71        private static final int UID_OFFSET = 24;
72
73        // Layout for event log v1 format, v2 and v3 use HEADER_SIZE_OFFSET
74        private static final int V1_PAYLOAD_START = 20;
75        private static final int DATA_OFFSET = 4;
76
77        // Value types
78        private static final byte INT_TYPE    = 0;
79        private static final byte LONG_TYPE   = 1;
80        private static final byte STRING_TYPE = 2;
81        private static final byte LIST_TYPE   = 3;
82        private static final byte FLOAT_TYPE = 4;
83
84        /** @param data containing event, read from the system */
85        /*package*/ Event(byte[] data) {
86            mBuffer = ByteBuffer.wrap(data);
87            mBuffer.order(ByteOrder.nativeOrder());
88        }
89
90        /** @return the process ID which wrote the log entry */
91        public int getProcessId() {
92            return mBuffer.getInt(PROCESS_OFFSET);
93        }
94
95        /**
96         * @return the UID which wrote the log entry
97         * @hide
98         */
99        @SystemApi
100        public int getUid() {
101            try {
102                return mBuffer.getInt(UID_OFFSET);
103            } catch (IndexOutOfBoundsException e) {
104                // buffer won't contain the UID if the caller doesn't have permission.
105                return -1;
106            }
107        }
108
109        /** @return the thread ID which wrote the log entry */
110        public int getThreadId() {
111            return mBuffer.getInt(THREAD_OFFSET);
112        }
113
114        /** @return the wall clock time when the entry was written */
115        public long getTimeNanos() {
116            return mBuffer.getInt(SECONDS_OFFSET) * 1000000000l
117                    + mBuffer.getInt(NANOSECONDS_OFFSET);
118        }
119
120        /** @return the type tag code of the entry */
121        public int getTag() {
122            int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
123            if (offset == 0) {
124                offset = V1_PAYLOAD_START;
125            }
126            return mBuffer.getInt(offset);
127        }
128
129        /** @return one of Integer, Long, Float, String, null, or Object[] of same. */
130        public synchronized Object getData() {
131            try {
132                int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
133                if (offset == 0) {
134                    offset = V1_PAYLOAD_START;
135                }
136                mBuffer.limit(offset + mBuffer.getShort(LENGTH_OFFSET));
137                if ((offset + DATA_OFFSET) >= mBuffer.limit()) {
138                    // no payload
139                    return null;
140                }
141                mBuffer.position(offset + DATA_OFFSET); // Just after the tag.
142                return decodeObject();
143            } catch (IllegalArgumentException e) {
144                Log.wtf(TAG, "Illegal entry payload: tag=" + getTag(), e);
145                mLastWtf = e;
146                return null;
147            } catch (BufferUnderflowException e) {
148                Log.wtf(TAG, "Truncated entry payload: tag=" + getTag(), e);
149                mLastWtf = e;
150                return null;
151            }
152        }
153
154        /** @return the loggable item at the current position in mBuffer. */
155        private Object decodeObject() {
156            byte type = mBuffer.get();
157            switch (type) {
158            case INT_TYPE:
159                return mBuffer.getInt();
160
161            case LONG_TYPE:
162                return mBuffer.getLong();
163
164            case FLOAT_TYPE:
165                return mBuffer.getFloat();
166
167            case STRING_TYPE:
168                try {
169                    int length = mBuffer.getInt();
170                    int start = mBuffer.position();
171                    mBuffer.position(start + length);
172                    return new String(mBuffer.array(), start, length, "UTF-8");
173                } catch (UnsupportedEncodingException e) {
174                    Log.wtf(TAG, "UTF-8 is not supported", e);
175                    mLastWtf = e;
176                    return null;
177                }
178
179            case LIST_TYPE:
180                int length = mBuffer.get();
181                if (length < 0) length += 256;  // treat as signed byte
182                Object[] array = new Object[length];
183                for (int i = 0; i < length; ++i) array[i] = decodeObject();
184                return array;
185
186            default:
187                throw new IllegalArgumentException("Unknown entry type: " + type);
188            }
189        }
190
191        /** @hide */
192        public static Event fromBytes(byte[] data) {
193            return new Event(data);
194        }
195
196        /** @hide */
197        public byte[] getBytes() {
198            byte[] bytes = mBuffer.array();
199            return Arrays.copyOf(bytes, bytes.length);
200        }
201
202        /**
203         * Retreive the last WTF error generated by this object.
204         * @hide
205         */
206        //VisibleForTesting
207        public Exception getLastError() {
208            return mLastWtf;
209        }
210
211        /**
212         * Clear the error state for this object.
213         * @hide
214         */
215        //VisibleForTesting
216        public void clearError() {
217            mLastWtf = null;
218        }
219
220        /**
221         * @hide
222         */
223        @Override
224        public boolean equals(Object o) {
225            // Not using ByteBuffer.equals since it takes buffer position into account and we
226            // always use absolute positions here.
227            if (this == o) return true;
228            if (o == null || getClass() != o.getClass()) return false;
229            Event other = (Event) o;
230            return Arrays.equals(mBuffer.array(), other.mBuffer.array());
231        }
232
233        /**
234         * @hide
235         */
236        @Override
237        public int hashCode() {
238            // Not using ByteBuffer.hashCode since it takes buffer position into account and we
239            // always use absolute positions here.
240            return Arrays.hashCode(mBuffer.array());
241        }
242    }
243
244    // We assume that the native methods deal with any concurrency issues.
245
246    /**
247     * Record an event log message.
248     * @param tag The event type tag code
249     * @param value A value to log
250     * @return The number of bytes written
251     */
252    public static native int writeEvent(int tag, int value);
253
254    /**
255     * Record an event log message.
256     * @param tag The event type tag code
257     * @param value A value to log
258     * @return The number of bytes written
259     */
260    public static native int writeEvent(int tag, long value);
261
262    /**
263     * Record an event log message.
264     * @param tag The event type tag code
265     * @param value A value to log
266     * @return The number of bytes written
267     */
268    public static native int writeEvent(int tag, float value);
269
270    /**
271     * Record an event log message.
272     * @param tag The event type tag code
273     * @param str A value to log
274     * @return The number of bytes written
275     */
276    public static native int writeEvent(int tag, String str);
277
278    /**
279     * Record an event log message.
280     * @param tag The event type tag code
281     * @param list A list of values to log
282     * @return The number of bytes written
283     */
284    public static native int writeEvent(int tag, Object... list);
285
286    /**
287     * Read events from the log, filtered by type.
288     * @param tags to search for
289     * @param output container to add events into
290     * @throws IOException if something goes wrong reading events
291     */
292    public static native void readEvents(int[] tags, Collection<Event> output)
293            throws IOException;
294
295    /**
296     * Read events from the log, filtered by type, blocking until logs are about to be overwritten.
297     * @param tags to search for
298     * @param timestamp timestamp allow logs before this time to be overwritten.
299     * @param output container to add events into
300     * @throws IOException if something goes wrong reading events
301     * @hide
302     */
303    @SystemApi
304    public static native void readEventsOnWrapping(int[] tags, long timestamp,
305            Collection<Event> output)
306            throws IOException;
307
308    /**
309     * Get the name associated with an event type tag code.
310     * @param tag code to look up
311     * @return the name of the tag, or null if no tag has that number
312     */
313    public static String getTagName(int tag) {
314        readTagsFile();
315        return sTagNames.get(tag);
316    }
317
318    /**
319     * Get the event type tag code associated with an event name.
320     * @param name of event to look up
321     * @return the tag code, or -1 if no tag has that name
322     */
323    public static int getTagCode(String name) {
324        readTagsFile();
325        Integer code = sTagCodes.get(name);
326        return code != null ? code : -1;
327    }
328
329    /**
330     * Read TAGS_FILE, populating sTagCodes and sTagNames, if not already done.
331     */
332    private static synchronized void readTagsFile() {
333        if (sTagCodes != null && sTagNames != null) return;
334
335        sTagCodes = new HashMap<String, Integer>();
336        sTagNames = new HashMap<Integer, String>();
337
338        Pattern comment = Pattern.compile(COMMENT_PATTERN);
339        Pattern tag = Pattern.compile(TAG_PATTERN);
340        BufferedReader reader = null;
341        String line;
342
343        try {
344            reader = new BufferedReader(new FileReader(TAGS_FILE), 256);
345            while ((line = reader.readLine()) != null) {
346                if (comment.matcher(line).matches()) continue;
347
348                Matcher m = tag.matcher(line);
349                if (!m.matches()) {
350                    Log.wtf(TAG, "Bad entry in " + TAGS_FILE + ": " + line);
351                    continue;
352                }
353
354                try {
355                    int num = Integer.parseInt(m.group(1));
356                    String name = m.group(2);
357                    sTagCodes.put(name, num);
358                    sTagNames.put(num, name);
359                } catch (NumberFormatException e) {
360                    Log.wtf(TAG, "Error in " + TAGS_FILE + ": " + line, e);
361                }
362            }
363        } catch (IOException e) {
364            Log.wtf(TAG, "Error reading " + TAGS_FILE, e);
365            // Leave the maps existing but unpopulated
366        } finally {
367            try { if (reader != null) reader.close(); } catch (IOException e) {}
368        }
369    }
370}


代码路径:frameworks/base/core/jni/android_util_EventLog.cpp

(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/jni/android_util_EventLog.cpp)

16
17#include <fcntl.h>
18
19#include <log/log_event_list.h>
20
21#include <log/log.h>
22
23#include "JNIHelp.h"
24#include "core_jni_helpers.h"
25#include "jni.h"
26
27#define UNUSED  __attribute__((__unused__))
28
29namespace android {
30
31static jclass gCollectionClass;
32static jmethodID gCollectionAddID;
33
34static jclass gEventClass;
35static jmethodID gEventInitID;
36
37static jclass gIntegerClass;
38static jfieldID gIntegerValueID;
39
40static jclass gLongClass;
41static jfieldID gLongValueID;
42
43static jclass gFloatClass;
44static jfieldID gFloatValueID;
45
46static jclass gStringClass;
47
48/*
49 * In class android.util.EventLog:
50 *  static native int writeEvent(int tag, int value)
51 */
52static jint android_util_EventLog_writeEvent_Integer(JNIEnv* env UNUSED,
53                                                     jobject clazz UNUSED,
54                                                     jint tag, jint value)
55{
56    android_log_event_list ctx(tag);
57    ctx << (int32_t)value;
58    return ctx.write();
59}
60
61/*
62 * In class android.util.EventLog:
63 *  static native int writeEvent(long tag, long value)
64 */
65static jint android_util_EventLog_writeEvent_Long(JNIEnv* env UNUSED,
66                                                  jobject clazz UNUSED,
67                                                  jint tag, jlong value)
68{
69    android_log_event_list ctx(tag);
70    ctx << (int64_t)value;
71    return ctx.write();
72}
73
74/*
75 * In class android.util.EventLog:
76 *  static native int writeEvent(long tag, float value)
77 */
78static jint android_util_EventLog_writeEvent_Float(JNIEnv* env UNUSED,
79                                                  jobject clazz UNUSED,
80                                                  jint tag, jfloat value)
81{
82    android_log_event_list ctx(tag);
83    ctx << (float)value;
84    return ctx.write();
85}
86
87/*
88 * In class android.util.EventLog:
89 *  static native int writeEvent(int tag, String value)
90 */
91static jint android_util_EventLog_writeEvent_String(JNIEnv* env,
92                                                    jobject clazz UNUSED,
93                                                    jint tag, jstring value) {
94    android_log_event_list ctx(tag);
95    // Don't throw NPE -- I feel like it's sort of mean for a logging function
96    // to be all crashy if you pass in NULL -- but make the NULL value explicit.
97    if (value != NULL) {
98        const char *str = env->GetStringUTFChars(value, NULL);
99        ctx << str;
100        env->ReleaseStringUTFChars(value, str);
101    } else {
102        ctx << "NULL";
103    }
104    return ctx.write();
105}
106
107/*
108 * In class android.util.EventLog:
109 *  static native int writeEvent(long tag, Object... value)
110 */
111static jint android_util_EventLog_writeEvent_Array(JNIEnv* env, jobject clazz,
112                                                   jint tag, jobjectArray value) {
113    android_log_event_list ctx(tag);
114
115    if (value == NULL) {
116        ctx << "[NULL]";
117        return ctx.write();
118    }
119
120    jsize copied = 0, num = env->GetArrayLength(value);
121    for (; copied < num && copied < 255; ++copied) {
122        if (ctx.status()) break;
123        jobject item = env->GetObjectArrayElement(value, copied);
124        if (item == NULL) {
125            ctx << "NULL";
126        } else if (env->IsInstanceOf(item, gStringClass)) {
127            const char *str = env->GetStringUTFChars((jstring) item, NULL);
128            ctx << str;
129            env->ReleaseStringUTFChars((jstring) item, str);
130        } else if (env->IsInstanceOf(item, gIntegerClass)) {
131            ctx << (int32_t)env->GetIntField(item, gIntegerValueID);
132        } else if (env->IsInstanceOf(item, gLongClass)) {
133            ctx << (int64_t)env->GetLongField(item, gLongValueID);
134        } else if (env->IsInstanceOf(item, gFloatClass)) {
135            ctx << (float)env->GetFloatField(item, gFloatValueID);
136        } else {
137            jniThrowException(env,
138                    "java/lang/IllegalArgumentException",
139                    "Invalid payload item type");
140            return -1;
141        }
142        env->DeleteLocalRef(item);
143    }
144    return ctx.write();
145}
146
147static void readEvents(JNIEnv* env, int loggerMode, jintArray tags, jlong startTime, jobject out) {
148    struct logger_list *logger_list;
149    if (startTime) {
150        logger_list = android_logger_list_alloc_time(loggerMode,
151                log_time(startTime / NS_PER_SEC, startTime % NS_PER_SEC), 0);
152    } else {
153        logger_list = android_logger_list_alloc(loggerMode, 0, 0);
154    }
155    if (!logger_list) {
156        jniThrowIOException(env, errno);
157        return;
158    }
159
160    if (!android_logger_open(logger_list, LOG_ID_EVENTS)) {
161        jniThrowIOException(env, errno);
162        android_logger_list_free(logger_list);
163        return;
164    }
165
166    jsize tagLength = env->GetArrayLength(tags);
167    jint *tagValues = env->GetIntArrayElements(tags, NULL);
168
169    while (1) {
170        log_msg log_msg;
171        int ret = android_logger_list_read(logger_list, &log_msg);
172
173        if (ret == 0) {
174            break;
175        }
176        if (ret < 0) {
177            if (ret == -EINTR) {
178                continue;
179            }
180            if (ret == -EINVAL) {
181                jniThrowException(env, "java/io/IOException", "Event too short");
182            } else if (ret != -EAGAIN) {
183                jniThrowIOException(env, -ret);  // Will throw on return
184            }
185            break;
186        }
187
188        if (log_msg.id() != LOG_ID_EVENTS) {
189            continue;
190        }
191
192        int32_t tag = * (int32_t *) log_msg.msg();
193
194        int found = 0;
195        for (int i = 0; !found && i < tagLength; ++i) {
196            found = (tag == tagValues[i]);
197        }
198
199        if (found) {
200            jsize len = ret;
201            jbyteArray array = env->NewByteArray(len);
202            if (array == NULL) {
203                break;
204            }
205
206            jbyte *bytes = env->GetByteArrayElements(array, NULL);
207            memcpy(bytes, log_msg.buf, len);
208            env->ReleaseByteArrayElements(array, bytes, 0);
209
210            jobject event = env->NewObject(gEventClass, gEventInitID, array);
211            if (event == NULL) {
212                break;
213            }
214
215            env->CallBooleanMethod(out, gCollectionAddID, event);
216            env->DeleteLocalRef(event);
217            env->DeleteLocalRef(array);
218        }
219    }
220
221    android_logger_list_close(logger_list);
222
223    env->ReleaseIntArrayElements(tags, tagValues, 0);
224}
225
226/*
227 * In class android.util.EventLog:
228 *  static native void readEvents(int[] tags, Collection<Event> output)
229 *
230 *  Reads events from the event log
231 */
232static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz UNUSED,
233                                             jintArray tags,
234                                             jobject out) {
235
236    if (tags == NULL || out == NULL) {
237        jniThrowNullPointerException(env, NULL);
238        return;
239    }
240
241    readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, tags, 0, out);
242 }
243/*
244 * In class android.util.EventLog:
245 *  static native void readEventsOnWrapping(int[] tags, long timestamp, Collection<Event> output)
246 *
247 *  Reads events from the event log, blocking until events after timestamp are to be overwritten.
248 */
249static void android_util_EventLog_readEventsOnWrapping(JNIEnv* env, jobject clazz UNUSED,
250                                             jintArray tags,
251                                             jlong timestamp,
252                                             jobject out) {
253    if (tags == NULL || out == NULL) {
254        jniThrowNullPointerException(env, NULL);
255        return;
256    }
257    readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK | ANDROID_LOG_WRAP,
258            tags, timestamp, out);
259}
260
261/*
262 * JNI registration.
263 */
264static const JNINativeMethod gRegisterMethods[] = {
265    /* name, signature, funcPtr */
266    { "writeEvent", "(II)I", (void*) android_util_EventLog_writeEvent_Integer },
267    { "writeEvent", "(IJ)I", (void*) android_util_EventLog_writeEvent_Long },
268    { "writeEvent", "(IF)I", (void*) android_util_EventLog_writeEvent_Float },
269    { "writeEvent",
270      "(ILjava/lang/String;)I",
271      (void*) android_util_EventLog_writeEvent_String
272    },
273    { "writeEvent",
274      "(I[Ljava/lang/Object;)I",
275      (void*) android_util_EventLog_writeEvent_Array
276    },
277    { "readEvents",
278      "([ILjava/util/Collection;)V",
279      (void*) android_util_EventLog_readEvents
280    },
281    { "readEventsOnWrapping",
282      "([IJLjava/util/Collection;)V",
283      (void*) android_util_EventLog_readEventsOnWrapping
284    },
285};
286
287static struct { const char *name; jclass *clazz; } gClasses[] = {
288    { "android/util/EventLog$Event", &gEventClass },
289    { "java/lang/Integer", &gIntegerClass },
290    { "java/lang/Long", &gLongClass },
291    { "java/lang/Float", &gFloatClass },
292    { "java/lang/String", &gStringClass },
293    { "java/util/Collection", &gCollectionClass },
294};
295
296static struct { jclass *c; const char *name, *ft; jfieldID *id; } gFields[] = {
297    { &gIntegerClass, "value", "I", &gIntegerValueID },
298    { &gLongClass, "value", "J", &gLongValueID },
299    { &gFloatClass, "value", "F", &gFloatValueID },
300};
301
302static struct { jclass *c; const char *name, *mt; jmethodID *id; } gMethods[] = {
303    { &gEventClass, "<init>", "([B)V", &gEventInitID },
304    { &gCollectionClass, "add", "(Ljava/lang/Object;)Z", &gCollectionAddID },
305};
306
307int register_android_util_EventLog(JNIEnv* env) {
308    for (int i = 0; i < NELEM(gClasses); ++i) {
309        jclass clazz = FindClassOrDie(env, gClasses[i].name);
310        *gClasses[i].clazz = MakeGlobalRefOrDie(env, clazz);
311    }
312
313    for (int i = 0; i < NELEM(gFields); ++i) {
314        *gFields[i].id = GetFieldIDOrDie(env,
315                *gFields[i].c, gFields[i].name, gFields[i].ft);
316    }
317
318    for (int i = 0; i < NELEM(gMethods); ++i) {
319        *gMethods[i].id = GetMethodIDOrDie(env,
320                *gMethods[i].c, gMethods[i].name, gMethods[i].mt);
321    }
322
323    return RegisterMethodsOrDie(
324            env,
325            "android/util/EventLog",
326            gRegisterMethods, NELEM(gRegisterMethods));
327}
328
329}; // namespace android

4.Logcat工具

Logcat是内置在Android系统中的一个实用工具,可以在主机上执行 adb logcat命令来查看目标设备上的日志记录

代码主要路径:

http://androidxref.com/8.0.0_r4/xref/

    /system/core/include/log/logprint.h
    /system/core/include/log/event_tag_map.h
    /system/core/include/log/logger.h
    /system/core/include/android/log.h
    /system/core/liblog/event_tag_map.cpp

    /system/core/logcat/(目录)

由于平时我们主要是使用此logcat工具或者平台提供的MTKlogger或者hiview来抓取log,所以我们暂时不对此log工具进行讲解

主要说一下logcat的用法:

adb logcat 命令格式 : adb logcat [选项] [过滤项], 其中 选项 和 过滤项 在 中括号 [] 中, 说明这是可选的;
-- "-s"选项 : 设置输出日志的标签, 只显示该标签的日志;
--"-f"选项 : 将日志输出到文件, 默认输出到标准输出流中, -f 参数执行不成功;
--"-r"选项 : 按照每千字节输出日志, 需要 -f 参数, 不过这个命令没有执行成功;
--"-n"选项 : 设置日志输出的最大数目, 需要 -r 参数, 这个执行感觉跟 adb logcat效果一样;
--"-v"选项 : 设置日志的输出格式, 注意只能设置一项;
--"-c"选项 : 清空所有的日志缓存信息;
--"-d"选项 : 将缓存的日志输出到屏幕上, 并且不会阻塞;
--"-t"选项 : 输出最近的几行日志, 输出完退出, 不阻塞;
--"-g"选项 : 查看日志缓冲区信息;
--"-b"选项 : 加载一个日志缓冲区, 默认是 main;
--"-B"选项 : 以二进制形式输出日志;


(2) 过滤项解析
过滤项格式 : <tag>[:priority] , 标签:日志等级, 默认的日志过滤项是 " *:I " ;
-- V : Verbose (明细);
-- D : Debug (调试);
-- I : Info (信息);
-- W : Warn (警告);
-- E : Error (错误);
-- F: Fatal (严重错误);
-- S : Silent(Super all output) (最高的优先级, 可能不会记载东西);


2. 使用管道过滤日志
(1) 过滤固定字符串
过滤固定字符串 : 只要命令行出现的日志都可以过滤, 不管是不是标签;
(2) 使用正则表达式匹配

分析日志 : 该日志开头两个字符是 "V/", 后面开始就是标签, 写一个正则表达式 "^..ActivityManager", 就可以匹配日志中的 "V/ActivityManager" 字符串;





----------------------------------------------------------------------------------------------------------------------------

源码地址:http://androidxref.com/8.0.0_r4/xref/system/core/liblog/logger_write.c

/system/core/liblog/logger_write.c

/*

 * Copyright (C) 2007-2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include <errno.h>
#include <stdatomic.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>


#ifdef __BIONIC__
#include <android/set_abort_message.h>
#endif


#include <log/event_tag_map.h>
#include <log/log_transport.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>


#include "config_read.h" /* __android_log_config_read_close() definition */
#include "config_write.h"
#include "log_portability.h"
#include "logger.h"


#define LOG_BUF_SIZE 1024


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;


/*
 * This is used by the C++ code to decide if it should write logs through
 * the C code.  Basically, if /dev/socket/logd is available, we're running in
 * the simulator rather than a desktop tool and want to use the device.
 */
static enum {
  kLogUninitialized,
  kLogNotAvailable,
  kLogAvailable
} g_log_status = kLogUninitialized;


static int check_log_uid_permissions() {//对进程权限进行检查
#if defined(__ANDROID__)
  uid_t uid = __android_log_uid();


  /* Matches clientHasLogCredentials() in logd */
  if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
    uid = geteuid();
    if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
      gid_t gid = getgid();
      if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
        gid = getegid();
        if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
          int num_groups;
          gid_t* groups;


          num_groups = getgroups(0, NULL);
          if (num_groups <= 0) {
            return -EPERM;
          }
          groups = calloc(num_groups, sizeof(gid_t));
          if (!groups) {
            return -ENOMEM;
          }
          num_groups = getgroups(num_groups, groups);
          while (num_groups > 0) {
            if (groups[num_groups - 1] == AID_LOG) {
              break;
            }
            --num_groups;
          }
          free(groups);
          if (num_groups <= 0) {
            return -EPERM;
          }
        }
      }
    }
  }
#endif
  return 0;
}


static void __android_log_cache_available(
    struct android_log_transport_write* node) {//对log缓存进行检查
  size_t i;


  if (node->logMask) {
    return;
  }


  for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
    if (node->write && (i != LOG_ID_KERNEL) &&
        ((i != LOG_ID_SECURITY) || (check_log_uid_permissions() == 0)) &&
        (!node->available || ((*node->available)(i) >= 0))) {
      node->logMask |= 1 << i;
    }
  }
}


LIBLOG_ABI_PUBLIC int __android_log_dev_available() {//是否允许kernel的log打印
  struct android_log_transport_write* node;


  if (list_empty(&__android_log_transport_write)) {
    return kLogUninitialized;
  }


  write_transport_for_each(node, &__android_log_transport_write) {
    __android_log_cache_available(node);
    if (node->logMask) {
      return kLogAvailable;
    }
  }
  return kLogNotAvailable;
}


#if defined(__ANDROID__)
static atomic_uintptr_t tagMap;
#endif


/*
 * Release any logger resources. A new log write will immediately re-acquire.
 */
LIBLOG_ABI_PUBLIC void __android_log_close() {//关闭log写入
  struct android_log_transport_write* transport;
#if defined(__ANDROID__)
  EventTagMap* m;
#endif


  __android_log_lock();


  write_to_log = __write_to_log_init;


  /*
   * Threads that are actively writing at this point are not held back
   * by a lock and are at risk of dropping the messages with a return code
   * -EBADF. Prefer to return error code than add the overhead of a lock to
   * each log writing call to guarantee delivery. In addition, anyone
   * calling this is doing so to release the logging resources and shut down,
   * for them to do so with outstanding log requests in other threads is a
   * disengenuous use of this function.
   */


  write_transport_for_each(transport, &__android_log_persist_write) {
    if (transport->close) {
      (*transport->close)();
    }
  }


  write_transport_for_each(transport, &__android_log_transport_write) {
    if (transport->close) {
      (*transport->close)();
    }
  }


  __android_log_config_write_close();


#if defined(__ANDROID__)
  /*
   * Additional risk here somewhat mitigated by immediately unlock flushing
   * the processor cache. The multi-threaded race that we choose to accept,
   * to minimize locking, is an atomic_load in a writer picking up a value
   * just prior to entering this routine. There will be an use after free.
   *
   * Again, anyone calling this is doing so to release the logging resources
   * is most probably going to quiesce then shut down; or to restart after
   * a fork so the risk should be non-existent. For this reason we
   * choose a mitigation stance for efficiency instead of incuring the cost
   * of a lock for every log write.
   */
  m = (EventTagMap*)atomic_exchange(&tagMap, (uintptr_t)0);
#endif


  __android_log_unlock();


#if defined(__ANDROID__)
  if (m != (EventTagMap*)(uintptr_t)-1LL) android_closeEventTagMap(m);
#endif
}


/* log_init_lock assumed */
static int __write_to_log_initialize() {
  struct android_log_transport_write* transport;
  struct listnode* n;
  int i = 0, ret = 0;


  __android_log_config_write();
  write_transport_for_each_safe(transport, n, &__android_log_transport_write) {
    __android_log_cache_available(transport);
    if (!transport->logMask) {
      list_remove(&transport->node);
      continue;
    }
    if (!transport->open || ((*transport->open)() < 0)) {
      if (transport->close) {
        (*transport->close)();
      }
      list_remove(&transport->node);
      continue;
    }
    ++ret;
  }
  write_transport_for_each_safe(transport, n, &__android_log_persist_write) {
    __android_log_cache_available(transport);
    if (!transport->logMask) {
      list_remove(&transport->node);
      continue;
    }
    if (!transport->open || ((*transport->open)() < 0)) {
      if (transport->close) {
        (*transport->close)();
      }
      list_remove(&transport->node);
      continue;
    }
    ++i;
  }
  if (!ret && !i) {
    return -ENODEV;
  }


  return ret;
}


/*
 * Extract a 4-byte value from a byte stream. le32toh open coded
 */
static inline uint32_t get4LE(const uint8_t* src) {//从字节流中提取一个4字节的值。le32toh开放编码
  return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
}


static int __write_to_log_daemon(log_id_t log_id, struct iovec* vec, size_t nr) {
  struct android_log_transport_write* node;
  int ret;
  struct timespec ts;
  size_t len, i;


  for (len = i = 0; i < nr; ++i) {
    len += vec[i].iov_len;
  }
  if (!len) {
    return -EINVAL;
  }


#if defined(__ANDROID__)
  clock_gettime(android_log_clockid(), &ts);


  if (log_id == LOG_ID_SECURITY) {
    if (vec[0].iov_len < 4) {
      return -EINVAL;
    }


    ret = check_log_uid_permissions();
    if (ret < 0) {
      return ret;
    }
    if (!__android_log_security()) {
      /* If only we could reset downstream logd counter */
      return -EPERM;
    }
  } else if (log_id == LOG_ID_EVENTS) {
    const char* tag;
    size_t len;
    EventTagMap *m, *f;


    if (vec[0].iov_len < 4) {
      return -EINVAL;
    }


    tag = NULL;
    len = 0;
    f = NULL;
    m = (EventTagMap*)atomic_load(&tagMap);


    if (!m) {
      ret = __android_log_trylock();
      m = (EventTagMap*)atomic_load(&tagMap); /* trylock flush cache */
      if (!m) {
        m = android_openEventTagMap(NULL);
        if (ret) { /* trylock failed, use local copy, mark for close */
          f = m;
        } else {
          if (!m) { /* One chance to open map file */
            m = (EventTagMap*)(uintptr_t)-1LL;
          }
          atomic_store(&tagMap, (uintptr_t)m);
        }
      }
      if (!ret) { /* trylock succeeded, unlock */
        __android_log_unlock();
      }
    }
    if (m && (m != (EventTagMap*)(uintptr_t)-1LL)) {
      tag = android_lookupEventTag_len(m, &len, get4LE(vec[0].iov_base));
    }
    ret = __android_log_is_loggable_len(ANDROID_LOG_INFO, tag, len,
                                        ANDROID_LOG_VERBOSE);
    if (f) { /* local copy marked for close */
      android_closeEventTagMap(f);
    }
    if (!ret) {
      return -EPERM;
    }
  } else {
    /* Validate the incoming tag, tag content can not split across iovec */
    char prio = ANDROID_LOG_VERBOSE;
    const char* tag = vec[0].iov_base;
    size_t len = vec[0].iov_len;
    if (!tag) {
      len = 0;
    }
    if (len > 0) {
      prio = *tag;
      if (len > 1) {
        --len;
        ++tag;
      } else {
        len = vec[1].iov_len;
        tag = ((const char*)vec[1].iov_base);
        if (!tag) {
          len = 0;
        }
      }
    }
    /* tag must be nul terminated */
    if (tag && strnlen(tag, len) >= len) {
      tag = NULL;
    }


    if (!__android_log_is_loggable_len(prio, tag, len - 1, ANDROID_LOG_VERBOSE)) {
      return -EPERM;
    }
  }
#else
  /* simulate clock_gettime(CLOCK_REALTIME, &ts); */
  {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    ts.tv_sec = tv.tv_sec;
    ts.tv_nsec = tv.tv_usec * 1000;
  }
#endif


  ret = 0;
  i = 1 << log_id;
  write_transport_for_each(node, &__android_log_transport_write) {
    if (node->logMask & i) {
      ssize_t retval;
      retval = (*node->write)(log_id, &ts, vec, nr);
      if (ret >= 0) {
        ret = retval;
      }
    }
  }


  write_transport_for_each(node, &__android_log_persist_write) {
    if (node->logMask & i) {
      (void)(*node->write)(log_id, &ts, vec, nr);
    }
  }


  return ret;
}


static int __write_to_log_init(log_id_t log_id, struct iovec* vec, size_t nr) {
  __android_log_lock();


  if (write_to_log == __write_to_log_init) {
    int ret;


    ret = __write_to_log_initialize();
    if (ret < 0) {
      __android_log_unlock();
      if (!list_empty(&__android_log_persist_write)) {
        __write_to_log_daemon(log_id, vec, nr);
      }
      return ret;
    }


    write_to_log = __write_to_log_daemon;
  }


  __android_log_unlock();


  return write_to_log(log_id, vec, nr);
}


LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char* tag,
                                          const char* msg) {//写入应用层log
  return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
}


LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
                                              const char* tag, const char* msg) {//在默认情况下,函数__android_log_buf_write写入的日志记录类型为main。然后,如果传进来的日志记录的标签以“RIL”等标志开头,那么它会被认为是类型是radio的日志记录
  struct iovec vec[3];
  char tmp_tag[32];


  if (!tag) tag = "";


  /* XXX: This needs to go! */
  if ((bufID != LOG_ID_RADIO) &&
      (!strcmp(tag, "HTC_RIL") ||
       !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
       !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" 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;
    /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
    snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
    tag = tmp_tag;
  }


#if __BIONIC__
  if (prio == ANDROID_LOG_FATAL) {
    android_set_abort_message(msg);
  }
#endif


  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);
}


LIBLOG_ABI_PUBLIC int __android_log_vprint(int prio, const char* tag,
                                           const char* fmt, va_list ap) {//通过调用,写入应用层log
  char buf[LOG_BUF_SIZE];


  vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);


  return __android_log_write(prio, tag, buf);
}


LIBLOG_ABI_PUBLIC int __android_log_print(int prio, const char* tag,
                                          const char* fmt, ...) {
  va_list ap;
  char 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);
}


LIBLOG_ABI_PUBLIC int __android_log_buf_print(int bufID, int prio,
                                              const char* tag, const char* fmt,
                                              ...) {
  va_list ap;
  char buf[LOG_BUF_SIZE];


  va_start(ap, fmt);
  vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
  va_end(ap);


  return __android_log_buf_write(bufID, prio, tag, buf);
}


LIBLOG_ABI_PUBLIC void __android_log_assert(const char* cond, const char* tag,
                                            const char* fmt, ...) {//写入应用层log
  char buf[LOG_BUF_SIZE];


  if (fmt) {
    va_list ap;
    va_start(ap, fmt);
    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
    va_end(ap);
  } else {
    /* Msg not provided, log condition.  N.B. Do not use cond directly as
     * format string as it could contain spurious '%' syntax (e.g.
     * "%d" in "blocks%devs == 0").
     */
    if (cond)
      snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
    else
      strcpy(buf, "Unspecified assertion failed");
  }


  // Log assertion failures to stderr for the benefit of "adb shell" users
  // and gtests (http://b/23675822).
  struct iovec iov[2] = {
    { buf, strlen(buf) }, { (char*)"\n", 1 },
  };
  TEMP_FAILURE_RETRY(writev(2, iov, 2));


  __android_log_write(ANDROID_LOG_FATAL, tag, buf);
  abort(); /* abort so we have a chance to debug the situation */
           /* NOTREACHED */
}


LIBLOG_ABI_PUBLIC int __android_log_bwrite(int32_t tag, const void* payload,
                                           size_t len) {
  struct iovec vec[2];


  vec[0].iov_base = &tag;
  vec[0].iov_len = sizeof(tag);
  vec[1].iov_base = (void*)payload;
  vec[1].iov_len = len;


  return write_to_log(LOG_ID_EVENTS, vec, 2);
}


LIBLOG_ABI_PUBLIC int __android_log_security_bwrite(int32_t tag,
                                                    const void* payload,
                                                    size_t len) {//整数写入安全日志
  struct iovec vec[2];


  vec[0].iov_base = &tag;
  vec[0].iov_len = sizeof(tag);
  vec[1].iov_base = (void*)payload;
  vec[1].iov_len = len;


  return write_to_log(LOG_ID_SECURITY, vec, 2);
}


/*
 * Like __android_log_bwrite, but takes the type as well.  Doesn't work
 * for the general case where we're generating lists of stuff, but very
 * handy if we just want to dump an integer into the log.
 */
LIBLOG_ABI_PUBLIC int __android_log_btwrite(int32_t tag, char type,
                                            const void* payload, size_t len) {//整数写入log
  struct iovec vec[3];


  vec[0].iov_base = &tag;
  vec[0].iov_len = sizeof(tag);
  vec[1].iov_base = &type;
  vec[1].iov_len = sizeof(type);
  vec[2].iov_base = (void*)payload;
  vec[2].iov_len = len;


  return write_to_log(LOG_ID_EVENTS, vec, 3);
}


/*
 * Like __android_log_bwrite, but used for writing strings to the
 * event log.
 */
LIBLOG_ABI_PUBLIC int __android_log_bswrite(int32_t tag, const char* payload) {//字符串写入event的log
  struct iovec vec[4];
  char type = EVENT_TYPE_STRING;
  uint32_t len = strlen(payload);


  vec[0].iov_base = &tag;
  vec[0].iov_len = sizeof(tag);
  vec[1].iov_base = &type;
  vec[1].iov_len = sizeof(type);
  vec[2].iov_base = &len;
  vec[2].iov_len = sizeof(len);
  vec[3].iov_base = (void*)payload;
  vec[3].iov_len = len;


  return write_to_log(LOG_ID_EVENTS, vec, 4);
}


/*
 * Like __android_log_security_bwrite, but used for writing strings to the
 * security log.
 */
LIBLOG_ABI_PUBLIC int __android_log_security_bswrite(int32_t tag,
                                                     const char* payload) {//字符串写入安全log的日志
  struct iovec vec[4];
  char type = EVENT_TYPE_STRING;
  uint32_t len = strlen(payload);


  vec[0].iov_base = &tag;
  vec[0].iov_len = sizeof(tag);
  vec[1].iov_base = &type;
  vec[1].iov_len = sizeof(type);
  vec[2].iov_base = &len;
  vec[2].iov_len = sizeof(len);
  vec[3].iov_base = (void*)payload;
  vec[3].iov_len = len;


  return write_to_log(LOG_ID_SECURITY, vec, 4);
}


static int __write_to_log_null(log_id_t log_id, struct iovec* vec, size_t nr) {//log写入设备是否为空进行判断
  size_t len, i;


  if ((log_id < LOG_ID_MIN) || (log_id >= LOG_ID_MAX)) {
    return -EINVAL;
  }


  for (len = i = 0; i < nr; ++i) {
    len += vec[i].iov_len;
  }
  if (!len) {
    return -EINVAL;
  }
  return len;
}


/* Following functions need access to our internal write_to_log status */


LIBLOG_HIDDEN int __android_log_transport;


LIBLOG_ABI_PUBLIC int android_set_log_transport(int transport_flag) {////设置内部log状态
  int retval;


  if (transport_flag < 0) {
    return -EINVAL;
  }


  retval = LOGGER_NULL;


  __android_log_lock();


  if (transport_flag & LOGGER_NULL) {
    write_to_log = __write_to_log_null;


    __android_log_unlock();


    return retval;
  }


  __android_log_transport &= LOGGER_LOCAL | LOGGER_LOGD | LOGGER_STDERR;


  transport_flag &= LOGGER_LOCAL | LOGGER_LOGD | LOGGER_STDERR;


  if (__android_log_transport != transport_flag) {
    __android_log_transport = transport_flag;
    __android_log_config_write_close();
    __android_log_config_read_close();


    write_to_log = __write_to_log_init;
    /* generically we only expect these two values for write_to_log */
  } else if ((write_to_log != __write_to_log_init) &&
             (write_to_log != __write_to_log_daemon)) {
    write_to_log = __write_to_log_init;
  }


  retval = __android_log_transport;


  __android_log_unlock();


  return retval;
}


LIBLOG_ABI_PUBLIC int android_get_log_transport() {//得到的内部log状态
  int ret = LOGGER_DEFAULT;


  __android_log_lock();
  if (write_to_log == __write_to_log_null) {
    ret = LOGGER_NULL;
  } else {
    __android_log_transport &= LOGGER_LOCAL | LOGGER_LOGD | LOGGER_STDERR;
    ret = __android_log_transport;
    if ((write_to_log != __write_to_log_init) &&
        (write_to_log != __write_to_log_daemon)) {
      ret = -EINVAL;
    }
  }
  __android_log_unlock();


  return ret;
}