Android8.0.0-r4的log系統

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類型的日誌是與無線設備相關的,數量龐大,所以單獨記錄。


                                                                                    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(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"選項 : 設置輸出日誌的標籤, 只顯示該標籤的日誌;
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/ --"-t"選項 : 輸出最近的幾行日誌, 輸出完退出, 不阻塞;--"-g"選項 : 查看日誌緩衝區信息;--"-b"選項 : 加載一個日誌緩衝區, 默認是 main;--"-B"選項 : 以二進制形式輸出日誌;(2) 過濾項解析過濾項格式 : <tag>[:priority] , 標籤:日誌等級, 默認的日誌過濾項是 " *:I " ;-- V : Verbose (明細);-- D : Debug (調試);

相關文章
相關標籤/搜索