赞
踩
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在开始的时候被设置为函数__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.<YOUR_LOG_TAG> <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.<YOUR_LOG_TAG>=<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 ProjectCopyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。