HarmonyOS技术社区 · 2021年05月07日

鸿蒙的DFX子系统

作者:liangkz  更新时间:2021.05.05

我们仍然是先对子系统的目录结构做一次整理,做成表格,把模块之间的调用关系理一下:

鸿蒙的DFX子系统

鸿蒙的DFX子系统

1. Hi3861 平台如上表,上电后在SystemInit阶段会依次init:HiviewConfigInit、HiLogInit、hiview service

[system\_init] HOS\_SystemInit begin: %%%%%%%%%%%

[system\_init] MODULE\_INIT(core)============================

[hiview\_config] CORE\_INIT\_PRI(<span class="colour" style="color: rgb(224, 62, 45);">HiviewConfigInit</span>, 0);

[hiview\_log] HiLogInit. CORE\_INIT\_PRI(<span class="colour" style="color: rgb(224, 62, 45);">HiLogInit</span>, 0)

[hiview\_output\_log] InitCoreLogOutput. call HiviewRegisterMsgHandle

[system\_init] SYS\_INIT(service)============================

[<span class="colour" style="color: rgb(224, 62, 45);">hiview\_service</span>] SYS\_SERVICE\_INIT(<span class="colour" style="color: rgb(224, 62, 45);">Init</span>).

[samgr\_lite] RegisterService(name: <span class="colour" style="color: rgb(224, 62, 45);">hiview</span>)

[hiview\_service] Init.InitHiviewComponent.

[hiview\_file] InitHiviewFile

......

......

[hiview\_service] <span class="colour" style="color: rgb(224, 62, 45);">Initialize</span>.

我们分别来看一下他们都做了些什么事情:

<span class="colour" style="color: rgb(224, 62, 45);">A. HiviewConfigInit</span>

位于:Hi3861/base/hiviewdfx/utils/lite/hiview\_config.c

其主要是初始化全局变量g\_hiviewConfig的配置,如下

鸿蒙的DFX子系统

  • hiviewInited:标记hiview service是否已经完成初始化。hiview service完成初始化之后将其置为TRUE,

“The communication of task can be use after the service is running.”,包括了相关的Message Handle才可用。

  • outputOption:标记Control log output mode. default to OUTPUT\_OPTION\_FLOW.
typedef enum {
    //不经过buffer,直接在终端上实时打印log,Debug版本建议用这个
    OUTPUT_OPTION_DEBUG = 0,    /* Output to the UART without buffer. Commercial versions are forbidden. */

    //不会实时打印log,先保存到buffer里,满足条件时才会通过SAMGR发消息一次性打印一条或多条log到终端上
    OUTPUT_OPTION_FLOW,        /* Output to UART via SAMGR */

    //不会实时打印log,先保存到buffer里,满足条件时才会通过SAMGR发消息将buffer的log写入TextFile
    OUTPUT_OPTION_TEXT_FILE,     /* Output to Text File: “/user/log/debug.log”,  see ‘HIVIEW_FILE_PATH_LOG’ */

    //不会实时打印log,先保存到buffer里,满足条件时才会通过SAMGR发消息将buffer的log写入BinFile
    OUTPUT_OPTION_BIN_FILE,

    OUTPUT_OPTION_MAX
} HiviewOutputOption;
  • level:标记Control log output level. Default to HILOG\_LV\_DEBUG.

低于此标记级别的log不会打印出来(?),还是不会被记录到TEXT\_FILE/BIN\_FILE里(??)

#define HILOG_LV_INVALID  0
#define HILOG_LV_DEBUG   1
#define HILOG_LV_INFO      2
#define HILOG_LV_WARN    3
#define HILOG_LV_ERROR    4
#define HILOG_LV_FATAL     5
#define HILOG_LV_MAX      6

<span class="colour" style="color: rgb(224, 62, 45);">B. HiLogInit</span>

位于:Hi3861/base/hiviewdfx/frameworks/hilog\_lite/mini/hiview\_log.c

鸿蒙的DFX子系统

  •  InitCoreLogOutput();

鸿蒙的DFX子系统

先去初始化全局变量HiviewCache <span class="colour" style="color: rgb(224, 62, 45);"> g\_logCache</span>

typedef struct {
    HiviewMutexId_t  mutex;
    uint16 wCursor;    // 0-65535
    uint16 usedSize;    // 0-65535,buffer已经使用掉的size
    uint16 size;        // cache size 0-65535,由LOG_STATIC_CACHE_SIZE指定,1024 Byte
    HiviewCacheType  type;
    uint8 *buffer;      // Circular buffer,由g_logCacheBuffer 指定的空间,1024 Byte 
} HiviewCache;

而全局变量 HiviewFile  <span class="colour" style="color: rgb(224, 62, 45);">g\_logFile</span>,这是在上面将outputOption标记设置为 OUTPUT\_OPTION\_TEXT\_FILE/BIN\_FILE 时用得上的配置,

如输出TextFile时,文件会生成在“user/log/debug.log”。

接下来是注册三个MsgHandle,用于处理满足条件时,将<span class="colour" style="color: rgb(0, 0, 0);">g\_logCache/g\_logCacheBuffer 中的log写入文件 或者通过Uart在默认终端上打印出来。这中间还有一个重新格式化log的处理,如:</span>

HILOG\_INFO(HILOG\_MODULE\_SAMGR, "<span class="colour" style="color: rgb(0, 0, 0);">Initialized all system and application services!"); </span>

这条log会处理成:

00 00:00:00 0 220 I 1/SAMGR: Initialized all system and application services!

前面新增一串字符分别代表着:开机以来的天数+时:分:秒+0+task+logLevel+module+moduleName.

task这个看起来并不是打印这个log的任务的TaskID,貌似是可以自行修改的,待验证。

logLevel 就是:

static char g_logLevelInfo[HILOG_LV_MAX] = {
    'N',   // "NONE"
    'D',   // "DEBUG"
    'I',    // "INFO"
    'W',  // "WARN"
    'E',   // "ERROR"
    'F'    // "FATAL"
};

module就是枚举HiLogModuleType定义的数字,这里的1就是 HILOG\_MODULE\_SAMGR 的值。

moduleName就是module对应的字符名字,见下面通过HiLogRegisterModule()注册的module参数。

  • HiLogRegisterModule()

注册log的模块,按照官方文档的“Hilog\_lite开发指导”中的例子进行配置即可。

  • HiviewRegisterInitFunc()

注册InitLogOutput()是为了在hiview service
init时创建和初始化log输出的TextFile/BinFile等文件的相关信息,outputOption ==
OUTPUT\_OPTION\_DEBUG/OUTPUT\_OPTION\_FLOW 是不需要创建文件的。

注册InitLogLimit()是为了在hiview service init时给log的打印设置一些限制条件:

    SetLimitThreshold(HILOG\_MODULE\_HIVIEW, LOG\_LIMIT\_LEVEL3);

    SetLimitThreshold(HILOG\_MODULE\_APP, LOG\_LIMIT\_LEVEL2);

过于频繁地打印log,有可能会导致log的丢失。

<span class="colour" style="color: rgb(224, 62, 45);">C. hiview service</span>

位于:Hi3861/base/hiviewdfx/services/hiview\_lite/hiview\_service.c

鸿蒙的DFX子系统

先是向SAMGR注册了g\_hiviewService以及FeatureApi,然后通过InitHiviewComponent()去依次执行
g\_hiviewInitFuncList[ ] 中的 InitLogOutput()和InitLogLimit()做相关的配置。

注意,这里仅仅是向SAMGR注册服务和注册MsgHandle API而已,还需要等到后面SAMGR把各种资源环境配置好后,才会调用g\_hiviewService.Initialize()去初始化和拉起hiview service,提供log方面的相关服务。

2. 在接下来的系统启动过程、系统运行过程、应用运行过程中,只要有调用上表C的声明中 log.h/hiview\_log.h头文件定义的宏,来打印log,就都会跑到下面所分析的流程中去。

hiview\_log.h 定义了:一些宏、枚举、辅助函数和

/*
 * Interface for printing basic logs. Use the macro definition interface instead of directly using this interface.
 * @param module Module ID.
 * @param level Log Level.
 * @param nums Parameters automatically generated by macro.
 * @param fmt Format string.
 * @attention Do not use this interface directly, you should use the HILOG_XXX interface.
 */
void HiLogPrintf(uint8 module, uint8 level, const char *nums, const char *fmt, ...) __attribute__((format(printf, 4, 5)));
#define HILOG_DEBUG(mod, fmt, ...)  HiLogPrintf(mod, HILOG_LV_DEBUG, FUN_ARG_NUM(__VA_ARGS__), fmt, ##__VA_ARGS__)
#define HILOG_INFO(mod, fmt, ...)    HiLogPrintf(mod, HILOG_LV_INFO, FUN_ARG_NUM(__VA_ARGS__), fmt, ##__VA_ARGS__)
#define HILOG_WARN(mod, fmt, ...)   HiLogPrintf(mod, HILOG_LV_WARN, FUN_ARG_NUM(__VA_ARGS__), fmt, ##__VA_ARGS__)
#define HILOG_ERROR(mod, fmt, ...)   HiLogPrintf(mod, HILOG_LV_ERROR, FUN_ARG_NUM(__VA_ARGS__), fmt, ##__VA_ARGS__)
#define HILOG_FATAL(mod, fmt, ...)    HiLogPrintf(mod, HILOG_LV_FATAL, FUN_ARG_NUM(__VA_ARGS__), fmt, ##__VA_ARGS__)

系统建议不要直接使用HiLogPrintf()来打印log,而是使用下面的一组宏来分级别/类型来打印log。

鸿蒙的DFX子系统

HiLogPrintf() 的实现在:Hi3861/base/hiviewdfx/frameworks/hilog\_lite/mini/hiview\_log.c

经过一些判断后,调用  Hi3861/base/hiviewdfx/frameworks/hilog\_lite/mini/hiview\_output\_log.c

文件内的OutputLog():

鸿蒙的DFX子系统

Hi3861/base/hiviewdfx/services/hiview\_lite/hiview\_service.c

【这里的MessageHandle()和Output()函数,如果进一步深入去分析和理解,就会涉及到samgr\_lite组件的一些东西了,这里先不进一步细说。文末我把我做的两张图附上,大家可以先自行理解一下。】

鸿蒙的DFX子系统

鸿蒙的DFX子系统

hiview service通过MessageHandle()调用之前InitCoreLogOutput()注册的MsgHandle API来处理相关消息:

实时打印log、把log写入TextFile或者写入BinFile。

鸿蒙的DFX子系统

最上面表格中“D的实现”中关于hiview\_cache.c、hiview\_file.c、hiview\_util.c等辅助函数的实现以及DFX系统外部提供的支持,就请各位自己去研究了。

Hi3516工程上的目录结构,相比Hi3861的多了:

  • hilog.cpp  C++类对上面几个宏的封装;上层应用开发,有自己的JS/Java的相关类的封装,请自行根据API参考文档进行配置和调用。
  • hiview\_applogcat.c  apphilogcat 服务进程,负责从日志设备(dev/hilog)读取数据,格式化输出到终端,同时也写入磁盘文件。
  • hiview\_logcat.c  编译成可执行程序hilogcat,看起来是可以通过shell执行,传入参数来动态调整log的打印,不过并不会写入磁盘文件。

我没有Hi3516平台,暂无法验证。

附上两张我在整理 HiviewService 时做的展开图片:

鸿蒙的DFX子系统



鸿蒙的DFX子系统



作者:liangkz
想了解更多内容,请访问51CTO和华为合作共建的鸿蒙社区:https://harmonyos.51cto.com

21_9.jpg

推荐阅读
关注数
2957
内容数
446
华为鸿蒙相关技术,活动及资讯,欢迎关注及加入创作
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息