临文乍了了,彻卷兀若无。这篇文章主要讲述OpenHarmony 源码解析之DFX子系统-Hiview(上)相关的知识,希望能为你提供帮助。
【OpenHarmony 源码解析之DFX子系统-Hiview(上)】作者:吴文璐
1 简介DFX(Design for X)子系统是为了提升软件质量设计的工具集,目前包含的内容主要有:DFR(Design for Reliability,可靠性)和DFT(Design for Testability,可测试性)特性。
已实现以下功能:
- HiLog:流水日志。
- HiSysEvent:系统事件记录接口。
- HiView:插件平台。
- FaultLoggerd:应用故障订阅和收集。
- HiAppEvent: js应用事件记录接口。
文章图片
1.2 Hiview简介
Hiview是一个跨平台的终端设备维测服务集。目前开源部分仅包含插件管理平台和系统事件源。
Hiview架构图如下:
文章图片
Hiview由框架和插件组成,分别为:
- 操作系统适配层(adapter),对使用的系统服务的接口进行适配。
- Hiview基础定义(hiview base),包括插件基类、管道的定义,事件、事件队列定义以及一些工具类。
- Hiview的核心模块(hiview core),包括插件配置,插件管理以及事件源。
- Hiview服务(hiview services),目前仅包括hiview运行信息dump功能。
- Hiview插件(plugins),为独立功能的业务模块。
格式化的事件通过HiSysEvent API上报至hiview进行处理,如下图:
文章图片
- 应用框架、系统服务使用HiSysEvent组件上报系统事件。
- Hiview中SysEventSource获取消息,解析并组装成管道事件分发给插件处理。
/base/hiviewdfx/hiview.
├── adapter#平台适配
│├── service#服务适配
│└── system_service #系统接口适配
├── base#模块定义,工具类
│└── utility
├── build#编译脚本
├── core#插件管理核心代码
├── include#公共定义
├── plugins#插件
├── service#HiviewService服务
└── utility#工具类
2 源码分析本文主要分析hiview插件管理平台的初始化,和事件处理流程。
hiview是个常驻服务,在开机阶段启动。
base/hiviewdfx/hiview/service/config/hiview.cfg定义如下
"jobs" : [
"name" : "post-fs-data",
"cmds" : [
"mkdir /data/log/ 0770 system log",
"mkdir /data/log/faultlog/ 0770 system system",
"mkdir /data/log/faultlog/temp/ 0770 system system",
"mkdir /data/log/faultlog/faultlogger/ 0770 system system",
"start hiview"
]],
"services" : [
"name" : "hiview",
"path" : ["/system/bin/hiview"],
"uid" : "system",
"gid" : ["system", "log"],
"writepid" : [
"/dev/cpuset/system-background/tasks"
],
"socket" : [
"hisysevent dgram 0666 root system passcred"
]]
2.1 初始化
hiview的入口函数定义在base/hiviewdfx/hiview/main.cpp中
```C++
int main(int argc UNUSED, char* argv[] UNUSED)
auto& hiview = OHOS::HiviewDFX::HiviewPlatform::GetInstance();
// process cmdline
hiview.ProcessArgsRequest(argc, argv);
// 初始化环境,主要解析配置文件,加载插件
if (!hiview.InitEnvironment())
HIVIEW_LOGW("Fail to init plugin environment. exit");
return -1;
// 启动HiviewService服务,该服务提供了hiview运行信息dump功能
auto hiviewService = std::make_unique<
OHOS::HiviewDFX::HiviewService>
();
hiviewService->
StartService();
return 0;
HiviewPlatform::InitEnvironment()函数实现如下:```C++
bool HiviewPlatform::InitEnvironment(const std::string&
defaultDir, const std::string&
cloudUpdateDir,
const std::string&
workDir, const std::string&
persistDir)// 创建工作目录,目前目录名使用了默认的空字符串,所以并未实际创建工作目录
ValidateAndCreateDirectories(defaultDir, cloudUpdateDir, workDir, persistDir);
// update beta config
UpdateBetaConfigIfNeed();
// check whether hiview is already started
ExitHiviewIfNeed();
// 解析"/system/etc/hiview/plugin_config"插件配置文件
std::string cfgPath = GetPluginConfigPath();
PluginConfig config(cfgPath);
if (!config.StartParse())//...........注[1]
HIVIEW_LOGE("Fail to parse plugin config. exit!");
return false;
// 启动插件管理平台消息队列
StartPlatformDispatchQueue();
// init global context helper, remove in the future
HiviewGlobal::CreateInstance(static_cast<
HiviewContext&
>
(*this));
//加载插件
LoadBusinessPlugin(config);
isReady_ = true;
NotifyPluginReady();
return true;
注[1]处PluginConfig::StartParse()函数会按照特定规则去解析插件配置文件:
```C++
if (field == " plugins" )
ParsePlugin(strTmp);
else if (field == " pipelines" )
ParsePipeline(strTmp);
else if (field == " pipelinegroups" )
ParsePipelineGroup(strTmp);
目前使用的插件配置文件/system/etc/hiview/plugin_config内容如下:
plugins:3
SysEventSource[thread:sysevent_source]:0 static
Faultlogger[]:0 static
SysEventService[thread:sysevent_service]:0 static
pipelines:1
SysEventPipeline:SysEventService Faultlogger
pipelinegroups:1
SysEventSource:SysEventPipeline
- 注:base/hiviewdfx/hiview/plugins 下有eventloggereventservicefaultloggerfreeze_detectorhicollie_collector五个插件目录,而目前插件配置文件里实际只用到了Faultlogger和SysEventService。PluginConfig::StartParse()解析完之后会把相关信息保存到列表中。类图如下:
![uml_pluginconfig.png](https://s4.51cto.com/images/blog/202201/12143022_61de757ea96c221252.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)PluginConfig::ParsePipelineGroup()代码如下```C++
void PluginConfig::ParsePipelineGroup(const std::string&
pipelineGroup)std::smatch result;
// EventSourceExample:FromTwo2Three FromThree2Two
if (!regex_search(pipelineGroup, result, std::regex("(\\\\S+)\\\\s*:(.+)")))
HIVIEW_LOGW("Fail to match pipeline group expression.");
return;
const int pipelineGroupNameField = 1;
const int pipelineNameListField = 2;
std::string eventSourceName = StringUtil::TrimStr(result.str(pipelineGroupNameField));
auto ret = std::find_if(pluginInfoList_.begin(), pluginInfoList_.end(), [&
](PluginInfo&
info)
if (info.name == eventSourceName)
info.isEventSource = true;
info.pipelineNameList = StringUtil::SplitStr(result.str(pipelineNameListField));
return true;
return false;
);
if (ret != std::end(pluginInfoList_))
HIVIEW_LOGD("%s is an event source.", eventSourceName.c_str());
说明:
- 在解析pipelinegroups时,如果发现pipelineGroupName和pluginInfoList中某个插件的name一致,则把该插件PluginInfo.isEventSource置为true并且把pipelineNameList赋值给PluginInfo.pipelineNameList。
- 结合/system/etc/hiview/plugin_config配置文件,可以看到SysEventSource插件是带管道(SysEventPipeline)的,插件SysEventService和Faultlogger隶属于管道SysEventPipeline,用于处理SysEventSource扔给管道的事件。
代码如下
```C++
void HiviewPlatform::LoadBusinessPlugin(const PluginConfig& config)
// start to load plugin
// 1. 遍历pluginInfoList,根据插件名创建插件。因为目前配置的插件加载延时(loadDelay)为0,所以直接走[2],调用CreatePlugin()创建插件并添加到pluginMap_中。
auto const& pluginInfoList = config.GetPluginInfoList();
for (auto const& pluginInfo : pluginInfoList)
HIVIEW_LOGI(" Start to create plugin %publics delay:%publicd" , pluginInfo.name.cstr(),
pluginInfo.loadDelay);
if (pluginInfo.loadDelay > 0)//.............[1]
auto task = std::bind(& HiviewPlatform::ScheduleCreateAndInitPlugin, this, pluginInfo);
sharedWorkLoop-> AddTimerEvent(nullptr, nullptr, task, pluginInfo.loadDelay, false);
else//...............[2]
CreatePlugin(pluginInfo);
// 2. 遍历pipelineInfoList,调用CreatePipeline()创建管道并添加到pipelines_中。
auto const& pipelineInfoList = config.GetPipelineInfoList();
for (auto const& pipelineInfo : pipelineInfoList)
HIVIEW_LOGI(" Start to create pipeline %publics" , pipelineInfo.name.c_str());
CreatePipeline(pipelineInfo);
// 3. 遍历pluginInfoList,调用InitPlugin()初始化插件
for (auto const&
pluginInfo : pluginInfoList)
HIVIEW_LOGI("Start to Load plugin %publics", pluginInfo.name.c_str());
InitPlugin(config, pluginInfo);
//............注[1]CleanupUnusedResources();
**说明:**注[1]InitPlugin()这一步中,如果插件的workHandlerType为thread,则绑定工作线程EventLoop。如果插件是EventSource类型,则绑定管道Pipeline,并且调用StartEventSource开启消息监听。代码如下:```C++
void HiviewPlatform::InitPlugin(const PluginConfig&
config __UNUSED, const PluginConfig::PluginInfo&
pluginInfo)auto&
plugin = pluginMap_[pluginInfo.name];
if (plugin == nullptr)
return;
// 如果插件的workHandlerType为thread,则绑定工作线程EventLoop。
if (pluginInfo.workHandlerType == "thread")
auto workLoop = GetAvaliableWorkLoop(pluginInfo.workHandlerName);
plugin->
BindWorkLoop(workLoop);
auto begin = TimeUtil::GenerateTimestamp();
plugin->
OnLoad();
// 如果插件是EventSource类型,则添加管道Pipeline,并且调用StartEventSource开启消息监听
if (pluginInfo.isEventSource)
auto sharedSource = std::static_pointer_cast<
EventSource>
(plugin);
if (sharedSource == nullptr)
HIVIEW_LOGE("Fail to cast plugin to event source!");
return;
for (auto&
pipelineName : pluginInfo.pipelineNameList)
sharedSource->
AddPipeline(pipelines_[pipelineName]);
StartEventSource(sharedSource);
auto end = TimeUtil::GenerateTimestamp();
HIVIEW_LOGI("Plugin %publics loadtime:%public" PRIu64 ".", pluginInfo.name.c_str(), end - begin);
至此,插件管理平台初始化工作已完成。
2.2 事件处理流程
结合插件配置文件,目前实际使用的插件类图如下:
文章图片
说明:
- 前文最后的代码段提到,如果插件是EventSource类型,则绑定管道,并且调用StartEventSource开启消息监听。结合类图,只有SysEventSource是EventSource类型的插件,所以只有SysEventSource持有管道。
- EventSource类型的插件会监听HiSysEvent接口发来的消息,解析并组装成管道事件,分发给管道中的插件处理。
```C++
void SysEventSource::StartEventSource()
HIVIEW_LOGI(" SysEventSource start" );
std::shared_ptr< EventReceiver> sysEventReceiver = std::make_shared< SysEventReceiver> (*this);
eventServer.AddReceiver(sysEventReceiver);
eventServer.Start();
SysEventSource有个成员变量eventServer,EventServer会开启socketserver端用于接收HiSysEvent接口发来的socket消息。类图如下:
![uml_eventsource.png](https://s4.51cto.com/images/blog/202201/12143022_61de757ea96d545765.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
![uml_eventsource](pictures/uml_eventsource.png)**说明:**- 1.SysEventSource::StartEventSource()中把SysEventReceiver对象加入到EventServer的receivers_容器中。
- 2.EventServer收到socket消息之后,调用SysEventReceiver::HandlerEvent(const std::string&
rawMsg)方法处理接收到的消息。
- 3.SysEventReceiver::HandlerEvent()方法中会调用SysEventParser::Parser(const std::string&
rawMsg)方法解析消息并组装成SysEvent对象,然后调用EventSource::PublishPipelineEvent(std::shared_ptr<
PipelineEvent>
event)方法把管道事件发布出去。EventSource::PublishPipelineEvent()代码如下:```C++
bool EventSource::PublishPipelineEvent(std::shared_ptr<
PipelineEvent>
event)HIVIEW_LOGD("EventSource PublishPipelineEvent");
if (event == nullptr)
return false;
if (Audit::IsEnabled())
auto digest = GetPluginInfo() + Audit::DOMAIN_DELIMITER + event->
GetEventInfo();
Audit::WriteAuditEvent(Audit::StatsEvent::PIPELINE_EVENT_CREATE, event->
createTime_, digest);
for (auto&
pipeline : listeners_)
if ((pipeline != nullptr) &
&
(pipeline->
CanProcessEvent(event)))
// one event can only be processed by one pipeline
pipeline->
ProcessEvent(event);
return true;
return false;
结合上面的类图,EventSource持有管道列表对象listeners_,EventSource::PublishPipelineEvent()函数中会遍历该列表,调用Pipeline::ProcessEvent(std::shared_ptr< PipelineEvent> event)函数去处理管道事件。(Pipeline对象是在HiviewPlatform::InitPlugin()函数中被加入到EventSource.listeners_中的。)
Pipeline类型有个成员变量std::list< std::weakptr< Plugin> > processors,
在插件平台初始化的时候,HiviewPlatform::CreatePipeline()函数中已经把Plugin插件对象加入到了processors_列表中。
接下来分析Pipeline::ProcessEvent()函数做了什么。
```C++
void Pipeline::ProcessEvent(std::sharedptr< PipelineEvent> event)
event-> SetPipelineInfo(name, processors_);
event-> OnContinue();
把Pipeline的processors_对象赋给了PipelineEvent的processors_对象,然后调用
PipelineEvent::OnContinue()函数。
接下来分析PipelineEvent::OnContinue()函数:```C++
bool PipelineEvent::OnContinue()// 判断hasFinish_标志位和processors_列表是否已经为空,如已为空,结束本次事件传递
if ((!hasFinish_) &
&
processors_.empty())
return OnFinish();
// once the event start delivering
// the call OnContinue means one has done the processing of the event
// this may be called by upstream event processor or the framework
if (Audit::IsEnabled() &
&
startDeliver_)
Audit::WriteAuditEvent(Audit::StatsEvent::PIPELINE_EVENT_HANDLE_OUT,
createTime_, std::to_string(Thread::GetTid()));
// the framework will call OnContinue when the event is assigned to a pipeline
if (!startDeliver_)
startDeliver_ = true;
// 取出processors_列表中第一个Plugin元素,并从列表弹出
std::weak_ptr<
Plugin>
plugin = processors_.front();
processors_.pop_front();
if (auto pluginPtr = plugin.lock())
if (!pluginPtr->
CanProcessMoreEvents())
handler_->
PauseDispatch(plugin);
if (Audit::IsEnabled())
Audit::WriteAuditEvent(Audit::StatsEvent::PIPELINE_EVENT_HANDLE_IN, createTime_,
pluginPtr->
GetHandlerInfo());
// 判断当前Plugin是否开启了事件工作队列,如有则加入事件队列处理,如没有直接调用OnEventProxy
if (auto workLoop = pluginPtr->
GetWorkLoop())
workLoop->
AddEvent(pluginPtr, shared_from_this());
//............[1]
else
pluginPtr->
OnEventProxy(shared_from_this());
//..........[2]else
return OnContinue();
return true;
不管插件是否使用了事件队列,最终都会调用到Plugin::OnEventProxy()函数来处理管道事件。
Plugin::OnEventProxy()函数实现如下:
```C++
bool Plugin::OnEventProxy(std::shared_ptr< Event> event)
if (event == nullptr)
return false;
std::shared_ptr<
Event>
dupEvent = event;
auto processorSize = dupEvent->
GetPendingProcessorSize();
dupEvent->
ResetPendingStatus();
bool ret = OnEvent(dupEvent);
//..............注[1]if (!dupEvent->
IsPipelineEvent())
if (Audit::IsEnabled())
Audit::WriteAuditEvent(Audit::StatsEvent::QUEUE_EVENT_OUT, dupEvent->
createTime_,
std::to_string(Thread::GetTid()));
else
if ((!dupEvent->
HasFinish() &
&
!dupEvent->
HasPending()) &
&
(processorSize == dupEvent->
GetPendingProcessorSize()))
dupEvent->
OnContinue();
//.............注[2]return ret;
先调用注[1]OnEvent()函数处理事件,再判断管道事件传递是否已结束,如未结束则调用注[2]PipelineEvent::OnContinue()函数继续把管道事件传递给后面的
插件处理。结合目前的插件配置文件,整个插件管理平台的消息处理流程大致如下:EventServer接收到HiSysEvent组件接口发来的消息 -->
SysEventReceiver::HandlerEvent() -->
SysEventParser::Parser() -->
EventSource::PublishPipelineEvent() -->
Pipeline::ProcessEvent() -->
PipelineEvent::OnContinue() -->
SysEventService::OnEventProxy -->
SysEventService::OnEvent -->
PipelineEvent::OnContinue() -->
Faultlogger::OnEventProxy -->
Faultlogger::OnEvent -->
结束至此,事件处理流程已分析完。## 3 总结以上内容首先分析了hiview插件管理平台的初始化,然后对事件的处理流程做了分析。后续会详细讲解base/hiviewdfx/hiview/plugins目录下每个插件的源码。## 更多原创内容请关注:[深开鸿技术团队](https://harmonyos.51cto.com/person/posts/15292440)入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。[想了解更多关于鸿蒙的内容,请访问:](https://harmonyos.51cto.com/#bkwz)[51CTO和华为官方合作共建的鸿蒙技术社区](https://harmonyos.51cto.com/#bkwz)https://harmonyos.51cto.com/#bkwz::: hljs-center![21_9.jpg](https://s2.51cto.com/images/20210924/1632469265578939.jpg?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=):::
推荐阅读
- Renix签名字段详解——网络测试仪实操
- WordPress主菜单在我的主题中出现了两次,为什么()
- 主题检查找到DOS和UNIX样式行的结尾
- 高级自定义字段的三元运算符
- Tax_Query无法与WP_Query一起使用
- 在导航中使用语言按钮切换语言WordPress
- 滑动手势和WordPress模板
- 使用CSS设置论文下拉菜单的样式
- 在不创建新表的情况下为WordPress插件存储变量