在分析Android系统或者应用相关的问题时,经常会查看EventLog,它非常简洁明了地展现当前系统以及应用行为的各种状态,简单的看下其原理。
在文件frameworks/base/services/core/java/com/android/server/EventLogTags.logtags
有如下内容:
# ---------------------------
# PowerManagerService.java
# ---------------------------
# This is logged when the device is being forced to sleep (typically by
# the user pressing the power button).
2724 power_sleep_requested (wakeLocksCleared|1|1)
# This is logged when the screen on broadcast has completed
2725 power_screen_broadcast_send (wakelockCount|1|1)
# This is logged when the screen broadcast has completed
2726 power_screen_broadcast_done (on|1|5),(broadcastDuration|2|3),(wakelockCount|1|1)
# This is logged when the screen on broadcast has completed
2727 power_screen_broadcast_stop (which|1|5),(wakelockCount|1|1)
# This is logged when the screen is turned on or off.
2728 power_screen_state (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1)
# This is logged when the partial wake lock (keeping the device awake
# regardless of whether the screen is off) is acquired or released.
2729 power_partial_wake_state (releasedorAcquired|1|5),(tag|3)
#
# Leave IDs through 2739 for more power logs (2730 used by battery_discharge above)
#
实际上EventLogTags.logtags类文件还有很多,例如:
frameworks/native/services/surfaceflinger/EventLog/EventLogTags.logtag
frameworks/base/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
frameworks/base/services/core/java/com/android/server/am/EventLogTags.logtags
根据:
# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
# negative values alone for now.)
#
# Tag names are one or more ASCII letters and numbers or underscores, i.e.
# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
# impacts log readability, the latter makes regex searches more annoying).
#
# Tag numbers and names are separated by whitespace. Blank lines and lines
# starting with '#' are ignored.
#
# Optionally, after the tag names can be put a description for the value(s)
# of the tag. Description are in the format
# (|data type[|data unit])
# Multiple values are separated by commas.
#
# The data type is a number from the following values:
# 1: int
# 2: long
# 3: string
# 4: list
# 5: float
#
# The data unit is a number taken from the following list:
# 1: Number of objects
# 2: Number of bytes
# 3: Number of milliseconds
# 4: Number of allocations
# 5: Id
# 6: Percent
# Default value for data of type int/long is 2 (bytes).
#
# TODO: generate ".java" and ".h" files with integer constants from this file.
我们来解析以下这段话的意思
2728 power_screen_state (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1)
格式 (Tag numbers) (|data type[|data unit])
EventLogTags.logtags类文件,使用 “#” 做开头,注释一行;
Tag numbers:2728; Tag numbers 是10进制数,范围为0 到 2^31;
Tag name:power_screen_state;Tag name是由一个或者多个ASCII码加数字或者下划线组合而成,例如[A-Z][a-z][0-9]_,禁止包括空格和标点符合。影响log的阅读性;
Tag numbers和Tag name中间使用空格隔开;
参数: (offOrOn|1|5), name:offOrOn,data type:1(int型),data unit:5(Id);多个参数使用逗号隔开,例如(offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1)
Android通过build/core/base_rules.mk和build/tools/java-event-log-tags.py。把各个模块的EventLogTags.logtags文件生成对应的EventLogTags.java文件 参照:
###########################################################
## logtags: Add .logtags files to global list, emit java source
###########################################################
logtags_sources := $(filter %.logtags,$(LOCAL_SRC_FILES))
ifneq ($(strip $(logtags_sources)),)
event_log_tags := $(addprefix $(LOCAL_PATH)/,$(logtags_sources))
# Emit a java source file with constants for the tags, if
# LOCAL_MODULE_CLASS is "APPS" or "JAVA_LIBRARIES".
ifneq ($(filter $(LOCAL_MODULE_CLASS),APPS JAVA_LIBRARIES),)
logtags_java_sources := $(patsubst %.logtags,%.java,$(addprefix $(intermediates.COMMON)/src/, $(logtags_sources)))
logtags_sources := $(addprefix $(TOP_DIR)$(LOCAL_PATH)/, $(logtags_sources))
$(logtags_java_sources): $(intermediates.COMMON)/src/%.java: $(TOPDIR)$(LOCAL_PATH)/%.logtags $(TARGET_OUT_COMMON_INTERMEDIATES)/all-event-log-tags.txt
$(transform-logtags-to-java)
endif
else
logtags_java_sources :=
event_log_tags :=
endif
例如,把frameworks/base/services/core/java/com/android/server/EventLogTags.logtags文件解析生成:
out/target/common/obj/JAVA_LIBRARIES/services.core_intermediates/src/java/com/android/server/EventLogTags.java
frameworks/base/services/core/java/com/android/server/am/EventLogTags.logtags解析生成:
out/target/common/obj/JAVA_LIBRARIES/services.core_intermediates/src/java/com/android/server/am/EventLogTags.java
查看 out/target/common/obj/JAVA_LIBRARIES/services.core_intermediates/src/java/com/android/server
/EventLogTags.java
可以看出EventLogTags.logtags的一条内容项:
2728 power_screen_state (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1)
被解析为一个静态变量POWER_SCREEN_STATE和一个静态函数writePowerScreenState。
public class EventLogTags {
...
/** 2728 power_screen_state (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1) */
public static final int POWER_SCREEN_STATE = 2728;
...
public static void writePowerScreenState(int offoron, int becauseofuser, long totaltouchdowntime, int touchcycles) {
android.util.EventLog.writeEvent(POWER_SCREEN_STATE, offoron, becauseofuser, totaltouchdowntime, touchcycles);
}
...
}
举例:notifier.java代码里面有如下调用:
EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
当然还可以如下使用,效果一样:
EventLogTags.writePowerScreenState(1, 0, 0, 0);
大致流程如下:
writeEvent -> android_util_EventLog.cpp -> logd_write_kern.c(liblog.so) ->
Uio.c(liblog.so)
eventlog可以通过以下命令来输出
adb logcat -b events
代码都在:
system/core/logcat/logcat.cpp
system/core/liblog/log_read_kern.c
最主要的main函数,大致步骤如下:
解析"-b events";
准备好log_device_t数据;
设置输出地方,例如终端或者log文件;
打开LOG文件,保存fd;
设置输出地方,例如终端或者log文件;
读取logfd里面的内容;
多个设备监测信息更新,例如多个终端输出;
输出LOG头,例如:
----------Logcat----------
--------- beginning of system
输出LOG;
重新整理log结构。
具体代码如下:
int main(int argc, char **argv)
{
...
for (;;) {
...
switch(ret) {
...
case 'b': {//解析"-b events"
if (strcmp(optarg, "all") == 0) {
while (devices) {
dev = devices;
devices = dev->next;
delete dev;
}
devices = dev = NULL;
g_devCount = 0;
for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
const char *name = android_log_id_to_name((log_id_t)i);
log_id_t log_id = android_name_to_log_id(name);
if (log_id != (log_id_t)i) {
continue;
}
bool binary = strcmp(name, "events") == 0;
log_device_t* d = new log_device_t(name, binary);
if (dev) {
dev->next = d;
dev = d;
} else {
devices = dev = d;
}
g_devCount++;
}
break;
}
bool binary = strcmp(optarg, "events") == 0;
if (devices) {
dev = devices;
while (dev->next) {
dev = dev->next;
}
dev->next = new log_device_t(optarg, binary); //准备好log_device_t数据
} else {
devices = new log_device_t(optarg, binary);
}
g_devCount++;
}
break;
case 'B':
g_printBinary = 1;
break;
...
}
}
...
setupOutput();//设置输出地方,例如终端或者log文件
...
while (dev) {
...
//打开LOG文件,保存fd
dev->logger = android_logger_open(logger_list,
android_name_to_log_id(dev->device));
...
}
...
//以下是LOG输出
dev = NULL;
log_device_t unexpected("unexpected", false);
while (1) {
...
int ret = android_logger_list_read(logger_list, &log_msg);//读取logfd里面的内容
...
//多个设备监测。例如多个终端输出
for(d = devices; d; d = d->next) {
if (android_name_to_log_id(d->device) == log_msg.id()) {
break;
}
}
if (!d) {
g_devCount = 2; // set to Multiple
d = &unexpected;
d->binary = log_msg.id() == LOG_ID_EVENTS;
}
/**
* 输出LOG头,例如
* ----------Logcat----------
* --------- beginning of system
**/
if (dev != d) {
dev = d;
maybePrintStart(dev, printDividers);
}
//输出LOG
if (g_printBinary) {
printBinary(&log_msg);
} else {
processBuffer(dev, &log_msg);
}
}
//整理log结构
android_logger_list_free(logger_list);
return EXIT_SUCCESS;
}