Android EventLog

概述

   在分析Android系统或者应用相关的问题时,经常会查看EventLog,它非常简洁明了地展现当前系统以及应用行为的各种状态,简单的看下其原理。


1. EventLogTags.logtags介绍

   在文件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

2. EventLogTags.logtags内容解析

2.1.system/core/logcat/event.logtags对这类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])

  1. EventLogTags.logtags类文件,使用 “#” 做开头,注释一行;

  2. Tag numbers:2728; Tag numbers 是10进制数,范围为0 到 2^31;

  3. Tag name:power_screen_state;Tag name是由一个或者多个ASCII码加数字或者下划线组合而成,例如[A-Z][a-z][0-9]_,禁止包括空格和标点符合。影响log的阅读性;

  4. Tag numbers和Tag name中间使用空格隔开;

  5. 参数: (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)

3. 解析生成文件EventLogTags.java

   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

4. EventLogTags和EventLog调用:

   查看 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);

5. writeEvent的处理流程:

   大致流程如下:

writeEvent -> android_util_EventLog.cpp -> logd_write_kern.c(liblog.so) ->
Uio.c(liblog.so)

6. logcat -b events输出

   eventlog可以通过以下命令来输出

adb logcat -b events

   代码都在:

system/core/logcat/logcat.cpp
system/core/liblog/log_read_kern.c

   最主要的main函数,大致步骤如下:

  1. 解析"-b events";

  2. 准备好log_device_t数据;

  3. 设置输出地方,例如终端或者log文件;

  4. 打开LOG文件,保存fd;

  5. 设置输出地方,例如终端或者log文件;

  6. 读取logfd里面的内容;

  7. 多个设备监测信息更新,例如多个终端输出;

  8. 输出LOG头,例如:

    ----------Logcat----------

    --------- beginning of system

  9. 输出LOG;

  10. 重新整理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;
}

你可能感兴趣的:(android-源码分析)