update OpenHarmony 2.0 Canary

This commit is contained in:
mamingshuai 2021-06-02 00:04:49 +08:00
parent ec05f5afdf
commit 153bf94ba7
717 changed files with 138657 additions and 73 deletions

15
.gitattributes vendored Normal file
View File

@ -0,0 +1,15 @@
*.tgz filter=lfs diff=lfs merge=lfs -text
*.trp filter=lfs diff=lfs merge=lfs -text
*.apk filter=lfs diff=lfs merge=lfs -text
*.jar filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.asm filter=lfs diff=lfs merge=lfs -text
*.8svn filter=lfs diff=lfs merge=lfs -text
*.9svn filter=lfs diff=lfs merge=lfs -text
*.dylib filter=lfs diff=lfs merge=lfs -text
*.exe filter=lfs diff=lfs merge=lfs -text
*.a filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text
*.bin filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text

178
LICENSE Normal file
View File

@ -0,0 +1,178 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

73
OAT.xml Executable file
View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) 2021 Huawei Device Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Notes:
This is project config file for OpenHarmony OSS Audit Tool, if you have any questions or concerns, please email chenyaxun@huawei.com.
-->
<!-- OAT(OSS Audit Tool) configuration guide:
basedir: Root dir, the basedir + project path is the real source file location.
licensefile:
1.If the project don't have "LICENSE" in root dir, please define all the license files in this project in , OAT will check license files according to this rule.
tasklist(only for batch mode):
1. task: Define oat check thread, each task will start a new thread.
2. task name: Only an name, no practical effect.
3. task policy: Default policy for projects under this task, this field is required and the specified policy must defined in policylist.
4. task filter: Default filefilter for projects under this task, this field is required and the specified filefilter must defined in filefilterlist.
5. task project: Projects to be checked, the path field define the source root dir of the project.
policyList:
1. policy: All policyitems will be merged to default OAT.xml rules, the name of policy doesn't affect OAT check process.
2. policyitem: The fields type, name, path, desc is required, and the fields rule, group, filefilter is optional,the default value is:
<policyitem type="" name="" path="" desc="" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
3. policyitem type:
"compatibility" is used to check license compatibility in the specified path;
"license" is used to check source license header in the specified path;
"copyright" is used to check source copyright header in the specified path;
"import" is used to check source dependency in the specified path, such as import ... ,include ...
"filetype" is used to check file type in the specified path, supported file types: archive, binary
"filename" is used to check whether the specified file exists in the specified path(support projectroot in default OAT.xml), supported file names: LICENSE, README, README.OpenSource
4. policyitem name: This field is used for define the license, copyright, "*" means match all, the "!" prefix means could not match this value. For example, "!GPL" means can not use GPL license.
5. policyitem path: This field is used for define the source file scope to apply this policyitem, the "!" prefix means exclude the files. For example, "!.*/lib/.*" means files in lib dir will be exclude while process this policyitem.
6. policyitem rule and group: These two fields are used together to merge policy results. "may" policyitems in the same group means any one in this group passed, the result will be passed.
7. policyitem filefilter: Used to bind filefilter which define filter rules.
8. filefilter: Filter rules, the type filename is used to filter file name, the type filepath is used to filter file path.
Note:If the text contains special characters, please escape them according to the following rules:
" == &gt;
& == &gt;
' == &gt;
< == &gt;
> == &gt;
-->
<configuration>
<oatconfig>
<filefilterlist>
<filefilter name="defaultPolicyFilter" desc="Filters for compatibilitylicense header policies">
<filteritem type="filepath" name="device/plugins/memory_plugin/test/utresources/proc/.*" desc="test resource file, no license header"/>
</filefilter>
<filefilter name="copyrightPolicyFilter" desc="Filters for copyright header policies" >
<filteritem type="filepath" name="device/plugins/memory_plugin/test/utresources/proc/.*" desc="test resource file, no copyright header"/>
</filefilter>
<filefilter name="binaryFileTypePolicyFilter" desc="Filters for binary file policies" >
<filteritem type="filepath" name="host/ohosprofiler/src/main/resources/trace.db" desc="the binary file for host, the file is self-developed"/>
<filteritem type="filepath" name="host/ohosprofiler/src/main/resources/ohos/devtools.tar" desc="the binary file for host, the file is self-developed"/>
<filteritem type="filepath" name="host/ohosprofiler/src/test/resources/Demo.trace" desc="the binary file for host, the file is self-developed"/>
</filefilter>
</filefilterlist>
</oatconfig>
</configuration>

View File

@ -1,36 +0,0 @@
# developtools_profiler
#### Description
Performance profiler that provides an analytics tool for the memory, bytrace plug-in, and IDE, as well as plug-in capabilities | 性能调优模块提供了实时内存、bytrace插件和ide侧的分析工具并提供了插件化能力
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

View File

@ -1,37 +0,0 @@
# developtools_profiler
#### 介绍
Performance profiler that provides an analytics tool for the memory, bytrace plug-in, and IDE, as well as plug-in capabilities | 性能调优模块提供了实时内存、bytrace插件和ide侧的分析工具并提供了插件化能力
#### 软件架构
软件架构说明
#### 安装教程
1. xxxx
2. xxxx
3. xxxx
#### 使用说明
1. xxxx
2. xxxx
3. xxxx
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
#### 特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

374
README_zh.md Executable file
View File

@ -0,0 +1,374 @@
# 性能调优组件<a name="ZH-CN_TOPIC_0000001149491319"></a>
- [简介](#section6874544183112)
- [架构图](#section1514713331342)
- [目录](#section1742612449345)
- [说明](#section2165102016359)
- [接口说明](#section558917318367)
- [使用说明](#section681316903611)
- [调测验证:](#section35362541215)
- [\#ZH-CN\_TOPIC\_0000001149491319/section3753165410213](#section3753165410213)
- [相关仓](#section1293495681320)
## 简介<a name="section6874544183112"></a>
性能调优组件包含系统和应用调优框架,旨在为开发者提供一套性能调优平台,可以用来分析内存、性能等问题。
该组件整体分为PC端和设备端两部分PC端最终作为deveco studio的插件进行发布内部主要包括分为UI绘制、设备管理、进程管理、插件管理、数据导入、数据存储、 数据分析、Session管理、配置管理等模块设备端主要包括命令行工具、服务进程、插件集合、应用程序组件等模块。设备端提供了插件扩展能力对外提供了插件接口基于该扩展能力可以按需定义自己的能力并集成到框架中来目前基于插件能力已经完成了实时内存插件和trace插件。下文会重点对设备端提供的插件能力进行介绍。
## 架构图<a name="section1514713331342"></a>
![](figures/zh-cn_image_0000001162598155.png)
## 目录<a name="section1742612449345"></a>
```
/developtools/profiler
├── device # 设备侧代码目录
│ └── base
│ ├── include # 基础功能的头文件代码目录
│ ├── src # 基础功能的源文件代码目录
│ ├── test # 基础功能的测试代码目录
│ └── cmds
│ ├── include # 对外命令行模块的头文件代码目录
│ ├── src # 对外命令行模块的源文件代码目录
│ ├── test # 对外命令行模块的测试代码目录
│ └── plugins
│ ├── api # 插件模块对外提供的接口文件代码目录
│ └── include # 插件模块对外提供的接口头文件代码目录
│ └── src # 插件模块对外提供的接口源文件代码目录
│ ├── memory_plugin # 内存插件模块代码目录
│ └── include # 内存插件模块头文件代码目录
│ └── src # 内存插件模块源文件代码目录
│ └── test # 内存插件模块测试代码目录
│ ├── trace_plugin # trace插件模块代码目录
│ └── include # trace插件模块头文件代码目录
│ └── src # trace插件模块源文件代码目录
│ └── test # trace插件模块测试代码目录
├── host # 主机侧代码目录
│ └── ohosprofiler # 主机侧调优模块代码目录
│ └── src # 主机侧调优模块源文件代码目录
├── protos # 项目中的proto格式文件的代码目录
│ └── innerkits # 对内部子系统暴露的头文件存放目录
│ └── builtin # JS应用框架对外暴露JS三方module API接口存放目录
├── trace_analyzer # bytrace解析模块的代码目录
│ └── include # bytrace解析模块的公共头文件存放目录
│ └── src # bytrace解析模块功能源文件存放目录
├── interfaces # 项目中接口的代码目录
│ └── innerkits # 模块间接口的代码目录
│ └── kits # 对外提供接口存放目录
```
## 说明<a name="section2165102016359"></a>
下面针对设备端对外提供的插件扩展能力进行接口和使用说明。
### 接口说明<a name="section558917318367"></a>
下面是设备端插件模块对外提供的接口:
- PluginModuleCallbacks为插件模块对外提供的回调接口插件管理模块通过该回调接口列表与每一个插件模块进行交互每一个新增插件都需要实现该接口列表中的函数。
**表 1** PluginModuleCallbacks接口列表
<a name="table214mcpsimp"></a>
<table><thead align="left"><tr id="row221mcpsimp"><th class="cellrowborder" valign="top" width="30%" id="mcps1.2.4.1.1"><p id="p223mcpsimp"><a name="p223mcpsimp"></a><a name="p223mcpsimp"></a>接口名</p>
</th>
<th class="cellrowborder" valign="top" width="30.020000000000003%" id="mcps1.2.4.1.2"><p id="p225mcpsimp"><a name="p225mcpsimp"></a><a name="p225mcpsimp"></a>类型</p>
</th>
<th class="cellrowborder" valign="top" width="39.98%" id="mcps1.2.4.1.3"><p id="p227mcpsimp"><a name="p227mcpsimp"></a><a name="p227mcpsimp"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row229mcpsimp"><td class="cellrowborder" valign="top" width="30%" headers="mcps1.2.4.1.1 "><p id="p231mcpsimp"><a name="p231mcpsimp"></a><a name="p231mcpsimp"></a>PluginModuleCallbacks::onPluginSessionStart</p>
</td>
<td class="cellrowborder" valign="top" width="30.020000000000003%" headers="mcps1.2.4.1.2 "><p id="p233mcpsimp"><a name="p233mcpsimp"></a><a name="p233mcpsimp"></a>int (*PluginSessionStartCallback)(const uint8_t* configData, uint32_t configSize);</p>
</td>
<td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.2.4.1.3 "><a name="ul1467809165112"></a><a name="ul1467809165112"></a><ul id="ul1467809165112"><li>功能:<p id="p1208131116548"><a name="p1208131116548"></a><a name="p1208131116548"></a>插件会话开始接口,开始插件会话时会被调用,用来下发插件配置</p>
</li><li>输入参数:<p id="p104087130518"><a name="p104087130518"></a><a name="p104087130518"></a>configData配置信息内存块起始地址</p>
<p id="p32731219115114"><a name="p32731219115114"></a><a name="p32731219115114"></a>configSize配置信息内存块字节数</p>
</li><li>返回值:<p id="p4892128135110"><a name="p4892128135110"></a><a name="p4892128135110"></a>0成功</p>
<p id="p1621513010517"><a name="p1621513010517"></a><a name="p1621513010517"></a>-1失败</p>
</li></ul>
</td>
</tr>
<tr id="row236mcpsimp"><td class="cellrowborder" valign="top" width="30%" headers="mcps1.2.4.1.1 "><p id="p238mcpsimp"><a name="p238mcpsimp"></a><a name="p238mcpsimp"></a>PluginModuleCallbacks::onPluginReportResult</p>
</td>
<td class="cellrowborder" valign="top" width="30.020000000000003%" headers="mcps1.2.4.1.2 "><p id="p240mcpsimp"><a name="p240mcpsimp"></a><a name="p240mcpsimp"></a>int (*PluginReportResultCallback)(uint8_t* bufferData, uint32_t bufferSize);</p>
</td>
<td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.2.4.1.3 "><a name="ul1046263617524"></a><a name="ul1046263617524"></a><ul id="ul1046263617524"><li>功能:<p id="p621321105415"><a name="p621321105415"></a><a name="p621321105415"></a>插件结果上报接口类型,当任务下发后,框架采集任务会周期性调用此接口请求回填数据</p>
</li><li>输入参数:<p id="p12796339115211"><a name="p12796339115211"></a><a name="p12796339115211"></a>bufferData: 存放结果的内存缓冲区起始地址</p>
<p id="p1163214085219"><a name="p1163214085219"></a><a name="p1163214085219"></a>bufferSize: 存放结果的内存缓冲区的字节数</p>
</li><li>返回值:<p id="p114391444135212"><a name="p114391444135212"></a><a name="p114391444135212"></a>大于0已经填充的内存字节数</p>
<p id="p117881419526"><a name="p117881419526"></a><a name="p117881419526"></a>等于0没有填充任何内容</p>
<p id="p7337174625218"><a name="p7337174625218"></a><a name="p7337174625218"></a>小于0失败</p>
</li></ul>
</td>
</tr>
<tr id="row243mcpsimp"><td class="cellrowborder" valign="top" width="30%" headers="mcps1.2.4.1.1 "><p id="p245mcpsimp"><a name="p245mcpsimp"></a><a name="p245mcpsimp"></a>PluginModuleCallbacks::onPluginSessionStop</p>
</td>
<td class="cellrowborder" valign="top" width="30.020000000000003%" headers="mcps1.2.4.1.2 "><p id="p247mcpsimp"><a name="p247mcpsimp"></a><a name="p247mcpsimp"></a>int (*PluginSessionStopCallback)();</p>
</td>
<td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.2.4.1.3 "><a name="ul975785275211"></a><a name="ul975785275211"></a><ul id="ul975785275211"><li>功能:<p id="p11471347135914"><a name="p11471347135914"></a><a name="p11471347135914"></a>采集会话结束接口</p>
</li><li>返回值:<p id="p4301105945210"><a name="p4301105945210"></a><a name="p4301105945210"></a>0成功</p>
<p id="p145541757125214"><a name="p145541757125214"></a><a name="p145541757125214"></a>-1失败</p>
</li></ul>
</td>
</tr>
<tr id="row250mcpsimp"><td class="cellrowborder" valign="top" width="30%" headers="mcps1.2.4.1.1 "><p id="p252mcpsimp"><a name="p252mcpsimp"></a><a name="p252mcpsimp"></a>PluginModuleCallbacks::onRegisterWriterStruct</p>
</td>
<td class="cellrowborder" valign="top" width="30.020000000000003%" headers="mcps1.2.4.1.2 "><p id="p254mcpsimp"><a name="p254mcpsimp"></a><a name="p254mcpsimp"></a>int (*RegisterWriterStructCallback)(WriterStruct* writer);</p>
</td>
<td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.2.4.1.3 "><a name="ul11459712105318"></a><a name="ul11459712105318"></a><ul id="ul11459712105318"><li>功能:<p id="p16725350135912"><a name="p16725350135912"></a><a name="p16725350135912"></a>采集框架注册写数据接口当插件管理模块向插件注册此接口插件可以主动调用write句柄进行写入数据</p>
</li><li>输入参数:<p id="p741312324531"><a name="p741312324531"></a><a name="p741312324531"></a>writer 写者指针</p>
</li><li>返回值:<p id="p1937282325319"><a name="p1937282325319"></a><a name="p1937282325319"></a>0成功</p>
<p id="p3613421185314"><a name="p3613421185314"></a><a name="p3613421185314"></a>-1失败</p>
</li></ul>
</td>
</tr>
</tbody>
</table>
- WriterStruct是上面onRegisterWriterStruct接口中的参数主要实现写数据接口将插件中采集的数据通过该接口进行写入。
**表 2** WriterStruct接口列表
<a name="table1469161115240"></a>
<table><thead align="left"><tr id="row124691911182413"><th class="cellrowborder" valign="top" width="30%" id="mcps1.2.4.1.1"><p id="p14469151118247"><a name="p14469151118247"></a><a name="p14469151118247"></a>接口名</p>
</th>
<th class="cellrowborder" valign="top" width="30.020000000000003%" id="mcps1.2.4.1.2"><p id="p114691119249"><a name="p114691119249"></a><a name="p114691119249"></a>类型</p>
</th>
<th class="cellrowborder" valign="top" width="39.98%" id="mcps1.2.4.1.3"><p id="p134701611172413"><a name="p134701611172413"></a><a name="p134701611172413"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row5470201102420"><td class="cellrowborder" valign="top" width="30%" headers="mcps1.2.4.1.1 "><p id="p144702115242"><a name="p144702115242"></a><a name="p144702115242"></a>WriterStruct::write</p>
</td>
<td class="cellrowborder" valign="top" width="30.020000000000003%" headers="mcps1.2.4.1.2 "><p id="p347010119246"><a name="p347010119246"></a><a name="p347010119246"></a>long (*WriteFuncPtr)(WriterStruct* writer, const void* data, size_t size);</p>
</td>
<td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.2.4.1.3 "><a name="ul1783144245320"></a><a name="ul1783144245320"></a><ul id="ul1783144245320"><li>功能:<p id="p11675175517597"><a name="p11675175517597"></a><a name="p11675175517597"></a>写接口将插件中采集的数据通过writer进行写入</p>
</li><li>输入参数:<p id="p1812314462537"><a name="p1812314462537"></a><a name="p1812314462537"></a>writer写者指针</p>
<p id="p498224618534"><a name="p498224618534"></a><a name="p498224618534"></a>data数据缓冲区首字节指针</p>
<p id="p368519478533"><a name="p368519478533"></a><a name="p368519478533"></a>size: 数据缓冲区的字节数</p>
</li><li>返回值:<p id="p162857527531"><a name="p162857527531"></a><a name="p162857527531"></a>0成功</p>
<p id="p101121150185318"><a name="p101121150185318"></a><a name="p101121150185318"></a>-1失败</p>
</li></ul>
</td>
</tr>
<tr id="row84706116243"><td class="cellrowborder" valign="top" width="30%" headers="mcps1.2.4.1.1 "><p id="p2047081142415"><a name="p2047081142415"></a><a name="p2047081142415"></a>WriterStruct::flush</p>
</td>
<td class="cellrowborder" valign="top" width="30.020000000000003%" headers="mcps1.2.4.1.2 "><p id="p194111838267"><a name="p194111838267"></a><a name="p194111838267"></a>bool (*FlushFuncPtr)(WriterStruct* writer);</p>
</td>
<td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.2.4.1.3 "><a name="ul9562185717538"></a><a name="ul9562185717538"></a><ul id="ul9562185717538"><li>功能:<p id="p744185910594"><a name="p744185910594"></a><a name="p744185910594"></a>触发数据上传接口</p>
</li><li>输入参数:<p id="p69601111504"><a name="p69601111504"></a><a name="p69601111504"></a>writer写者指针</p>
</li><li>返回值:<p id="p970375016"><a name="p970375016"></a><a name="p970375016"></a>true成功</p>
<p id="p1314495407"><a name="p1314495407"></a><a name="p1314495407"></a>false失败</p>
</li></ul>
</td>
</tr>
</tbody>
</table>
- 下面是插件模块对外提供的总入口主要包括表1中的插件模块回调函数以及插件名称、插件模块需要申请的内存大小。
**表 3** PluginModuleStruct接口列表
<a name="table14418172393018"></a>
<table><thead align="left"><tr id="row14188236300"><th class="cellrowborder" valign="top" width="30%" id="mcps1.2.4.1.1"><p id="p041820239304"><a name="p041820239304"></a><a name="p041820239304"></a>接口名</p>
</th>
<th class="cellrowborder" valign="top" width="30.020000000000003%" id="mcps1.2.4.1.2"><p id="p34181823153010"><a name="p34181823153010"></a><a name="p34181823153010"></a>类型</p>
</th>
<th class="cellrowborder" valign="top" width="39.98%" id="mcps1.2.4.1.3"><p id="p10418023123011"><a name="p10418023123011"></a><a name="p10418023123011"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row16418623143016"><td class="cellrowborder" valign="top" width="30%" headers="mcps1.2.4.1.1 "><p id="p625018817318"><a name="p625018817318"></a><a name="p625018817318"></a>PluginModuleStruct::callbacks</p>
</td>
<td class="cellrowborder" valign="top" width="30.020000000000003%" headers="mcps1.2.4.1.2 "><p id="p162501689312"><a name="p162501689312"></a><a name="p162501689312"></a>PluginModuleCallbacks*</p>
</td>
<td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.2.4.1.3 "><p id="p122501085317"><a name="p122501085317"></a><a name="p122501085317"></a>功能:定义插件回调函数列表</p>
</td>
</tr>
<tr id="row241952313015"><td class="cellrowborder" valign="top" width="30%" headers="mcps1.2.4.1.1 "><p id="p325018863113"><a name="p325018863113"></a><a name="p325018863113"></a>PluginModuleStruct::name</p>
</td>
<td class="cellrowborder" valign="top" width="30.020000000000003%" headers="mcps1.2.4.1.2 "><p id="p4250138123112"><a name="p4250138123112"></a><a name="p4250138123112"></a>C style string</p>
</td>
<td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.2.4.1.3 "><p id="p425019883115"><a name="p425019883115"></a><a name="p425019883115"></a>功能:定义插件名称</p>
</td>
</tr>
<tr id="row49481758173013"><td class="cellrowborder" valign="top" width="30%" headers="mcps1.2.4.1.1 "><p id="p1125010813316"><a name="p1125010813316"></a><a name="p1125010813316"></a>PluginModuleStruct::resultBufferSizeHint</p>
</td>
<td class="cellrowborder" valign="top" width="30.020000000000003%" headers="mcps1.2.4.1.2 "><p id="p142509810319"><a name="p142509810319"></a><a name="p142509810319"></a>uint32_t</p>
</td>
<td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.2.4.1.3 "><p id="p1525112853115"><a name="p1525112853115"></a><a name="p1525112853115"></a>功能:用于提示插件管理模块调用数据上报接口时使用的内存缓冲区字节数</p>
</td>
</tr>
</tbody>
</table>
### 使用说明<a name="section681316903611"></a>
下面介绍在设备端基于性能调优框架提供的插件能力,新增一个插件涉及到的关键开发步骤:
1. 编写proto数据定义文件_plugin\_data.proto_定义数据源格式数据源格式决定了插件上报哪些数据
```
message PluginData {
int32 pid = 1;
string name = 2;
uint64 count1 = 3;
uint64 count2 = 4;
uint64 count3 = 5;
......
}
```
2. 编写数据数据源配置文件_plugin\_config.proto_采集的行为可以根据配置进行变化可以设置数据源上报间隔等信息
```
message PluginConfig {
int32 pid = 1;
bool report_interval = 2;
int report_counter_id_1 = 3;
int report_counter_id_2 = 4;
......
}
```
3. 定义PluginModuleCallbacks实现插件回调接口定义PluginModuleStruct类型的g\_pluginModule全局变量注册插件信息。
```
static PluginModuleCallbacks callbacks = {
    PluginSessionStart,
    PluginReportResult,
    PluginSessionStop,
};
PluginModuleStruct g_pluginModule = {&callbacks, "test-plugin", MAX_BUFFER_SIZE};
```
4. 通过PluginSessionStart名字可以自己定义实现插件回调接口列表的onPluginSessionStart接口主要处理插件的开始流程。
```
int PluginSessionStart(const uint8_t* configData, uint32_t configSize)
{
......
return 0;
}
```
5. 通过PluginReportResult名字可以自己定义实现插件回调接口列表的onPluginReportResult接口将插件内部采集的信息通过该接口进行上报
```
int PluginReportResult(uint8_t* bufferData, uint32_t bufferSize)
{
......
return 0;
}
```
6. 通过PluginSessionStop名字可以自己定义实现插件回调接口列表的onPluginSessionStop接口主要进行插件停止后的操作流程。
```
int PluginSessionStop()
{
......
return 0;
}
```
7. 编写proto gn构建脚本, 生成protobuf源文件protobuf源文件编译生成目标文件:
```
action("plugin_cpp_gen") {
script = "${OHOS_PROFILER_DIR}/build/protoc.sh" //依赖的编译工具链
sources = [ //定义的插件相关的proto文件比如插件配置文件、插件数据对应的proto文件
"plugin_data.proto",
"plugin_config.proto",
]
outputs = [ //通过protoc编译生成的结果文件
"plugin_data.pb.h",
"plugin_data.pb.cc",
"plugin_config.pb.h",
"plugin_config.pb.cc",
]
args = [
"--cpp_out",
"$proto_rel_out_dir",
"--proto_path",
rebase_path(".", root_build_dir),
]
deps = [
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})",
]
}
ohos_source_set("plug_cpp") { //将定义的proto文件生成cpp文件
deps = [
":plugin_cpp_gen",
]
public_deps = [
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite",
]
include_dirs = [ "$proto_out_dir" ]
sources = [ //目标plug_cpp中包括的源文件
"plugin_data.pb.h",
"plugin_data.pb.cc",
"plugin_config.pb.h",
"plugin_config.pb.cc",
]
}
```
8. 编写插件GN构建脚本:
```
ohos_shared_library("***plugin") {
output_name = "***plugin"
sources = [
"src/***plugin.cpp", //插件中的源文件
]
include_dirs = [
"../api/include",
"${OHOS_PROFILER_DIR}/device/base/include",
]
deps = [
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc_lib",
"${OHOS_PROFILER_DIR}/protos/types/plugins/**:plug_cpp", //上面ohos_source_set中生成的plug_cpp
]
install_enable = true
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
}
```
### 调测验证:<a name="section35362541215"></a>
插件动态库生成后可以自己编写测试代码通过dlopen加载动态库并调用上面代码中实现的插件模块回调函数进行验证。
```
int main(int argc, char** argv)
{
void* handle;
PluginModuleStruct* memplugin;
    handle = dlopen("./libplugin.z.so", RTLD_LAZY); //动态打开上面生成的插件动态库
    if (handle == nullptr) {
        HILOGD("dlopen err:%s.", dlerror());
        return 0;
    }
memplugin = (PluginModuleStruct*)dlsym(handle, "g_pluginModule"); //获取开发步骤3中定义的g_pluginModule全局变量
//check memplugin->callbacks // 通过该指针调用上面开发步骤3中定义的回调函数
return 0;
```
## 相关仓<a name="section1293495681320"></a>
研发工具链子系统
**developtools\_profiler**
developtools\_hdc\_standard
developtools\_bytrace\_standard

35
build/config.gni Executable file
View File

@ -0,0 +1,35 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
OHOS_PROFILER_DIR = get_path_info("..", "abspath")
OHOS_PROFILER_3RDPARTY_DIR = get_path_info("../../../third_party/", "abspath")
OHOS_PROFILER_3RDPARTY_GRPC_DIR = "${OHOS_PROFILER_3RDPARTY_DIR}/grpc"
OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR =
"${OHOS_PROFILER_3RDPARTY_DIR}/protobuf"
OHOS_PROFILER_3RDPARTY_GOOGLETEST_DIR =
"${OHOS_PROFILER_3RDPARTY_DIR}/googletest"
OHOS_PROFILER_SUBSYS_NAME = "developtools"
OHOS_PROFILER_PART_NAME = "profiler"
OHOS_PROFILER_TEST_MODULE_OUTPUT_PATH = "profiler"
build_l2 = false
if (getenv("BUILD_L2") == "true") {
build_l2 = true
}
print("build_l2 =", build_l2)
print("OHOS_PROFILER_DIR = ", OHOS_PROFILER_DIR)
print("OHOS_PROFILER_3RDPARTY_DIR = ", OHOS_PROFILER_3RDPARTY_DIR)
print("OHOS_PROFILER_3RDPARTY_GRPC_DIR = ", OHOS_PROFILER_3RDPARTY_GRPC_DIR)
print("OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR = ", OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR)
print("OHOS_PROFILER_3RDPARTY_GOOGLETEST_DIR", OHOS_PROFILER_3RDPARTY_GOOGLETEST_DIR)

21
build/gcov.sh Executable file
View File

@ -0,0 +1,21 @@
#!/bin/bash
# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -e
DIR=$(dirname $(realpath ${BASH_SOURCE[0]}))
TOP=$(realpath $DIR/../../..)
CLANG_DIR=$TOP/prebuilts/clang/host/linux-x86/clang-r353983c
if [ ! -e "$CLANG_DIR" ]; then
CLANG_DIR=$TOP/prebuilts/clang/ohos/linux-x86_64/llvm
fi
$CLANG_DIR/bin/llvm-cov gcov $@

38
build/lcov.sh Executable file
View File

@ -0,0 +1,38 @@
#!/bin/bash
# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -e
DIR=$(dirname $(realpath ${BASH_SOURCE[0]}))
TOP=$(realpath $DIR/../../..)
HOST_OUT=$TOP/hos/out/hos-arm/clang_x64
if [ ! -e "$HOST_OUT" ]; then
HOST_OUT=$TOP/out/ohos-arm-release/clang_x64
fi
# collect and convert all gcno and gcda to test.info
lcov -c -d $HOST_OUT -o test.info --gcov-tool $DIR/gcov.sh
if [ $? -ne 0 ]; then
echo "Install lcov: sudo apt install lcov"
fi
# filter out system headers
lcov -r test.info \
'/usr/include/*' \
'*/hos/out/*' \
'*/hos/third_party/*' \
'*/third_party/grpc/*' \
-o test.info
# generate html report
genhtml -o html test.info

28
build/protoc.sh Executable file
View File

@ -0,0 +1,28 @@
#!/bin/bash
# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -e
THIS_DIR=$(dirname ${BASH_SOURCE[0]})
PROJECT_TOP=$(realpath $THIS_DIR/../../..)
OHOS_X64_OUT=$PROJECT_TOP/$2/clang_x64
LIBCXX_X64_OUT=$PROJECT_TOP/$1/ndk/libcxx/linux_x86_64
SUBSYS_X64_OUT=$PROJECT_TOP/$2/clang_x64/developtools/developtools
PROTOC=$PROJECT_TOP/$2/clang_x64/developtools/developtools/protoc
PARAMS=$*
PARAMS_FILTER="$1 $2"
echo "EXEC: LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT $PROTOC ${PARAMS[@]:${#PARAMS_FILTER}}"
LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT exec $PROTOC ${PARAMS[@]:${#PARAMS_FILTER}}

29
build/run.sh Executable file
View File

@ -0,0 +1,29 @@
#!/bin/bash
# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -e
DIR=$(dirname $(realpath ${BASH_SOURCE[0]}))
TOP=$(realpath $DIR/../../..)
SUBSYS=developtools
HOST_OUT=$TOP/hos/out/hos-arm/clang_x64
LIB_PATH=$LIB_PATH:$HOST_OUT/devtools/devtools
LIB_PATH=$LIB_PATH:$HOST_OUT/$SUBSYS/$SUBSYS
LIB_PATH=$LIB_PATH:$HOST_OUT/common/common
LIB_PATH=$LIB_PATH:$LD_LIBRARY_PATH
# remove old coverage data
find $HOST_OUT -name '*.gcda' | xargs rm -v
# run UT executable
echo LD_LIBRARY_PATH=$LIB_PATH $@
LD_LIBRARY_PATH=$LIB_PATH $@

1
device/.clang-format Symbolic link
View File

@ -0,0 +1 @@
../tools/.clang-format

38
device/BUILD.gn Executable file
View File

@ -0,0 +1,38 @@
# Copyright (C) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("base/config.gni")
group("hiprofiler_targets") {
deps = [
"cmds:hiprofiler_cmd",
"plugins/api:hiprofiler_plugins",
"plugins/memory_plugin:memdataplugin",
"services/profiler_service:hiprofilerd",
"services/shared_memory:shared_memory",
"plugins/bytrace_plugin:bytraceplugin",
]
}
group("unittest") {
testonly = true
deps = [
"base/test:unittest",
"plugins/api/test:unittest",
"plugins/memory_plugin/test:unittest",
"services/ipc/test:unittest",
"services/plugin_service/test:unittest",
"services/profiler_service/test:unittest",
"services/shared_memory/test:unittest",
]
}

60
device/base/BUILD.gn Executable file
View File

@ -0,0 +1,60 @@
# Copyright (C) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/ohos.gni")
import("config.gni")
# compile options for gcov
config("hiprofiler_test_config") {
cflags = []
if (enable_debuginfo) {
cflags += [ "-g" ]
}
if (enable_coverage && current_toolchain == host_toolchain) {
cflags += [
# clang coverage options:
"--coverage",
"-mllvm",
"-limited-coverage-experimental=true",
"-fno-use-cxa-atexit",
]
ldflags = [ "--coverage" ]
}
}
config("hiprofiler_base_config") {
include_dirs = [
"include",
"//utils/native/base/include"
]
}
ohos_source_set("hiprofiler_base") {
sources = [
"src/schedule_task_manager.cpp",
]
public_configs = [
":hiprofiler_test_config",
":hiprofiler_base_config",
]
if (current_toolchain != host_toolchain) {
defines = [ "HAVE_HILOG" ]
if (build_l2) {
external_deps = [ "shared_library:libhilog" ]
} else {
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
}
}
}

32
device/base/config.gni Executable file
View File

@ -0,0 +1,32 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("../../build/config.gni")
build_tests = false
enable_debuginfo = false
enable_coverage = false
if (getenv("BUILD_UT") == "true") {
build_tests = true
enable_debuginfo = true
enable_coverage = true
}
if (getenv("BUILD_MT") == "true") {
build_tests = true
enable_debuginfo = true
}
print("build_tests = ", build_tests)
print("enable_debuginfo =", enable_debuginfo)
print("enable_coverage =", enable_coverage)

131
device/base/include/logging.h Executable file
View File

@ -0,0 +1,131 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LOGGING_H
#define LOGGING_H
#ifndef LOG_TAG
#define LOG_TAG ""
#endif
#ifdef HAVE_HILOG
#include "hilog/log.h"
#undef LOG_TAG
#define LOG_TAG "Hiprofiler"
#else
#include <mutex>
#include <string>
#include <securec.h>
#include <sys/syscall.h>
#include <stdarg.h>
#include <time.h>
#include <unistd.h>
#include <vector>
static inline long GetTid()
{
return syscall(SYS_gettid);
}
enum {
HILOG_UNKNOWN = 0,
HILOG_DEFAULT,
HILOG_VERBOSE,
HILOG_DEBUG,
HILOG_INFO,
HILOG_WARN,
HILOG_ERROR,
HILOG_FATAL,
HILOG_SILENT,
};
namespace {
constexpr int NS_PER_MS_LOG = 1000 * 1000;
}
static inline std::string GetTimeStr()
{
char timeStr[64];
struct timespec ts;
struct tm tmStruct;
clock_gettime(CLOCK_REALTIME, &ts);
localtime_r(&ts.tv_sec, &tmStruct);
size_t used = strftime(timeStr, sizeof(timeStr), "%m-%d %H:%M:%S", &tmStruct);
snprintf_s(&timeStr[used], sizeof(timeStr) - used, sizeof(timeStr) - used - 1, ".%03ld",
ts.tv_nsec / NS_PER_MS_LOG);
return timeStr;
}
typedef const char *ConstCharPtr;
static inline int HiLogPrintArgs(int prio, ConstCharPtr tag, ConstCharPtr fmt, va_list vargs)
{
static std::mutex mtx;
static std::vector<std::string> prioNames = {"U", " ", "V", "D", "I", "W", "E", "F", "S"};
std::unique_lock<std::mutex> lock(mtx);
int count =
fprintf(stderr, "%s %7d %7ld %5s %s ", GetTimeStr().c_str(), getpid(), GetTid(), prioNames[prio].c_str(), tag);
count += vfprintf(stderr, fmt, vargs);
count += fprintf(stderr, "\n");
return count;
}
static inline int __hilog_log_print(int prio, ConstCharPtr tag, ConstCharPtr fmt, ...)
{
int count;
va_list vargs;
va_start(vargs, fmt);
count = HiLogPrintArgs(prio, tag, fmt, vargs);
va_end(vargs);
return count;
}
#define HILOG_DEBUG(LOG_CORE, fmt, ...) __hilog_log_print(HILOG_DEBUG, LOG_TAG, fmt, ##__VA_ARGS__)
#define HILOG_INFO(LOG_CORE, fmt, ...) __hilog_log_print(HILOG_INFO, LOG_TAG, fmt, ##__VA_ARGS__)
#define HILOG_WARN(LOG_CORE, fmt, ...) __hilog_log_print(HILOG_WARN, LOG_TAG, fmt, ##__VA_ARGS__)
#define HILOG_ERROR(LOG_CORE, fmt, ...) __hilog_log_print(HILOG_ERROR, LOG_TAG, fmt, ##__VA_ARGS__)
#endif
#define STD_PTR(K, T) std::K##_ptr<T>
#define CHECK_NOTNULL(ptr, retval, fmt, ...) \
do { \
if (ptr == nullptr) { \
HILOG_WARN(LOG_CORE, "CHECK_NOTNULL(%s) in %s:%d FAILED, " fmt, #ptr, __func__, __LINE__, ##__VA_ARGS__); \
return retval; \
} \
} while (0)
#define CHECK_TRUE(expr, retval, fmt, ...) \
do { \
if (!(expr)) { \
HILOG_WARN(LOG_CORE, "CHECK_TRUE(%s) in %s:%d FAILED, " fmt, #expr, __func__, __LINE__, ##__VA_ARGS__); \
return retval; \
} \
} while (0)
#define RETURN_IF(expr, retval, fmt, ...) \
do { \
if ((expr)) { \
HILOG_WARN(LOG_CORE, fmt, ##__VA_ARGS__); \
return retval; \
} \
} while (0)
#endif

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SCHEDULE_TASK_MANAGER_H
#define SCHEDULE_TASK_MANAGER_H
#include <atomic>
#include <chrono>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <thread>
#include <unordered_map>
#include "logging.h"
class ScheduleTaskManager {
public:
static ScheduleTaskManager& GetInstance();
using ms = std::chrono::milliseconds;
bool ScheduleTask(const std::string& name,
const std::function<void(void)>& callback,
const std::chrono::milliseconds& repeatInterval);
bool ScheduleTask(const std::string& name,
const std::function<void(void)>& callback,
const std::chrono::milliseconds& repeatInterval,
std::chrono::milliseconds initialDelay);
bool UnscheduleTask(const std::string& name);
void Shutdown();
ScheduleTaskManager();
~ScheduleTaskManager();
private:
using Clock = std::chrono::steady_clock;
using TimePoint = std::chrono::time_point<Clock>;
struct Task {
std::string name;
std::function<void(void)> callback;
std::chrono::milliseconds repeatInterval;
std::chrono::milliseconds initialDelay;
TimePoint lastRunTime;
};
using SharedTask = STD_PTR(shared, Task);
using WeakTask = STD_PTR(weak, Task);
static std::chrono::milliseconds NormalizeInterval(std::chrono::milliseconds interval);
void DumpTask(const SharedTask& task);
void ScheduleThread();
bool TakeFront(TimePoint& time, WeakTask& task);
private:
mutable std::mutex taskMutex_;
std::condition_variable taskCv_;
std::atomic<bool> runScheduleThread_ = true;
std::multimap<TimePoint, WeakTask> timeMap_;
std::unordered_map<std::string, SharedTask> taskMap_;
std::thread scheduleThread_;
};
#endif // !SCHEDULE_TASK_MANAGER_H

View File

@ -0,0 +1,173 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "schedule_task_manager.h"
#include <ctime>
#include <iostream>
#include <mutex>
#include "logging.h"
#include "securec.h"
namespace {
constexpr std::chrono::milliseconds POLL_INTERVAL = std::chrono::milliseconds(5000);
constexpr std::chrono::milliseconds MIN_REPEAT_INTERVAL = std::chrono::milliseconds(10);
constexpr std::chrono::milliseconds ZERO_INTERVAL = std::chrono::milliseconds(0);
} // namespace
ScheduleTaskManager& ScheduleTaskManager::GetInstance()
{
static ScheduleTaskManager instance;
return instance;
}
ScheduleTaskManager::ScheduleTaskManager()
{
scheduleThread_ = std::thread(&ScheduleTaskManager::ScheduleThread, this);
}
ScheduleTaskManager::~ScheduleTaskManager()
{
Shutdown();
if (scheduleThread_.joinable()) {
scheduleThread_.join();
}
}
void ScheduleTaskManager::Shutdown()
{
std::lock_guard<std::mutex> guard(taskMutex_);
runScheduleThread_ = false;
taskCv_.notify_one();
}
std::chrono::milliseconds ScheduleTaskManager::NormalizeInterval(std::chrono::milliseconds interval)
{
if (interval <= ZERO_INTERVAL) {
return ZERO_INTERVAL;
}
if (interval < MIN_REPEAT_INTERVAL) {
return MIN_REPEAT_INTERVAL;
}
return interval / MIN_REPEAT_INTERVAL * MIN_REPEAT_INTERVAL;
}
bool ScheduleTaskManager::ScheduleTask(const std::string& name,
const std::function<void(void)>& callback,
const std::chrono::milliseconds& repeatInterval)
{
return ScheduleTask(name, callback, repeatInterval, repeatInterval);
}
bool ScheduleTaskManager::ScheduleTask(const std::string& name,
const std::function<void(void)>& callback,
const std::chrono::milliseconds& repeatInterval,
std::chrono::milliseconds initialDelay)
{
auto task = std::make_shared<Task>();
task->name = name;
task->callback = callback;
task->initialDelay = initialDelay;
task->repeatInterval = NormalizeInterval(repeatInterval);
std::lock_guard<std::mutex> guard(taskMutex_);
if (taskMap_.count(name) > 0) {
HILOG_WARN(LOG_CORE, "task name %s already exists!", name.c_str());
return false;
}
taskMap_[name] = task;
timeMap_.insert(std::make_pair(Clock::now() + initialDelay, task));
taskCv_.notify_one();
HILOG_DEBUG(LOG_CORE, "add schedule %s, total: %zu ", name.c_str(), taskMap_.size());
return true;
}
bool ScheduleTaskManager::UnscheduleTask(const std::string& name)
{
HILOG_DEBUG(LOG_CORE, "del schedule %s, total: %zu", name.c_str(), taskMap_.size());
std::unique_lock<std::mutex> lck(taskMutex_);
auto it = taskMap_.find(name);
if (it != taskMap_.end()) {
taskMap_.erase(it);
return true;
}
return false;
}
bool ScheduleTaskManager::TakeFront(TimePoint& time, WeakTask& task)
{
std::unique_lock<std::mutex> lck(taskMutex_);
// thread wait until task insert or shutdown
while (timeMap_.empty() && runScheduleThread_) {
taskCv_.wait_for(lck, POLL_INTERVAL);
}
if (!runScheduleThread_) {
return false;
}
time = timeMap_.begin()->first;
task = timeMap_.begin()->second;
timeMap_.erase(timeMap_.begin());
return true;
}
void ScheduleTaskManager::DumpTask(const SharedTask& task)
{
if (task) {
long msecs = std::chrono::duration_cast<ms>(task->lastRunTime.time_since_epoch()).count();
HILOG_DEBUG(LOG_CORE, "{name = %s, interval = %lld, delay = %lld, lastRun = %ld}",
task->name.c_str(), task->repeatInterval.count(), task->initialDelay.count(), msecs);
}
}
void ScheduleTaskManager::ScheduleThread()
{
while (true) {
// take front task from task queue
TimePoint targetTime;
WeakTask targetTask;
if (!TakeFront(targetTime, targetTask)) {
break;
}
// delay to target time
auto currentTime = Clock::now();
if (targetTime >= currentTime) {
std::this_thread::sleep_for(targetTime - currentTime);
}
// promote to shared_ptr
auto task = targetTask.lock();
DumpTask(task);
if (task != nullptr) {
// call task callback
task->callback();
task->lastRunTime = currentTime;
// re-insert task to map if it's a repeat task
if (task->repeatInterval.count() != 0) {
std::unique_lock<std::mutex> guard(taskMutex_);
timeMap_.insert(std::make_pair(targetTime + task->repeatInterval, task));
}
}
}
}

53
device/base/test/BUILD.gn Executable file
View File

@ -0,0 +1,53 @@
# Copyright (C) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/test.gni")
import("../../base/config.gni")
module_output_path = "${OHOS_PROFILER_TEST_MODULE_OUTPUT_PATH}/device"
config("module_private_config") {
visibility = [":*"]
if (current_toolchain != host_toolchain) {
defines = [ "HAVE_HILOG" ]
}
}
ohos_unittest("hiprofiler_base_ut") {
module_out_path = module_output_path
deps = [
"../:hiprofiler_base",
"//third_party/googletest:gtest",
]
configs = [
":module_private_config"
]
include_dirs = [ "//third_party/googletest/googletest/include/gtest" ]
sources = [
"unittest/schedule_task_manager_test.cpp",
]
cflags = [
"-Wno-inconsistent-missing-override",
"-Dprivate=public", #allow test code access private members
]
external_deps = [
"hiviewdfx_hilog_native:libhilog",
]
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
}
group("unittest") {
testonly = true
deps = [
":hiprofiler_base_ut",
]
}

View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <atomic>
#include <chrono>
#include <hwext/gtest-ext.h>
#include <hwext/gtest-tag.h>
#include <thread>
#include "schedule_task_manager.h"
using namespace testing::ext;
namespace {
class ScheduleTaskManagerTest : public testing::Test {
protected:
static void SetUpTestCase() {}
static void TearDownTestCase() {}
};
/**
* @tc.name: base
* @tc.desc: Get Instance.
* @tc.type: FUNC
*/
HWTEST_F(ScheduleTaskManagerTest, GetInstance, TestSize.Level1)
{
ScheduleTaskManager::GetInstance();
}
/**
* @tc.name: base
* @tc.desc: Single task processing.
* @tc.type: FUNC
*/
HWTEST_F(ScheduleTaskManagerTest, ScheduleTaskOneshot, TestSize.Level1)
{
std::atomic<int> count = 0;
ScheduleTaskManager::ms initalDelay{10};
ScheduleTaskManager scheduleTaskManager;
EXPECT_TRUE(scheduleTaskManager.ScheduleTask(
"task-1", [&]() { count++; }, ScheduleTaskManager::ms{0}, initalDelay));
std::this_thread::sleep_for(initalDelay + initalDelay);
EXPECT_EQ(count.load(), 1);
}
/**
* @tc.name: base
* @tc.desc: Repetitive task processing.
* @tc.type: FUNC
*/
HWTEST_F(ScheduleTaskManagerTest, ScheduleTaskRepeated, TestSize.Level1)
{
std::atomic<int> count = 0;
constexpr int cnt = 5;
ScheduleTaskManager::ms repeatInterval{100};
ScheduleTaskManager::ms initalDelay{10};
ScheduleTaskManager scheduleTaskManager;
EXPECT_TRUE(scheduleTaskManager.ScheduleTask(
"task-2", [&]() { count++; }, repeatInterval, initalDelay));
int expected = 0;
std::this_thread::sleep_for(initalDelay + initalDelay);
for (int i = 0; i < cnt; i++) {
expected++;
EXPECT_EQ(count.load(), expected);
std::this_thread::sleep_for(repeatInterval);
}
}
/**
* @tc.name: base
* @tc.desc: Unschedule Task.
* @tc.type: FUNC
*/
HWTEST_F(ScheduleTaskManagerTest, UnscheduleTask, TestSize.Level1)
{
std::atomic<int> count = 0;
constexpr int cnt = 5;
std::string taskName = "task-3";
ScheduleTaskManager::ms repeatInterval{100};
ScheduleTaskManager::ms initalDelay{10};
ScheduleTaskManager scheduleTaskManager;
EXPECT_TRUE(scheduleTaskManager.ScheduleTask(
taskName, [&]() { count++; }, repeatInterval));
int expected = 0;
std::this_thread::sleep_for(initalDelay);
for (int i = 0; i < cnt; i++) {
std::this_thread::sleep_for(repeatInterval);
expected++;
EXPECT_EQ(count.load(), expected);
}
EXPECT_TRUE(scheduleTaskManager.UnscheduleTask(taskName));
scheduleTaskManager.Shutdown();
EXPECT_EQ(count.load(), expected);
}
} // namespace

41
device/cmds/BUILD.gn Executable file
View File

@ -0,0 +1,41 @@
# Copyright (C) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/ohos.gni")
import("../base/config.gni")
ohos_source_set("command_line") {
sources = [
"src/command_line.cpp",
"src/command_param.cpp",
"src/command_param_switch.cpp",
"src/command_param_text.cpp",
]
include_dirs = [ "include" ]
}
ohos_executable("hiprofiler_cmd") {
sources = [
"src/main.cpp",
]
include_dirs = [ "include" ]
deps = [
":command_line",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite",
"${OHOS_PROFILER_DIR}/protos/services:profiler_services_proto",
"${OHOS_PROFILER_DIR}/protos/services:service_types_proto",
]
install_enable = true
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMMAND_LINE_H
#define COMMAND_LINE_H
#include "command_param.h"
#include "command_param_switch.h"
#include "command_param_text.h"
#include <vector>
#ifdef VT100_ENABLE
#define VT100_RED "\033[31m"
#define VT100_GREEN "\033[32m"
#define VT100_YELLOW "\033[33m"
#define VT100_BLUE "\033[34m"
#define VT100_PURPLE "\033[35m"
#define VT100_CYAN "\033[36m"
#define VT100_WHITE "\033[37m"
#define VT100_CLOSE "\033[0m"
#define VT100_BRIGHT "\033[1m"
#define VT100_UNDERLINE "\033[4m"
#define VT100_FLASH "\033[5m"
#else
#define VT100_RED ""
#define VT100_GREEN ""
#define VT100_YELLOW ""
#define VT100_BLUE ""
#define VT100_PURPLE ""
#define VT100_CYAN ""
#define VT100_WHITE ""
#define VT100_CLOSE ""
#define VT100_BRIGHT ""
#define VT100_UNDERLINE ""
#define VT100_FLASH ""
#endif
class CommandLine {
public:
static CommandLine& GetInstance();
int AnalyzeParam(std::vector<std::string> argv);
void AddParamSwitch(const std::string& filter1, const std::string& filter2, bool &pbool, const std::string& desc);
void AddParamText(const std::string& filter1,
const std::string& filter2,
std::string& pstr,
const std::string& desc);
void PrintHelp();
private:
CommandLine();
~CommandLine();
int paramIdx_;
std::map<uint32_t, std::shared_ptr<CommandParam>> commandParams_;
int CheckParam(const std::string& s1, const std::string& s2);
};
#endif

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMMAND_PARAM_H
#define COMMAND_PARAM_H
#include <cstdint>
#include <list>
#include <map>
#include <ostream>
enum PARAM_TYPE { PARAM_TYPE_SWITCH, PARAM_TYPE_TEXT };
class CommandParam {
public:
enum PARAM_TYPE paramType_;
std::string sDescriptor_;
std::list<std::string> paramFilter_;
void AddFilter(const std::string& filterName);
bool IsInFilter(const std::string& filterName);
};
#endif

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMMAND_SWITCH_H
#define COMMAND_SWITCH_H
#include "command_param.h"
class CommandParamSwitch : public CommandParam {
public:
CommandParamSwitch(bool& value);
~CommandParamSwitch() {}
void SetValue(bool value);
private:
bool& boolSwitch_;
};
#endif

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMMAND_TEXT_H
#define COMMAND_TEXT_H
#include "command_param.h"
class CommandParamText : public CommandParam {
public:
CommandParamText(std::string& s);
~CommandParamText() {}
void SetValue(const std::string& s);
private:
std::string& stringText_;
};
#endif

View File

@ -0,0 +1,144 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "command_line.h"
#include <cstdint>
#include <cstdio>
#include <list>
#include <map>
#include <ostream>
#include "command_param.h"
#include "command_param_switch.h"
#include "command_param_text.h"
CommandLine& CommandLine::GetInstance()
{
static CommandLine commandLine;
return commandLine;
}
CommandLine::CommandLine()
{
paramIdx_ = 0;
}
CommandLine::~CommandLine() {}
void CommandLine::AddParamText(const std::string& filter1,
const std::string& filter2,
std::string& pstr,
const std::string& desc)
{
auto pret = std::make_shared<CommandParamText>(pstr);
if (!filter1.empty()) {
pret->AddFilter(filter1);
}
if (!filter2.empty()) {
pret->AddFilter(filter2);
}
pret->paramType_ = PARAM_TYPE_TEXT;
pret->sDescriptor_ = desc;
commandParams_[paramIdx_++] = pret;
}
void CommandLine::AddParamSwitch(const std::string& filter1,
const std::string& filter2,
bool &pbool,
const std::string& desc)
{
auto pret = std::make_shared<CommandParamSwitch>(pbool);
if (!filter1.empty()) {
pret->AddFilter(filter1);
}
if (!filter2.empty()) {
pret->AddFilter(filter2);
}
pret->paramType_ = PARAM_TYPE_SWITCH;
pret->sDescriptor_ = desc;
commandParams_[paramIdx_++] = pret;
}
namespace {
const int USED_PARAM_ONE = 1;
const int USED_PARAM_TWO = 2;
const int USED_PARAM_ERR = 99999;
const int MAX_TAB_COUNT = 2;
} // namespace
int CommandLine::CheckParam(const std::string& s1, const std::string& s2)
{
for (auto it = commandParams_.begin(); it != commandParams_.end(); ++it) {
auto p = it->second;
if (!p->IsInFilter(s1)) {
continue;
}
switch (p->paramType_) {
case PARAM_TYPE_SWITCH: {
CommandParamSwitch* pswitch = (CommandParamSwitch*)p.get();
pswitch->SetValue(true);
return USED_PARAM_ONE;
} break;
case PARAM_TYPE_TEXT: {
CommandParamText* ptext = (CommandParamText*)p.get();
if (s2 != "") {
ptext->SetValue(s2);
return USED_PARAM_TWO;
}
printf("%s lost content\n", s1.c_str());
return USED_PARAM_ERR;
} break;
default:
printf("unknown type\n");
break;
}
}
printf("unknown param '%s'\n", s1.c_str());
return USED_PARAM_ERR;
}
int CommandLine::AnalyzeParam(std::vector<std::string> argv)
{
size_t i = 1;
while (i < argv.size()) {
i += CheckParam(argv[i], (i + 1 < argv.size()) ? argv[i + 1] : "");
}
if (i >= USED_PARAM_ERR) {
return -1;
}
return 1;
}
void CommandLine::PrintHelp()
{
printf("%shelp :\n", VT100_RED);
for (auto it = commandParams_.begin(); it != commandParams_.end(); ++it) {
auto p = it->second;
int i = 0;
for (std::string temp : p->paramFilter_) {
i++;
if (i == 1) {
printf(" %-16s", temp.c_str());
} else {
printf(" %-2s", temp.c_str());
break;
}
}
for (; i < MAX_TAB_COUNT; i++) {
printf(" ");
}
printf(" : %s\n", p->sDescriptor_.c_str());
}
printf("%s", VT100_CLOSE);
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "command_param.h"
#include <algorithm>
#include <list>
#include <map>
void CommandParam::AddFilter(const std::string& filterName)
{
if (IsInFilter(filterName)) {
return;
}
paramFilter_.push_back(filterName);
}
bool CommandParam::IsInFilter(const std::string& filterName)
{
return std::any_of(paramFilter_.begin(), paramFilter_.end(),
[filterName](std::string s) { return s == filterName; });
}

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "command_param_switch.h"
CommandParamSwitch::CommandParamSwitch(bool& value) : boolSwitch_(value) {}
void CommandParamSwitch::SetValue(bool value)
{
boolSwitch_ = value;
}

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "command_param_text.h"
CommandParamText::CommandParamText(std::string& s) : stringText_(s) {}
void CommandParamText::SetValue(const std::string& s)
{
stringText_ = s;
}

242
device/cmds/src/main.cpp Normal file
View File

@ -0,0 +1,242 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "command_line.h"
#include "profiler_service.grpc.pb.h"
#include "google/protobuf/text_format.h"
#include <grpcpp/grpcpp.h>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <ostream>
#include <vector>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <sys/types.h>
namespace {
const int ADDR_BUFFER_SIZE = 128;
const int MS_PER_S = 1000;
std::string GetIpAddr()
{
char addressBuffer[ADDR_BUFFER_SIZE] = {0};
struct ifaddrs* ifAddrStruct = nullptr;
void* tmpAddrPtr = nullptr;
getifaddrs(&ifAddrStruct);
while (ifAddrStruct != nullptr) {
if (ifAddrStruct->ifa_addr->sa_family == AF_INET) {
// is a valid IP4 Address
tmpAddrPtr = &((reinterpret_cast<struct sockaddr_in*>(ifAddrStruct->ifa_addr))->sin_addr);
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
if (strcmp(addressBuffer, "127.0.0.1") != 0) {
return addressBuffer;
}
} else if (ifAddrStruct->ifa_addr->sa_family == AF_INET6) { // check it is IP6
// is a valid IP6 Address
tmpAddrPtr = &((reinterpret_cast<struct sockaddr_in*>(ifAddrStruct->ifa_addr))->sin_addr);
inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
}
ifAddrStruct = ifAddrStruct->ifa_next;
}
return addressBuffer;
}
std::string ReadFileToString(const std::string& fileName)
{
std::ifstream inputString(fileName, std::ios::in);
if (!inputString) {
printf("can't open %s\n", fileName.c_str());
return "";
}
std::string content(std::istreambuf_iterator<char> {inputString}, std::istreambuf_iterator<char> {});
return content;
}
std::string ReadConfigContent(const std::string& configFileName)
{
std::string content;
if (configFileName == "-") { // Read configuration information from standard input
std::string line;
while (std::getline(std::cin, line)) {
content += line + "\n";
}
} else {
content = ReadFileToString(configFileName);
}
return content;
}
std::unique_ptr<CreateSessionRequest> MakeCreateRequest(const std::string& configFileName,
const std::string& keepSecond, const std::string& outputFileName)
{
auto request = std::make_unique<CreateSessionRequest>();
auto sessionConfig = request->mutable_session_config();
if (!request || !sessionConfig) {
return nullptr;
}
std::string content = ReadConfigContent(configFileName);
if (content.empty()) {
return nullptr;
}
if (!google::protobuf::TextFormat::ParseFromString(content, request.get())) {
printf("config file [%s] format error!\n", configFileName.c_str());
return nullptr;
}
request->set_request_id(0);
if (!keepSecond.empty()) {
int ks = std::stoi(keepSecond);
if (ks > 0) {
sessionConfig->set_sample_duration(ks * MS_PER_S);
}
}
if (!outputFileName.empty()) {
sessionConfig->set_result_file(outputFileName);
}
return request;
}
std::unique_ptr<IProfilerService::Stub> GetProfilerServiceStub()
{
auto grpcChannel = grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials());
if (grpcChannel == nullptr) {
printf("FAIL\nCreate gRPC channel failed!\n");
return nullptr;
}
return IProfilerService::NewStub(grpcChannel);
}
uint32_t CreateSession(const std::string& configFileName,
const std::string& keepSecond, const std::string& outputFileName)
{
auto profilerStub = GetProfilerServiceStub();
if (profilerStub == nullptr) {
printf("FAIL\nGet profiler service stub failed!\n");
return 0;
}
auto request = MakeCreateRequest(configFileName, keepSecond, outputFileName);
if (!request) {
printf("FAIL\nMakeCreateRequest failed!\n");
return 0;
}
CreateSessionResponse createResponse;
grpc::ClientContext createSessionContext;
grpc::Status status = profilerStub->CreateSession(&createSessionContext, *request, &createResponse);
if (!status.ok()) {
printf("FAIL\nCreateSession FAIL\n");
return 0;
}
return createResponse.session_id();
}
bool StartSession(const std::string& configFileName,
const std::string& keepSecond, const std::string& outputFileName)
{
uint32_t sessionId = CreateSession(configFileName, keepSecond, outputFileName);
auto profilerStub = GetProfilerServiceStub();
if (profilerStub == nullptr) {
printf("FAIL\nGet profiler service stub failed!\n");
return false;
}
StartSessionRequest startRequest;
StartSessionResponse startResponse;
startRequest.set_request_id(0);
startRequest.set_session_id(sessionId);
grpc::ClientContext startSessionContext;
grpc::Status status = profilerStub->StartSession(&startSessionContext, startRequest, &startResponse);
if (!status.ok()) {
printf("FAIL\nStartSession FAIL\n");
return false;
}
return true;
}
} // namespace
int main(int argc, char* argv[])
{
CommandLine* pCmdLine = &CommandLine::GetInstance();
bool isGetGrpcAddr = false;
pCmdLine->AddParamSwitch("--getport", "-q", isGetGrpcAddr, "get grpc address");
std::string configFileName;
pCmdLine->AddParamText("--config", "-c", configFileName, "start trace by config file");
std::string traceKeepSecond;
pCmdLine->AddParamText("--time", "-t", traceKeepSecond, "trace time");
std::string outputFileName;
pCmdLine->AddParamText("--out", "-o", outputFileName, "output file name");
bool isHelp = false;
pCmdLine->AddParamSwitch("--help", "-h", isHelp, "make some help");
bool isBackground = false;
pCmdLine->AddParamSwitch("--background", "-d", isBackground, "run in background");
std::vector<std::string> argvVector;
for (int i = 0; i < argc; i++) {
argvVector.push_back(argv[i]);
}
if (argc < 1 || pCmdLine->AnalyzeParam(argvVector) < 0 || isHelp) {
pCmdLine->PrintHelp();
exit(0);
}
if (isGetGrpcAddr) {
auto profilerStub = GetProfilerServiceStub();
if (profilerStub == nullptr) {
printf("FAIL\nGet profiler service stub failed!\n");
return -1;
}
GetCapabilitiesRequest request;
GetCapabilitiesResponse response;
request.set_request_id(0);
grpc::ClientContext context;
grpc::Status status = profilerStub->GetCapabilities(&context, request, &response);
if (!status.ok()) {
printf("FAIL\nService not started\n");
return -1;
}
printf("OK\nip:%s\nport:50051\n", GetIpAddr().c_str());
return 0;
}
if (!configFileName.empty()) {
// Read the configFileNameconvert to protobuf objectstructure 'CreateSession',Send 'StartSession' command to
// profilerd
if (StartSession(configFileName, traceKeepSecond, outputFileName)) {
printf("OK\ntracing...\n");
}
exit(0);
}
return 0;
}

29
device/format-code.sh Executable file
View File

@ -0,0 +1,29 @@
#!/bin/bash
#
# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
set -e
DIR=$(dirname $(realpath ${BASH_SOURCE[0]}))
TOP=$(realpath $DIR/../../..)
CLANG_DIR=$TOP/prebuilts/clang/ohos/linux-x86_64/llvm/bin
GN_DIR=$TOP/prebuilts/build-tools/linux-x86/bin
export PATH=$CLANG_DIR:$GN_DIR:$PATH
echo "formatting C/C++ code ..."
find $@ -name '*.h' -o -name '*.cpp' | xargs clang-format --verbose -i
echo "formatting GN code ..."
find $@ -name '*.gn' -o -name '*.gni' | xargs gn format

81
device/plugins/api/BUILD.gn Executable file
View File

@ -0,0 +1,81 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/ohos.gni")
import("../../base/config.gni")
config("hiprofiler_plugins_config") {
include_dirs = [
"./include",
"./src",
"../../base/include/",
"${OHOS_PROFILER_DIR}/device/services/ipc/include",
"${OHOS_PROFILER_DIR}/device/services/shared_memory/include",
"${OHOS_PROFILER_DIR}/interfaces/kits",
]
cflags = [ "-pthread" ]
if (current_toolchain != host_toolchain) {
cflags += [ "-DHAVE_HILOG" ]
}
}
ohos_source_set("plugins_sources") {
include_dirs = [
"./include",
"../../base/include/",
"${OHOS_PROFILER_DIR}/interfaces/kits",
"//utils/native/base/include",
]
sources = [
"src/buffer_writer.cpp",
"src/command_poller.cpp",
"src/plugin_module.cpp",
"src/plugin_manager.cpp",
"src/plugin_watcher.cpp",
"src/writer_adapter.cpp",
]
public_deps = [
"${OHOS_PROFILER_DIR}/device/services/shared_memory:shared_memory",
"${OHOS_PROFILER_DIR}/protos/services:plugin_services_proto",
"${OHOS_PROFILER_DIR}/protos/services:service_types_proto",
"../../base:hiprofiler_base",
"//utils/native/base:utilsbase",
]
public_configs = [ ":hiprofiler_plugins_config" ]
if (current_toolchain != host_toolchain) {
if (build_l2) {
external_deps = [ "shared_library:libhilog" ]
} else {
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
}
}
}
ohos_executable("hiprofiler_plugins") {
deps = [
":plugins_sources",
]
sources = [
"src/main.cpp",
]
if (current_toolchain != host_toolchain) {
defines = [ "HAVE_HILOG" ]
if (build_l2) {
external_deps = [ "shared_library:libhilog" ]
} else {
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
}
}
install_enable = true
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
}

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WRITER_H
#define WRITER_H
#include <stddef.h>
class Writer {
public:
virtual ~Writer() {}
virtual long Write(const void* data, size_t size) = 0;
virtual bool Flush() = 0;
};
#endif // !WRITER_H

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "buffer_writer.h"
#include "command_poller.h"
#include "logging.h"
#include "plugin_service_types.pb.h"
#include "share_memory_allocator.h"
BufferWriter::BufferWriter(std::string name,
uint32_t size,
int fd,
const CommandPollerPtr& cp,
uint32_t pluginId)
: pluginName_(name)
{
HILOG_DEBUG(LOG_CORE, "CreateMemoryBlockRemote %s %d %d", name.c_str(), size, fd);
shareMemoryBlock_ = ShareMemoryAllocator::GetInstance().CreateMemoryBlockRemote(name, size, fd);
if (shareMemoryBlock_ == nullptr) {
HILOG_DEBUG(LOG_CORE, "shareMemoryBlock_ == nullptr=");
}
commandPoller_ = cp;
pluginId_ = pluginId;
}
BufferWriter::~BufferWriter()
{
ShareMemoryAllocator::GetInstance().ReleaseMemoryBlockRemote(pluginName_);
}
long BufferWriter::Write(const void* data, size_t size)
{
if (shareMemoryBlock_ == nullptr) {
return false;
}
HILOG_DEBUG(LOG_CORE, "BufferWriter Write %zu", size);
return shareMemoryBlock_->PutRaw(reinterpret_cast<const int8_t*>(data), static_cast<uint32_t>(size));
}
bool BufferWriter::WriteProtobuf(google::protobuf::Message& pmsg)
{
if (shareMemoryBlock_ == nullptr) {
return false;
}
HILOG_DEBUG(LOG_CORE, "BufferWriter Write %zu", pmsg.ByteSizeLong());
return shareMemoryBlock_->PutProtobuf(pmsg);
}
bool BufferWriter::Flush()
{
return true;
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BUFFER_WRITER_H
#define BUFFER_WRITER_H
#include <memory>
#include "plugin_module_api.h"
#include "share_memory_allocator.h"
#include "writer.h"
class CommandPoller;
using CommandPollerPtr = STD_PTR(shared, CommandPoller);
class BufferWriter : public Writer {
public:
BufferWriter(std::string name, uint32_t size, int fd, const CommandPollerPtr& cp, uint32_t pluginId);
~BufferWriter();
long Write(const void* data, size_t size) override;
bool Flush() override;
bool WriteProtobuf(google::protobuf::Message& pmsg);
private:
std::string pluginName_;
std::shared_ptr<ShareMemoryBlock> shareMemoryBlock_;
CommandPollerPtr commandPoller_;
uint32_t pluginId_;
};
#endif // BUFFER_WRITER_H

View File

@ -0,0 +1,169 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "command_poller.h"
#include "buffer_writer.h"
#include "plugin_manager.h"
#include "socket_context.h"
CommandPoller::CommandPoller(const PluginManagerPtr& p)
: requestIdAutoIncrease_(1), pluginManager_(p)
{
Connect(DEFAULT_UNIX_SOCKET_PATH);
}
CommandPoller::~CommandPoller() {}
uint32_t CommandPoller::GetRequestId()
{
return requestIdAutoIncrease_++;
}
bool CommandPoller::OnCreateSessionCmd(const CreateSessionCmd& cmd, SocketContext& context) const
{
HILOG_DEBUG(LOG_CORE, "OnCreateSessionCmd PROC");
uint32_t bufferSize = cmd.buffer_sizes(0);
ProfilerPluginConfig config = cmd.plugin_configs(0);
std::vector<ProfilerPluginConfig> configVec;
configVec.push_back(config);
auto pluginManager = pluginManager_.lock(); // promote to shared_ptr
CHECK_NOTNULL(pluginManager, false, "promote FAILED!");
if (!pluginManager->LoadPlugin(config.name())) {
HILOG_DEBUG(LOG_CORE, "OnCreateSessionCmd FAIL 1");
return false;
}
int fd = -1;
if (bufferSize != 0) {
HILOG_DEBUG(LOG_CORE, "OnCreateSessionCmd bufferSize = %d", bufferSize);
fd = context.ReceiveFileDiscriptor();
HILOG_DEBUG(LOG_CORE, "OnCreateSessionCmd fd = %d", fd);
}
if (!pluginManager->CreateWriter(config.name(), bufferSize, fd)) {
HILOG_DEBUG(LOG_CORE, "OnCreateSessionCmd CreateWriter FAIL");
return false;
}
if (!pluginManager->CreatePluginSession(configVec)) {
HILOG_DEBUG(LOG_CORE, "OnCreateSessionCmd CreatePluginSession FAIL");
return false;
}
HILOG_DEBUG(LOG_CORE, "OnCreateSessionCmd OK");
return true;
}
bool CommandPoller::OnDestroySessionCmd(const DestroySessionCmd& cmd) const
{
HILOG_DEBUG(LOG_CORE, "OnDestroySessionCmd PROC");
uint32_t pluginId = cmd.plugin_ids(0);
std::vector<uint32_t> pluginIdVec;
pluginIdVec.push_back(pluginId);
auto pluginManager = pluginManager_.lock(); // promote to shared_ptr
CHECK_NOTNULL(pluginManager, false, "promote FAILED!");
if (!pluginManager->DestroyPluginSession(pluginIdVec)) {
HILOG_DEBUG(LOG_CORE, "OnDestroySessionCmd DestroyPluginSession FAIL");
return false;
}
if (!pluginManager->ResetWriter(pluginId)) {
HILOG_DEBUG(LOG_CORE, "OnDestroySessionCmd ResetWriter FAIL");
return false;
}
if (!pluginManager->UnloadPlugin(pluginId)) {
HILOG_DEBUG(LOG_CORE, "OnDestroySessionCmd UnloadPlugin FAIL");
return false;
}
HILOG_DEBUG(LOG_CORE, "OnDestroySessionCmd OK");
return true;
}
bool CommandPoller::OnStartSessionCmd(const StartSessionCmd& cmd) const
{
HILOG_DEBUG(LOG_CORE, "OnStartSessionCmd PROC");
std::vector<uint32_t> pluginIds;
pluginIds.push_back(cmd.plugin_ids(0));
std::vector<ProfilerPluginConfig> configVec;
configVec.push_back(cmd.plugin_configs(0));
auto pluginManager = pluginManager_.lock(); // promote to shared_ptr
CHECK_NOTNULL(pluginManager, false, "promote FAILED!");
if (!pluginManager->StartPluginSession(pluginIds, configVec)) {
HILOG_DEBUG(LOG_CORE, "OnStartSessionCmd FAIL");
return false;
}
HILOG_DEBUG(LOG_CORE, "OnStartSessionCmd OK");
return true;
}
bool CommandPoller::OnStopSessionCmd(const StopSessionCmd& cmd) const
{
HILOG_DEBUG(LOG_CORE, "OnStopSessionCmd PROC");
std::vector<uint32_t> pluginIds;
pluginIds.push_back(cmd.plugin_ids(0));
auto pluginManager = pluginManager_.lock(); // promote to shared_ptr
CHECK_NOTNULL(pluginManager, false, "promote FAILED!");
if (!pluginManager->StopPluginSession(pluginIds)) {
HILOG_DEBUG(LOG_CORE, "OnStopSessionCmd FAIL");
return false;
}
HILOG_DEBUG(LOG_CORE, "OnStopSessionCmd OK");
return true;
}
bool CommandPoller::OnGetCommandResponse(SocketContext& context, ::GetCommandResponse& response)
{
HILOG_DEBUG(LOG_CORE, "OnGetCommandResponse");
std::this_thread::sleep_for(std::chrono::milliseconds(10));
NotifyResultRequest nrr;
nrr.set_request_id(1);
nrr.set_command_id(response.command_id());
PluginResult* pr = nrr.add_result();
ProfilerPluginState* status = pr->mutable_status();
if (response.has_create_session_cmd()) {
if (OnCreateSessionCmd(response.create_session_cmd(), context)) {
status->set_state(ProfilerPluginState::LOADED);
} else {
status->set_state(ProfilerPluginState::REGISTERED);
}
} else if (response.has_destroy_session_cmd()) {
if (OnDestroySessionCmd(response.destroy_session_cmd())) {
status->set_state(ProfilerPluginState::REGISTERED);
} else {
status->set_state(ProfilerPluginState::LOADED);
}
} else if (response.has_start_session_cmd()) {
if (OnStartSessionCmd(response.start_session_cmd())) {
status->set_state(ProfilerPluginState::IN_SESSION);
} else {
status->set_state(ProfilerPluginState::LOADED);
}
} else if (response.has_stop_session_cmd()) {
if (OnStopSessionCmd(response.stop_session_cmd())) {
status->set_state(ProfilerPluginState::LOADED);
} else {
status->set_state(ProfilerPluginState::IN_SESSION);
}
} else {
HILOG_DEBUG(LOG_CORE, "OnGetCommandResponse FAIL");
return false;
}
HILOG_DEBUG(LOG_CORE, "OnGetCommandResponse OK %d", nrr.command_id());
NotifyResult(nrr);
return true;
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMMAND_POLLER_H
#define COMMAND_POLLER_H
#include <memory>
class PluginManager;
class CreateSessionCmd;
class DestroySessionCmd;
class StartSessionCmd;
class StopSessionCmd;
#include "logging.h"
#include "plugin_service.ipc.h"
using PluginManagerPtr = STD_PTR(shared, PluginManager);
class CommandPoller final : public IPluginServiceClient {
public:
explicit CommandPoller(const PluginManagerPtr& p);
~CommandPoller();
bool OnCreateSessionCmd(const CreateSessionCmd& cmd, SocketContext& context) const;
bool OnDestroySessionCmd(const DestroySessionCmd& cmd) const;
bool OnStartSessionCmd(const StartSessionCmd& cmd) const;
bool OnStopSessionCmd(const StopSessionCmd& cmd) const;
uint32_t GetRequestId();
protected:
bool OnGetCommandResponse(SocketContext& context, ::GetCommandResponse& response) override;
private:
uint32_t requestIdAutoIncrease_;
std::weak_ptr<PluginManager> pluginManager_;
};
#endif // !COMMAND_POLLER_H

58
device/plugins/api/src/main.cpp Executable file
View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "command_poller.h"
#include "logging.h"
#include "plugin_manager.h"
#include "plugin_service_types.pb.h"
#include "plugin_watcher.h"
#include "schedule_task_manager.h"
#include "writer_adapter.h"
namespace {
#if defined(__i386__) || defined(__x86_64__)
const char DEFAULT_PLUGIN_PATH[] = "./";
#else
const char DEFAULT_PLUGIN_PATH[] = "/data/local/tmp/";
#endif
const int SLEEP_ONE_SECOND = 1000;
} // namespace
int main(int argc, char* argv[])
{
std::string pluginDir(DEFAULT_PLUGIN_PATH);
if (argv[1] != nullptr) {
HILOG_DEBUG(LOG_CORE, "pluginDir = %s", argv[1]);
pluginDir = argv[1];
}
auto pluginManager = std::make_shared<PluginManager>();
CHECK_NOTNULL(pluginManager, 1, "create PluginManager FAILED!");
auto commandPoller = std::make_shared<CommandPoller>(pluginManager);
CHECK_NOTNULL(commandPoller, 1, "create CommandPoller FAILED!");
pluginManager->SetCommandPoller(commandPoller);
PluginWatcher watcher(pluginManager);
watcher.ScanPlugins(pluginDir);
watcher.WatchPlugins(pluginDir);
while (true) {
std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_ONE_SECOND));
}
return 0;
}

View File

@ -0,0 +1,358 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "plugin_manager.h"
#include <functional>
#include "command_poller.h"
#include "logging.h"
#include "plugin_service_types.pb.h"
PluginManager::~PluginManager() {}
void PluginManager::SetCommandPoller(const CommandPollerPtr& p)
{
this->commandPoller_ = p;
}
bool PluginManager::AddPlugin(const std::string& pluginPath)
{
PluginModuleInfo info;
if (pluginIds_.find(pluginPath) != pluginIds_.end()) {
HILOG_DEBUG(LOG_CORE, "already add");
return false;
}
auto plugin = std::make_shared<PluginModule>(pluginPath);
if (!plugin->Load()) {
HILOG_DEBUG(LOG_CORE, "load failed");
return false;
}
if (!plugin->BindFunctions()) {
HILOG_DEBUG(LOG_CORE, "BindFunctions failed %s", pluginPath.c_str());
return false;
}
if (!plugin->GetInfo(info)) {
HILOG_DEBUG(LOG_CORE, "getinfo failed");
return false;
}
HILOG_DEBUG(LOG_CORE, "add plugin name = %s", pluginPath.c_str());
if (!plugin->Unload()) {
HILOG_DEBUG(LOG_CORE, "unload failed");
return false;
}
RegisterPluginRequest request;
request.set_request_id(commandPoller_->GetRequestId());
request.set_path(pluginPath);
request.set_sha256("");
request.set_name(pluginPath);
request.set_buffer_size_hint(0);
RegisterPluginResponse response;
if (commandPoller_->RegisterPlugin(request, response)) {
if (response.status() == 0) {
HILOG_DEBUG(LOG_CORE, "response.plugin_id() = %d", response.plugin_id());
pluginIds_[pluginPath] = response.plugin_id();
pluginModules_.insert(std::pair<uint32_t, std::shared_ptr<PluginModule>>(response.plugin_id(), plugin));
HILOG_DEBUG(LOG_CORE, "RegisterPlugin OK");
} else {
HILOG_DEBUG(LOG_CORE, "RegisterPlugin FAIL 1");
return false;
}
} else {
HILOG_DEBUG(LOG_CORE, "RegisterPlugin FAIL 2");
return false;
}
return true;
}
bool PluginManager::RemovePlugin(const std::string& pluginPath)
{
auto it = pluginIds_.find(pluginPath);
if (it == pluginIds_.end()) {
HILOG_DEBUG(LOG_CORE, "plugin not exist");
return false;
}
uint32_t index = it->second;
UnregisterPluginRequest request;
request.set_request_id(commandPoller_->GetRequestId());
request.set_plugin_id(index);
UnregisterPluginResponse response;
if (commandPoller_->UnregisterPlugin(request, response)) {
if (response.status() != 0) {
HILOG_DEBUG(LOG_CORE, "RegisterPlugin FAIL 1");
return false;
}
} else {
HILOG_DEBUG(LOG_CORE, "RegisterPlugin FAIL 2");
return false;
}
auto itPluginModules = pluginModules_.find(index);
if (it == pluginIds_.end()) {
HILOG_DEBUG(LOG_CORE, "plugin not exist");
return false;
}
pluginModules_.erase(itPluginModules);
pluginIds_.erase(it);
return true;
}
bool PluginManager::LoadPlugin(const std::string& pluginPath)
{
HILOG_DEBUG(LOG_CORE, "size = %zu", pluginIds_.size());
auto it = pluginIds_.find(pluginPath);
if (it == pluginIds_.end()) {
HILOG_DEBUG(LOG_CORE, "plugin not exist");
return false;
}
uint32_t index = it->second;
if (!pluginModules_[index]->Load()) {
return false;
}
if (!pluginModules_[index]->BindFunctions()) {
return false;
}
return true;
}
bool PluginManager::UnloadPlugin(const std::string& pluginPath)
{
auto it = pluginIds_.find(pluginPath);
if (it == pluginIds_.end()) {
HILOG_DEBUG(LOG_CORE, "plugin not exist");
return false;
}
return UnloadPlugin(it->second);
}
bool PluginManager::UnloadPlugin(const uint32_t pluginId)
{
HILOG_INFO(LOG_CORE, "%s:UnloadPlugin ready!", __func__);
if (pluginModules_.find(pluginId) == pluginModules_.end()) {
HILOG_DEBUG(LOG_CORE, "plugin not exist");
return false;
}
if (!pluginModules_[pluginId]->Unload()) {
return false;
}
return true;
}
bool PluginManager::CreatePluginSession(const std::vector<ProfilerPluginConfig>& config)
{
HILOG_DEBUG(LOG_CORE, "CreatePluginSession");
for (size_t idx = 0; idx < config.size(); ++idx) {
HILOG_DEBUG(LOG_CORE, "config->name() = %s", config[idx].name().c_str());
auto it = pluginIds_.find(config[idx].name());
if (it == pluginIds_.end()) {
HILOG_DEBUG(LOG_CORE, "plugin not find");
return false;
}
HILOG_DEBUG(LOG_CORE, "index = %d", it->second);
pluginModules_[it->second]->SetConfigData(config[idx].config_data());
}
return true;
}
bool PluginManager::DestroyPluginSession(const std::vector<uint32_t>& pluginIds)
{
for (uint32_t id : pluginIds) {
auto it = pluginModules_.find(id);
if (it == pluginModules_.end()) {
HILOG_DEBUG(LOG_CORE, "plugin not find");
return false;
}
}
return true;
}
bool PluginManager::StartPluginSession(const std::vector<uint32_t>& pluginIds,
const std::vector<ProfilerPluginConfig>& config)
{
HILOG_INFO(LOG_CORE, "%s: ready!", __func__);
size_t idx = 0;
for (uint32_t id : pluginIds) {
auto it = pluginModules_.find(id);
if (it == pluginModules_.end()) {
HILOG_DEBUG(LOG_CORE, "plugin not find");
return false;
}
auto configData = pluginModules_[id]->GetConfigData();
if (!pluginModules_[id]->StartSession(
reinterpret_cast<const uint8_t*>(configData.c_str()), configData.size())) {
return false;
}
if (pluginModules_[id]->GetSampleMode() == PluginModule::POLLING) {
if (idx > config.size()) {
HILOG_WARN(LOG_CORE, "idx %d out of size %zu", idx, config.size());
return false;
}
uint32_t sampleInterval = config[idx].sample_interval();
std::string pluginName = config[idx].name();
HILOG_DEBUG(LOG_CORE, "sampleInterval = %d", sampleInterval);
HILOG_DEBUG(LOG_CORE, "name = %s", pluginName.c_str());
if (!scheduleTaskManager_.ScheduleTask(pluginName, std::bind(&PluginManager::PullResult, this, id),
ScheduleTaskManager::ms(sampleInterval))) {
HILOG_DEBUG(LOG_CORE, "ScheduleTask failed");
return false;
}
}
idx++;
}
return true;
}
bool PluginManager::StopPluginSession(const std::vector<uint32_t>& pluginIds)
{
HILOG_INFO(LOG_CORE, "%s:stop session ready!", __func__);
for (uint32_t id : pluginIds) {
if (pluginModules_.find(id) == pluginModules_.end()) {
HILOG_DEBUG(LOG_CORE, "plugin not find");
return false;
}
if (pluginModules_[id]->GetSampleMode() == PluginModule::POLLING) {
for (auto it : pluginIds_) {
if (it.second == id) {
HILOG_DEBUG(LOG_CORE, "find plugin name = %s", it.first.c_str());
if (!scheduleTaskManager_.UnscheduleTask(it.first)) {
return false;
}
}
}
}
if (!pluginModules_[id]->StopSession()) {
return false;
}
}
return true;
}
bool PluginManager::SubmitResult(const PluginResult& pluginResult)
{
HILOG_DEBUG(LOG_CORE, "==================SubmitResult ===============");
NotifyResultRequest request;
if (commandPoller_ == nullptr) {
HILOG_DEBUG(LOG_CORE, "SubmitResult:commandPoller_ is null");
return false;
}
request.set_request_id(commandPoller_->GetRequestId());
request.set_command_id(0);
PluginResult* p = request.add_result();
*p = pluginResult;
NotifyResultResponse response;
if (!commandPoller_->NotifyResult(request, response)) {
HILOG_DEBUG(LOG_CORE, "SubmitResult FAIL 1");
return false;
}
if (response.status() != 0) {
HILOG_DEBUG(LOG_CORE, "SubmitResult FAIL 2");
return false;
}
HILOG_DEBUG(LOG_CORE, "SubmitResult OK");
return true;
}
bool PluginManager::PullResult(uint32_t pluginId)
{
HILOG_INFO(LOG_CORE, "%s: ready!", __func__);
uint32_t size = 0;
std::string name;
HILOG_DEBUG(LOG_CORE, "PullResult pluginId = %d", pluginId);
auto it = pluginModules_.find(pluginId);
if (it == pluginModules_.end()) {
HILOG_DEBUG(LOG_CORE, "plugin not find");
return false;
}
pluginModules_[pluginId]->GetBufferSizeHint(size);
pluginModules_[pluginId]->GetPluginName(name);
std::unique_ptr<uint8_t[]> buffer {new (std::nothrow) uint8_t[size]};
if (buffer == nullptr) {
HILOG_DEBUG(LOG_CORE, "buffer new failed!");
} else {
HILOG_DEBUG(LOG_CORE, "buffer new success!");
}
int length = it->second->ReportResult(buffer.get(), size);
if (length < 0) {
return false;
}
HILOG_DEBUG(LOG_CORE, "PullResult length = %d", length);
HILOG_DEBUG(LOG_CORE, "PullResult name = %s", name.c_str());
ProfilerPluginData pluginData;
pluginData.set_name(name);
pluginData.set_status(0);
pluginData.set_data(buffer.get(), length);
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
pluginData.set_clock_id(ProfilerPluginData::CLOCKID_REALTIME);
pluginData.set_tv_sec(ts.tv_sec);
pluginData.set_tv_nsec(ts.tv_nsec);
auto writer = pluginModules_[pluginId]->GetWriter();
CHECK_NOTNULL(writer, false, "PullResult GetWriter nullptr");
std::static_pointer_cast<BufferWriter>(writer)->WriteProtobuf(pluginData);
return true;
}
bool PluginManager::CreateWriter(std::string pluginName, uint32_t bufferSize, int fd)
{
auto it = pluginIds_.find(pluginName);
if (it == pluginIds_.end()) {
HILOG_DEBUG(LOG_CORE, "plugin not exist");
return false;
}
uint32_t index = it->second;
if (bufferSize > 0) {
HILOG_DEBUG(LOG_CORE, "%s Use ShareMemory %d", pluginName.c_str(), bufferSize);
pluginModules_[index]->RegisterWriter(
std::make_shared<BufferWriter>(pluginName, bufferSize, fd, commandPoller_, index));
} else {
HILOG_ERROR(LOG_CORE, "no shared memory buffer allocated!");
return false;
}
return true;
}
bool PluginManager::ResetWriter(uint32_t pluginId)
{
if (pluginModules_.find(pluginId) == pluginModules_.end()) {
HILOG_DEBUG(LOG_CORE, "plugin not exist");
return false;
}
HILOG_DEBUG(LOG_CORE, "ResetWriter %u", pluginId);
pluginModules_[pluginId]->RegisterWriter(nullptr);
return true;
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef PLUGIN_MANAGER_H
#define PLUGIN_MANAGER_H
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "plugin_module.h"
#include "schedule_task_manager.h"
class ProfilerPluginConfig;
class PluginResult;
class CommandPoller;
class PluginManager {
public:
virtual ~PluginManager();
bool AddPlugin(const std::string& pluginPath);
bool RemovePlugin(const std::string& pluginPath);
bool LoadPlugin(const std::string& pluginPath);
bool UnloadPlugin(const std::string& pluginPath);
bool UnloadPlugin(const uint32_t pluginId);
// CommandPoller will call the following four interfaces after receiving the command
bool CreatePluginSession(const std::vector<ProfilerPluginConfig>& config);
bool DestroyPluginSession(const std::vector<uint32_t>& pluginIds);
bool StartPluginSession(const std::vector<uint32_t>& pluginIds, const std::vector<ProfilerPluginConfig>& config);
bool StopPluginSession(const std::vector<uint32_t>& pluginIds);
// call the 'PluginModule::ReportResult' and 'PluginManager::SubmitResult' according to 'pluginId'
// creat PluginResult for current plug-in inside
bool PullResult(uint32_t pluginId);
// for test
virtual bool SubmitResult(const PluginResult& pluginResult);
bool CreateWriter(std::string pluginName, uint32_t bufferSize, int fd);
bool ResetWriter(uint32_t pluginId);
void SetCommandPoller(const CommandPollerPtr& p);
private:
std::map<uint32_t, std::shared_ptr<PluginModule>> pluginModules_;
std::map<std::string, uint32_t> pluginIds_; // pluginName maps to pluginId
CommandPollerPtr commandPoller_;
ScheduleTaskManager scheduleTaskManager_;
};
#endif // PLUGIN_MANAGER_H

View File

@ -0,0 +1,241 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "plugin_module.h"
#include <dlfcn.h>
#include <iostream>
#include "logging.h"
#include "plugin_module_api.h"
PluginModule::PluginModule(const std::string& path) : handle_(nullptr), path_(path), structPtr_(nullptr) {}
PluginModule::~PluginModule() {}
std::string PluginModule::ComputeSha256()
{
return "";
}
bool PluginModule::Load()
{
char realPath[PATH_MAX + 1] = {0};
if (handle_ != nullptr) {
HILOG_DEBUG(LOG_CORE, "already open");
return false;
}
if (realpath(path_.c_str(), realPath) == nullptr) {
HILOG_ERROR(LOG_CORE, "so filename invalid, errno=%d", errno);
return false;
}
std::string rpath = realPath; // for SC warning
handle_ = dlopen(rpath.c_str(), RTLD_NOW);
if (handle_ == nullptr) {
HILOG_DEBUG(LOG_CORE, "dlopen err:%s.", dlerror());
return false;
}
return true;
}
bool PluginModule::Unload()
{
HILOG_INFO(LOG_CORE, "%s:unload ready!", __func__);
if (handle_ != nullptr) {
HILOG_INFO(LOG_CORE, "Unload plugin");
int ret = dlclose(handle_);
HILOG_INFO(LOG_CORE, "Unload plugin ret = %d", ret);
handle_ = nullptr;
structPtr_ = nullptr;
return true;
}
return false;
}
bool PluginModule::GetInfo(PluginModuleInfo& info)
{
if (handle_ != nullptr) {
if (structPtr_ == nullptr) {
return false;
}
info.bufferSizeHint = structPtr_->resultBufferSizeHint;
info.name.assign(structPtr_->name);
return true;
}
return false;
}
PluginModule::SampleMode PluginModule::GetSampleMode() const
{
if (structPtr_ && structPtr_->callbacks) {
if (structPtr_->callbacks->onPluginReportResult != nullptr) {
return POLLING;
} else if (structPtr_->callbacks->onRegisterWriterStruct != nullptr) {
return STREAMING;
}
}
return UNKNOWN;
}
void PluginModule::SetConfigData(const std::string& data)
{
configData_ = data;
}
std::string PluginModule::GetConfigData() const
{
return configData_;
}
bool PluginModule::GetPluginName(std::string& pluginName)
{
if (handle_ != nullptr) {
if (structPtr_ == nullptr) {
return false;
}
pluginName.assign(structPtr_->name);
return true;
}
return false;
}
bool PluginModule::GetBufferSizeHint(uint32_t& bufferSizeHint)
{
if (handle_ != nullptr) {
if (structPtr_ == nullptr) {
return false;
}
bufferSizeHint = structPtr_->resultBufferSizeHint;
return true;
}
return false;
}
bool PluginModule::IsLoaded()
{
return (handle_ != nullptr);
}
bool PluginModule::BindFunctions()
{
if (handle_ == nullptr) {
HILOG_DEBUG(LOG_CORE, "plugin not load");
return false;
}
if (structPtr_ == nullptr) {
structPtr_ = (PluginModuleStruct*)dlsym(handle_, "g_pluginModule");
if (structPtr_ == nullptr) {
HILOG_DEBUG(LOG_CORE, "structPtr_ == nullptr");
return false;
}
}
if (structPtr_->callbacks == nullptr) {
HILOG_DEBUG(LOG_CORE, "structPtr_->callbacks == nullptr");
return false;
}
if ((structPtr_->callbacks->onPluginSessionStart == nullptr) ||
(structPtr_->callbacks->onPluginSessionStop == nullptr)) {
HILOG_DEBUG(LOG_CORE, "onPluginSessionStart == nullptr");
return false;
}
return true;
}
bool PluginModule::StartSession(const uint8_t* buffer, uint32_t size)
{
HILOG_DEBUG(LOG_CORE, "StartSession");
if (handle_ == nullptr) {
HILOG_DEBUG(LOG_CORE, "plugin not load");
return false;
}
HILOG_DEBUG(LOG_CORE, "size = %u, ", size);
if (structPtr_ != nullptr && structPtr_->callbacks != nullptr) {
if (structPtr_->callbacks->onPluginSessionStart) {
return (structPtr_->callbacks->onPluginSessionStart(buffer, size) == 0);
}
}
return false;
}
bool PluginModule::StopSession()
{
HILOG_INFO(LOG_CORE, "%s:stop Session ready!", __func__);
if (handle_ == nullptr) {
HILOG_DEBUG(LOG_CORE, "plugin not load");
return false;
}
if (structPtr_ != nullptr && structPtr_->callbacks != nullptr) {
if (structPtr_->callbacks->onPluginSessionStop != nullptr) {
return (structPtr_->callbacks->onPluginSessionStop() == 0);
}
}
return false;
}
int32_t PluginModule::ReportResult(uint8_t* buffer, uint32_t size)
{
HILOG_INFO(LOG_CORE, "%s: ready!", __func__);
HILOG_DEBUG(LOG_CORE, "ReportResult");
if (handle_ == nullptr) {
HILOG_DEBUG(LOG_CORE, "plugin not open");
return -1;
}
if (first_) {
lastTime_ = std::chrono::steady_clock::now();
first_ = false;
} else {
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
std::chrono::duration<int, std::milli> interval =
std::chrono::duration_cast<std::chrono::duration<int, std::milli>>(t1 - lastTime_);
HILOG_DEBUG(LOG_CORE, "the id equals %u interval is %d milli seconds", size, interval.count());
lastTime_ = t1;
}
if (structPtr_ != nullptr && structPtr_->callbacks != nullptr) {
if (structPtr_->callbacks->onPluginReportResult != nullptr) {
HILOG_INFO(LOG_CORE, "%s: call plugin ready!", __func__);
return structPtr_->callbacks->onPluginReportResult(buffer, size);
}
}
return -1;
}
bool PluginModule::RegisterWriter(const BufferWriterPtr writer)
{
writerAdapter_ = std::make_shared<WriterAdapter>();
writerAdapter_->SetWriter(writer);
if (structPtr_ != nullptr && structPtr_->callbacks != nullptr) {
if (structPtr_->callbacks->onRegisterWriterStruct != nullptr) {
return structPtr_->callbacks->onRegisterWriterStruct(writerAdapter_->GetStruct());
}
}
return true;
}
WriterPtr PluginModule::GetWriter()
{
if (writerAdapter_ == nullptr) {
HILOG_DEBUG(LOG_CORE, "PluginModule 111111, nullptr");
return nullptr;
}
return writerAdapter_->GetWriter();
}

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef PLUGIN_MODULE_H
#define PLUGIN_MODULE_H
#include <chrono>
#include <memory>
#include <string>
#include "buffer_writer.h"
#include "writer_adapter.h"
struct PluginModuleInfo {
std::string name;
uint32_t bufferSizeHint = 0;
};
struct PluginModuleStruct;
struct WriterStruct;
using BufferWriterPtr = STD_PTR(shared, BufferWriter);
class PluginModule {
public:
enum SampleMode {
UNKNOWN,
POLLING,
STREAMING,
};
explicit PluginModule(const std::string& path = "");
~PluginModule();
std::string ComputeSha256();
bool Load();
bool Unload();
SampleMode GetSampleMode() const;
bool GetInfo(PluginModuleInfo& info);
bool GetPluginName(std::string& pluginName);
bool GetBufferSizeHint(uint32_t& bufferSizeHint);
bool IsLoaded();
bool BindFunctions();
bool StartSession(const uint8_t* buffer, uint32_t size);
bool StopSession();
int32_t ReportResult(uint8_t* buffer, uint32_t size);
bool RegisterWriter(const BufferWriterPtr writer);
WriterPtr GetWriter();
void SetConfigData(const std::string& data);
std::string GetConfigData() const;
private:
void* handle_;
std::string path_;
std::string pluginName_;
std::string configData_;
PluginModuleStruct* structPtr_;
std::shared_ptr<WriterAdapter> writerAdapter_;
std::chrono::steady_clock::time_point lastTime_;
bool first_ = true;
};
#endif // !PLUGIN_MODULE_H

View File

@ -0,0 +1,184 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "plugin_watcher.h"
#include <climits>
#include <cstdio>
#include <cstring>
#include <dirent.h>
#include <sys/inotify.h>
#include <unistd.h>
#include "logging.h"
#include "plugin_manager.h"
#include "securec.h"
namespace {
constexpr uint32_t MAX_BUF_SIZE = 1024;
} // namespace
PluginWatcher::PluginWatcher(const PluginManagerPtr& pluginManager)
: inotifyFd_(-1), pluginManager_(pluginManager), runMonitor_(true)
{
inotifyFd_ = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
if (inotifyFd_ < 0) {
HILOG_INFO(LOG_CORE, "%s inotify_init1 failed! inotifyFd_ : %d", __FUNCTION__, inotifyFd_);
} else {
monitorThread_ = std::thread(&PluginWatcher::Monitor, this);
}
}
PluginWatcher::~PluginWatcher()
{
runMonitor_ = false;
for (auto it = wdToDir_.begin(); it != wdToDir_.end(); ++it) {
inotify_rm_watch(inotifyFd_, it->first);
}
if (inotifyFd_ != -1) {
close(inotifyFd_);
}
monitorThread_.join();
}
void PluginWatcher::ScanPlugins(const std::string& pluginDir)
{
DIR* dir = nullptr;
struct dirent* entry = nullptr;
char fullpath[PATH_MAX + 1] = {0};
realpath(pluginDir.c_str(), fullpath);
HILOG_INFO(LOG_CORE, "scan plugin from directory %s", fullpath);
dir = opendir(fullpath);
if (dir == nullptr) {
return;
}
while (true) {
entry = readdir(dir);
if (!entry) {
HILOG_INFO(LOG_CORE, "%s readdir finish!", __FUNCTION__);
break;
}
std::string fileName = entry->d_name;
if (entry->d_type & DT_REG) {
size_t pos = fileName.rfind(".so");
if (pos != std::string::npos && (pos == fileName.length() - strlen(".so"))) {
OnPluginAdded(std::string(fullpath) + '/' + fileName);
}
}
}
closedir(dir);
return;
}
void PluginWatcher::WatchPlugins(const std::string& pluginDir)
{
char fullpath[PATH_MAX + 1] = {0};
realpath(pluginDir.c_str(), fullpath);
int wd = inotify_add_watch(inotifyFd_, fullpath, IN_ALL_EVENTS);
if (wd < 0) {
HILOG_INFO(LOG_CORE, "inotify_add_watch add directory %s failed", pluginDir.c_str());
return;
}
HILOG_INFO(LOG_CORE, "inotify_add_watch add directory %s success", fullpath);
std::lock_guard<std::mutex> guard(mtx_);
wdToDir_.insert(std::pair<int, std::string>(wd, std::string(fullpath)));
}
void PluginWatcher::Monitor()
{
const struct inotify_event* event = nullptr;
char buffer[MAX_BUF_SIZE] = {'\0'};
struct timeval time;
char* ptr = nullptr;
int ret = 0;
while (runMonitor_) {
fd_set rFds;
FD_ZERO(&rFds);
FD_SET(inotifyFd_, &rFds);
time.tv_sec = 1;
time.tv_usec = 0;
ret = select(inotifyFd_ + 1, &rFds, nullptr, nullptr, &time);
if (ret < 0) {
continue;
} else if (!ret) {
continue;
} else if (FD_ISSET(inotifyFd_, &rFds)) {
ssize_t readLength = read(inotifyFd_, buffer, MAX_BUF_SIZE);
if (readLength == -1) {
continue;
}
for (ptr = buffer; ptr < buffer + readLength; ptr += sizeof(struct inotify_event) + event->len) {
event = reinterpret_cast<const struct inotify_event*>(ptr);
std::unique_lock<std::mutex> guard(mtx_, std::adopt_lock);
const std::string& pluginDir = wdToDir_[event->wd];
guard.unlock();
if (event->mask & IN_ISDIR) {
continue;
}
std::string fileName = event->name;
size_t pos = fileName.rfind(".so");
if (pos == std::string::npos || (pos != fileName.length() - strlen(".so"))) {
continue;
}
switch (event->mask) {
case IN_CLOSE_WRITE:
case IN_MOVED_TO:
OnPluginAdded(pluginDir + '/' + fileName);
break;
case IN_DELETE:
case IN_MOVED_FROM:
OnPluginRemoved(pluginDir + '/' + fileName);
break;
default:
break;
}
}
if (memset_s(buffer, MAX_BUF_SIZE, 0, MAX_BUF_SIZE) != EOK) {
HILOG_ERROR(LOG_CORE, "memset_s error!");
}
}
}
}
void PluginWatcher::OnPluginAdded(const std::string& pluginPath)
{
auto pluginManager = pluginManager_.lock();
if (pluginManager != nullptr) {
if (pluginManager->AddPlugin(pluginPath)) {
HILOG_INFO(LOG_CORE, "plugin %s add success", pluginPath.c_str());
} else {
HILOG_INFO(LOG_CORE, "pluginPath %s add failed", pluginPath.c_str());
}
} else {
HILOG_INFO(LOG_CORE, "%s weak_ptr pluginManager lock failed!", __FUNCTION__);
}
}
void PluginWatcher::OnPluginRemoved(const std::string& pluginPath)
{
auto pluginManager = pluginManager_.lock();
if (pluginManager != nullptr) {
if (pluginManager->RemovePlugin(pluginPath)) {
HILOG_INFO(LOG_CORE, "pluginPath %s remove success", pluginPath.c_str());
} else {
HILOG_INFO(LOG_CORE, "pluginPath %s remove failed", pluginPath.c_str());
}
} else {
HILOG_INFO(LOG_CORE, "%s weak_ptr pluginManager lock failed!", __FUNCTION__);
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef PLUGIN_WATCHER_H
#define PLUGIN_WATCHER_H
#include <logging.h>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
class PluginManager;
using PluginManagerPtr = STD_PTR(shared, PluginManager);
class PluginWatcher {
public:
explicit PluginWatcher(const PluginManagerPtr& pluginManager);
~PluginWatcher();
void ScanPlugins(const std::string& pluginDir);
void WatchPlugins(const std::string& pluginDir);
private:
int inotifyFd_;
std::weak_ptr<PluginManager> pluginManager_;
std::map<int, std::string> wdToDir_;
std::thread monitorThread_;
std::mutex mtx_;
bool runMonitor_;
virtual void OnPluginAdded(const std::string& pluginPath);
virtual void OnPluginRemoved(const std::string& pluginPath);
void MonitorEventName(uint32_t mask, const std::string& fileName, const std::string& pluginDir);
void Monitor();
};
#endif // !PLUGIN_WATCHER_H

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "writer_adapter.h"
WriterAdapter::WriterAdapter()
{
writerStruct_.write = &WriterAdapter::WriteFunc;
writerStruct_.flush = &WriterAdapter::FlushFunc;
}
WriterAdapter::~WriterAdapter() {}
void WriterAdapter::SetWriter(const WriterPtr& writer)
{
writer_ = writer;
}
WriterPtr WriterAdapter::GetWriter()
{
return writer_;
}
const WriterStruct* WriterAdapter::GetStruct()
{
return &writerStruct_;
}
long WriterAdapter::WriteFunc(WriterStruct* writer, const void* data, size_t size)
{
WriterAdapter* writerAdaptor = reinterpret_cast<WriterAdapter*>(writer);
if (writerAdaptor && writerAdaptor->writer_) {
return writerAdaptor->writer_->Write(data, size);
}
return 0;
}
bool WriterAdapter::FlushFunc(WriterStruct* writer)
{
WriterAdapter* writerAdaptor = reinterpret_cast<WriterAdapter*>(writer);
if (writerAdaptor && writerAdaptor->writer_) {
return writerAdaptor->writer_->Flush();
}
return false;
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WRITER_ADAPTER_H
#define WRITER_ADAPTER_H
#include <memory>
#include "logging.h"
#include "plugin_module_api.h"
#include "writer.h"
using WriterPtr = STD_PTR(shared, Writer);
class WriterAdapter {
public:
WriterAdapter();
~WriterAdapter();
const WriterStruct* GetStruct();
void SetWriter(const WriterPtr& writer);
WriterPtr GetWriter();
private:
static long WriteFunc(WriterStruct* writer, const void* data, size_t size);
static bool FlushFunc(WriterStruct* writer);
private:
WriterStruct writerStruct_;
WriterPtr writer_;
};
#endif // !WRITER_ADAPTER_H

View File

@ -0,0 +1,64 @@
# Copyright (C) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/test.gni")
import("../../../base/config.gni")
module_output_path = "${OHOS_PROFILER_TEST_MODULE_OUTPUT_PATH}/device"
config("module_private_config") {
visibility = [":*"]
}
config("cflags_config") {
cflags = [
"-Wno-sign-compare",
"-pthread",
"-Dprivate=public", #allow test code access private members
"-Dprotected=public", #allow test code access private members
]
}
ohos_unittest("hiprofiler_plugins_ut") {
module_out_path = module_output_path
deps = [
"../:plugins_sources",
"${OHOS_PROFILER_DIR}/device/services/plugin_service:hiprofiler_plugin_service",
"${OHOS_PROFILER_DIR}/device/services/profiler_service:profiler_service",
"//third_party/googletest:gmock",
"//third_party/googletest:gtest",
]
include_dirs = [
"//third_party/googletest/googletest/include/gtest",
]
sources = [
"unittest/writer_adapter_test.cpp",
"unittest/plugin_manager_test.cpp",
"unittest/plugin_watcher_test.cpp",
"unittest/services_ipc_test.cpp",
"unittest/services_profiler_service_test.cpp",
"unittest/services_shared_memory_test.cpp",
"unittest/services_plugin_service_test.cpp",
]
configs = [ ":cflags_config" ]
external_deps = [
"hiviewdfx_hilog_native:libhilog",
]
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
}
group("unittest") {
testonly = true
deps = [
":hiprofiler_plugins_ut",
]
}

View File

@ -0,0 +1,148 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <google/protobuf/message.h>
#include <grpcpp/health_check_service_interface.h>
#include <hwext/gtest-ext.h>
#include <hwext/gtest-tag.h>
#include <thread>
#include "command_poller.h"
#include "grpc/impl/codegen/log.h"
#include "logging.h"
#include "plugin_manager.h"
#include "plugin_service.h"
#include "plugin_service.ipc.h"
#include "profiler_service.h"
#include "socket_context.h"
using google::protobuf::Message;
using namespace testing::ext;
namespace {
const static std::string SUCCESS_PLUGIN_NAME = "libmemdataplugin.z.so";
std::string g_testPluginDir("/data/local/tmp/");
class PluginManagerTest : public ::testing::Test {
protected:
static constexpr auto TEMP_DELAY = std::chrono::milliseconds(20);
static void SetUpTestCase()
{
#if defined(__i386__) || defined(__x86_64__)
char pluginDir[PATH_MAX + 1] = {0};
if (readlink("/proc/self/exe", pluginDir, PATH_MAX) > 0) {
char* pos = strrchr(pluginDir, '/');
if (pos != nullptr) {
*(pos++) = '\0';
printf("-----> pluginDir = %s\n", pluginDir);
g_testPluginDir = pluginDir;
}
}
#endif
printf("======> pluginDir = %s\n", g_testPluginDir.c_str());
std::this_thread::sleep_for(TEMP_DELAY);
printf("SetUpTestCase success\n");
}
static void TearDownTestCase()
{
}
};
/**
* @tc.name: plugin
* @tc.desc: Plug-in normal loading and removal process test.
* @tc.type: FUNC
*/
HWTEST_F(PluginManagerTest, SuccessPlugin, TestSize.Level1)
{
auto pluginManage = std::make_shared<PluginManager>();
auto commandPoller = std::make_shared<CommandPoller>(pluginManage);
pluginManage->SetCommandPoller(commandPoller);
const uint8_t configData[] = {0x30, 0x01, 0x38, 0x01, 0x42, 0x01, 0x01};
ProfilerPluginConfig config;
const std::vector<uint32_t> pluginIdsVector = {1};
config.set_name(g_testPluginDir + "/" + SUCCESS_PLUGIN_NAME);
config.set_config_data((const void*)configData, 7);
config.set_sample_interval(1000);
EXPECT_FALSE(pluginManage->LoadPlugin(g_testPluginDir + "/" + SUCCESS_PLUGIN_NAME));
EXPECT_FALSE(pluginManage->UnloadPlugin(g_testPluginDir + "/" + SUCCESS_PLUGIN_NAME));
EXPECT_FALSE(pluginManage->AddPlugin(g_testPluginDir + "/" + SUCCESS_PLUGIN_NAME));
EXPECT_FALSE(pluginManage->AddPlugin(g_testPluginDir + "/" + SUCCESS_PLUGIN_NAME));
EXPECT_FALSE(pluginManage->RemovePlugin(g_testPluginDir + "/" + SUCCESS_PLUGIN_NAME));
EXPECT_FALSE(pluginManage->RemovePlugin(g_testPluginDir + "/" + SUCCESS_PLUGIN_NAME));
EXPECT_FALSE(pluginManage->AddPlugin(g_testPluginDir + "/" + SUCCESS_PLUGIN_NAME));
EXPECT_FALSE(pluginManage->LoadPlugin(g_testPluginDir + "/" + SUCCESS_PLUGIN_NAME));
EXPECT_FALSE(pluginManage->LoadPlugin(g_testPluginDir + "/" + SUCCESS_PLUGIN_NAME));
EXPECT_FALSE(pluginManage->UnloadPlugin(g_testPluginDir + "/" + SUCCESS_PLUGIN_NAME));
EXPECT_FALSE(pluginManage->LoadPlugin(g_testPluginDir + "/" + SUCCESS_PLUGIN_NAME));
std::vector<ProfilerPluginConfig> configVec;
configVec.push_back(config);
EXPECT_FALSE(pluginManage->CreatePluginSession(configVec));
EXPECT_FALSE(pluginManage->StartPluginSession(pluginIdsVector, configVec));
std::this_thread::sleep_for(TEMP_DELAY);
EXPECT_FALSE(pluginManage->StopPluginSession(pluginIdsVector));
EXPECT_FALSE(pluginManage->DestroyPluginSession(pluginIdsVector));
}
/**
* @tc.name: plugin
* @tc.desc: get sample Mode.
* @tc.type: FUNC
*/
HWTEST_F(PluginManagerTest, GetSampleMode, TestSize.Level1)
{
PluginModule pluginModule;
pluginModule.GetSampleMode();
}
/**
* @tc.name: plugin
* @tc.desc: Plug-in data acquisition process test.
* @tc.type: FUNC
*/
HWTEST_F(PluginManagerTest, PluginManager, TestSize.Level1)
{
PluginManager pluginManager;
PluginModuleInfo info;
pluginManager.UnloadPlugin(0);
PluginResult pluginResult;
pluginManager.SubmitResult(pluginResult);
pluginManager.PullResult(0);
pluginManager.CreateWriter("", 0, -1);
pluginManager.ResetWriter(-1);
PluginModule pluginModule;
pluginModule.ComputeSha256();
pluginModule.Unload();
pluginModule.GetInfo(info);
std::string str("memory-plugin");
pluginModule.GetPluginName(str);
uint32_t num = 0;
pluginModule.GetBufferSizeHint(num);
pluginModule.IsLoaded();
BufferWriter bufferWriter("", 0, -1, nullptr, 0);
bufferWriter.Write(nullptr, 0);
bufferWriter.Flush();
}
} // namespace

View File

@ -0,0 +1,184 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <fcntl.h>
#include <gmock/gmock.h>
#include <hwext/gtest-ext.h>
#include <hwext/gtest-tag.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <vector>
#include "plugin_manager.h"
#include "plugin_watcher.h"
#include "logging.h"
using namespace testing::ext;
namespace {
static std::vector<std::string> g_cmpFileList;
static std::vector<std::string> g_createFileList = {
"lib_6.so", "lib_5.so", "lib_8.so", "lib_4.so", "test1.txt"
};
std::vector<int> g_createFdList;
static std::vector<std::string> g_addFileList = {
"libadd_6.so", "libadd_5.so", "libadd_8.so", "libadd_4.so", "test2.txt"
};
static std::vector<std::string> g_expectFileList = {
"libadd_6.so", "libadd_5.so", "libadd_8.so", "libadd_4.so",
"lib_6.so", "lib_5.so", "lib_8.so", "lib_4.so"
};
static int g_defaultFileMode = 0777;
#if defined(__i386__) || defined(__x86_64__)
const static std::string DEFAULT_TEST_PATH = "./";
#else
const static std::string DEFAULT_TEST_PATH = "/data/local/tmp/";
#endif
class PluginWatchTest : public ::testing::Test {
protected:
static constexpr int TEMP_DELAY = 10 * 1000;
static void SetUpTestCase() {}
static void TearDownTestCase() {}
void SetUp() override {}
void TearDown() override {}
};
class MockPluginWatcher : public PluginWatcher {
public:
MockPluginWatcher(const PluginManagerPtr& pluginManager) : PluginWatcher(pluginManager) {}
~MockPluginWatcher() = default;
MOCK_METHOD1(OnPluginAdded, void(const std::string&));
MOCK_METHOD1(OnPluginRemoved, void(const std::string&));
};
static void OnPluginAddedStub(const std::string& path)
{
g_cmpFileList.push_back(path);
sort(g_cmpFileList.begin(), g_cmpFileList.end());
return;
}
static void OnPluginRemovedStub(const std::string& path)
{
for (auto iter = g_cmpFileList.cbegin(); iter != g_cmpFileList.cend(); iter++) {
if (*iter == path) {
g_cmpFileList.erase(iter);
break;
}
}
return;
}
static void CreateFile()
{
for (auto it : g_createFileList) {
int fd = creat(it.c_str(), g_defaultFileMode);
g_createFdList.push_back(fd);
}
}
static void AddFile()
{
for (auto it : g_addFileList) {
int fd = creat(it.c_str(), g_defaultFileMode);
if (fd < 0) {
return;
}
write(fd, "testcase", 1);
close(fd);
}
return;
}
static void DeleteFile()
{
for (auto it : g_createFileList) {
for (auto fd : g_createFdList) {
close(fd);
}
remove(it.c_str());
}
for (auto it : g_addFileList) {
remove(it.c_str());
}
return;
}
static bool CheckFileList()
{
sort(g_expectFileList.begin(), g_expectFileList.end());
if (g_expectFileList.size() != g_cmpFileList.size()) {
return false;
}
for (size_t i = 0; i < g_expectFileList.size(); i++) {
char fullpath[PATH_MAX + 1] = {0};
realpath(g_expectFileList.at(i).c_str(), fullpath);
if (g_cmpFileList.at(i) != fullpath) {
return false;
}
}
return true;
}
/**
* @tc.name: plugin
* @tc.desc: Monitor the plugin loading in the test directory.
* @tc.type: FUNC
*/
HWTEST_F(PluginWatchTest, SingleWatchDirTest, TestSize.Level1)
{
auto pluginManage = std::make_shared<PluginManager>();
MockPluginWatcher watcher(pluginManage);
EXPECT_CALL(watcher, OnPluginAdded(testing::_)).WillRepeatedly(testing::Invoke(OnPluginAddedStub));
EXPECT_CALL(watcher, OnPluginRemoved(testing::_)).WillRepeatedly(testing::Invoke(OnPluginRemovedStub));
g_createFdList.clear();
CreateFile();
watcher.ScanPlugins(DEFAULT_TEST_PATH);
watcher.WatchPlugins(DEFAULT_TEST_PATH);
usleep(TEMP_DELAY);
AddFile();
usleep(TEMP_DELAY);
EXPECT_EQ(CheckFileList(), false);
DeleteFile();
usleep(TEMP_DELAY);
EXPECT_EQ(g_cmpFileList.empty(), true);
}
/**
* @tc.name: plugin
* @tc.desc: Plug-in process exception test.
* @tc.type: FUNC
*/
HWTEST_F(PluginWatchTest, OnPluginAdded, TestSize.Level1)
{
const auto pluginManage = std::make_shared<PluginManager>();
PluginWatcher pluginWatcher(pluginManage);
pluginWatcher.OnPluginAdded("");
pluginWatcher.OnPluginRemoved("");
}
} // namespace

View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <hwext/gtest-ext.h>
#include <hwext/gtest-tag.h>
#include <thread>
#include "client_map.h"
#include "plugin_service.ipc.h"
#include "service_entry.h"
#include "socket_context.h"
#include "unix_socket_client.h"
#include "unix_socket_server.h"
using namespace testing::ext;
namespace {
class ServicesIpcTest : public ::testing::Test {
protected:
static constexpr auto TEMP_DELAY = std::chrono::milliseconds(10);
static void SetUpTestCase() {}
static void TearDownTestCase() {}
};
/**
* @tc.name: ipc
* @tc.desc: Socket send/recv interface.
* @tc.type: FUNC
*/
HWTEST_F(ServicesIpcTest, ProtocolProc, TestSize.Level1)
{
ServiceBase serviceBase;
SocketContext socketContext;
ASSERT_FALSE(serviceBase.ProtocolProc(socketContext, 0, nullptr, 0));
ASSERT_TRUE(!socketContext.SendRaw(-1, nullptr, 0, 0));
ASSERT_TRUE(!socketContext.SendFileDescriptor(-1));
ASSERT_EQ(socketContext.ReceiveFileDiscriptor(), -1);
ASSERT_EQ(socketContext.RawProtocolProc(-1, nullptr, -1), -1);
}
/**
* @tc.name: ipc
* @tc.desc: Client link.
* @tc.type: FUNC
*/
HWTEST_F(ServicesIpcTest, ClientSocket, TestSize.Level1)
{
ServiceEntry serviceEntry;
ClientMap::GetInstance().PutClientSocket(0, serviceEntry);
ASSERT_EQ(ClientMap::GetInstance().AutoRelease(), 1);
ClientConnection* clientConnection = new ClientConnection(0, serviceEntry);
ASSERT_EQ(clientConnection->RawProtocolProc(-1, nullptr, 0), -1);
}
/**
* @tc.name: plugin
* @tc.desc: Abnormal client link.
* @tc.type: FUNC
*/
HWTEST_F(ServicesIpcTest, unixSocketClient, TestSize.Level1)
{
UnixSocketClient unixSocketClient;
ServiceBase serviceBase;
ASSERT_TRUE(!unixSocketClient.Connect("asdf", serviceBase));
}
/**
* @tc.name: plugin
* @tc.desc: Start unixSocket Server.
* @tc.type: FUNC
*/
HWTEST_F(ServicesIpcTest, UnixSocketServer, TestSize.Level1)
{
UnixSocketServer unixSocketServer;
unixSocketServer.UnixSocketAccept(nullptr);
ServiceEntry serviceEntry;
ASSERT_TRUE(unixSocketServer.StartServer("", serviceEntry));
}
/**
* @tc.name: plugin
* @tc.desc: Server process monitoring.
* @tc.type: FUNC
*/
HWTEST_F(ServicesIpcTest, ServiceEntry, TestSize.Level1)
{
ServiceEntry serviceEntry;
IPluginServiceServer pluginService;
serviceEntry.StartServer("test_unix_socket_service_entry");
serviceEntry.RegisterService(pluginService);
serviceEntry.FindServiceByName(pluginService.serviceName_);
std::this_thread::sleep_for(TEMP_DELAY);
GetTimeMS();
GetTimeUS();
GetTimeNS();
IPluginServiceClient pluginClient;
ASSERT_FALSE(pluginClient.Connect(""));
std::this_thread::sleep_for(TEMP_DELAY);
}
} // namespace

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <hwext/gtest-ext.h>
#include <hwext/gtest-tag.h>
#include "plugin_service.h"
#include "plugin_session.h"
#include "profiler_data_repeater.h"
using namespace testing::ext;
using PluginServicePtr = STD_PTR(shared, PluginService);
class ServicesPluginServiceTest : public ::testing::Test {
protected:
static void SetUpTestCase() {}
static void TearDownTestCase() {}
};
/**
* @tc.name: plugin
* @tc.desc: Session flow test, get session id by plugin name.
* @tc.type: FUNC
*/
HWTEST_F(ServicesPluginServiceTest, PluginService1, TestSize.Level1)
{
PluginServicePtr pluginService = std::make_shared<PluginService>();
ProfilerPluginConfig ppc;
ppc.set_name("abc.so");
ppc.set_plugin_sha256("ASDFAADSF");
ppc.set_sample_interval(20);
pluginService->CreatePluginSession(ppc, std::make_shared<ProfilerDataRepeater>(4096));
pluginService->StartPluginSession(ppc);
pluginService->StopPluginSession("abc.so");
pluginService->DestroyPluginSession("abc.so");
pluginService->GetPluginIdByName("abc.so");
}
/**
* @tc.name: plugin
* @tc.desc: Session flow test, get plugin status.
* @tc.type: FUNC
*/
HWTEST_F(ServicesPluginServiceTest, PluginService2, TestSize.Level1)
{
PluginServicePtr pluginService = std::make_shared<PluginService>();
ProfilerPluginConfig ppc;
ppc.set_name("abc.so");
ppc.set_plugin_sha256("ASDFAADSF");
ppc.set_sample_interval(20);
ProfilerSessionConfig::BufferConfig bc;
bc.set_pages(1);
bc.set_policy(ProfilerSessionConfig_BufferConfig_Policy_RECYCLE);
pluginService->CreatePluginSession(ppc, bc, std::make_shared<ProfilerDataRepeater>(4096));
pluginService->StartPluginSession(ppc);
pluginService->StopPluginSession("abc.so");
pluginService->GetPluginStatus();
PluginInfo pi;
pi.id = 0;
pi.name = "abc.so";
pi.path = "abc.so";
pi.sha256 = "asdfasdf";
pluginService->RemovePluginInfo(pi);
}

View File

@ -0,0 +1,435 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <hwext/gtest-ext.h>
#include <hwext/gtest-tag.h>
#include "logging.h"
#include "plugin_service.h"
#include "plugin_session.h"
#include "profiler_capability_manager.h"
#include "profiler_data_repeater.h"
#include "profiler_service.h"
#include "result_demuxer.h"
#include "trace_file_reader.h"
#include "trace_file_writer.h"
using namespace testing::ext;
namespace {
#if defined(__i386__) || defined(__x86_64__)
const std::string DEFAULT_TEST_PATH("./");
#else
const std::string DEFAULT_TEST_PATH("/data/local/tmp/");
#endif
using PluginServicePtr = STD_PTR(shared, PluginService);
using ProfilerDataRepeaterPtr = STD_PTR(shared, ProfilerDataRepeater);
using ProfilerServicePtr = STD_PTR(shared, ProfilerService);
using ProfilerPluginDataPtr = STD_PTR(shared, ProfilerPluginData);
constexpr int DATA_MAX_SIZE = 10;
class ServicesProfilerServiceTest : public ::testing::Test {
protected:
ProfilerPluginConfig config;
ProfilerSessionConfig::BufferConfig bufferConfig;
PluginInfo pluginInfo;
PluginServicePtr service;
ProfilerDataRepeaterPtr repeater;
ProfilerServicePtr service_;
std::unique_ptr<grpc::ServerContext> context_;
std::atomic<int> requestCounter{0};
static void SetUpTestCase() {}
static void TearDownTestCase() {}
void SetUp() override
{
config.set_name("test_session");
bufferConfig.set_pages(0);
pluginInfo.name = config.name();
service = std::make_shared<PluginService>();
repeater = std::make_shared<ProfilerDataRepeater>(DATA_MAX_SIZE);
if (service) {
service->AddPluginInfo(pluginInfo);
}
service_ = std::make_shared<ProfilerService>(service);
context_ = std::make_unique<grpc::ServerContext>();
}
void TearDown() override
{
if (service) {
service->RemovePluginInfo(pluginInfo);
}
ProfilerCapabilityManager::GetInstance().pluginCapabilities_.clear();
}
};
/**
* @tc.name: plugin
* @tc.desc: Plugin session flow test.
* @tc.type: FUNC
*/
HWTEST_F(ServicesProfilerServiceTest, PluginSession, TestSize.Level1)
{
auto session = std::make_shared<PluginSession>(config, nullptr, nullptr);
EXPECT_NE(session, nullptr);
EXPECT_FALSE(session->IsAvailable());
EXPECT_FALSE(session->Create());
config.set_name("test_session2");
session = std::make_shared<PluginSession>(config, service, repeater);
repeater->Size();
session.reset();
config.set_name("test_session3");
session = std::make_shared<PluginSession>(config, service, repeater);
ASSERT_NE(session->GetState(), PluginSession::CREATED);
EXPECT_FALSE(session->Start());
ASSERT_NE(session->GetState(), PluginSession::STARTED);
EXPECT_FALSE(session->Stop());
ASSERT_NE(session->GetState(), PluginSession::CREATED);
EXPECT_FALSE(session->Destroy());
EXPECT_EQ(session->GetState(), PluginSession::INITIAL);
// recreate is OK
EXPECT_FALSE(session->Create());
EXPECT_FALSE(session->Destroy());
repeater->Reset();
}
/**
* @tc.name: plugin
* @tc.desc: Streaming session test.
* @tc.type: FUNC
*/
HWTEST_F(ServicesProfilerServiceTest, TraceFileWriter, TestSize.Level1)
{
std::string path = "trace.bin";
auto writer = std::make_shared<TraceFileWriter>(path);
EXPECT_NE(writer, nullptr);
std::string testData = "Hello, Wrold!";
EXPECT_EQ(writer->Write(testData.data(), testData.size()), sizeof(uint32_t) + testData.size());
EXPECT_EQ(writer->Flush(), true);
ProfilerPluginData pluginData;
pluginData.set_name("ABC");
pluginData.set_status(0);
pluginData.set_data("DEF");
EXPECT_GT(writer->Write(pluginData), 0);
}
/**
* @tc.name: plugin
* @tc.desc: Streaming session test.
* @tc.type: FUNC
*/
HWTEST_F(ServicesProfilerServiceTest, TraceFileReader, TestSize.Level1)
{
std::string path = "trace-write-msg.bin";
auto writer = std::make_shared<TraceFileWriter>(path);
ASSERT_NE(writer, nullptr);
constexpr int n = 100;
for (int i = 1; i <= n; i++) {
ProfilerPluginData pluginData{};
pluginData.set_name("test_name");
pluginData.set_status(i);
pluginData.set_data("Hello, Wrold!");
long bytes = writer->Write(pluginData);
EXPECT_EQ(bytes, sizeof(uint32_t) + pluginData.ByteSizeLong());
HILOG_INFO(LOG_CORE, "[%d/%d] write %ld bytes to %s.", i, n, bytes, path.c_str());
}
writer.reset(); // make sure write done!
auto reader = std::make_shared<TraceFileReader>();
ASSERT_NE(reader, nullptr);
ASSERT_TRUE(reader->Open(path));
for (int i = 1; i <= n; i++) {
ProfilerPluginData data{};
long bytes = reader->Read(data);
HILOG_INFO(LOG_CORE, "data = {%s, %d, %s}", data.name().c_str(), data.status(), data.data().c_str());
HILOG_INFO(LOG_CORE, "read %ld bytes from %s", bytes, path.c_str());
}
ASSERT_TRUE(reader->Open(path));
long bytes = 0;
do {
ProfilerPluginData data{};
bytes = reader->Read(data);
HILOG_INFO(LOG_CORE, "data = {%s, %d, %s}", data.name().c_str(), data.status(), data.data().c_str());
HILOG_INFO(LOG_CORE, "read %ld bytes from %s", bytes, path.c_str());
} while (bytes > 0);
ASSERT_EQ(reader->Read(nullptr, 0), 0);
}
/**
* @tc.name: service
* @tc.desc: Streaming session report result test.
* @tc.type: FUNC
*/
HWTEST_F(ServicesProfilerServiceTest, ResultDemuxer1, TestSize.Level1)
{
std::string path = "demux.bin";
ProfilerDataRepeaterPtr repeater = std::make_shared<ProfilerDataRepeater>(DATA_MAX_SIZE);
auto demuxer = std::make_shared<ResultDemuxer>(repeater);
EXPECT_NE(demuxer, nullptr);
demuxer->SetTraceWriter(nullptr);
auto writer = std::make_shared<TraceFileWriter>(path);
EXPECT_NE(writer, nullptr);
demuxer->SetTraceWriter(writer);
const int putCount = 20;
const int putDelayUs = 10 * 1000;
demuxer->StartTakeResults();
std::thread dataProducer([=] {
for (int i = 0; i < putCount; i++) {
auto pluginData = std::make_shared<ProfilerPluginData>();
ASSERT_NE(pluginData, nullptr);
pluginData->set_name("test-" + std::to_string(i));
pluginData->set_status(i);
repeater->PutPluginData(pluginData);
HILOG_DEBUG(LOG_CORE, "put test data %d...", i);
usleep(putDelayUs);
}
repeater->PutPluginData(nullptr);
});
HILOG_DEBUG(LOG_CORE, "wating producer thread done...");
dataProducer.join();
}
/**
* @tc.name: service
* @tc.desc: Streaming session report result test.
* @tc.type: FUNC
*/
HWTEST_F(ServicesProfilerServiceTest, ResultDemuxer2, TestSize.Level1)
{
std::string path = "demux.bin";
ProfilerDataRepeaterPtr repeater = std::make_shared<ProfilerDataRepeater>(DATA_MAX_SIZE);
auto demuxer = std::make_shared<ResultDemuxer>(repeater);
ASSERT_NE(demuxer, nullptr);
auto writer = std::make_shared<TraceFileWriter>(path);
EXPECT_NE(writer, nullptr);
demuxer->SetTraceWriter(writer);
const int putCount = 30;
const int putDelayUs = 10 * 1000;
demuxer->StartTakeResults();
std::thread dataProducer([=] {
for (int i = 0; i < putCount; i++) {
auto pluginData = std::make_shared<ProfilerPluginData>();
ASSERT_NE(pluginData, nullptr);
pluginData->set_name("AB-" + std::to_string(i));
pluginData->set_status(i);
HILOG_DEBUG(LOG_CORE, "put test data %d...", i);
if (!repeater->PutPluginData(pluginData)) {
HILOG_WARN(LOG_CORE, "put test data %d FAILED!", i);
break;
}
usleep(putDelayUs);
}
});
usleep((putCount / 2) * putDelayUs);
demuxer->StopTakeResults();
repeater->Close();
HILOG_DEBUG(LOG_CORE, "wating producer thread done...");
dataProducer.join();
}
/**
* @tc.name: server
* @tc.desc: Profiler capacity management.
* @tc.type: FUNC
*/
HWTEST_F(ServicesProfilerServiceTest, ProfilerCapabilityManager, TestSize.Level1)
{
std::vector<ProfilerPluginCapability> caps = ProfilerCapabilityManager::GetInstance().GetCapabilities();
for (int i = 0; i < caps.size(); i++) {
auto cap = caps[i];
EXPECT_TRUE(ProfilerCapabilityManager::GetInstance().RemoveCapability(cap.name()));
}
caps.clear();
EXPECT_EQ(ProfilerCapabilityManager::GetInstance().GetCapability("xxx"), nullptr);
EXPECT_EQ(ProfilerCapabilityManager::GetInstance().GetCapabilities().size(), 0);
caps = ProfilerCapabilityManager::GetInstance().GetCapabilities();
EXPECT_EQ(caps.size(), 0);
const int n = 10;
for (int i = 0; i < n; i++) {
ProfilerPluginCapability cap;
cap.set_path("/system/lib/libcap_" + std::to_string(i) + ".so");
cap.set_name("cap_" + std::to_string(i));
EXPECT_TRUE(ProfilerCapabilityManager::GetInstance().AddCapability(cap));
EXPECT_EQ(ProfilerCapabilityManager::GetInstance().GetCapabilities().size(), i + 1);
}
for (int i = 0; i < n; i++) {
ProfilerPluginCapability cap;
cap.set_name("cap_" + std::to_string(i));
auto capPtr = ProfilerCapabilityManager::GetInstance().GetCapability(cap.name());
ASSERT_NE(capPtr, nullptr);
EXPECT_EQ(capPtr->name(), cap.name());
}
ProfilerPluginCapability cap1;
cap1.set_path("/system/lib/libcap1.so");
cap1.set_name("cap1");
EXPECT_TRUE(ProfilerCapabilityManager::GetInstance().AddCapability(cap1));
cap1.set_path("/system/lib/libcap2.so");
EXPECT_TRUE(ProfilerCapabilityManager::GetInstance().UpdateCapability(cap1.name(), cap1));
EXPECT_TRUE(ProfilerCapabilityManager::GetInstance().RemoveCapability(cap1.name()));
caps = ProfilerCapabilityManager::GetInstance().GetCapabilities();
EXPECT_EQ(caps.size(), n);
for (int i = 0; i < caps.size(); i++) {
auto cap = caps[i];
EXPECT_TRUE(ProfilerCapabilityManager::GetInstance().RemoveCapability(cap.name()));
EXPECT_EQ(ProfilerCapabilityManager::GetInstance().GetCapabilities().size(), n - (i + 1));
}
}
/**
* @tc.name: server
* @tc.desc: Profiler data repeater.
* @tc.type: FUNC
*/
HWTEST_F(ServicesProfilerServiceTest, ProfilerDataRepeater, TestSize.Level1)
{
const int itemCounts = 10000;
const int bufferSize = itemCounts;
auto inDataRepeater = std::make_shared<ProfilerDataRepeater>(bufferSize);
ASSERT_NE(inDataRepeater, nullptr);
auto outDataRepeater = std::make_shared<ProfilerDataRepeater>(bufferSize);
ASSERT_NE(outDataRepeater, nullptr);
auto f = [](int x) { return 2 * x + 1; };
std::thread worker([&]() {
for (int i = 0; i < itemCounts; i++) {
auto xData = inDataRepeater->TakePluginData();
// compute in worker thread
int x = xData ? std::stoi(xData->data()) : 0;
int y = f(x);
auto yData = std::make_shared<ProfilerPluginData>();
yData->set_data(std::to_string(y));
outDataRepeater->PutPluginData(yData);
}
});
std::vector<int> yVec;
for (int i = 0; i < itemCounts; i++) {
int x0 = i;
auto xData = std::make_shared<ProfilerPluginData>();
xData->set_data(std::to_string(x0));
inDataRepeater->PutPluginData(xData);
int y0 = f(x0);
yVec.push_back(y0);
}
worker.join();
std::vector<ProfilerPluginDataPtr> pluginDataVec;
auto count = outDataRepeater->TakePluginData(pluginDataVec);
EXPECT_EQ(count, yVec.size());
for (size_t i = 0; i < pluginDataVec.size(); i++) {
auto yData = pluginDataVec[i];
int y = yData ? std::stoi(yData->data()) : 0;
EXPECT_EQ(y, yVec[i]);
}
}
/**
* @tc.name: server
* @tc.desc: Session flow test.
* @tc.type: FUNC
*/
HWTEST_F(ServicesProfilerServiceTest, ProfilerService1, TestSize.Level1)
{
ASSERT_NE(service_, nullptr);
ASSERT_NE(context_, nullptr);
GetCapabilitiesRequest request;
GetCapabilitiesResponse response;
ProfilerPluginCapability cap;
cap.set_name("cap1");
ProfilerCapabilityManager::GetInstance().AddCapability(cap);
request.set_request_id(++requestCounter);
auto status = service_->GetCapabilities(context_.get(), &request, &response);
EXPECT_EQ(status.error_code(), grpc::StatusCode::OK);
EXPECT_GT(response.capabilities_size(), 0);
HILOG_DEBUG(LOG_CORE, "GetCapabilities, capabilities_size = %d", response.capabilities_size());
}
/**
* @tc.name: server
* @tc.desc: Session flow test.
* @tc.type: FUNC
*/
HWTEST_F(ServicesProfilerServiceTest, ProfilerService2, TestSize.Level1)
{
ASSERT_NE(service_, nullptr);
ASSERT_NE(context_, nullptr);
CreateSessionRequest request;
CreateSessionResponse response;
auto status = service_->CreateSession(context_.get(), &request, &response);
EXPECT_NE(status.error_code(), grpc::StatusCode::OK);
StartSessionRequest startrequest;
StartSessionResponse startresponse;
startrequest.set_session_id(0);
startrequest.set_request_id(++requestCounter);
status = service_->StartSession(context_.get(), &startrequest, &startresponse);
EXPECT_NE(status.error_code(), grpc::StatusCode::OK);
StopSessionRequest stoprequest;
StopSessionResponse stopresponse;
stoprequest.set_session_id(0);
stoprequest.set_request_id(++requestCounter);
status = service_->StopSession(context_.get(), &stoprequest, &stopresponse);
EXPECT_NE(status.error_code(), grpc::StatusCode::OK);
DestroySessionRequest destroyrequest;
DestroySessionResponse destroyresponse;
destroyrequest.set_session_id(0);
destroyrequest.set_request_id(++requestCounter);
status = service_->DestroySession(context_.get(), &destroyrequest, &destroyresponse);
EXPECT_NE(status.error_code(), grpc::StatusCode::OK);
}
} // namespace

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <hwext/gtest-ext.h>
#include <hwext/gtest-tag.h>
#include <thread>
#include "plugin_service_types.pb.h"
#include "share_memory_allocator.h"
#include "share_memory_block.h"
using namespace testing::ext;
namespace {
class ServicesSharedMemoryTest : public ::testing::Test {
protected:
static void SetUpTestCase() {}
static void TearDownTestCase() {}
};
/**
* @tc.name: server
* @tc.desc: Shared memory flow test.
* @tc.type: FUNC
*/
HWTEST_F(ServicesSharedMemoryTest, SharedMemoryBlock, TestSize.Level1)
{
ShareMemoryBlock shareMemoryBlock;
ASSERT_TRUE(shareMemoryBlock.CreateBlock("testname", 1024));
shareMemoryBlock.GetName();
shareMemoryBlock.GetSize();
shareMemoryBlock.GetfileDescriptor();
shareMemoryBlock.SetDropType(ShareMemoryBlock::DropType::DROP_NONE);
int8_t data[100];
for (int i = 0; i < 20; i++) {
*((uint32_t*)data) = i;
shareMemoryBlock.PutRaw(data, 100);
}
int8_t* p = shareMemoryBlock.GetFreeMemory(100);
ASSERT_TRUE(p == nullptr);
do {
p = const_cast<int8_t*>(shareMemoryBlock.GetDataPoint());
printf("%p,p=%d\n", p, *((int*)p));
} while (shareMemoryBlock.Next() && shareMemoryBlock.GetDataSize() > 0);
NotifyResultResponse response;
response.set_status(123);
ASSERT_TRUE(shareMemoryBlock.PutProtobuf(response));
ASSERT_TRUE(shareMemoryBlock.GetDataSize() > 0);
response.ParseFromArray(shareMemoryBlock.GetDataPoint(), shareMemoryBlock.GetDataSize());
ASSERT_TRUE(response.status() == 123);
ASSERT_TRUE(shareMemoryBlock.ReleaseBlock());
}
/**
* @tc.name: server
* @tc.desc: Shared memory abnormal flow test.
* @tc.type: FUNC
*/
HWTEST_F(ServicesSharedMemoryTest, SharedMemoryAllocator, TestSize.Level1)
{
ASSERT_TRUE(ShareMemoryAllocator::GetInstance().CreateMemoryBlockLocal("testname", 1) ==
nullptr); // 创建内存块大小<1024返回空
ASSERT_TRUE(ShareMemoryAllocator::GetInstance().CreateMemoryBlockLocal("testname", 1024) != nullptr); // 成功创建
ASSERT_TRUE(ShareMemoryAllocator::GetInstance().CreateMemoryBlockLocal("testname", 1024) ==
nullptr); // 创建同名内存块返回空
ASSERT_TRUE(ShareMemoryAllocator::GetInstance().ReleaseMemoryBlockLocal("testname"));
ASSERT_FALSE(ShareMemoryAllocator::GetInstance().ReleaseMemoryBlockLocal("or")); // 释放不存在的内存块返回-1
}
} // namespace

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "writer_adapter.h"
#include <hwext/gtest-ext.h>
#include <hwext/gtest-tag.h>
using namespace testing::ext;
namespace {
class WriterAdapterTest : public ::testing::Test {
protected:
static void SetUpTestCase() {}
static void TearDownTestCase() {}
};
/**
* @tc.name: plugin
* @tc.desc: Write data to shared memory through writer.
* @tc.type: FUNC
*/
HWTEST_F(WriterAdapterTest, Writer, TestSize.Level1)
{
WriterAdapter writerAdapter;
writerAdapter.GetWriter();
writerAdapter.GetStruct();
}
/**
* @tc.name: plugin
* @tc.desc: Write data to shared memory through writer.
* @tc.type: FUNC
*/
HWTEST_F(WriterAdapterTest, Func, TestSize.Level1)
{
WriterAdapter writerAdapter;
writerAdapter.WriteFunc(nullptr, nullptr, 0);
writerAdapter.FlushFunc(nullptr);
}
} // namespace

View File

@ -0,0 +1,61 @@
# Copyright (C) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/ohos.gni")
import("../../base/config.gni")
config("bytraceplugin_config") {
include_dirs = [
"../api/include",
"${OHOS_PROFILER_DIR}/interfaces/kits",
"../../services/profiler_service/src",
"../../base/include",
"include",
"//utils/native/base/include",
]
}
ohos_shared_library("bytraceplugin") {
output_name = "bytraceplugin"
sources = [
"src/bytrace_module.cpp",
]
public_configs = [ ":bytraceplugin_config" ]
public_deps = [
"${OHOS_PROFILER_DIR}/protos/types/plugins/bytrace_plugin:bytrace_plugin_protos_cpp",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc_lib",
]
if (current_toolchain != host_toolchain) {
defines = [ "HAVE_HILOG" ]
if (build_l2) {
external_deps = [ "shared_library:libhilog" ]
} else {
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
}
}
install_enable = true
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
}
ohos_executable("test_bytraceplugin") {
output_name = "test_bytraceplugin"
sources = [
"src/run_test.cpp",
]
deps = [
":bytraceplugin",
]
install_enable = true
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BYTRACE_MODULE_H
#define BYTRACE_MODULE_H
#include "plugin_module_api.h"
int BytracePluginSessionStart(const uint8_t* configData, const uint32_t configSize);
int BytraceRegisterWriterStruct(WriterStruct* writer);
int BytracePluginSessionStop();
#endif // BYTRACE_MODULE_H

View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "bytrace_module.h"
#include <poll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <vector>
#include "bytrace_plugin_config.pb.h"
#include "logging.h"
#include "securec.h"
namespace {
const std::string CMD_PATH = "/system/bin/bytrace";
int g_processNum = -1;
constexpr uint32_t MAX_BUFFER_SIZE = 4 * 1024 * 1024;
bool RunWithConfig(const BytracePluginConfig& config)
{
std::vector<std::string> args;
args.push_back("bytrace");
if (config.buffe_size() != 0) {
args.push_back("-b");
args.push_back(std::to_string(config.buffe_size()));
}
if (config.time() != 0) {
args.push_back("-t");
args.push_back(std::to_string(config.time()));
}
if (!config.clock().empty()) {
args.push_back("--trace_clock");
args.push_back(config.clock());
}
if (!config.outfile_name().empty()) {
args.push_back("-o");
args.push_back(config.outfile_name());
}
if (!config.categories().empty()) {
for (std::string category : config.categories()) {
args.push_back(category);
}
}
std::vector<char*> params;
std::string cmdPrintStr = "";
for (std::string& it : args) {
cmdPrintStr += (it + " ");
params.push_back(const_cast<char*>(it.c_str()));
}
params.push_back(nullptr);
HILOG_INFO(LOG_CORE, "call bytrace::Run: %s", cmdPrintStr.c_str());
execv(CMD_PATH.data(), &params[0]);
return true;
}
} // namespace
int BytracePluginSessionStart(const uint8_t* configData, const uint32_t configSize)
{
BytracePluginConfig config;
HILOG_INFO(LOG_CORE, "BytracePluginSessionStart %u", configSize);
CHECK_TRUE(config.ParseFromArray(configData, configSize), 0, "parse config FAILED!");
g_processNum = fork();
CHECK_TRUE(g_processNum >= 0, -1, "create process FAILED!");
if (g_processNum == 0) {
// child process
CHECK_TRUE(RunWithConfig(config), 0, "run bytrace FAILED!");
_exit(0);
}
return 0;
}
int BytraceRegisterWriterStruct(const WriterStruct* writer)
{
return 0;
}
int BytracePluginSessionStop()
{
if (g_processNum > 0) {
// parent process
int status = 0;
// judge if child process have exited.
if (waitpid(g_processNum, &status, WNOHANG) == 0) {
// send SIGKILL to child process.
if (kill(g_processNum, SIGINT)) {
HILOG_WARN(LOG_CORE, "BytracePluginSessionStop kill child process failed.");
} else {
HILOG_INFO(LOG_CORE, "BytracePluginSessionStop kill child process success.");
}
}
// report child process exit status.
if (WIFEXITED(status)) {
HILOG_INFO(LOG_CORE, "child %d exit with status %d!", g_processNum,
WEXITSTATUS(static_cast<unsigned>(status)));
} else if (WIFSIGNALED(status)) {
HILOG_INFO(LOG_CORE, "child %d exit with signal %d!", g_processNum,
WTERMSIG(static_cast<unsigned>(status)));
} else if (WIFSTOPPED(status)) {
HILOG_INFO(LOG_CORE, "child %d stopped by signal %d", g_processNum,
WSTOPSIG(static_cast<unsigned>(status)));
} else {
HILOG_INFO(LOG_CORE, "child %d otherwise", g_processNum);
}
}
return 0;
}
static PluginModuleCallbacks g_callbacks = {
BytracePluginSessionStart,
nullptr, // onPluginReportResult
BytracePluginSessionStop,
BytraceRegisterWriterStruct,
};
PluginModuleStruct g_pluginModule = {&g_callbacks, "bytrace_plugin", MAX_BUFFER_SIZE};

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "bytrace_module.h"
#include "bytrace_plugin_config.pb.h"
#include "logging.h"
namespace {
constexpr uint32_t TRACE_TIME = 8;
constexpr uint32_t WAIT_TIME = 9;
constexpr uint32_t BUFFE_SIZE = 1024;
}
int main()
{
WriterStruct writer;
BytraceRegisterWriterStruct(&writer);
BytracePluginConfig config;
config.set_clock("boot");
config.set_time(TRACE_TIME);
config.set_buffe_size(BUFFE_SIZE);
config.set_outfile_name("/data/local/tmp/bytrace.txt");
config.add_categories("sched");
std::vector<char> buffer(config.ByteSizeLong());
CHECK_TRUE(config.SerializeToArray(buffer.data(), buffer.size()), 0, "Serialize config FAILED!");
CHECK_TRUE(BytracePluginSessionStart(reinterpret_cast<uint8_t*>(buffer.data()), buffer.size()) == 0, 0,
"call start callback FAILED!");
sleep(WAIT_TIME);
BytracePluginSessionStop();
return 0;
}

View File

@ -0,0 +1,49 @@
# Copyright (C) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/ohos.gni")
import("../../base/config.gni")
ohos_shared_library("memdataplugin") {
output_name = "memdataplugin"
sources = [
"src/buffer_splitter.cpp",
"src/memory_data_plugin.cpp",
"src/memory_module.cpp",
"src/smaps_stats.cpp",
]
include_dirs = [
"include",
"../api/include",
"${OHOS_PROFILER_DIR}/interfaces/kits",
"${OHOS_PROFILER_DIR}/device/base/include",
"//utils/native/base/include",
]
deps = [
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc_lib",
"${OHOS_PROFILER_DIR}/protos/types/plugins/memory_data:memory_data_cpp",
"//utils/native/base:utilsbase",
]
if (current_toolchain != host_toolchain) {
defines = [ "HAVE_HILOG" ]
if (build_l2) {
external_deps = [ "shared_library:libhilog" ]
} else {
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
}
}
public_configs = [ "${OHOS_PROFILER_DIR}/device/base:hiprofiler_test_config" ]
install_enable = true
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _BUFFER_SPLITTER_H_
#define _BUFFER_SPLITTER_H_
#include <string>
/**
* Description: Buffer Splitter Class
* The BufferSplitter class object splits the buffer content by moving the pointer
* Except for the last character, other buffer contents are not modified during the segmentation
*/
class BufferSplitter {
public:
/* During construction, buf[size-1] will be forcibly modified to '\ 0'
The constructor will automatically call the NextLine to initialize the first line of data */
BufferSplitter(const char* buf, int size);
~BufferSplitter() {}
/* Find and update the next line header pointer, and line length. Length does not include '\ n' and '\ 0' */
bool NextLine();
/* Find and update the NextWord's head pointer and Word length according to the delimiter within the
current line range. The length calculation does not include the 'delimiter' */
/* When the current line cannot find a specific 'delimiter', it can
be split from the current position according to the new 'delimiter' */
bool NextWord(char delimiter);
const char* CurWord()
{
return curWord_;
}
size_t CurWordSize() const
{
return curWordSize_;
}
char* CurLine()
{
return curLine_;
}
size_t CurLineSize() const
{
return curLineSize_;
}
private:
char* curWord_ = nullptr;
size_t curWordSize_ = 0;
char* next_;
char* curLine_ = nullptr;
size_t curLineSize_ = 0;
char* nextLine_;
char* end_;
};
#endif

View File

@ -0,0 +1,171 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MEMORY_DATA_PLUGIN_H
#define MEMORY_DATA_PLUGIN_H
#include <algorithm>
#include <dirent.h>
#include <fcntl.h>
#include <inttypes.h>
#include <iomanip>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <unordered_map>
#include <utility>
#include "logging.h"
#include "memory_plugin_config.pb.h"
#include "memory_plugin_result.pb.h"
#include "smaps_stats.h"
struct Proto2StrMapping {
int protobufid;
const char* procstr;
};
constexpr Proto2StrMapping meminfoMapping[] = {
{SysMeminfoType::MEMINFO_UNSPECIFIED, "MemUnspecified"},
{SysMeminfoType::MEMINFO_MEM_TOTAL, "MemTotal"},
{SysMeminfoType::MEMINFO_MEM_FREE, "MemFree"},
{SysMeminfoType::MEMINFO_MEM_AVAILABLE, "MemAvailable"},
{SysMeminfoType::MEMINFO_BUFFERS, "Buffers"},
{SysMeminfoType::MEMINFO_CACHED, "Cached"},
{SysMeminfoType::MEMINFO_SWAP_CACHED, "SwapCached"},
{SysMeminfoType::MEMINFO_ACTIVE, "Active"},
{SysMeminfoType::MEMINFO_INACTIVE, "Inactive"},
{SysMeminfoType::MEMINFO_ACTIVE_ANON, "Active(anon)"},
{SysMeminfoType::MEMINFO_INACTIVE_ANON, "Inactive(anon)"},
{SysMeminfoType::MEMINFO_ACTIVE_FILE, "Active(file)"},
{SysMeminfoType::MEMINFO_INACTIVE_FILE, "Inactive(file)"},
{SysMeminfoType::MEMINFO_UNEVICTABLE, "Unevictable"},
{SysMeminfoType::MEMINFO_MLOCKED, "Mlocked"},
{SysMeminfoType::MEMINFO_SWAP_TOTAL, "SwapTotal"},
{SysMeminfoType::MEMINFO_SWAP_FREE, "SwapFree"},
{SysMeminfoType::MEMINFO_DIRTY, "Dirty"},
{SysMeminfoType::MEMINFO_WRITEBACK, "Writeback"},
{SysMeminfoType::MEMINFO_ANON_PAGES, "AnonPages"},
{SysMeminfoType::MEMINFO_MAPPED, "Mapped"},
{SysMeminfoType::MEMINFO_SHMEM, "Shmem"},
};
struct ProcStatusMapping {
int procid;
const char* procstr;
};
enum StatusType {
PRO_TGID = 1,
PRO_NAME,
PRO_VMSIZE,
PRO_VMRSS,
PRO_RSSANON,
PRO_RSSFILE,
PRO_RSSSHMEM,
PRO_VMSWAP,
PRO_VMLCK,
PRO_VMHWM,
};
constexpr ProcStatusMapping procStatusMapping[] = {
{StatusType::PRO_TGID, "Tgid"}, {StatusType::PRO_NAME, "Name"}, {StatusType::PRO_VMSIZE, "VmSize"},
{StatusType::PRO_VMRSS, "VmRSS"}, {StatusType::PRO_RSSANON, "RssAnon"}, {StatusType::PRO_RSSFILE, "RssFile"},
{StatusType::PRO_RSSSHMEM, "RssShmem"}, {StatusType::PRO_VMSWAP, "VmSwap"}, {StatusType::PRO_VMLCK, "VmLck"},
{StatusType::PRO_VMHWM, "VmHWM"},
};
enum ErrorType {
RET_NULL_ADDR,
RET_IVALID_PID,
RET_TGID_VALUE_NULL,
RET_FAIL = -1,
RET_SUCC = 0,
};
enum FileType {
FILE_STATUS = 0,
FILE_OOM,
FILE_SMAPS,
};
struct ProcfdMapping {
int procid;
const char* file;
};
constexpr ProcfdMapping procfdMapping[] = {
{FileType::FILE_STATUS, "status"},
{FileType::FILE_OOM, "oom_score_adj"},
{FileType::FILE_SMAPS, "smaps"},
};
class MemoryDataPlugin {
public:
MemoryDataPlugin();
~MemoryDataPlugin();
int Start(const uint8_t* configData, uint32_t configSize);
int Report(uint8_t* configData, uint32_t configSize);
int Stop();
void SetPath(char* path)
{
testpath_ = path;
};
void WriteProcesseList(MemoryData& data);
void WriteProcinfoByPidfds(ProcessMemoryInfo* processinfo, int32_t pid);
DIR* OpenDestDir(const char* dirPath);
int32_t GetValidPid(DIR* dirp);
// for test change static
int ParseNumber(std::string line);
private:
/* data */
MemoryConfig protoConfig_;
void* buffer_;
int meminfoFd_;
int vmstatFd_;
std::map<std::string, int> meminfoCounters_;
void InitProto2StrVector();
std::vector<const char*> meminfoStrList_;
// SmapsStats *
void WriteVmstat(MemoryData& data);
void WriteMeminfo(MemoryData& data);
std::unordered_map<int32_t, std::vector<int>> pidFds_;
std::vector<int32_t> seenPids_;
char* testpath_;
int32_t err_;
int32_t ReadFile(int fd);
std::vector<int> OpenProcPidFiles(int32_t pid);
int32_t ReadProcPidFile(int32_t pid, const char* pFileName);
void WriteProcessInfo(MemoryData& data, int32_t pid);
void SetEmptyProcessInfo(ProcessMemoryInfo* processinfo);
void WriteOomInfo(ProcessMemoryInfo* processinfo, int32_t pid);
void WriteProcess(ProcessMemoryInfo* processinfo, const char* pFile, uint32_t fileLen, int32_t pid);
void WriteAppsummary(ProcessMemoryInfo* processinfo, SmapsStats& smapInfo);
void SetProcessInfo(ProcessMemoryInfo* processinfo, int key, const char* word);
bool BufnCmp(const char* src, int srcLen, const char* key, int keyLen);
bool addPidBySort(int32_t pid);
int GetProcStatusId(const char* src, int srcLen);
bool ParseMemInfo(const char* data, ProcessMemoryInfo* memoryInfo);
bool GetMemInfoByDumpsys(uint32_t pid, ProcessMemoryInfo* memoryInfo);
};
#endif

View File

@ -0,0 +1,254 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SMAPS_STATS_H
#define SMAPS_STATS_H
#include "logging.h"
#include <cinttypes>
#include <cstdio>
#include <fstream>
#include <inttypes.h>
#include <iostream>
#include <memory>
#include <string>
#include <sys/mman.h>
struct stats_t {
int pss;
int swappablePss;
int rss;
int privateDirty;
int sharedDirty;
int privateClean;
int sharedClean;
int swappedOut;
int swappedOutPss;
};
enum NumType {
FIFTH_FIELD = 5,
HEX_BASE = 16,
DEC_BASE = 10,
};
struct MapPiecesInfo_t {
uint64_t start_addr;
uint64_t end_addr;
std::string name;
};
struct MemUsageInfo_t {
uint64_t vss;
uint64_t rss;
uint64_t pss;
uint64_t uss;
uint64_t swap;
uint64_t swap_pss;
uint64_t private_clean;
uint64_t private_dirty;
uint64_t shared_clean;
uint64_t shared_dirty;
};
enum vmemifoType {
VMHEAP_NULL = -2,
VMHEAP_NEEDFIX = -1,
VMHEAP_UNKNOWN,
VMHEAP_DALVIK,
VMHEAP_NATIVE,
VMHEAP_DALVIK_OTHER,
VMHEAP_STACK,
VMHEAP_CURSOR,
VMHEAP_ASHMEM,
VMHEAP_GL_DEV,
VMHEAP_UNKNOWN_DEV,
VMHEAP_SO,
VMHEAP_JAR,
VMHEAP_TTF,
VMHEAP_DEX,
VMHEAP_OAT,
VMHEAP_ART,
VMHEAP_UNKNOWN_MAP,
VMHEAP_GRAPHICS,
VMHEAP_GL,
VMHEAP_OTHER_MEMTRACK,
// Dalvik extra sections (heap).
VMHEAP_DALVIK_NORMAL,
VMHEAP_DALVIK_LARGE,
VMHEAP_DALVIK_ZYGOTE,
VMHEAP_DALVIK_NON_MOVING,
// Dalvik other extra sections.
VMHEAP_DALVIK_OTHER_LINEARALLOC,
VMHEAP_DALVIK_OTHER_ACCOUNTING,
VMHEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE,
VMHEAP_DALVIK_OTHER_APP_CODE_CACHE,
VMHEAP_DALVIK_OTHER_COMPILER_METADATA,
VMHEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE,
// Boot vdex / app dex / app vdex
VMHEAP_DEX_BOOT_VDEX,
VMHEAP_DEX_APP_DEX,
VMHEAP_DEX_APP_VDEX,
// App art, boot art.
VMHEAP_ART_APP,
VMHEAP_ART_BOOT,
_NUM_HEAP,
_NUM_EXCLUSIVE_HEAP = VMHEAP_OTHER_MEMTRACK + 1,
_NUM_CORE_HEAP = VMHEAP_NATIVE + 1
};
enum OpsType {
OPS_START = 1,
OPS_END,
};
struct vMeminfoAreaMapping {
int ops;
const char* heapstr;
int heapid[2];
};
constexpr vMeminfoAreaMapping vmaMemheap[] = {
{OpsType::OPS_START, "[heap]", {vmemifoType::VMHEAP_NATIVE, vmemifoType::VMHEAP_NULL}},
{OpsType::OPS_START, "[stack", {vmemifoType::VMHEAP_STACK, vmemifoType::VMHEAP_NULL}},
};
// [anon:
constexpr vMeminfoAreaMapping vmaMemanon[] = {
{OpsType::OPS_START, "[anon:libc_malloc]", {vmemifoType::VMHEAP_NATIVE, vmemifoType::VMHEAP_NULL}},
{OpsType::OPS_START, "[anon:scudo:", {vmemifoType::VMHEAP_NATIVE, vmemifoType::VMHEAP_NULL}},
{OpsType::OPS_START, "[anon:GWP-ASan", {vmemifoType::VMHEAP_NATIVE, vmemifoType::VMHEAP_NULL}},
{OpsType::OPS_START, "[anon:stack_and_tls:", {vmemifoType::VMHEAP_STACK, vmemifoType::VMHEAP_NULL}},
{OpsType::OPS_START,
"[anon:dalvik-LinearAlloc",
{vmemifoType::VMHEAP_DALVIK_OTHER, vmemifoType::VMHEAP_DALVIK_OTHER_LINEARALLOC}},
{OpsType::OPS_START, "[anon:dalvik-alloc space", {vmemifoType::VMHEAP_DALVIK, vmemifoType::VMHEAP_DALVIK_NORMAL}},
{OpsType::OPS_START, "[anon:dalvik-main space", {vmemifoType::VMHEAP_DALVIK, vmemifoType::VMHEAP_DALVIK_NORMAL}},
{OpsType::OPS_START,
"[anon:dalvik-large object space",
{vmemifoType::VMHEAP_DALVIK, vmemifoType::VMHEAP_DALVIK_LARGE}},
{OpsType::OPS_START,
"[anon:dalvik-free list large object space",
{vmemifoType::VMHEAP_DALVIK, vmemifoType::VMHEAP_DALVIK_LARGE}},
{OpsType::OPS_START,
"[anon:dalvik-non moving space",
{vmemifoType::VMHEAP_DALVIK, vmemifoType::VMHEAP_DALVIK_NON_MOVING}},
{OpsType::OPS_START, "[anon:dalvik-zygote space", {vmemifoType::VMHEAP_DALVIK, vmemifoType::VMHEAP_DALVIK_ZYGOTE}},
{OpsType::OPS_START,
"[anon:dalvik-indirect ref",
{vmemifoType::VMHEAP_DALVIK_OTHER, vmemifoType::VMHEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE}},
{OpsType::OPS_START,
"[anon:dalvik-jit-code-cache",
{vmemifoType::VMHEAP_DALVIK_OTHER, vmemifoType::VMHEAP_DALVIK_OTHER_APP_CODE_CACHE}},
{OpsType::OPS_START,
"[anon:dalvik-data-code-cache",
{vmemifoType::VMHEAP_DALVIK_OTHER, vmemifoType::VMHEAP_DALVIK_OTHER_APP_CODE_CACHE}},
{OpsType::OPS_START,
"[anon:dalvik-CompilerMetadata",
{vmemifoType::VMHEAP_DALVIK_OTHER, vmemifoType::VMHEAP_DALVIK_OTHER_COMPILER_METADATA}},
{OpsType::OPS_START,
"[anon:dalvik-",
{vmemifoType::VMHEAP_DALVIK_OTHER, vmemifoType::VMHEAP_DALVIK_OTHER_ACCOUNTING}},
{OpsType::OPS_START, "[anon:", {vmemifoType::VMHEAP_UNKNOWN, vmemifoType::VMHEAP_NULL}},
};
constexpr vMeminfoAreaMapping vmaMemfd[] = {
{OpsType::OPS_START,
"/memfd:jit-cache",
{vmemifoType::VMHEAP_DALVIK_OTHER, vmemifoType::VMHEAP_DALVIK_OTHER_APP_CODE_CACHE}},
{OpsType::OPS_START,
"/memfd:jit-zygote-cache",
{vmemifoType::VMHEAP_DALVIK_OTHER, vmemifoType::VMHEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE}},
};
// dev
constexpr vMeminfoAreaMapping vmaMemdev[] = {
{OpsType::OPS_START, "/dev/kgsl-3d0", {vmemifoType::VMHEAP_GL_DEV, vmemifoType::VMHEAP_NULL}},
{OpsType::OPS_START, "/dev/ashmem/CursorWindow", {vmemifoType::VMHEAP_CURSOR, vmemifoType::VMHEAP_NULL}},
{OpsType::OPS_START,
"/dev/ashmem/jit-zygote-cache",
{vmemifoType::VMHEAP_DALVIK_OTHER, vmemifoType::VMHEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE}},
{OpsType::OPS_START, "/dev/ashmem", {vmemifoType::VMHEAP_ASHMEM, vmemifoType::VMHEAP_NULL}},
{OpsType::OPS_START, "/dev/", {vmemifoType::VMHEAP_UNKNOWN_DEV, vmemifoType::VMHEAP_NULL}},
};
constexpr vMeminfoAreaMapping vmaMemsuffix[] = {
{OpsType::OPS_END, ".so", {vmemifoType::VMHEAP_SO, vmemifoType::VMHEAP_NULL}},
{OpsType::OPS_END, ".jar", {vmemifoType::VMHEAP_JAR, vmemifoType::VMHEAP_NULL}},
{OpsType::OPS_END, ".ttf", {vmemifoType::VMHEAP_TTF, vmemifoType::VMHEAP_NULL}},
{OpsType::OPS_END, ".oat", {vmemifoType::VMHEAP_OAT, vmemifoType::VMHEAP_NULL}},
{OpsType::OPS_END, ".odex", {vmemifoType::VMHEAP_DEX, vmemifoType::VMHEAP_DEX_APP_DEX}},
{OpsType::OPS_END, ".vdex", {vmemifoType::VMHEAP_DEX, vmemifoType::VMHEAP_NEEDFIX}},
{OpsType::OPS_END, ".art", {vmemifoType::VMHEAP_ART, vmemifoType::VMHEAP_NEEDFIX}},
{OpsType::OPS_END, ".art]", {vmemifoType::VMHEAP_ART, vmemifoType::VMHEAP_NEEDFIX}},
};
class SmapsStats {
public:
SmapsStats() {}
SmapsStats(const std::string path) : testpath_(path){};
~SmapsStats() {}
bool ParseMaps(int pid);
int GetProcessJavaHeap();
int GetProcessNativeHeap();
int GetProcessCode();
int GetProcessStack();
int GetProcessGraphics();
int GetProcessPrivateOther();
int GetProcessSystem();
private:
stats_t stats_[_NUM_HEAP] = {{0}};
bool lastline_ = false;
std::string testpath_;
int GetTotalPrivateClean();
int GetTotalPrivateDirty();
int GetPrivate(int type);
int GetTotalPss();
int GetTotalSwappedOutPss();
void ReviseStatsData();
bool ReadVmemareasFile(const std::string& path);
bool ParseMapHead(std::string& line, MapPiecesInfo_t& head);
bool SetMapAddrInfo(std::string& line, MapPiecesInfo_t& head);
bool GetMemUsageField(std::string& line, MemUsageInfo_t& memusage);
void CollectVmemAreasData(const MapPiecesInfo_t& mempic,
const MemUsageInfo_t& memusage,
uint64_t& prevEnd,
int& prevHeap);
bool GetVmaIndex(std::string name, uint32_t namesz, int32_t heapIndex[2], bool& swappable);
uint64_t GetSwapablepssValue(const MemUsageInfo_t& memusage, bool swappable);
void SetVmemAreasData(int index, uint64_t swapablePss, const MemUsageInfo_t& usage);
void HeapIndexFix(std::string name, const char* key, int32_t heapIndex[2]);
bool GetVMAStuId(int ops,
std::string name,
const vMeminfoAreaMapping* vma,
int count,
int32_t heapIndex[2],
bool& swappable);
};
#endif

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "buffer_splitter.h"
BufferSplitter::BufferSplitter(const char* buf, int size)
{
next_ = const_cast<char*>(buf);
nextLine_ = const_cast<char*>(buf);
end_ = next_ + size;
if (size) {
next_[size - 1] = '\0';
NextLine();
}
}
bool BufferSplitter::NextLine()
{
char delimiter = '\n';
curLine_ = nullptr;
curLineSize_ = 0;
curWord_ = nullptr;
curWordSize_ = 0;
if (next_ < end_) {
next_ = nextLine_;
}
for (; next_ < end_; next_++) {
if (*next_ == delimiter) {
continue;
}
curLine_ = next_;
while (true) {
if (++next_ >= end_) {
curLineSize_ = static_cast<size_t>(end_ - curLine_ - 1);
next_ = curLine_;
nextLine_ = end_;
break;
}
if (*next_ == delimiter) {
nextLine_ = ++next_;
next_ = curLine_;
curLineSize_ = static_cast<size_t>(nextLine_ - curLine_ - 1);
break;
}
}
if (curLineSize_ > 0) {
return true;
}
curLine_ = nullptr;
break;
}
return false;
}
bool BufferSplitter::NextWord(char delimiter)
{
char* nextBak = next_;
curWord_ = nullptr;
curWordSize_ = 0;
for (; next_ < nextLine_; next_++) {
if (isspace(*next_) || *next_ == delimiter) {
continue;
}
curWord_ = next_;
while (true) {
if (++next_ >= nextLine_) {
curWordSize_ = 0;
curWord_ = nullptr;
next_ = nextBak;
break;
}
if (*next_ == delimiter) {
curWordSize_ = static_cast<size_t>(next_ - curWord_);
++next_;
break;
}
}
if (curWordSize_ > 0) {
return true;
}
break;
}
return false;
}

View File

@ -0,0 +1,644 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "memory_data_plugin.h"
#include <sstream>
#include "buffer_splitter.h"
#include "securec.h"
#include "smaps_stats.h"
namespace {
static const char* CMD_FORMAT = "dumpsys meminfo --local ";
constexpr size_t READ_BUFFER_SIZE = 1024 * 16;
static const int BUF_MAX_LEN = 2048;
} // namespace
MemoryDataPlugin::MemoryDataPlugin()
{
buffer_ = nullptr;
meminfoFd_ = -1;
vmstatFd_ = -1;
testpath_ = nullptr;
err_ = -1;
InitProto2StrVector();
SetPath(const_cast<char*>("/proc"));
}
MemoryDataPlugin::~MemoryDataPlugin()
{
HILOG_INFO(LOG_CORE, "plugin:~MemoryDataPlugin!");
if (buffer_ != nullptr) {
free(buffer_);
buffer_ = nullptr;
}
if (meminfoFd_ > 0) {
close(meminfoFd_);
meminfoFd_ = -1;
}
if (vmstatFd_ > 0) {
close(vmstatFd_);
vmstatFd_ = -1;
}
for (auto it = pidFds_.begin(); it != pidFds_.end(); it++) {
for (int i = FILE_STATUS; i <= FILE_SMAPS; i++) {
if (it->second[i] != -1) {
close(it->second[i]);
}
}
}
return;
}
void MemoryDataPlugin::InitProto2StrVector()
{
int maxprotobufid = 0;
for (unsigned int i = 0; i < sizeof(meminfoMapping) / sizeof(meminfoMapping[0]); i++) {
maxprotobufid = std::max(meminfoMapping[i].protobufid, maxprotobufid);
}
meminfoStrList_.resize(maxprotobufid + 1);
for (unsigned int i = 0; i < sizeof(meminfoMapping) / sizeof(meminfoMapping[0]); i++) {
meminfoStrList_[meminfoMapping[i].protobufid] = meminfoMapping[i].procstr;
}
return;
}
int MemoryDataPlugin::Start(const uint8_t* configData, uint32_t configSize)
{
buffer_ = malloc(READ_BUFFER_SIZE);
if (buffer_ == nullptr) {
HILOG_ERROR(LOG_CORE, "plugin:malloc buffer_ fail");
return RET_FAIL;
}
if (protoConfig_.ParseFromArray(configData, configSize) <= 0) {
HILOG_ERROR(LOG_CORE, "plugin:ParseFromArray failed");
return RET_FAIL;
}
if (protoConfig_.report_sysmem_mem_info()) {
char fileName[PATH_MAX + 1] = {0};
char realPath[PATH_MAX + 1] = {0};
if (snprintf_s(fileName, sizeof(fileName), sizeof(fileName) - 1, "%s/meminfo", testpath_) < 0) {
HILOG_ERROR(LOG_CORE, "snprintf_s error");
}
if (realpath(fileName, realPath) == nullptr) {
HILOG_ERROR(LOG_CORE, "plugin:realpath failed, errno=%d", errno);
return RET_FAIL;
}
meminfoFd_ = open(realPath, O_RDONLY | O_CLOEXEC);
if (meminfoFd_ == -1) {
HILOG_ERROR(LOG_CORE, "plugin:open failed, fileName, errno=%d", errno);
return RET_FAIL;
}
}
if (protoConfig_.report_sysmem_vmem_info()) {
vmstatFd_ = open("/proc/vmstat", O_RDONLY | O_CLOEXEC);
if (vmstatFd_ == -1) {
HILOG_ERROR(LOG_CORE, "plugin:Failed to open(/proc/vmstat), errno=%d", errno);
return RET_FAIL;
}
}
if (protoConfig_.sys_meminfo_counters().size() > 0) {
for (int i = 0; i < protoConfig_.sys_meminfo_counters().size(); i++) {
if (meminfoStrList_[protoConfig_.sys_meminfo_counters(i)]) {
meminfoCounters_.emplace(meminfoStrList_[protoConfig_.sys_meminfo_counters(i)],
protoConfig_.sys_meminfo_counters(i));
}
}
}
if (protoConfig_.pid().size() > 0) {
for (int i = 0; i < protoConfig_.pid().size(); i++) {
int32_t pid = protoConfig_.pid(i);
pidFds_.emplace(pid, OpenProcPidFiles(pid));
}
}
HILOG_INFO(LOG_CORE, "plugin:start success!");
return RET_SUCC;
}
void MemoryDataPlugin::WriteMeminfo(MemoryData& data)
{
int readsize = ReadFile(meminfoFd_);
if (readsize == RET_FAIL) {
HILOG_ERROR(LOG_CORE, "%s:read meminfoFd fail!", __func__);
return;
}
BufferSplitter totalbuffer((const char*)buffer_, readsize);
do {
if (!totalbuffer.NextWord(':')) {
continue;
}
const_cast<char *>(totalbuffer.CurWord())[totalbuffer.CurWordSize()] = '\0';
auto it = meminfoCounters_.find(totalbuffer.CurWord());
if (it == meminfoCounters_.end()) {
continue;
}
int counter_id = it->second;
if (!totalbuffer.NextWord(' ')) {
continue;
}
auto value = static_cast<uint64_t>(strtoll(totalbuffer.CurWord(), nullptr, DEC_BASE));
auto* meminfo = data.add_meminfo();
meminfo->set_key(static_cast<SysMeminfoType>(counter_id));
meminfo->set_value(value);
} while (totalbuffer.NextLine());
return;
}
void MemoryDataPlugin::WriteVmstat(MemoryData& data)
{
return;
}
void MemoryDataPlugin::WriteAppsummary(ProcessMemoryInfo* processinfo, SmapsStats& smapInfo)
{
processinfo->mutable_memsummary()->set_java_heap(smapInfo.GetProcessJavaHeap());
processinfo->mutable_memsummary()->set_native_heap(smapInfo.GetProcessNativeHeap());
processinfo->mutable_memsummary()->set_code(smapInfo.GetProcessCode());
processinfo->mutable_memsummary()->set_stack(smapInfo.GetProcessStack());
processinfo->mutable_memsummary()->set_graphics(smapInfo.GetProcessGraphics());
processinfo->mutable_memsummary()->set_private_other(smapInfo.GetProcessPrivateOther());
processinfo->mutable_memsummary()->set_system(smapInfo.GetProcessSystem());
}
int MemoryDataPlugin::ParseNumber(std::string line)
{
return atoi(line.substr(line.find_first_of("01234567890")).c_str());
}
bool MemoryDataPlugin::ParseMemInfo(const char* data, ProcessMemoryInfo* memoryInfo)
{
bool ready = false;
bool done = false;
std::istringstream ss(data);
std::string line;
while (std::getline(ss, line)) {
HILOG_INFO(LOG_CORE, "line: %s", line.c_str());
std::string s(line);
if (s.find("App Summary") != s.npos) {
HILOG_INFO(LOG_CORE, "ready");
ready = true;
continue;
}
if (ready) {
if (s.find("Java Heap:") != s.npos) {
memoryInfo->mutable_memsummary()->set_java_heap(ParseNumber(s));
continue;
}
if (s.find("Native Heap:") != s.npos) {
memoryInfo->mutable_memsummary()->set_native_heap(ParseNumber(s));
continue;
}
if (s.find("Code:") != s.npos) {
memoryInfo->mutable_memsummary()->set_code(ParseNumber(s));
continue;
}
if (s.find("Stack:") != s.npos) {
memoryInfo->mutable_memsummary()->set_stack(ParseNumber(s));
continue;
}
if (s.find("Graphics:") != s.npos) {
memoryInfo->mutable_memsummary()->set_graphics(ParseNumber(s));
continue;
}
if (s.find("Private Other:") != s.npos) {
memoryInfo->mutable_memsummary()->set_private_other(ParseNumber(s));
continue;
}
if (s.find("System:") != s.npos) {
memoryInfo->mutable_memsummary()->set_system(ParseNumber(s));
done = true;
break;
}
}
}
return done;
}
bool MemoryDataPlugin::GetMemInfoByDumpsys(uint32_t pid, ProcessMemoryInfo* memoryInfo)
{
std::string fullCmd = CMD_FORMAT + std::to_string(pid);
HILOG_INFO(LOG_CORE, "popen cmd = %s", fullCmd.c_str());
std::unique_ptr<uint8_t[]> buffer {new (std::nothrow) uint8_t[BUF_MAX_LEN]};
std::unique_ptr<FILE, int (*)(FILE*)> fp(popen(fullCmd.c_str(), "r"), pclose);
if (!fp) {
HILOG_INFO(LOG_CORE, "popen error");
return false;
}
HILOG_INFO(LOG_CORE, "popen ok");
fread(buffer.get(), 1, BUF_MAX_LEN, fp.get());
buffer.get()[BUF_MAX_LEN - 1] = '\0';
return ParseMemInfo(reinterpret_cast<char*>(buffer.get()), memoryInfo);
}
int MemoryDataPlugin::Report(uint8_t* data, uint32_t dataSize)
{
MemoryData dataProto;
uint32_t length;
if (protoConfig_.report_process_tree()) {
HILOG_DEBUG(LOG_CORE, "plugin:report process list");
WriteProcesseList(dataProto);
}
if (protoConfig_.report_sysmem_mem_info()) {
HILOG_DEBUG(LOG_CORE, "plugin:report system mem_info list");
WriteMeminfo(dataProto);
}
if (protoConfig_.report_sysmem_vmem_info()) {
HILOG_DEBUG(LOG_CORE, "plugin:report system vmem_info list");
WriteVmstat(dataProto);
}
if (protoConfig_.pid().size() > 0) {
HILOG_DEBUG(LOG_CORE, "plugin:set pid counter, cnt = %d", protoConfig_.pid().size());
for (int i = 0; i < protoConfig_.pid().size(); i++) {
int32_t pid = protoConfig_.pid(i);
auto* processinfo = dataProto.add_processesinfo();
if (protoConfig_.report_process_mem_info()) {
HILOG_DEBUG(LOG_CORE, "plugin:need report meminfo pid(%d)", pid);
WriteProcinfoByPidfds(processinfo, pid);
}
if (protoConfig_.report_app_mem_info()) {
if (protoConfig_.report_app_mem_by_dumpsys()) {
HILOG_DEBUG(LOG_CORE, "plugin:report_app_mem_by_dumpsys");
GetMemInfoByDumpsys(pid, processinfo);
} else {
HILOG_DEBUG(LOG_CORE, "plugin:need report appmeminfo pid(%d)", pid);
SmapsStats smapInfo;
smapInfo.ParseMaps(pid);
WriteAppsummary(processinfo, smapInfo);
}
}
}
}
length = dataProto.ByteSizeLong();
if (length > dataSize) {
return -length;
}
if (dataProto.SerializeToArray(data, length) > 0) {
HILOG_DEBUG(LOG_CORE, "plugin:report success! length = %d", length);
return length;
}
return 0;
}
int MemoryDataPlugin::Stop()
{
if (buffer_ != nullptr) {
free(buffer_);
buffer_ = nullptr;
}
if (meminfoFd_ > 0) {
close(meminfoFd_);
meminfoFd_ = -1;
}
if (vmstatFd_ > 0) {
close(vmstatFd_);
vmstatFd_ = -1;
}
for (auto it = pidFds_.begin(); it != pidFds_.end(); it++) {
for (int i = FILE_STATUS; i <= FILE_SMAPS; i++) {
if (it->second[i] != -1) {
close(it->second[i]);
}
}
}
HILOG_INFO(LOG_CORE, "plugin:stop success!");
return 0;
}
void MemoryDataPlugin::WriteProcinfoByPidfds(ProcessMemoryInfo* processinfo, int32_t pid)
{
char* end = nullptr;
int32_t readSize;
readSize = ReadFile(pidFds_[pid][FILE_STATUS]);
if (readSize != RET_FAIL) {
WriteProcess(processinfo, (char*)buffer_, readSize, pid);
} else {
SetEmptyProcessInfo(processinfo);
}
if (ReadFile(pidFds_[pid][FILE_OOM]) != RET_FAIL) {
processinfo->set_oom_score_adj(strtol((char*)buffer_, &end, DEC_BASE));
} else {
processinfo->set_oom_score_adj(0);
}
return;
}
int32_t MemoryDataPlugin::ReadFile(int fd)
{
if ((buffer_ == nullptr) || (fd == -1)) {
HILOG_ERROR(LOG_CORE, "%s:Empty address, or invalid fd", __func__);
return RET_FAIL;
}
int readsize = pread(fd, buffer_, READ_BUFFER_SIZE - 1, 0);
if (readsize <= 0) {
HILOG_ERROR(LOG_CORE, "Failed to read(%d), errno=%d", fd, errno);
err_ = errno;
return RET_FAIL;
}
return readsize;
}
std::vector<int> MemoryDataPlugin::OpenProcPidFiles(int32_t pid)
{
int fd = -1;
char fileName[PATH_MAX + 1] = {0};
char realPath[PATH_MAX + 1] = {0};
int count = sizeof(procfdMapping) / sizeof(procfdMapping[0]);
std::vector<int> profds;
for (int i = 0; i < count; i++) {
if (snprintf_s(fileName, sizeof(fileName), sizeof(fileName) - 1,
"%s/%d/%s", testpath_, pid, procfdMapping[i].file) < 0) {
HILOG_ERROR(LOG_CORE, "snprintf_s error");
}
if (realpath(fileName, realPath) == nullptr) {
HILOG_ERROR(LOG_CORE, "plugin:realpath failed, errno=%d", errno);
}
fd = open(realPath, O_RDONLY | O_CLOEXEC);
if (fd == -1) {
HILOG_ERROR(LOG_CORE, "Failed to open(%s), errno=%d", fileName, errno);
}
profds.emplace(profds.begin() + i, fd);
}
return profds;
}
DIR* MemoryDataPlugin::OpenDestDir(const char* dirPath)
{
DIR* destDir = nullptr;
destDir = opendir(dirPath);
if (destDir == nullptr) {
HILOG_ERROR(LOG_CORE, "Failed to opendir(%s), errno=%d", dirPath, errno);
}
return destDir;
}
int32_t MemoryDataPlugin::GetValidPid(DIR* dirp)
{
if (!dirp) return 0;
while (struct dirent* dirEnt = readdir(dirp)) {
if (dirEnt->d_type != DT_DIR) {
continue;
}
int32_t pid = atoi(dirEnt->d_name);
if (pid) {
return pid;
}
}
return 0;
}
int32_t MemoryDataPlugin::ReadProcPidFile(int32_t pid, const char* pFileName)
{
char fileName[PATH_MAX + 1] = {0};
char realPath[PATH_MAX + 1] = {0};
int fd = -1;
ssize_t bytesRead;
if (snprintf_s(fileName, sizeof(fileName), sizeof(fileName) - 1, "%s/%d/%s", testpath_, pid, pFileName) < 0) {
HILOG_ERROR(LOG_CORE, "snprintf_s error");
}
if (realpath(fileName, realPath) == nullptr) {
HILOG_ERROR(LOG_CORE, "plugin:realpath failed, errno=%d", errno);
return RET_FAIL;
}
fd = open(realPath, O_RDONLY | O_CLOEXEC);
if (fd == -1) {
HILOG_INFO(LOG_CORE, "Failed to open(%s), errno=%d", fileName, errno);
err_ = errno;
return RET_FAIL;
}
if (buffer_ == nullptr) {
HILOG_INFO(LOG_CORE, "%s:Empty address, buffer_ is NULL", __func__);
err_ = RET_NULL_ADDR;
close(fd);
return RET_FAIL;
}
bytesRead = read(fd, buffer_, READ_BUFFER_SIZE - 1);
if (bytesRead <= 0) {
close(fd);
HILOG_INFO(LOG_CORE, "Failed to read(%s), errno=%d", fileName, errno);
err_ = errno;
return RET_FAIL;
}
close(fd);
return bytesRead;
}
bool MemoryDataPlugin::BufnCmp(const char* src, int srcLen, const char* key, int keyLen)
{
if (!src || !key || (srcLen < keyLen)) {
return false;
}
for (int i = 0; i < keyLen; i++) {
if (*src++ != *key++) {
return false;
}
}
return true;
}
bool MemoryDataPlugin::addPidBySort(int32_t pid)
{
auto pidsEnd = seenPids_.end();
auto it = std::lower_bound(seenPids_.begin(), pidsEnd, pid);
if (it != pidsEnd && *it == pid) {
return false;
}
it = seenPids_.insert(it, std::move(pid));
return true;
}
int MemoryDataPlugin::GetProcStatusId(const char* src, int srcLen)
{
int count;
count = sizeof(procStatusMapping) / sizeof(procStatusMapping[0]);
for (int i = 0; i < count; i++) {
if (BufnCmp(src, srcLen, procStatusMapping[i].procstr, strlen(procStatusMapping[i].procstr))) {
return procStatusMapping[i].procid;
}
}
return RET_FAIL;
}
void MemoryDataPlugin::SetProcessInfo(ProcessMemoryInfo* processinfo, int key, const char* word)
{
char* end = nullptr;
switch (key) {
case PRO_TGID: {
processinfo->set_pid(strtoul(word, &end, DEC_BASE));
} break;
case PRO_VMSIZE: {
uint64_t vm_size_kb = strtoul(word, &end, DEC_BASE);
processinfo->set_vm_size_kb(vm_size_kb);
} break;
case PRO_VMRSS: {
uint64_t vm_rss_kb = strtoul(word, &end, DEC_BASE);
processinfo->set_vm_rss_kb(vm_rss_kb);
} break;
case PRO_RSSANON: {
uint64_t rss_anon_kb = strtoul(word, &end, DEC_BASE);
processinfo->set_rss_anon_kb(rss_anon_kb);
} break;
case PRO_RSSFILE: {
uint64_t rss_file_kb = strtoul(word, &end, DEC_BASE);
processinfo->set_rss_file_kb(rss_file_kb);
} break;
case PRO_RSSSHMEM: {
uint64_t rss_shmem_kb = strtoul(word, &end, DEC_BASE);
processinfo->set_rss_shmem_kb(rss_shmem_kb);
} break;
case PRO_VMSWAP: {
uint64_t vm_swap_kb = strtoul(word, &end, DEC_BASE);
processinfo->set_vm_swap_kb(vm_swap_kb);
} break;
case PRO_VMLCK: {
uint64_t vm_locked_kb = strtoul(word, &end, DEC_BASE);
processinfo->set_vm_locked_kb(vm_locked_kb);
} break;
case PRO_VMHWM: {
uint64_t vm_hwm_kb = strtoul(word, &end, DEC_BASE);
processinfo->set_vm_hwm_kb(vm_hwm_kb);
} break;
default:
break;
}
return;
}
void MemoryDataPlugin::WriteProcess(ProcessMemoryInfo* processinfo, const char* pFile, uint32_t fileLen, int32_t pid)
{
BufferSplitter totalbuffer(const_cast<const char*>(pFile), fileLen + 1);
do {
totalbuffer.NextWord(':');
if (!totalbuffer.CurWord()) {
return;
}
int key = GetProcStatusId(totalbuffer.CurWord(), totalbuffer.CurWordSize());
totalbuffer.NextWord('\n');
if (!totalbuffer.CurWord()) {
continue;
}
if (key == PRO_NAME) {
processinfo->set_name(totalbuffer.CurWord(), totalbuffer.CurWordSize());
}
SetProcessInfo(processinfo, key, totalbuffer.CurWord());
} while (totalbuffer.NextLine());
// update process name
int32_t ret = ReadProcPidFile(pid, "cmdline");
if (ret > 0) {
processinfo->set_name(static_cast<char*>(buffer_), strlen(static_cast<char*>(buffer_)));
HILOG_ERROR(LOG_CORE, "%s:update process name=%s", __func__, processinfo->name().c_str());
}
}
void MemoryDataPlugin::SetEmptyProcessInfo(ProcessMemoryInfo* processinfo)
{
processinfo->set_pid(-1);
processinfo->set_name("null");
processinfo->set_vm_size_kb(0);
processinfo->set_vm_rss_kb(0);
processinfo->set_rss_anon_kb(0);
processinfo->set_rss_file_kb(0);
processinfo->set_rss_shmem_kb(0);
processinfo->set_vm_swap_kb(0);
processinfo->set_vm_locked_kb(0);
processinfo->set_vm_hwm_kb(0);
processinfo->set_oom_score_adj(0);
}
void MemoryDataPlugin::WriteOomInfo(ProcessMemoryInfo* processinfo, int32_t pid)
{
char* end = nullptr;
if (ReadProcPidFile(pid, "oom_score_adj") == RET_FAIL) {
processinfo->set_oom_score_adj(0);
return;
}
if (buffer_ == nullptr) {
processinfo->set_oom_score_adj(0);
HILOG_ERROR(LOG_CORE, "%s:invalid params, read buffer_ is NULL", __func__);
return;
}
processinfo->set_oom_score_adj(strtol((char*)buffer_, &end, DEC_BASE));
}
void MemoryDataPlugin::WriteProcessInfo(MemoryData& data, int32_t pid)
{
int32_t ret = ReadProcPidFile(pid, "status");
if (ret == RET_FAIL) {
SetEmptyProcessInfo(data.add_processesinfo());
return;
}
if ((buffer_ == nullptr) || (ret == 0)) {
HILOG_ERROR(LOG_CORE, "%s:invalid params, read buffer_ is NULL", __func__);
return;
}
auto* processinfo = data.add_processesinfo();
WriteProcess(processinfo, (char*)buffer_, ret, pid);
WriteOomInfo(processinfo, pid);
}
void MemoryDataPlugin::WriteProcesseList(MemoryData& data)
{
DIR* procDir = nullptr;
procDir = OpenDestDir(testpath_);
if (procDir == nullptr) {
return;
}
while (int32_t pid = GetValidPid(procDir)) {
if (find(seenPids_.begin(), seenPids_.end(), pid) == seenPids_.end()) {
addPidBySort(pid);
}
}
for (unsigned int i = 0; i < seenPids_.size(); i++) {
WriteProcessInfo(data, seenPids_[i]);
}
closedir(procDir);
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "memory_data_plugin.h"
#include <mutex>
#include <sys/types.h>
#include "plugin_module_api.h"
namespace {
constexpr uint32_t MAX_BUFFER_SIZE = 4 * 1024 * 1024;
std::unique_ptr<MemoryDataPlugin> g_plugin = nullptr;
std::mutex g_taskMutex;
} // namespace
static int MemDataPluginSessionStart(const uint8_t* configData, uint32_t configSize)
{
std::lock_guard<std::mutex> guard(g_taskMutex);
g_plugin = std::make_unique<MemoryDataPlugin>();
return g_plugin->Start(configData, configSize);
}
static int MemPluginReportResult(uint8_t* bufferData, uint32_t bufferSize)
{
std::lock_guard<std::mutex> guard(g_taskMutex);
return g_plugin->Report(bufferData, bufferSize);
}
static int MemPluginSessionStop()
{
std::lock_guard<std::mutex> guard(g_taskMutex);
HILOG_INFO(LOG_CORE, "%s:stop Session success!", __func__);
g_plugin->Stop();
g_plugin = nullptr;
return 0;
}
static int MemRegisterWriterStruct(const WriterStruct* writer)
{
return 0;
}
static PluginModuleCallbacks g_callbacks = {
MemDataPluginSessionStart,
MemPluginReportResult,
MemPluginSessionStop,
MemRegisterWriterStruct,
};
PluginModuleStruct g_pluginModule = {&g_callbacks, "memory-plugin", MAX_BUFFER_SIZE};

View File

@ -0,0 +1,422 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "smaps_stats.h"
#include "securec.h"
namespace {
bool MatchHead(const std::string& name, const char* str)
{
return strncmp(name.c_str(), str, strlen(str)) == 0;
}
bool MatchTail(const std::string& name, std::string str)
{
int index = name.size() - str.size();
if (index < 0) {
return false;
}
return (name.substr(index) == str);
}
} // namespace
bool SmapsStats::ParseMaps(int pid)
{
std::string smaps_path = std::string("/proc/") + std::to_string(pid) + std::string("/smaps");
if (testpath_.size() > 0) {
smaps_path = testpath_ + std::to_string(pid) + std::string("/smaps");
}
HILOG_INFO(LOG_CORE, "smaps path:%s", smaps_path.c_str());
ReadVmemareasFile(smaps_path);
ReviseStatsData();
return true;
}
bool SmapsStats::ReadVmemareasFile(const std::string& path)
{
bool findMapHead = false;
MapPiecesInfo_t mappic = {0};
MemUsageInfo_t memusage = {0};
uint64_t prevEnd = 0;
int prevHeap = 0;
std::ifstream input(path, std::ios::in);
if (input.fail()) {
HILOG_ERROR(LOG_CORE, "open %s failed, errno = %d", path.c_str(), errno);
return false;
}
do {
if (!input.good()) {
return false;
}
std::string line;
getline(input, line);
line += '\n';
if (!findMapHead) {
// 00400000-00409000 r-xp 00000000 fc:00 426998 /usr/lib/gvfs/gvfsd-http
ParseMapHead(line, mappic);
findMapHead = true;
continue;
}
if (findMapHead && GetMemUsageField(line, memusage)) {
if (!lastline_) {
continue;
}
}
CollectVmemAreasData(mappic, memusage, prevEnd, prevHeap);
findMapHead = false;
lastline_ = false;
} while (!input.eof());
input.close();
return true;
}
bool SmapsStats::GetVMAStuId(int ops,
std::string name,
const vMeminfoAreaMapping* vma,
int count,
int32_t heapIndex[2],
bool& swappable)
{
for (int i = 0; i < count; i++) {
if (ops == OPS_START) {
if (MatchHead(name, vma[i].heapstr)) {
heapIndex[0] = vma[i].heapid[0];
heapIndex[1] = vma[i].heapid[1];
swappable = false;
return true;
}
} else if (ops == OPS_END) {
if (MatchTail(name, vma[i].heapstr)) {
if (vma[i].heapid[1] == VMHEAP_NEEDFIX) {
HeapIndexFix(name, vma[i].heapstr, heapIndex);
} else {
heapIndex[0] = vma[i].heapid[0];
heapIndex[1] = vma[i].heapid[1];
}
swappable = true;
return true;
}
}
}
return false;
}
bool SmapsStats::GetVmaIndex(std::string name, uint32_t namesz, int32_t heapIndex[2], bool& swappable)
{
switch (name[0]) {
case '[':
if (MatchHead(name, "[heap]") || MatchHead(name, "[stack")) {
int count = sizeof(vmaMemheap) / sizeof(vmaMemheap[0]);
return GetVMAStuId(OPS_START, name, vmaMemheap, count, heapIndex, swappable);
} else if (MatchHead(name, "[anon:")) {
if (MatchHead(name, "[anon:dalvik-")) {
int count = sizeof(vmaMemsuffix) / sizeof(vmaMemsuffix[0]);
if (GetVMAStuId(OPS_END, name, vmaMemsuffix, count, heapIndex, swappable)) {
return true;
}
}
int count = sizeof(vmaMemanon) / sizeof(vmaMemanon[0]);
return GetVMAStuId(OPS_START, name, vmaMemanon, count, heapIndex, swappable);
}
break;
case '/':
if (MatchHead(name, "/memfd:")) {
int count = sizeof(vmaMemfd) / sizeof(vmaMemfd[0]);
return GetVMAStuId(OPS_START, name, vmaMemfd, count, heapIndex, swappable);
} else if (MatchHead(name, "/dev/")) {
int count = sizeof(vmaMemdev) / sizeof(vmaMemdev[0]);
return GetVMAStuId(OPS_START, name, vmaMemdev, count, heapIndex, swappable);
} else {
int count = sizeof(vmaMemsuffix) / sizeof(vmaMemsuffix[0]);
return GetVMAStuId(OPS_END, name, vmaMemsuffix, count, heapIndex, swappable);
}
break;
default:
int count = sizeof(vmaMemsuffix) / sizeof(vmaMemsuffix[0]);
return GetVMAStuId(OPS_END, name, vmaMemsuffix, count, heapIndex, swappable);
break;
}
if (namesz > strlen(".dex") && strstr(name.c_str(), ".dex") != nullptr) {
heapIndex[0] = VMHEAP_DEX;
heapIndex[1] = VMHEAP_DEX_APP_DEX;
swappable = true;
return true;
}
return false;
}
void SmapsStats::CollectVmemAreasData(const MapPiecesInfo_t& mempic,
const MemUsageInfo_t& memusage,
uint64_t& prevEnd,
int& prevHeap)
{
std::string name;
int32_t heapIndex[2] = {VMHEAP_UNKNOWN, VMHEAP_NULL};
bool swappable = false;
uint64_t swapablePss = 0;
if (MatchTail(mempic.name, " (deleted)")) {
name = mempic.name.substr(0, mempic.name.size() - strlen(" (deleted)"));
} else {
name = mempic.name;
}
uint32_t namesz = name.size();
if (!GetVmaIndex(name, namesz, heapIndex, swappable)) {
if (namesz > 0) {
heapIndex[0] = VMHEAP_UNKNOWN_MAP;
} else if (mempic.start_addr == prevEnd && prevHeap == VMHEAP_SO) {
// bss section of a shared library
heapIndex[0] = VMHEAP_SO;
}
}
prevEnd = mempic.end_addr;
prevHeap = heapIndex[0];
swapablePss = GetSwapablepssValue(memusage, swappable);
SetVmemAreasData(heapIndex[0], swapablePss, memusage);
if ((heapIndex[1] != VMHEAP_NULL) && (heapIndex[1] != VMHEAP_NEEDFIX)) {
SetVmemAreasData(heapIndex[1], swapablePss, memusage);
}
}
void SmapsStats::ReviseStatsData()
{
// Summary data to VMHEAP_UNKNOWN
for (int i = _NUM_CORE_HEAP; i < _NUM_EXCLUSIVE_HEAP; i++) {
stats_[VMHEAP_UNKNOWN].pss += stats_[i].pss;
stats_[VMHEAP_UNKNOWN].swappablePss += stats_[i].swappablePss;
stats_[VMHEAP_UNKNOWN].rss += stats_[i].rss;
stats_[VMHEAP_UNKNOWN].privateDirty += stats_[i].privateDirty;
stats_[VMHEAP_UNKNOWN].sharedDirty += stats_[i].sharedDirty;
stats_[VMHEAP_UNKNOWN].privateClean += stats_[i].privateClean;
stats_[VMHEAP_UNKNOWN].sharedClean += stats_[i].sharedClean;
stats_[VMHEAP_UNKNOWN].swappedOut += stats_[i].swappedOut;
stats_[VMHEAP_UNKNOWN].swappedOutPss += stats_[i].swappedOutPss;
}
}
bool SmapsStats::SetMapAddrInfo(std::string& line, MapPiecesInfo_t& head)
{
const char* pStr = line.c_str();
char* end = nullptr;
// start_addr
head.start_addr = strtoull(pStr, &end, HEX_BASE);
if (end == pStr || *end != '-') {
return false;
}
pStr = end + 1;
// end_addr
head.end_addr = strtoull(pStr, &end, HEX_BASE);
if (end == pStr) {
return false;
}
return true;
}
bool SmapsStats::ParseMapHead(std::string& line, MapPiecesInfo_t& head)
{
if (!SetMapAddrInfo(line, head)) {
return false;
}
size_t newlineops = 0;
size_t wordsz = 0;
std::string newline = line;
for (int i = 0; i < FIFTH_FIELD; i++) {
std::string word = newline;
wordsz = word.find(" ");
if (wordsz == std::string::npos) {
return false;
}
word = newline.substr(0, wordsz);
newlineops = newline.find_first_not_of(" ", wordsz);
newline = newline.substr(newlineops);
}
head.name = newline.substr(0, newline.size() - 1);
return true;
}
bool SmapsStats::GetMemUsageField(std::string& line, MemUsageInfo_t& memusage)
{
char field[64];
int len;
const char* pLine = line.c_str();
int ret = sscanf_s(pLine, "%63s %n", field, sizeof(field), &len);
if (ret == 1 && *field && field[strlen(field) - 1] == ':') {
const char* c = pLine + len;
std::string strfield(field);
switch (field[0]) {
case 'P':
if (MatchHead(strfield, "Pss:")) {
memusage.pss = strtoull(c, nullptr, DEC_BASE);
} else if (MatchHead(strfield, "Private_Clean:")) {
uint64_t prcl = strtoull(c, nullptr, DEC_BASE);
memusage.private_clean = prcl;
memusage.uss += prcl;
} else if (MatchHead(strfield, "Private_Dirty:")) {
uint64_t prdi = strtoull(c, nullptr, DEC_BASE);
memusage.private_dirty = prdi;
memusage.uss += prdi;
}
break;
case 'S':
if (MatchHead(strfield, "Size:")) {
memusage.vss = strtoull(c, nullptr, DEC_BASE);
} else if (MatchHead(strfield, "Shared_Clean:")) {
memusage.shared_clean = strtoull(c, nullptr, DEC_BASE);
} else if (MatchHead(strfield, "Shared_Dirty:")) {
memusage.shared_dirty = strtoull(c, nullptr, DEC_BASE);
} else if (MatchHead(strfield, "Swap:")) {
memusage.swap = strtoull(c, nullptr, DEC_BASE);
} else if (MatchHead(strfield, "SwapPss:")) {
memusage.swap_pss = strtoull(c, nullptr, DEC_BASE);
}
break;
case 'R':
if (MatchHead(strfield, "Rss:")) {
memusage.rss = strtoull(c, nullptr, DEC_BASE);
}
break;
case 'V':
if (MatchHead(strfield, "VmFlags:")) {
lastline_ = true;
}
break;
default:
break;
}
return true;
}
return false;
}
uint64_t SmapsStats::GetSwapablepssValue(const MemUsageInfo_t& memusage, bool swappable)
{
const MemUsageInfo_t& usage = memusage;
uint64_t swapablePss = 0;
if (swappable && (usage.pss > 0)) {
float sharing_proportion = 0.0f;
if ((usage.shared_clean > 0) || (usage.shared_dirty > 0)) {
sharing_proportion = (usage.pss - usage.uss) / (usage.shared_clean + usage.shared_dirty);
}
swapablePss = (sharing_proportion * usage.shared_clean) + usage.private_clean;
}
return swapablePss;
}
void SmapsStats::SetVmemAreasData(int index, uint64_t swapablePss, const MemUsageInfo_t& usage)
{
stats_[index].pss += usage.pss;
stats_[index].swappablePss += swapablePss;
stats_[index].rss += usage.rss;
stats_[index].privateDirty += usage.private_dirty;
stats_[index].sharedDirty += usage.shared_dirty;
stats_[index].privateClean += usage.private_clean;
stats_[index].sharedClean += usage.shared_clean;
stats_[index].swappedOut += usage.swap;
stats_[index].swappedOutPss += usage.swap_pss;
}
void SmapsStats::HeapIndexFix(std::string name, const char* key, int32_t heapIndex[2])
{
if (!strncmp(key, ".vdex", sizeof(".vdex"))) {
if ((strstr(name.c_str(), "@boot") != nullptr) || (strstr(name.c_str(), "/boot") != nullptr) ||
(strstr(name.c_str(), "/apex") != nullptr)) {
heapIndex[0] = VMHEAP_DEX;
heapIndex[1] = VMHEAP_DEX_BOOT_VDEX;
} else {
heapIndex[0] = VMHEAP_DEX;
heapIndex[1] = VMHEAP_DEX_APP_VDEX;
}
} else if (!strncmp(key, ".art", sizeof(".art")) || !strncmp(key, ".art]", sizeof(".art]"))) {
if ((strstr(name.c_str(), "@boot") != nullptr) || (strstr(name.c_str(), "/boot") != nullptr) ||
(strstr(name.c_str(), "/apex") != nullptr)) {
heapIndex[0] = VMHEAP_ART;
heapIndex[1] = VMHEAP_ART_BOOT;
} else {
heapIndex[0] = VMHEAP_ART;
heapIndex[1] = VMHEAP_ART_APP;
}
}
}
int SmapsStats::GetProcessJavaHeap()
{
return stats_[VMHEAP_DALVIK].privateDirty + GetPrivate(VMHEAP_ART);
}
int SmapsStats::GetProcessNativeHeap()
{
return stats_[VMHEAP_NATIVE].privateDirty;
}
int SmapsStats::GetProcessCode()
{
return GetPrivate(VMHEAP_SO) + GetPrivate(VMHEAP_JAR) + GetPrivate(VMHEAP_TTF) +
GetPrivate(VMHEAP_DEX) + GetPrivate(VMHEAP_OAT) +
GetPrivate(VMHEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE) +
GetPrivate(VMHEAP_DALVIK_OTHER_APP_CODE_CACHE);
}
int SmapsStats::GetProcessStack()
{
return stats_[VMHEAP_STACK].privateDirty;
}
int SmapsStats::GetProcessGraphics()
{
return GetPrivate(VMHEAP_GL_DEV) + GetPrivate(VMHEAP_GRAPHICS) + GetPrivate(VMHEAP_GL);
}
int SmapsStats::GetProcessPrivateOther()
{
return GetTotalPrivateClean() + GetTotalPrivateDirty() - GetProcessJavaHeap() - GetProcessNativeHeap() -
GetProcessCode() - GetProcessStack() - GetProcessGraphics();
}
int SmapsStats::GetProcessSystem()
{
return GetTotalPss() - GetTotalPrivateClean() - GetTotalPrivateDirty();
}
int SmapsStats::GetTotalPrivateClean()
{
return stats_[VMHEAP_UNKNOWN].privateClean + stats_[VMHEAP_NATIVE].privateClean +
stats_[VMHEAP_DALVIK].privateClean;
}
int SmapsStats::GetTotalPrivateDirty()
{
return stats_[VMHEAP_UNKNOWN].privateDirty + stats_[VMHEAP_NATIVE].privateDirty +
stats_[VMHEAP_DALVIK].privateDirty;
}
int SmapsStats::GetPrivate(int type)
{
return stats_[type].privateDirty + stats_[type].privateClean;
}
int SmapsStats::GetTotalPss()
{
return stats_[VMHEAP_UNKNOWN].pss + stats_[VMHEAP_NATIVE].pss + stats_[VMHEAP_DALVIK].pss + GetTotalSwappedOutPss();
}
int SmapsStats::GetTotalSwappedOutPss()
{
return stats_[VMHEAP_UNKNOWN].swappedOutPss + stats_[VMHEAP_NATIVE].swappedOutPss +
stats_[VMHEAP_DALVIK].swappedOutPss;
}

View File

@ -0,0 +1,60 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/test.gni")
import("../../../base/config.gni")
module_output_path = "${OHOS_PROFILER_TEST_MODULE_OUTPUT_PATH}/device"
config("module_private_config") {
visibility = [":*"]
if (current_toolchain != host_toolchain) {
defines = [ "HAVE_HILOG" ]
}
}
ohos_unittest("memdataplugin_ut") {
module_out_path = module_output_path
sources = [
"unittest/buffer_splitter_unittest.cpp",
"unittest/memory_data_plugin_unittest.cpp",
]
deps = [
"${OHOS_PROFILER_DIR}/device/plugins/memory_plugin:memdataplugin",
"${OHOS_PROFILER_DIR}/protos/types/plugins/memory_data:memory_data_cpp",
"//third_party/googletest:gtest_main",
]
include_dirs = [
"../include",
"../../api/include",
"${OHOS_PROFILER_DIR}/interfaces/kits",
"${OHOS_PROFILER_DIR}/device/base/include",
"//third_party/googletest/googletest/include/gtest",
]
cflags = [
"-Wno-inconsistent-missing-override",
"-Dprivate=public", #allow test code access private members
]
external_deps = [
"hiviewdfx_hilog_native:libhilog",
]
configs = [ ":module_private_config" ]
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
resource_config_file = get_path_info("utresources/ohos_test.xml", "abspath")
}
group("unittest") {
testonly = true
deps = [
":memdataplugin_ut",
]
}

View File

@ -0,0 +1,446 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <memory>
#include <hwext/gtest-ext.h>
#include <hwext/gtest-tag.h>
#include "buffer_splitter.h"
using namespace testing::ext;
using ConstCharPtr = std::unique_ptr<const char>::pointer;
namespace {
class BufferSplitterUnittest : public ::testing::Test {
public:
static void SetUpTestCase() {}
static void TearDownTestCase() {}
void SetUp() {}
void TearDown() {}
};
struct TestElement {
int32_t index;
ConstCharPtr curLine;
size_t curLineSz;
ConstCharPtr curWord;
size_t curWordSz;
};
/**
* @tc.name: memory plugin
* @tc.desc: Constructed function test.
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, constructorWithNullptr, TestSize.Level1)
{
char* text = nullptr;
int readsize = 0;
BufferSplitter totalbuffer(text, readsize);
EXPECT_EQ(nullptr, totalbuffer.CurLine());
EXPECT_EQ((size_t)0, totalbuffer.CurLineSize());
EXPECT_EQ(nullptr, totalbuffer.CurWord());
EXPECT_EQ((size_t)0, totalbuffer.CurWordSize());
}
/**
* @tc.name: memory plugin
* @tc.desc: Constructed function test.
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, constructorWith1lengthBuffer01, TestSize.Level1)
{
char text[] = {'\0'};
int readsize = sizeof(text);
BufferSplitter totalbuffer(text, readsize);
EXPECT_EQ(nullptr, totalbuffer.CurLine());
EXPECT_EQ((size_t)0, totalbuffer.CurLineSize());
EXPECT_EQ(nullptr, totalbuffer.CurWord());
EXPECT_EQ((size_t)0, totalbuffer.CurWordSize());
}
/**
* @tc.name: memory plugin
* @tc.desc: Constructed function test.
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, constructorWith1lengthBuffer02, TestSize.Level1)
{
char text[] = {'\n'};
int readsize = sizeof(text);
BufferSplitter totalbuffer(text, readsize);
EXPECT_EQ(nullptr, totalbuffer.CurLine());
EXPECT_EQ((size_t)0, totalbuffer.CurLineSize());
EXPECT_EQ(nullptr, totalbuffer.CurWord());
EXPECT_EQ((size_t)0, totalbuffer.CurWordSize());
}
/**
* @tc.name: memory plugin
* @tc.desc: Constructed function test.
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, constructorWith1lengthBuffer03, TestSize.Level1)
{
char text[] = {'3'};
int readsize = sizeof(text);
BufferSplitter totalbuffer(text, readsize);
EXPECT_EQ(nullptr, totalbuffer.CurLine());
EXPECT_EQ((size_t)0, totalbuffer.CurLineSize());
EXPECT_EQ(nullptr, totalbuffer.CurWord());
EXPECT_EQ((size_t)0, totalbuffer.CurWordSize());
}
/**
* @tc.name: memory plugin
* @tc.desc: Constructed function test.
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, constructorWith1LineBuffer, TestSize.Level1)
{
char text[] = {'a', 'b', 'c', 'd', '\0'};
int readsize = sizeof(text);
BufferSplitter totalbuffer(text, readsize);
TestElement expect = {0, text, 4, nullptr, 0};
EXPECT_EQ(expect.curLine, totalbuffer.CurLine());
EXPECT_EQ(expect.curLineSz, totalbuffer.CurLineSize());
EXPECT_EQ(expect.curWord, totalbuffer.CurWord());
EXPECT_EQ(expect.curWordSz, totalbuffer.CurWordSize());
}
/**
* @tc.name: memory plugin
* @tc.desc: Constructed function test.
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, constructorWithMultipleLinesBuffer, TestSize.Level1)
{
char text[] = {'a', 'b', 'c', 'd', '\n', '1', '2', '3', '4', '5', '\0'};
TestElement expect = {0, text, 4, nullptr, 0};
int readsize = sizeof(text);
BufferSplitter totalbuffer(text, readsize);
EXPECT_EQ(expect.curLine, totalbuffer.CurLine());
EXPECT_EQ(expect.curLineSz, totalbuffer.CurLineSize());
EXPECT_EQ(expect.curWord, totalbuffer.CurWord());
EXPECT_EQ(expect.curWordSz, totalbuffer.CurWordSize());
}
/**
* @tc.name: memory plugin
* @tc.desc: Test NextLine().
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, NextLineWithOnlyOneLineBuffer, TestSize.Level1)
{
char text[] = {'a', 'b', 'c', 'd', '\0'};
TestElement expect = {0, text, 4, nullptr, 0};
int readsize = sizeof(text);
BufferSplitter totalbuffer(text, readsize);
EXPECT_EQ(expect.curLine, totalbuffer.CurLine());
EXPECT_EQ(expect.curLineSz, totalbuffer.CurLineSize());
EXPECT_EQ(expect.curWord, totalbuffer.CurWord());
EXPECT_EQ(expect.curWordSz, totalbuffer.CurWordSize());
EXPECT_FALSE(totalbuffer.NextLine());
EXPECT_EQ(nullptr, totalbuffer.CurLine());
EXPECT_EQ((size_t)0, totalbuffer.CurLineSize());
}
/**
* @tc.name: memory plugin
* @tc.desc: Test NextLine().
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, NextLineWithMultipleLinesBuffer, TestSize.Level1)
{
char text[] = {'a', 'b', 'c', 'd', '\n', '1', '2', '3', '4', '5', '6', '\0'};
TestElement expect[] = {{0, text, 4, nullptr, 0}, {5, &text[5], 6, nullptr, 0}};
int readsize = sizeof(text);
BufferSplitter totalbuffer(text, readsize);
size_t i = 0;
do {
EXPECT_EQ(expect[i].curLine, totalbuffer.CurLine());
EXPECT_EQ(expect[i].curLineSz, totalbuffer.CurLineSize());
EXPECT_EQ(expect[i].curWord, totalbuffer.CurWord());
EXPECT_EQ(expect[i].curWordSz, totalbuffer.CurWordSize());
i++;
} while (totalbuffer.NextLine());
}
/**
* @tc.name: memory plugin
* @tc.desc: Test NextWord().
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, NextWordWithOnlyOneLineBuffer01, TestSize.Level1)
{
char text[] = {'a', 'b', ' ', 'c', 'd', '\0'};
TestElement expect = {0, text, 5, text, 2};
int readsize = sizeof(text);
BufferSplitter totalbuffer(text, readsize);
EXPECT_EQ(expect.curLine, totalbuffer.CurLine());
EXPECT_EQ(expect.curLineSz, totalbuffer.CurLineSize());
EXPECT_TRUE(totalbuffer.NextWord(' '));
EXPECT_EQ(expect.curWord, totalbuffer.CurWord());
EXPECT_EQ(expect.curWordSz, totalbuffer.CurWordSize());
}
/**
* @tc.name: memory plugin
* @tc.desc: Test NextWord().
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, NextWordWithOnlyOneLineBuffer02, TestSize.Level1)
{
char text[] = {'a', 'b', ' ', 'c', 'd', ' ', '\0'};
TestElement expect[] = {{0, text, 6, text, 2}, {0, text, 4, &text[3], 2}};
int readsize = sizeof(text);
BufferSplitter totalbuffer(text, readsize);
EXPECT_EQ(expect[0].curLine, totalbuffer.CurLine());
EXPECT_EQ(expect[0].curLineSz, totalbuffer.CurLineSize());
size_t cnt = sizeof(expect) / sizeof(expect[0]);
for (size_t i = 0; i < cnt; i++) {
EXPECT_TRUE(totalbuffer.NextWord(' '));
EXPECT_EQ(expect[i].curWord, totalbuffer.CurWord());
EXPECT_EQ(expect[i].curWordSz, totalbuffer.CurWordSize());
}
}
/**
* @tc.name: memory plugin
* @tc.desc: Test NextWord().
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, NextWordWithOnlyOneLineBuffer03, TestSize.Level1)
{
char text[] = {'a', 'b', ' ', 'c', 'd', ' ', '\0'};
TestElement expect = {0, text, 6, text, 6};
int readsize = sizeof(text);
BufferSplitter totalbuffer(text, readsize);
EXPECT_EQ(expect.curLine, totalbuffer.CurLine());
EXPECT_EQ(expect.curLineSz, totalbuffer.CurLineSize());
EXPECT_TRUE(totalbuffer.NextWord('\0'));
EXPECT_EQ(expect.curWord, totalbuffer.CurWord());
EXPECT_EQ(expect.curWordSz, totalbuffer.CurWordSize());
}
/**
* @tc.name: memory plugin
* @tc.desc: Test NextWord().
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, NextWordWithOnlyOneLineBuffer04, TestSize.Level1)
{
char text[] = {'a', 'b', ' ', 'c', 'd', ' ', '\0'};
TestElement expect = {0, text, 6, nullptr, 0};
int readsize = sizeof(text);
BufferSplitter totalbuffer(text, readsize);
EXPECT_EQ(expect.curLine, totalbuffer.CurLine());
EXPECT_EQ(expect.curLineSz, totalbuffer.CurLineSize());
EXPECT_FALSE(totalbuffer.NextWord('e'));
EXPECT_EQ(expect.curWord, totalbuffer.CurWord());
EXPECT_EQ(expect.curWordSz, totalbuffer.CurWordSize());
}
/**
* @tc.name: memory plugin
* @tc.desc: Test NextWord().
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, NextWordWithMultipleLinesBuffer01, TestSize.Level1)
{
char text[] = {'a', 'b', ' ', 'c', 'd', ' ', '\n', '1', '2', ' ', '3', '4', '5', ' ', '6', '\0'};
TestElement expect[] = {
{0, text, 6, text, 2}, {0, text, 6, &text[3], 2}, {0, text, 6, &text[7], 2}, {0, text, 4, &text[10], 3}};
int readsize = sizeof(text);
BufferSplitter totalbuffer(text, readsize);
size_t expectWordCnt = 2;
size_t curLineCnt = 0;
do {
for (size_t i = 0; i < expectWordCnt; i++) {
EXPECT_TRUE(totalbuffer.NextWord(' '));
EXPECT_EQ(expect[(curLineCnt * 2) + i].curWord, totalbuffer.CurWord());
EXPECT_EQ(expect[(curLineCnt * 2) + i].curWordSz, totalbuffer.CurWordSize());
}
curLineCnt++;
} while (totalbuffer.NextLine());
}
/**
* @tc.name: memory plugin
* @tc.desc: Test NextWord().
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, NextWordWithMultipleLinesBuffer02, TestSize.Level1)
{
char text[] = {'a', 'b', ' ', 'c', 'd', ' ', '\n', '1', '2', ' ', '3', '4', '5', ' ', '6', '\0'};
TestElement expect[] = {
{0, text, 6, text, 2}, {0, text, 6, nullptr, 0}, {0, text, 6, &text[7], 2}, {0, text, 4, nullptr, 0}};
int readsize = sizeof(text);
BufferSplitter totalbuffer(text, readsize);
size_t expectWordCnt = 2;
size_t curLineCnt = 0;
do {
for (size_t i = 0; i < expectWordCnt; i++) {
if (i == 0) {
EXPECT_TRUE(totalbuffer.NextWord(' '));
}
if (i == 1) {
EXPECT_FALSE(totalbuffer.NextWord('#'));
}
EXPECT_EQ(expect[(curLineCnt * 2) + i].curWord, totalbuffer.CurWord());
EXPECT_EQ(expect[(curLineCnt * 2) + i].curWordSz, totalbuffer.CurWordSize());
}
curLineCnt++;
} while (totalbuffer.NextLine());
}
/**
* @tc.name: memory plugin
* @tc.desc: Test NextWord().
* @tc.type: FUNC
*/
HWTEST_F(BufferSplitterUnittest, NextWordWithMultipleLinesBuffer03, TestSize.Level1)
{
char text[] = {'a', 'b', ' ', 'c', 'd', ' ', '\n', '1', '2', ' ', '3', '4', '5', ' ', '6', '\0'};
TestElement expect[] = {
{0, text, 6, nullptr, 0}, {0, text, 6, text, 2}, {0, text, 6, nullptr, 0}, {0, text, 6, &text[7], 2}};
int readsize = sizeof(text);
BufferSplitter totalbuffer(text, readsize);
size_t expectWordCnt = 2;
size_t curLineCnt = 0;
do {
for (size_t i = 0; i < expectWordCnt; i++) {
if (i == 0) {
EXPECT_FALSE(totalbuffer.NextWord('#'));
}
if (i == 1) {
EXPECT_TRUE(totalbuffer.NextWord(' '));
}
EXPECT_EQ(expect[(curLineCnt * 2) + i].curWord, totalbuffer.CurWord());
EXPECT_EQ(expect[(curLineCnt * 2) + i].curWordSz, totalbuffer.CurWordSize());
}
curLineCnt++;
} while (totalbuffer.NextLine());
}
/**
* @tc.name: memory plugin
* @tc.desc: Test the scene that actually used,parse /proc/meminfo.
* @tc.type: FUNC
*/
namespace {
char g_kMockMeminfo[] = R"(
MemTotal: 16168736 kB
MemFree: 7154492 kB
MemAvailable: 15481028 kB
Buffers: 2397540 kB
Cached: 4711136 kB
SwapCached: 27628 kB
Active: 5556068 kB
Inactive: 1644560 kB
Active(anon): 62580 kB
Inactive(anon): 43352 kB
Active(file): 5493488 kB
Inactive(file): 1601208 kB
Unevictable: 388 kB
Mlocked: 0 kB
SwapTotal: 16777180 kB
SwapFree: 16500700 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 87672 kB
Mapped: 116988 kB
Shmem: 13980 kB
KReclaimable: 1568904 kB
Slab: 1641176 kB
SReclaimable: 1568904 kB
SUnreclaim: 72272 kB
KernelStack: 7008 kB
PageTables: 28244 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 24861548 kB
Committed_AS: 2569488 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 34260 kB
VmallocChunk: 0 kB
Percpu: 2912 kB
HardwareCorrupted: 0 kB
AnonHugePages: 0 kB
ShmemHugePages: 0 kB
ShmemPmdMapped: 0 kB
FileHugePages: 0 kB
FilePmdMapped: 0 kB
CmaTotal: 0 kB
CmaFree: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
Hugetlb: 0 kB
DirectMap4k: 1997488 kB
DirectMap2M: 14548992 kB
DirectMap1G: 0 kB)";
}
HWTEST_F(BufferSplitterUnittest, MemInfoBufferTEST, TestSize.Level1)
{
int readsize = sizeof(g_kMockMeminfo);
BufferSplitter totalbuffer(g_kMockMeminfo, readsize);
struct CStrCmp {
bool operator()(const char* a, const char* b) const
{
return strcmp(a, b) < 0;
}
};
std::map<const char*, int, CStrCmp> meminfo_counters_ = {{"MemTotal", 16168736},
{"Active", 5556068},
{"Inactive(anon)", 43352},
{"HugePages_Total", 0},
{"DirectMap1G", 0}};
do {
if (!totalbuffer.NextWord(':')) {
continue;
}
const_cast<char *>(totalbuffer.CurWord())[totalbuffer.CurWordSize()] = '\0';
auto it = meminfo_counters_.find(totalbuffer.CurWord());
if (it == meminfo_counters_.end()) {
continue;
}
int counter_id = it->second;
if (!totalbuffer.NextWord(' ')) {
continue;
}
auto value = static_cast<uint64_t>(strtoll(totalbuffer.CurWord(), nullptr, 10));
EXPECT_EQ((uint64_t)counter_id, value);
} while (totalbuffer.NextLine());
}
} // namespace

View File

@ -0,0 +1,579 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <hwext/gtest-ext.h>
#include <hwext/gtest-tag.h>
#include "memory_data_plugin.h"
using namespace testing::ext;
namespace {
#if defined(__i386__) || defined(__x86_64__)
const std::string DEFAULT_TEST_PATH("./");
#else
const std::string DEFAULT_TEST_PATH("/data/local/tmp/");
#endif
constexpr uint32_t BUF_SIZE = 4 * 1024 * 1024;
constexpr uint32_t BIT_WIDTH = 35;
std::string g_path;
const std::vector<int> g_expectPidList = {
1, 2, 11
};
struct TestElement {
int32_t pid;
std::string name;
// data from /proc/$pid/stat
uint64_t vm_size_kb;
uint64_t vm_rss_kb;
uint64_t rss_anon_kb;
uint64_t rss_file_kb;
uint64_t rss_shmem_kb;
uint64_t vm_swap_kb;
uint64_t vm_locked_kb;
uint64_t vm_hwm_kb;
int64_t oom_score_adj;
uint64_t java_heap;
uint64_t native_heap;
uint64_t code;
uint64_t stack;
uint64_t graphics;
uint64_t private_other;
};
TestElement g_singlepid = {-1, "null", 0, 0};
TestElement g_pidtarget[] = {
{1, "systemd", 226208, 9388, 2984, 6404, 0, 0, 0, 9616, -1, 3036, 4256, 288, 748, 0, 1388},
{2, "kthreadd", 0, 0, 0, 0, 0, 0, 0, 0, -100, 3036, 4260, 336, 760, 0, 4204},
{11, "rcu_sched", 0, 0, 0, 0, 0, 0, 0, 0, 0, 3036, 4272, 392, 772, 0, 7168},
};
unsigned long g_meminfo[] = {16168696, 1168452, 12363564, 2726188, 7370484, 29260, 8450388, 4807668,
2535372, 658832, 4148836, 132, 0, 63999996, 62211580, 0};
std::string GetFullPath(std::string path);
class MemoryDataPluginTest : public ::testing::Test {
public:
static void SetUpTestCase();
static void TearDownTestCase()
{
if (access(g_path.c_str(), F_OK) == 0) {
std::string str = "rm -rf " + GetFullPath(DEFAULT_TEST_PATH) + "utresources";
printf("TearDown--> %s\r\n", str.c_str());
system(str.c_str());
}
}
void SetUp() {}
void TearDown() {}
};
string Getexepath()
{
char buf[PATH_MAX] = "";
std::string path = "/proc/self/exe";
size_t rslt = readlink(path.c_str(), buf, sizeof(buf));
if (rslt < 0 || (rslt >= sizeof(buf))) {
return "";
}
buf[rslt] = '\0';
for (int i = rslt; i >= 0; i--) {
if (buf[i] == '/') {
buf[i + 1] = '\0';
break;
}
}
return buf;
}
void MyPrintfProcessMemoryInfo(MemoryData memoryData)
{
int index = memoryData.processesinfo_size();
for (int i = 0; i < index; ++i) {
ProcessMemoryInfo it = memoryData.processesinfo(i);
std::cout << it.pid() << "\t";
std::cout << std::setw(BIT_WIDTH) << std::setfill(' ') << it.name().c_str() << "\t";
std::cout << it.vm_size_kb() << "\t";
std::cout << it.vm_rss_kb() << "\t";
std::cout << it.rss_anon_kb() << "\t";
std::cout << it.rss_file_kb() << "\t";
std::cout << it.rss_shmem_kb() << "\t";
std::cout << it.vm_locked_kb() << "\t";
std::cout << it.vm_hwm_kb() << "\t";
std::cout << it.oom_score_adj() << "\t";
if (it.has_memsummary()) {
std::cout << "appsummary:\t";
AppSummary app = it.memsummary();
std::cout << app.java_heap() << "\t";
std::cout << app.native_heap() << "\t";
std::cout << app.code() << "\t";
std::cout << app.stack() << "\t";
std::cout << app.graphics() << "\t";
std::cout << app.private_other() << "\t";
std::cout << app.system() << "\t";
}
std::cout << std::endl;
}
}
bool PluginStub(std::vector<int> processList, MemoryDataPlugin& memoryPlugin, MemoryData& memoryData)
{
MemoryConfig protoConfig;
int configSize;
int ret;
// set config
if (processList.size() != 0) {
protoConfig.set_report_process_mem_info(true);
protoConfig.set_report_app_mem_info(true);
for (size_t i = 0; i < processList.size(); i++) {
protoConfig.add_pid(processList.at(i));
}
} else {
protoConfig.set_report_process_tree(true);
}
// serialize
configSize = protoConfig.ByteSizeLong();
std::vector<uint8_t> configData(configSize);
ret = protoConfig.SerializeToArray(configData.data(), configData.size());
// start
ret = memoryPlugin.Start(configData.data(), configData.size());
if (ret < 0) {
return false;
}
printf("ut: serialize success start plugin ret = %d\n", ret);
// report
std::vector<uint8_t> bufferData(BUF_SIZE);
ret = memoryPlugin.Report(bufferData.data(), bufferData.size());
if (ret > 0) {
memoryData.ParseFromArray(bufferData.data(), ret);
MyPrintfProcessMemoryInfo(memoryData);
return true;
}
return false;
}
bool pluginMeminfoStub(MemoryDataPlugin& memoryPlugin, MemoryData& memoryData)
{
MemoryConfig protoConfig;
int configSize;
int ret;
protoConfig.set_report_sysmem_mem_info(true);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_MEM_TOTAL);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_MEM_FREE);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_MEM_AVAILABLE);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_BUFFERS);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_CACHED);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_SWAP_CACHED);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_ACTIVE);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_INACTIVE);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_ACTIVE_ANON);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_INACTIVE_ANON);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_INACTIVE_FILE);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_UNEVICTABLE);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_MLOCKED);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_SWAP_TOTAL);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_SWAP_FREE);
protoConfig.add_sys_meminfo_counters(SysMeminfoType::MEMINFO_DIRTY);
// serialize
configSize = protoConfig.ByteSizeLong();
std::vector<uint8_t> configData(configSize);
ret = protoConfig.SerializeToArray(configData.data(), configData.size());
// start
ret = memoryPlugin.Start(configData.data(), configData.size());
if (ret < 0) {
return false;
}
printf("ut: serialize success start plugin ret = %d\n", ret);
// report
std::vector<uint8_t> bufferData(BUF_SIZE);
ret = memoryPlugin.Report(bufferData.data(), bufferData.size());
if (ret > 0) {
memoryData.ParseFromArray(bufferData.data(), ret);
return true;
}
return false;
}
bool pluginWriteVmstat(MemoryDataPlugin& memoryPlugin, MemoryData& memoryData)
{
MemoryConfig protoConfig;
int configSize;
int ret;
protoConfig.set_report_sysmem_vmem_info(true);
// serialize
configSize = protoConfig.ByteSizeLong();
std::vector<uint8_t> configData(configSize);
ret = protoConfig.SerializeToArray(configData.data(), configData.size());
// start
ret = memoryPlugin.Start(configData.data(), configData.size());
if (ret < 0) {
return false;
}
printf("ut: serialize success start plugin ret = %d\n", ret);
// report
std::vector<uint8_t> bufferData(BUF_SIZE);
ret = memoryPlugin.Report(bufferData.data(), bufferData.size());
if (ret > 0) {
memoryData.ParseFromArray(bufferData.data(), ret);
return true;
}
return false;
}
bool pluginDumpsys(MemoryDataPlugin& memoryPlugin, MemoryData& memoryData)
{
MemoryConfig protoConfig;
int configSize;
int ret;
protoConfig.set_report_process_mem_info(true);
protoConfig.set_report_app_mem_info(true);
protoConfig.add_pid(1);
protoConfig.set_report_app_mem_by_dumpsys(true);
// serialize
configSize = protoConfig.ByteSizeLong();
std::vector<uint8_t> configData(configSize);
ret = protoConfig.SerializeToArray(configData.data(), configData.size());
// start
ret = memoryPlugin.Start(configData.data(), configData.size());
if (ret < 0) {
return false;
}
printf("ut: serialize success start plugin ret = %d\n", ret);
// report
std::vector<uint8_t> bufferData(BUF_SIZE);
ret = memoryPlugin.Report(bufferData.data(), bufferData.size());
if (ret > 0) {
memoryData.ParseFromArray(bufferData.data(), ret);
return true;
}
return false;
}
std::string GetFullPath(std::string path)
{
if (path.size() > 0 && path[0] != '/') {
return Getexepath() + path;
}
return path;
}
#if defined(__i386__) || defined(__x86_64__)
bool CreatTestResource(std::string path, std::string exepath)
{
std::string str = "cp -r " + path + "utresources " + exepath;
printf("CreatTestResource:%s\n", str.c_str());
pid_t status = system(str.c_str());
if (-1 == status) {
printf("system error!");
} else {
printf("exit status value = [0x%x]\n", status);
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) == 0) {
return true;
} else {
printf("run shell script fail, script exit code: %d\n", WEXITSTATUS(status));
return false;
}
} else {
printf("exit status = [%d]\n", WEXITSTATUS(status));
return true;
}
}
return false;
}
#endif
void MemoryDataPluginTest::SetUpTestCase()
{
g_path = GetFullPath(DEFAULT_TEST_PATH);
printf("g_path:%s\n", g_path.c_str());
EXPECT_NE("", g_path);
#if defined(__i386__) || defined(__x86_64__)
if (DEFAULT_TEST_PATH != g_path) {
if ((access(std::string(g_path + "utresources/proc").c_str(), F_OK) != 0) &&
(access(std::string(DEFAULT_TEST_PATH + "utresources/proc").c_str(), F_OK) == 0)) {
EXPECT_TRUE(CreatTestResource(DEFAULT_TEST_PATH, g_path));
}
g_path += "utresources/proc";
}
#else
g_path += "utresources/proc";
#endif
printf("g_path:%s\n", g_path.c_str());
}
/**
* @tc.name: memory plugin
* @tc.desc: Test whether the path exists.
* @tc.type: FUNC
*/
HWTEST_F(MemoryDataPluginTest, Testpath, TestSize.Level1)
{
EXPECT_NE(g_path, "");
printf("g_path:%s\n", g_path.c_str());
}
/**
* @tc.name: memory plugin
* @tc.desc: Pid list test in a specific directory.
* @tc.type: FUNC
*/
HWTEST_F(MemoryDataPluginTest, Testpidlist, TestSize.Level1)
{
MemoryDataPlugin* memoryPlugin = new MemoryDataPlugin();
printf("g_path:%s\n", g_path.c_str());
DIR* dir = memoryPlugin->OpenDestDir(g_path.c_str());
EXPECT_NE(nullptr, dir);
std::vector<int> cmpPidList;
while (int32_t pid = memoryPlugin->GetValidPid(dir)) {
printf("pid = %d\n", pid);
cmpPidList.push_back(pid);
}
sort(cmpPidList.begin(), cmpPidList.end());
closedir(dir);
EXPECT_EQ(cmpPidList, g_expectPidList);
delete memoryPlugin;
}
/**
* @tc.name: memory plugin
* @tc.desc: Mem information test for specific pid.
* @tc.type: FUNC
*/
HWTEST_F(MemoryDataPluginTest, Testpluginformeminfo, TestSize.Level1)
{
MemoryDataPlugin memoryPlugin;
MemoryData memoryData;
memoryPlugin.SetPath(const_cast<char*>(g_path.c_str()));
printf("Testpluginformeminfo:setPath=%s\n", g_path.c_str());
EXPECT_TRUE(pluginMeminfoStub(memoryPlugin, memoryData));
int index = memoryData.meminfo().size();
EXPECT_EQ(16, index);
printf("Testpluginformeminfo:index=%d\n", index);
for (int i = 0; i < index; ++i) {
EXPECT_EQ(g_meminfo[i], memoryData.meminfo(i).value());
}
printf("\n");
// stop
memoryPlugin.Stop();
}
/**
* @tc.name: memory plugin
* @tc.desc: pid list information test for specific pid.
* @tc.type: FUNC
*/
HWTEST_F(MemoryDataPluginTest, Testpluginforsinglepid, TestSize.Level1)
{
MemoryDataPlugin memoryPlugin;
MemoryData memoryData;
std::vector<int> pid;
pid.push_back(5);
memoryPlugin.SetPath(const_cast<char*>(g_path.c_str()));
printf("Testpluginforsinglepid:setPath=%s\n", g_path.c_str());
EXPECT_TRUE(PluginStub(pid, memoryPlugin, memoryData));
int index = memoryData.processesinfo_size();
EXPECT_EQ(1, index);
printf("Testpluginforsinglepid:index=%d\n", index);
ProcessMemoryInfo it = memoryData.processesinfo(0);
EXPECT_EQ(g_singlepid.pid, it.pid());
printf("pid=%d\r\n", it.pid());
EXPECT_EQ(g_singlepid.name, it.name());
EXPECT_EQ(g_singlepid.vm_size_kb, it.vm_size_kb());
EXPECT_EQ(g_singlepid.vm_rss_kb, it.vm_rss_kb());
EXPECT_EQ(g_singlepid.rss_anon_kb, it.rss_anon_kb());
EXPECT_EQ(g_singlepid.rss_file_kb, it.rss_file_kb());
EXPECT_EQ(g_singlepid.rss_shmem_kb, it.rss_shmem_kb());
EXPECT_EQ(g_singlepid.vm_locked_kb, it.vm_locked_kb());
EXPECT_EQ(g_singlepid.vm_hwm_kb, it.vm_hwm_kb());
EXPECT_EQ(g_singlepid.oom_score_adj, it.oom_score_adj());
EXPECT_TRUE(it.has_memsummary());
AppSummary app = it.memsummary();
EXPECT_EQ(g_singlepid.java_heap, app.java_heap());
EXPECT_EQ(g_singlepid.native_heap, app.native_heap());
EXPECT_EQ(g_singlepid.code, app.code());
EXPECT_EQ(g_singlepid.stack, app.stack());
EXPECT_EQ(g_singlepid.graphics, app.graphics());
EXPECT_EQ(g_singlepid.private_other, app.private_other());
// stop
memoryPlugin.Stop();
}
/**
* @tc.name: memory plugin
* @tc.desc: pid list information test for specific pids.
* @tc.type: FUNC
*/
HWTEST_F(MemoryDataPluginTest, Testpluginforpids, TestSize.Level1)
{
std::vector<int> cmpPidList = g_expectPidList;
EXPECT_NE((size_t)0, cmpPidList.size());
MemoryDataPlugin memoryPlugin;
MemoryData memoryData;
memoryPlugin.SetPath(const_cast<char*>(g_path.c_str()));
printf("Testpluginforpids:setPath=%s\n", g_path.c_str());
EXPECT_TRUE(PluginStub(cmpPidList, memoryPlugin, memoryData));
int index = memoryData.processesinfo_size();
EXPECT_EQ(3, index);
printf("Testpluginforpids:index=%d\n", index);
for (int i = 0; i < index; ++i) {
ProcessMemoryInfo it = memoryData.processesinfo(i);
EXPECT_EQ(g_pidtarget[i].pid, it.pid());
printf("%d:pid=%d\r\n", i, it.pid());
EXPECT_EQ(g_pidtarget[i].name, it.name());
EXPECT_EQ(g_pidtarget[i].vm_size_kb, it.vm_size_kb());
EXPECT_EQ(g_pidtarget[i].vm_rss_kb, it.vm_rss_kb());
EXPECT_EQ(g_pidtarget[i].rss_anon_kb, it.rss_anon_kb());
EXPECT_EQ(g_pidtarget[i].rss_file_kb, it.rss_file_kb());
EXPECT_EQ(g_pidtarget[i].rss_shmem_kb, it.rss_shmem_kb());
EXPECT_EQ(g_pidtarget[i].vm_locked_kb, it.vm_locked_kb());
EXPECT_EQ(g_pidtarget[i].vm_hwm_kb, it.vm_hwm_kb());
EXPECT_EQ(g_pidtarget[i].oom_score_adj, it.oom_score_adj());
EXPECT_TRUE(it.has_memsummary());
}
// stop
memoryPlugin.Stop();
}
/**
* @tc.name: memory plugin
* @tc.desc: pid list information test for process tree.
* @tc.type: FUNC
*/
HWTEST_F(MemoryDataPluginTest, Testpluginforlist, TestSize.Level1)
{
std::vector<int> cmpPidList = g_expectPidList;
EXPECT_NE((size_t)0, cmpPidList.size());
MemoryDataPlugin memoryPlugin;
std::vector<int> pid;
MemoryData memoryData;
memoryPlugin.SetPath(const_cast<char*>(g_path.c_str()));
printf("Testpluginforlist:setPath=%s\n", g_path.c_str());
EXPECT_TRUE(PluginStub(pid, memoryPlugin, memoryData));
int index = memoryData.processesinfo_size();
EXPECT_EQ(3, index);
printf("Testpluginforlist:index=%d, pidsize=", index);
std::cout << pid.size() << std::endl;
for (int i = 0; i < index; ++i) {
ProcessMemoryInfo it = memoryData.processesinfo(i);
EXPECT_EQ(g_pidtarget[i].pid, it.pid());
printf("%d:pid=%d\r\n", i, it.pid());
EXPECT_EQ(g_pidtarget[i].name, it.name());
EXPECT_EQ(g_pidtarget[i].vm_size_kb, it.vm_size_kb());
EXPECT_EQ(g_pidtarget[i].vm_rss_kb, it.vm_rss_kb());
EXPECT_EQ(g_pidtarget[i].rss_anon_kb, it.rss_anon_kb());
EXPECT_EQ(g_pidtarget[i].rss_file_kb, it.rss_file_kb());
EXPECT_EQ(g_pidtarget[i].rss_shmem_kb, it.rss_shmem_kb());
EXPECT_EQ(g_pidtarget[i].vm_locked_kb, it.vm_locked_kb());
EXPECT_EQ(g_pidtarget[i].vm_hwm_kb, it.vm_hwm_kb());
EXPECT_EQ(g_pidtarget[i].oom_score_adj, it.oom_score_adj());
EXPECT_TRUE(!it.has_memsummary());
}
// stop
memoryPlugin.Stop();
}
/**
* @tc.name: memory plugin
* @tc.desc: Smaps stats info test for specific pids.
* @tc.type: FUNC
*/
HWTEST_F(MemoryDataPluginTest, TestSmapsStatsInfo, TestSize.Level1)
{
SmapsStats smap(std::string(g_path + "/"));
for (size_t i = 0; i < g_expectPidList.size(); i++) {
EXPECT_TRUE(smap.ParseMaps(g_expectPidList[i]));
EXPECT_EQ(g_pidtarget[i].java_heap, (uint64_t)(smap.GetProcessJavaHeap()));
EXPECT_EQ(g_pidtarget[i].native_heap, (uint64_t)(smap.GetProcessNativeHeap()));
EXPECT_EQ(g_pidtarget[i].code, (uint64_t)(smap.GetProcessCode()));
EXPECT_EQ(g_pidtarget[i].stack, (uint64_t)(smap.GetProcessStack()));
EXPECT_EQ(g_pidtarget[i].graphics, (uint64_t)(smap.GetProcessGraphics()));
EXPECT_EQ(g_pidtarget[i].private_other, (uint64_t)(smap.GetProcessPrivateOther()));
}
}
/**
* @tc.name: memory plugin
* @tc.desc: Vmstat info test for specific pids.
* @tc.type: FUNC
*/
HWTEST_F(MemoryDataPluginTest, TestpluginWriteVmstat, TestSize.Level1)
{
MemoryDataPlugin memoryPlugin;
MemoryData memoryData;
memoryPlugin.SetPath(const_cast<char*>(g_path.c_str()));
printf("Testpluginformeminfo:setPath=%s\n", g_path.c_str());
EXPECT_FALSE(pluginWriteVmstat(memoryPlugin, memoryData));
// stop
memoryPlugin.Stop();
}
/**
* @tc.name: memory plugin
* @tc.desc: Get information through Dumpsys.
* @tc.type: FUNC
*/
HWTEST_F(MemoryDataPluginTest, TestpluginDumpsys, TestSize.Level1)
{
MemoryDataPlugin memoryPlugin;
MemoryData memoryData;
memoryPlugin.SetPath(const_cast<char*>(g_path.c_str()));
printf("Testpluginformeminfo:setPath=%s\n", g_path.c_str());
EXPECT_TRUE(pluginDumpsys(memoryPlugin, memoryData));
std::string line = "01234567890";
memoryPlugin.ParseNumber(line);
// stop
memoryPlugin.Stop();
}
} // namespace

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 Huawei Device Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<configuration ver="2.0">
<target name="memdataplugin_ut">
<preparer>
<option name="push" value="proc/1/oom_score_adj -> /data/local/tmp/utresources/proc/1/" src="res"/>
<option name="push" value="proc/1/smaps -> /data/local/tmp/utresources/proc/1/" src="res"/>
<option name="push" value="proc/1/status -> /data/local/tmp/utresources/proc/1/" src="res"/>
<option name="push" value="proc/2/oom_score_adj -> /data/local/tmp/utresources/proc/2/" src="res"/>
<option name="push" value="proc/2/smaps -> /data/local/tmp/utresources/proc/2/" src="res"/>
<option name="push" value="proc/2/status -> /data/local/tmp/utresources/proc/2/" src="res"/>
<option name="push" value="proc/11/oom_score_adj -> /data/local/tmp/utresources/proc/11/" src="res"/>
<option name="push" value="proc/11/smaps -> /data/local/tmp/utresources/proc/11/" src="res"/>
<option name="push" value="proc/11/status -> /data/local/tmp/utresources/proc/11/" src="res"/>
<option name="push" value="proc/cmdline -> /data/local/tmp/utresources/proc/" src="res"/>
<option name="push" value="proc/meminfo -> /data/local/tmp/utresources/proc/" src="res"/>
</preparer>
</target>
</configuration>

View File

@ -0,0 +1 @@
-1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
Name: systemd
Umask: 0000
State: S (sleeping)
Tgid: 1
Ngid: 0
Pid: 1
PPid: 0
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 512
Groups:
NStgid: 1
NSpid: 1
NSpgid: 1
NSsid: 1
VmPeak: 290996 kB
VmSize: 226208 kB
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 9616 kB
VmRSS: 9388 kB
RssAnon: 2984 kB
RssFile: 6404 kB
RssShmem: 0 kB
VmData: 19420 kB
VmStk: 132 kB
VmExe: 1344 kB
VmLib: 10048 kB
VmPTE: 212 kB
VmSwap: 164 kB
HugetlbPages: 0 kB
CoreDumping: 0
THP_enabled: 1
Threads: 1
SigQ: 0/62970
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 7be3c0fe28014a03
SigIgn: 0000000000001000
SigCgt: 00000001800004ec
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
NoNewPrivs: 0
Seccomp: 0
Speculation_Store_Bypass: thread vulnerable
Cpus_allowed: 3f
Cpus_allowed_list: 0-5
Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 78718
nonvoluntary_ctxt_switches: 3443

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1,713 @@
564044f07000-564044f08000 r-xp 00000000 08:01 4587541 test/run
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd ex mr mw me dw sd
564045107000-564045108000 r--p 00000000 08:01 4587541 test/run
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd mr mw me dw ac sd
564045108000-564045109000 rw-p 00001000 08:01 4587541 test/run
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me dw ac sd
564045dbe000-564045ddf000 rw-p 00000000 00:00 0 [heap]
Size: 132 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 12 kB
Pss: 12 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 12 kB
Referenced: 12 kB
Anonymous: 12 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me ac sd
7f46756f6000-7f467570d000 r-xp 00000000 08:01 923931 /lib/x86_64-linux-gnu/libgcc_s.so.1
Size: 92 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 92 kB
Pss: 20 kB
Shared_Clean: 92 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 92 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd ex mr mw me sd
7f467570d000-7f467590c000 ---p 00017000 08:01 923931 /lib/x86_64-linux-gnu/libgcc_s.so.1
Size: 2044 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 0 kB
Pss: 0 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 0 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: mr mw me sd
7f467590c000-7f467590d000 r--p 00016000 08:01 923931 /lib/x86_64-linux-gnu/libgcc_s.so.1
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd mr mw me ac sd
7f467590d000-7f467590e000 rw-p 00017000 08:01 923931 /lib/x86_64-linux-gnu/libgcc_s.so.1
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me ac sd
7f467590e000-7f4675aab000 r-xp 00000000 08:01 929314 /lib/x86_64-linux-gnu/libm-2.27.so
Size: 1652 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 300 kB
Pss: 51 kB
Shared_Clean: 300 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 300 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd ex mr mw me sd
7f4675aab000-7f4675caa000 ---p 0019d000 08:01 929314 /lib/x86_64-linux-gnu/libm-2.27.so
Size: 2044 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 0 kB
Pss: 0 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 0 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: mr mw me sd
7f4675caa000-7f4675cab000 r--p 0019c000 08:01 929314 /lib/x86_64-linux-gnu/libm-2.27.so
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd mr mw me ac sd
7f4675cab000-7f4675cac000 rw-p 0019d000 08:01 929314 /lib/x86_64-linux-gnu/libm-2.27.so
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me ac sd
7f4675cac000-7f4675e93000 r-xp 00000000 08:01 929310 /lib/x86_64-linux-gnu/libc-2.27.so
Size: 1948 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 1136 kB
Pss: 19 kB
Shared_Clean: 1136 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 1136 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd ex mr mw me sd
7f4675e93000-7f4676093000 ---p 001e7000 08:01 929310 /lib/x86_64-linux-gnu/libc-2.27.so
Size: 2048 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 0 kB
Pss: 0 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 0 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: mr mw me sd
7f4676093000-7f4676097000 r--p 001e7000 08:01 929310 /lib/x86_64-linux-gnu/libc-2.27.so
Size: 16 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 16 kB
Pss: 16 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 16 kB
Referenced: 16 kB
Anonymous: 16 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd mr mw me ac sd
7f4676097000-7f4676099000 rw-p 001eb000 08:01 929310 /lib/x86_64-linux-gnu/libc-2.27.so
Size: 8 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 8 kB
Pss: 8 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 8 kB
Referenced: 8 kB
Anonymous: 8 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me ac sd
7f4676099000-7f467609d000 rw-p 00000000 00:00 0
Size: 16 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 12 kB
Pss: 12 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 12 kB
Referenced: 12 kB
Anonymous: 12 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me ac sd
7f467609d000-7f4676216000 r-xp 00000000 08:01 1190514 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
Size: 1508 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 780 kB
Pss: 301 kB
Shared_Clean: 780 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 780 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd ex mr mw me sd
7f4676216000-7f4676416000 ---p 00179000 08:01 1190514 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
Size: 2048 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 0 kB
Pss: 0 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 0 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: mr mw me sd
7f4676416000-7f4676420000 r--p 00179000 08:01 1190514 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
Size: 40 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 40 kB
Pss: 40 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 40 kB
Referenced: 40 kB
Anonymous: 40 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd mr mw me ac sd
7f4676420000-7f4676422000 rw-p 00183000 08:01 1190514 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
Size: 8 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 8 kB
Pss: 8 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 8 kB
Referenced: 8 kB
Anonymous: 8 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me ac sd
7f4676422000-7f4676426000 rw-p 00000000 00:00 0
Size: 16 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me ac sd
7f4676426000-7f467644f000 r-xp 00000000 08:01 927476 /lib/x86_64-linux-gnu/ld-2.27.so
Size: 164 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 164 kB
Pss: 3 kB
Shared_Clean: 164 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 164 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd ex mr mw me dw sd
7f4676634000-7f467663a000 rw-p 00000000 00:00 0
Size: 24 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 24 kB
Pss: 24 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 24 kB
Referenced: 24 kB
Anonymous: 24 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me ac sd
7f467664f000-7f4676650000 r--p 00029000 08:01 927476 /lib/x86_64-linux-gnu/ld-2.27.so
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd mr mw me dw ac sd
7f4676650000-7f4676651000 rw-p 0002a000 08:01 927476 /lib/x86_64-linux-gnu/ld-2.27.so
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me dw ac sd
7f4676651000-7f4676652000 rw-p 00000000 00:00 0
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me ac sd
7ffe45c9a000-7ffe45cbb000 rw-p 00000000 00:00 0 [stack]
Size: 132 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 12 kB
Pss: 12 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 12 kB
Referenced: 12 kB
Anonymous: 12 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me gd ac
7ffe45d41000-7ffe45d44000 r--p 00000000 00:00 0 [vvar]
Size: 12 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 0 kB
Pss: 0 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 0 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd mr pf io de dd sd
7ffe45d44000-7ffe45d45000 r-xp 00000000 00:00 0 [vdso]
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 0 kB
Shared_Clean: 4 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 4 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd ex mr mw me de sd
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 0 kB
Pss: 0 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 0 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: ex

View File

@ -0,0 +1,37 @@
Name: rcu_sched
Umask: 0000
State: I (idle)
Tgid: 11
Ngid: 0
Pid: 11
PPid: 2
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 64
Groups:
NStgid: 11
NSpid: 11
NSpgid: 0
NSsid: 0
Threads: 1
SigQ: 0/62967
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: ffffffffffffffff
SigCgt: 0000000000000000
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
NoNewPrivs: 0
Seccomp: 0
Speculation_Store_Bypass: thread vulnerable
Cpus_allowed: 3f
Cpus_allowed_list: 0-5
Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 18962428
nonvoluntary_ctxt_switches: 39

View File

@ -0,0 +1 @@
-100

View File

@ -0,0 +1,414 @@
5637ebe15000-5637ebe16000 r-xp 00000000 08:01 4587541 test/run
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 4 kB
Private_Dirty: 0 kB
Referenced: 4 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd ex mr mw me dw sd
5637ec015000-5637ec016000 r--p 00000000 08:01 4587541 test/run
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd mr mw me dw ac sd
5637ec016000-5637ec017000 rw-p 00001000 08:01 4587541 test/run
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me dw ac sd
5637ec60f000-5637ec630000 rw-p 00000000 00:00 0 [heap]
Size: 132 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me ac sd
7fa384a9e000-7fa384c85000 r-xp 00000000 08:01 929310 /lib/x86_64-linux-gnu/libc-2.27.so
Size: 1948 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 1200 kB
Pss: 20 kB
Shared_Clean: 1200 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 1200 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd ex mr mw me sd
7fa384c85000-7fa384e85000 ---p 001e7000 08:01 929310 /lib/x86_64-linux-gnu/libc-2.27.so
Size: 2048 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 0 kB
Pss: 0 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 0 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: mr mw me sd
7fa384e85000-7fa384e89000 r--p 001e7000 08:01 929310 /lib/x86_64-linux-gnu/libc-2.27.so
Size: 16 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 16 kB
Pss: 16 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 16 kB
Referenced: 16 kB
Anonymous: 16 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd mr mw me ac sd
7fa384e89000-7fa384e8b000 rw-p 001eb000 08:01 929310 /lib/x86_64-linux-gnu/libc-2.27.so
Size: 8 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 8 kB
Pss: 8 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 8 kB
Referenced: 8 kB
Anonymous: 8 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me ac sd
7fa384e8b000-7fa384e8f000 rw-p 00000000 00:00 0
Size: 16 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 12 kB
Pss: 12 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 12 kB
Referenced: 12 kB
Anonymous: 12 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me ac sd
7fa384e8f000-7fa384eb8000 r-xp 00000000 08:01 927476 /lib/x86_64-linux-gnu/ld-2.27.so
Size: 164 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 164 kB
Pss: 3 kB
Shared_Clean: 164 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 164 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd ex mr mw me dw sd
7fa3850a1000-7fa3850a3000 rw-p 00000000 00:00 0
Size: 8 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 8 kB
Pss: 8 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 8 kB
Referenced: 8 kB
Anonymous: 8 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me ac sd
7fa3850b8000-7fa3850b9000 r--p 00029000 08:01 927476 /lib/x86_64-linux-gnu/ld-2.27.so
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd mr mw me dw ac sd
7fa3850b9000-7fa3850ba000 rw-p 0002a000 08:01 927476 /lib/x86_64-linux-gnu/ld-2.27.so
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me dw ac sd
7fa3850ba000-7fa3850bb000 rw-p 00000000 00:00 0
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me ac sd
7ffc54ec0000-7ffc54ee1000 rw-p 00000000 00:00 0 [stack]
Size: 132 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 12 kB
Pss: 12 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 12 kB
Referenced: 12 kB
Anonymous: 12 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me gd ac
7ffc54f1c000-7ffc54f1f000 r--p 00000000 00:00 0 [vvar]
Size: 12 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 0 kB
Pss: 0 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 0 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd mr pf io de dd sd
7ffc54f1f000-7ffc54f20000 r-xp 00000000 00:00 0 [vdso]
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 0 kB
Shared_Clean: 4 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 4 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd ex mr mw me de sd
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
Size: 4 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 0 kB
Pss: 0 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 0 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: ex

View File

@ -0,0 +1,37 @@
Name: kthreadd
Umask: 0000
State: S (sleeping)
Tgid: 2
Ngid: 0
Pid: 2
PPid: 0
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 64
Groups:
NStgid: 2
NSpid: 2
NSpgid: 0
NSsid: 0
Threads: 1
SigQ: 0/62970
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: ffffffffffffffff
SigCgt: 0000000000000000
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
NoNewPrivs: 0
Seccomp: 0
Speculation_Store_Bypass: thread vulnerable
Cpus_allowed: 3f
Cpus_allowed_list: 0-5
Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 3372
nonvoluntary_ctxt_switches: 1

View File

@ -0,0 +1,53 @@
MemTotal: 16168696 kB
MemFree: 1168452 kB
MemAvailable: 12363564 kB
Buffers: 2726188 kB
Cached: 7370484 kB
SwapCached: 29260 kB
Active: 8450388 kB
Inactive: 4807668 kB
Active(anon): 2535372 kB
Inactive(anon): 658832 kB
Active(file): 5915016 kB
Inactive(file): 4148836 kB
Unevictable: 132 kB
Mlocked: 0 kB
SwapTotal: 63999996 kB
SwapFree: 62211580 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 3142688 kB
Mapped: 161520 kB
Shmem: 32820 kB
KReclaimable: 1468312 kB
Slab: 1545180 kB
SReclaimable: 1468312 kB
SUnreclaim: 76868 kB
KernelStack: 9200 kB
PageTables: 46928 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 72084344 kB
Committed_AS: 7746304 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 37652 kB
VmallocChunk: 0 kB
Percpu: 3200 kB
HardwareCorrupted: 0 kB
AnonHugePages: 0 kB
ShmemHugePages: 0 kB
ShmemPmdMapped: 0 kB
FileHugePages: 0 kB
FilePmdMapped: 0 kB
CmaTotal: 0 kB
CmaFree: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
Hugetlb: 0 kB
DirectMap4k: 1315504 kB
DirectMap2M: 15230976 kB
DirectMap1G: 0 kB

65
device/services/ipc/BUILD.gn Executable file
View File

@ -0,0 +1,65 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/ohos.gni")
import("../../base/config.gni")
ohos_source_set("ipc") {
sources = [
"src/client_connection.cpp",
"src/client_map.cpp",
"src/service_entry.cpp",
"src/socket_context.cpp",
"src/unix_socket_client.cpp",
"src/unix_socket_server.cpp",
]
include_dirs = [
"include",
"../../base/include",
"//utils/native/base/include",
]
if (current_toolchain != host_toolchain) {
defines = [ "HAVE_HILOG" ]
if (build_l2) {
external_deps = [ "shared_library:libhilog" ]
} else {
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
}
}
deps = [
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite",
"//utils/native/base:utilsbase",
]
public_configs = [ "../../base:hiprofiler_test_config" ]
}
ohos_executable("protoc_gen_ipc") {
sources = [
"src/ipc_generator.cpp",
"src/ipc_generator_impl.cpp",
"src/main.cpp",
]
include_dirs = [
"include",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}",
]
public_configs = [ "../../base:hiprofiler_test_config" ]
deps = [
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc_lib",
]
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CLIENT_CONNECTION_H
#define CLIENT_CONNECTION_H
#include "service_entry.h"
#include "socket_context.h"
#include <cstdint>
class ClientConnection final : public SocketContext {
public:
ClientConnection(int sfd, ServiceEntry& serviceEntry);
~ClientConnection();
int RawProtocolProc(uint32_t pnum, const int8_t* buf, const uint32_t size) override;
ServiceEntry* serviceEntry_;
std::string protoServiceName_;
};
#endif

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CLIENT_MAP_H
#define CLIENT_MAP_H
#include "client_connection.h"
#include <map>
class ServiceEntry;
class ClientMap {
public:
static ClientMap& GetInstance();
int PutClientSocket(int socketFileDescriptor, ServiceEntry& p);
int AutoRelease();
private:
ClientMap();
~ClientMap();
std::map<int, std::shared_ptr<ClientConnection>> socketClients_;
};
#endif

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef IPC_GENERATOR_H
#define IPC_GENERATOR_H
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/plugin.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include <map>
#include <string>
#include <vector>
class IpcGeneratorImpl;
class IpcGenerator : public google::protobuf::compiler::CodeGenerator {
public:
IpcGenerator();
~IpcGenerator();
bool Generate(const google::protobuf::FileDescriptor* file,
const std::string& parameter,
google::protobuf::compiler::GeneratorContext* context,
std::string* error) const override;
};
#endif

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef IPC_GENERATOR_IMPL_H
#define IPC_GENERATOR_IMPL_H
#include <map>
#include <ostream>
class IpcServices {
public:
IpcServices()
{
methodCount_ = 0;
}
~IpcServices() {}
std::string serviceName_;
std::map<int, std::string> methodList_;
std::map<int, std::string> requestList_;
std::map<int, std::string> responseList_;
int methodCount_;
bool AddMethod(std::string method, std::string request, std::string response)
{
for (int i = 0; i < methodCount_; i++) {
if (methodList_[i] == method) {
return false;
}
}
methodList_[methodCount_] = method;
requestList_[methodCount_] = request;
responseList_[methodCount_] = response;
methodCount_++;
return true;
}
};
class IpcGeneratorImpl {
public:
IpcGeneratorImpl();
~IpcGeneratorImpl();
std::string SetNames(std::string fileName, std::string packageName);
bool AddService(std::string serviceName);
bool AddServiceMethod(std::string serviceName,
std::string methodName,
std::string requestName,
std::string responseName);
std::string GenHeader();
std::string GenSource();
private:
std::string fileName_ = "";
std::string baseName_ = "";
std::string packageName_ = "";
std::string headFileName_ = "";
void GenerateHeader(std::string& header_str);
std::string GenSendResponseImpl(int servicep, const std::string& server_class_name);
std::string GenOnResponseImpl(int servicep, const std::string& client_class_name);
std::string GenServiceCallImpl(int servicep, const std::string& server_class_name);
std::string GenClientProcImpl(int servicep);
std::string GenClientRequestImpl(int servicep, const std::string& client_class_name);
std::string GenServiceProcImpl(int servicep);
std::map<int, IpcServices> serviceList_;
int serviceCount_ = 0;
std::map<int, std::string> enumMessageDict_;
};
#endif

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SERVICE_BASE_H
#define SERVICE_BASE_H
#include <mutex>
class SocketContext;
class ServiceBase {
public:
virtual ~ServiceBase() {}
virtual bool ProtocolProc(SocketContext& poc, uint32_t pnum, const int8_t* buf, const uint32_t size)
{
return false;
}
std::timed_mutex mWait_;
std::string serviceName_;
};
#endif

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SERVICE_ENTRY_H
#define SERVICE_ENTRY_H
#include "service_base.h"
#include <cstdint>
#include <map>
static const uint32_t PROTOCOL_TYPE_FILTER = 0xF0000000;
enum ProtocolType {
PROTOCOL_TYPE_RAW = 0,
PROTOCOL_TYPE_PROTOBUF = 0x10000000,
};
struct ProtocolHead {
uint32_t protoType;
uint32_t protoSize;
int8_t datas[0];
};
class UnixSocketServer;
class ServiceEntry {
public:
ServiceEntry();
~ServiceEntry();
bool StartServer(const std::string& addrname);
bool RegisterService(ServiceBase& psb);
const ServiceBase* FindServiceByName(const std::string& service_name);
private:
std::shared_ptr<UnixSocketServer> unixSocketServer_;
std::map<std::string, ServiceBase*> serviceMap_;
};
uint64_t GetTimeMS();
uint64_t GetTimeUS();
uint64_t GetTimeNS();
#endif

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOCKET_CONTEXT_H
#define SOCKET_CONTEXT_H
#include <cstdint>
#include <google/protobuf/message.h>
#include <thread>
#if defined(__i386__) || defined(__x86_64__)
const static char DEFAULT_UNIX_SOCKET_PATH[] = "hiprofiler_unix_socket";
#else
const static char DEFAULT_UNIX_SOCKET_PATH[] = "/data/local/tmp/hiprofiler_unix_socket";
#endif
class SocketContext;
class ServiceBase;
class ClientMap;
enum ClientState {
CLIENT_STAT_WORKING,
CLIENT_STAT_WAIT_THREAD_EXIT,
CLIENT_STAT_THREAD_EXITED,
};
enum RawProtocol {
RAW_PROTOCOL_POINTTO_SERVICE = 1,
};
struct RawPointToService {
char serviceName_[64];
};
class SocketContext {
public:
SocketContext();
virtual ~SocketContext();
bool SendRaw(uint32_t pnum, const int8_t* data, uint32_t size, int sockfd = -1);
bool SendProtobuf(uint32_t pnum, google::protobuf::Message& pmsg);
bool SendFileDescriptor(int fd);
int ReceiveFileDiscriptor();
protected:
friend class ClientMap;
int socketHandle_;
bool CreateRecvThread();
enum ClientState clientState_;
uint64_t lastProcMS_;
ServiceBase* serviceBase_;
virtual int RawProtocolProc(uint32_t pnum, const int8_t* buf, const uint32_t size);
private:
static void* UnixSocketRecv(void* pp);
std::thread recvThread_;
};
#endif

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef UNIX_SOCKET_CLIENT_H
#define UNIX_SOCKET_CLIENT_H
#include "socket_context.h"
#include <cstdint>
class ServiceBase;
class UnixSocketClient final : public SocketContext {
public:
UnixSocketClient();
~UnixSocketClient();
bool Connect(const std::string addrname, ServiceBase& serviceBase);
};
#endif

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef UNIX_SOCKET_SERVER_H
#define UNIX_SOCKET_SERVER_H
#include "socket_context.h"
#include <ostream>
#include <thread>
class ServiceEntry;
class UnixSocketServer {
public:
UnixSocketServer();
~UnixSocketServer();
int socketHandle_;
bool StartServer(const std::string& addrname, ServiceEntry& p);
std::string sAddrName_;
// private:
ServiceEntry* serviceEntry_;
private:
std::thread acceptThread_;
static void* UnixSocketAccept(void* p);
};
#endif

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "client_connection.h"
#include <cstdint>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "logging.h"
ClientConnection::ClientConnection(int sfd, ServiceEntry& serviceEntry)
{
serviceBase_ = nullptr;
socketHandle_ = sfd;
clientState_ = CLIENT_STAT_WORKING;
lastProcMS_ = GetTimeMS();
serviceEntry_ = &serviceEntry;
CreateRecvThread();
}
ClientConnection::~ClientConnection()
{
HILOG_INFO(LOG_CORE, "Client Released");
}
int ClientConnection::RawProtocolProc(uint32_t pnum, const int8_t* buf, const uint32_t size)
{
switch (pnum) {
case RAW_PROTOCOL_POINTTO_SERVICE: {
struct RawPointToService* prrs = (struct RawPointToService*)buf;
protoServiceName_ = prrs->serviceName_;
serviceBase_ = const_cast<ServiceBase*>(serviceEntry_->FindServiceByName(protoServiceName_));
HILOG_INFO(LOG_CORE, "RAW_PROTOCOL_POINTTO_SERVICE %s", protoServiceName_.c_str());
}
return 1;
default:
break;
}
return -1;
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "client_map.h"
#include <cstdio>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "logging.h"
ClientMap& ClientMap::GetInstance()
{
static ClientMap instance;
return instance;
}
ClientMap::ClientMap() {}
ClientMap::~ClientMap() {}
int ClientMap::PutClientSocket(int socketFileDescriptor, ServiceEntry& p)
{
if (socketClients_.find(socketFileDescriptor) == socketClients_.end()) {
socketClients_[socketFileDescriptor] = std::make_shared<ClientConnection>(socketFileDescriptor, p);
return 1;
}
return -1;
}
int ClientMap::AutoRelease()
{
for (auto iter = socketClients_.begin(); iter != socketClients_.end(); ++iter) {
auto p = iter->second;
switch (p->clientState_) {
case CLIENT_STAT_WORKING:
break;
case CLIENT_STAT_WAIT_THREAD_EXIT:
break;
case CLIENT_STAT_THREAD_EXITED:
HILOG_INFO(LOG_CORE, "AutoRelease release %d", iter->first);
socketClients_.erase(iter->first);
return 1;
break;
default:
break;
}
}
return 1;
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ipc_generator.h"
#include "ipc_generator_impl.h"
IpcGenerator::IpcGenerator() {}
IpcGenerator::~IpcGenerator() {}
bool IpcGenerator::Generate(const google::protobuf::FileDescriptor* file,
const std::string& parameter,
google::protobuf::compiler::GeneratorContext* context,
std::string* error) const
{
auto pcsp = std::make_shared<IpcGeneratorImpl>();
std::string base_name = pcsp->SetNames(file->name(), file->package());
for (int i = 0; i < file->service_count(); i++) {
const google::protobuf::ServiceDescriptor* service = file->service(i);
pcsp->AddService(service->name());
for (int j = 0; j < service->method_count(); j++) {
const google::protobuf::MethodDescriptor* method = service->method(j);
const google::protobuf::Descriptor* inputType = method->input_type();
const google::protobuf::Descriptor* outputType = method->output_type();
pcsp->AddServiceMethod(service->name(), method->name(), inputType->name(), outputType->name());
}
}
std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> header_output(context->Open(base_name + ".ipc.h"));
std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> source_output(context->Open(base_name + ".ipc.cc"));
::google::protobuf::io::CodedOutputStream header_out(header_output.get());
::google::protobuf::io::CodedOutputStream source_out(source_output.get());
std::string header_str = pcsp->GenHeader();
header_out.WriteString(header_str);
std::string source_str = pcsp->GenSource();
source_out.WriteString(source_str);
return true;
}

View File

@ -0,0 +1,455 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ipc_generator_impl.h"
IpcGeneratorImpl::IpcGeneratorImpl() {}
IpcGeneratorImpl::~IpcGeneratorImpl() {}
namespace {
const std::string BASE_HEADER_STRING = R"(
#pragma once
#include "#HEAD_FILE_NAME#.pb.h"
#include "service_base.h"
#include <cstdint>
#include <mutex>
class SocketContext;
class UnixSocketClient;
#PROTOCOL_ENUM#
class #SERVICE_CLASS_NAME#:public ServiceBase
{
public:
#SERVICE_CLASS_NAME#();
bool ProtocolProc(SocketContext &context, uint32_t pnum, const int8_t *buf, const uint32_t size) override;
#RESPONSE_DEFINE#
};
class #CLIENT_CLASS_NAME#:public ServiceBase
{
public:
#CLIENT_CLASS_NAME#();
std::shared_ptr<UnixSocketClient> unixSocketClient_;
bool Connect(const std::string addrname);
bool ProtocolProc(SocketContext &context, uint32_t pnum, const int8_t *buf, const uint32_t size) override;
google::protobuf::Message *presponse;
uint32_t waitingFor;
#VIRTUAL_RESPONSE_FUNC#
};
)";
const std::string BASE_SOURCE_STRING = R"(
#include "#HEAD_FILE_NAME#.ipc.h"
#include "#HEAD_FILE_NAME#.pb.h"
#include "socket_context.h"
#include "unix_socket_client.h"
#include "unix_socket_server.h"
#include <unistd.h>
namespace{
const uint32_t WAIT_FOR_EVER=24*60*60*1000;
}
#SERVICE_CLASS_NAME#::#SERVICE_CLASS_NAME#()
{
serviceName_="#SERVICE_NAME#";
}
#RESPONSE_IMPLEMENT#
#SERVICE_PROTOCOL_PROC_FUNC#
bool #SERVICE_CLASS_NAME#::ProtocolProc(SocketContext &context, uint32_t pnum, const int8_t *buf, const uint32_t size)
{
switch (pnum) {
#SERVICE_PROTOCOL_PROC#
}
return false;
}
#CLIENT_CLASS_NAME#::#CLIENT_CLASS_NAME#()
{
unixSocketClient_=nullptr;
serviceName_="#SERVICE_NAME#";
}
bool #CLIENT_CLASS_NAME#::Connect(const std::string addrname)
{
if (unixSocketClient_!=nullptr) {
return false;
}
unixSocketClient_ = std::make_shared<UnixSocketClient>();
if (!unixSocketClient_->Connect(addrname, *this)) {
unixSocketClient_=nullptr;
return false;
}
return true;
}
#CLIENT_SEND_REQUEST_PROC_FUNC#
#CLIENT_SEND_PROTOCOL_PROC_FUNC#
bool #CLIENT_CLASS_NAME#::ProtocolProc(SocketContext &context, uint32_t pnum, const int8_t *buf, const uint32_t size)
{
switch (pnum) {
#CLIENT_PROTOCOL_PROC#
}
if (waitingFor==pnum) {
waitingFor=-1;
mWait_.unlock();
}
return false;
}
)";
std::string SwapName(std::string s)
{
std::string ret = "";
bool b = true;
for (size_t i = 0; i < s.length(); i++) {
char c = s[i];
if (c == '_') {
b = true;
} else if (b && c >= 'a' && c <= 'z') {
ret += (c + 'A' - 'a');
b = false;
} else {
ret += c;
}
}
return ret;
}
std::string ReplaceStr(const std::string& base, const std::string& _from, const std::string& _to)
{
std::string ret = base;
while (true) {
size_t pos = ret.find(_from, 0);
if (pos == std::string::npos) {
break;
}
ret.replace(pos, _from.length(), _to);
}
return ret;
}
} // namespace
std::string IpcGeneratorImpl::SetNames(std::string fileName, std::string packageName)
{
fileName_ = fileName;
packageName_ = packageName + "::";
headFileName_ = "";
for (size_t i = 0; i < fileName.length(); i++) {
if (fileName.c_str()[i] == '.') {
break;
}
headFileName_ += fileName.c_str()[i];
}
baseName_ = SwapName(headFileName_);
serviceCount_ = 0;
serviceList_.clear();
enumMessageDict_.clear();
return headFileName_;
}
bool IpcGeneratorImpl::AddService(std::string serviceName)
{
for (int i = 0; i < serviceCount_; i++) {
if (serviceList_[i].serviceName_ == serviceName) {
return false;
}
}
serviceList_[serviceCount_].serviceName_ = serviceName;
serviceCount_++;
return true;
}
bool IpcGeneratorImpl::AddServiceMethod(std::string serviceName,
std::string methodName,
std::string requestName,
std::string responseName)
{
for (int i = 0; i < serviceCount_; i++) {
if (serviceList_[i].serviceName_ == serviceName) {
return serviceList_[i].AddMethod(methodName, requestName, responseName);
}
}
return false;
}
void IpcGeneratorImpl::GenerateHeader(std::string& header_str)
{
for (int i = 0; i < serviceCount_; i++) {
std::string server_class_name = serviceList_[i].serviceName_ + "Server";
header_str = ReplaceStr(header_str, "#SERVICE_CLASS_NAME#", server_class_name);
std::string tmp1 = "";
std::string tmp2 = "";
for (int j = 0; j < serviceList_[i].methodCount_; j++) {
tmp1 += "\tvirtual bool " + serviceList_[i].methodList_[j] + "(SocketContext &context," + packageName_ +
serviceList_[i].requestList_[j] + " &request," + packageName_ + serviceList_[i].responseList_[j] +
" &response);\n";
tmp2 += "\tbool SendResponse" + serviceList_[i].responseList_[j] + "(SocketContext &context," +
packageName_ + serviceList_[i].responseList_[j] + " &response);\n";
}
tmp1 += "\n" + tmp2;
header_str = ReplaceStr(header_str, "#RESPONSE_DEFINE#", tmp1);
std::string client_class_name = serviceList_[i].serviceName_ + "Client";
header_str = ReplaceStr(header_str, "#CLIENT_CLASS_NAME#", client_class_name);
tmp1 = "";
for (int j = 0; j < serviceList_[i].methodCount_; j++) {
tmp1 += "\tbool " + serviceList_[i].methodList_[j] + "(" + packageName_ + serviceList_[i].requestList_[j];
tmp1 += " &request," + packageName_ + serviceList_[i].responseList_[j];
tmp1 += " &response,uint32_t timeout_ms=5000);\n";
tmp1 += "\tbool " + serviceList_[i].methodList_[j] + "(" + packageName_ + serviceList_[i].requestList_[j];
tmp1 += " &request);\n";
}
tmp1 += "\n";
for (int j = 0; j < serviceList_[i].methodCount_; j++) {
tmp1 += "\tvirtual bool On" + serviceList_[i].responseList_[j] + "(SocketContext &context," + packageName_;
tmp1 += serviceList_[i].responseList_[j] + " &response);\n";
}
header_str = ReplaceStr(header_str, "#VIRTUAL_RESPONSE_FUNC#", tmp1);
}
}
std::string IpcGeneratorImpl::GenHeader()
{
std::string header_str = BASE_HEADER_STRING;
std::string tmp1, tmp2;
header_str = ReplaceStr(header_str, "#HEAD_FILE_NAME#", headFileName_);
if (serviceCount_ > 0) {
tmp1 = "enum {\n";
for (int i = 0; i < serviceCount_; i++) {
for (int j = 0; j < serviceList_[i].methodCount_; j++) {
tmp1 += "\tIpcProtocol" + baseName_ + serviceList_[i].requestList_[j];
tmp1 += "=" + std::to_string(j * 2) + ",\n";
tmp1 += "\tIpcProtocol" + baseName_ + serviceList_[i].responseList_[j];
tmp1 += "=" + std::to_string(j * 2 + 1) + ",\n";
}
}
tmp1 += "};";
} else {
tmp1 = "";
}
header_str = ReplaceStr(header_str, "#PROTOCOL_ENUM#", tmp1);
GenerateHeader(header_str);
header_str = ReplaceStr(header_str, "\t", " ");
return header_str;
}
namespace {
const std::string SEND_RESPONSE_IMPL_STRING = R"(
bool #SERVER_CLASS_NAME#::SendResponse#RESPONSE_NAME#(SocketContext &context,
#PACKAGE_NAME##RESPONSE_NAME# &response) {
context.SendProtobuf(#ENUM_STR#, response);
return false;
}
)";
}
std::string IpcGeneratorImpl::GenSendResponseImpl(int servicep, const std::string& server_class_name)
{
std::string ret = "";
for (int j = 0; j < serviceList_[servicep].methodCount_; j++) {
std::string enum_str = "IpcProtocol" + baseName_ + serviceList_[servicep].responseList_[j];
std::string tmp = ReplaceStr(SEND_RESPONSE_IMPL_STRING, "#SERVER_CLASS_NAME#", server_class_name);
tmp = ReplaceStr(tmp, "#RESPONSE_NAME#", serviceList_[servicep].responseList_[j]);
tmp = ReplaceStr(tmp, "#PACKAGE_NAME#", packageName_);
tmp = ReplaceStr(tmp, "#ENUM_STR#", enum_str);
ret += tmp;
}
return ret;
}
namespace {
const std::string ON_RESPONSE_IMPL_STRING = R"(
bool #CLIENT_CLASS_NAME#::On#RESPONSE_NAME#(SocketContext &context, #PACKAGE_NAME##RESPONSE_NAME# &response) {
return false;
}
)";
}
std::string IpcGeneratorImpl::GenOnResponseImpl(int servicep, const std::string& client_class_name)
{
std::string ret = "";
for (int j = 0; j < serviceList_[servicep].methodCount_; j++) {
std::string tmp = ReplaceStr(ON_RESPONSE_IMPL_STRING, "#CLIENT_CLASS_NAME#", client_class_name);
tmp = ReplaceStr(tmp, "#RESPONSE_NAME#", serviceList_[servicep].responseList_[j]);
tmp = ReplaceStr(tmp, "#PACKAGE_NAME#", packageName_);
ret += tmp;
}
return ret;
}
namespace {
const std::string SERVICE_CALL_IMPL_STRING = R"(
bool #SERVER_CLASS_NAME#::#METHOD_NAME#(SocketContext &context,
#PACKAGE_NAME##REQUEST_NAME# &request,
#PACKAGE_NAME##RESPONSE_NAME# &response){
return false;
}
)";
}
std::string IpcGeneratorImpl::GenServiceCallImpl(int servicep, const std::string& server_class_name)
{
std::string ret = "";
for (int j = 0; j < serviceList_[servicep].methodCount_; j++) {
std::string tmp = ReplaceStr(SERVICE_CALL_IMPL_STRING, "#SERVER_CLASS_NAME#", server_class_name);
tmp = ReplaceStr(tmp, "#SERVER_CLASS_NAME#", server_class_name);
tmp = ReplaceStr(tmp, "#METHOD_NAME#", serviceList_[servicep].methodList_[j]);
tmp = ReplaceStr(tmp, "#REQUEST_NAME#", serviceList_[servicep].requestList_[j]);
tmp = ReplaceStr(tmp, "#RESPONSE_NAME#", serviceList_[servicep].responseList_[j]);
tmp = ReplaceStr(tmp, "#PACKAGE_NAME#", packageName_);
ret += tmp;
}
return ret;
}
namespace {
const std::string CLIENT_PROC_IMPL_STRING = R"(
case IpcProtocol#BASE_NAME##REQUEST_NAME#:{
#PACKAGE_NAME##REQUEST_NAME# request;
#PACKAGE_NAME##RESPONSE_NAME# response;
request.ParseFromArray(buf, size);
if (#METHOD_NAME#(context, request, response)) {
context.SendProtobuf(IpcProtocol#BASE_NAME##RESPONSE_NAME#, response);
}
}
break;
)";
}
std::string IpcGeneratorImpl::GenClientProcImpl(int servicep)
{
std::string ret = "";
for (int j = 0; j < serviceList_[servicep].methodCount_; j++) {
std::string tmp = ReplaceStr(CLIENT_PROC_IMPL_STRING, "#BASE_NAME#", baseName_);
tmp = ReplaceStr(tmp, "#PACKAGE_NAME#", packageName_);
tmp = ReplaceStr(tmp, "#METHOD_NAME#", serviceList_[servicep].methodList_[j]);
tmp = ReplaceStr(tmp, "#REQUEST_NAME#", serviceList_[servicep].requestList_[j]);
tmp = ReplaceStr(tmp, "#RESPONSE_NAME#", serviceList_[servicep].responseList_[j]);
tmp = ReplaceStr(tmp, "#PACKAGE_NAME#", packageName_);
ret += tmp;
}
return ret;
}
namespace {
const std::string CLIENT_REQUEST_IMPL_STRING = R"(
bool #CLIENT_CLASS_NAME#::#METHOD_NAME#(#PACKAGE_NAME##REQUEST_NAME# &request,
#PACKAGE_NAME##RESPONSE_NAME# &response,
uint32_t timeout_ms)
{
mWait_.lock();
if (timeout_ms<=0) {
timeout_ms=WAIT_FOR_EVER;
}
waitingFor=IpcProtocol#BASE_NAME##RESPONSE_NAME#;
presponse=&response;
unixSocketClient_->SendProtobuf(IpcProtocol#BASE_NAME##REQUEST_NAME#, request);
if (mWait_.try_lock_for(std::chrono::milliseconds(timeout_ms))) {
mWait_.unlock();
return true;
}
waitingFor=-1;
mWait_.unlock();
return false;
}
bool #CLIENT_CLASS_NAME#::#METHOD_NAME#(#PACKAGE_NAME##REQUEST_NAME# &request)
{
unixSocketClient_->SendProtobuf(IpcProtocol#BASE_NAME##REQUEST_NAME#, request);
return true;
}
)";
}
std::string IpcGeneratorImpl::GenClientRequestImpl(int servicep, const std::string& client_class_name)
{
std::string ret = "";
for (int j = 0; j < serviceList_[servicep].methodCount_; j++) {
std::string tmp = ReplaceStr(CLIENT_REQUEST_IMPL_STRING, "#CLIENT_CLASS_NAME#", client_class_name);
tmp = ReplaceStr(tmp, "#METHOD_NAME#", serviceList_[servicep].methodList_[j]);
tmp = ReplaceStr(tmp, "#PACKAGE_NAME#", packageName_);
tmp = ReplaceStr(tmp, "#REQUEST_NAME#", serviceList_[servicep].requestList_[j]);
tmp = ReplaceStr(tmp, "#RESPONSE_NAME#", serviceList_[servicep].responseList_[j]);
tmp = ReplaceStr(tmp, "#BASE_NAME#", baseName_);
ret += tmp;
}
return ret;
}
namespace {
const std::string SERVICE_PROC_IMPL_STRING = R"(
case IpcProtocol#BASE_NAME##RESPONSE_NAME#:
{
if (waitingFor==pnum) {
presponse->ParseFromArray(buf, size);
}
else {
#PACKAGE_NAME##RESPONSE_NAME# response#NUM#;
response#NUM#.ParseFromArray(buf, size);
On#RESPONSE_NAME#(context, response#NUM#);
}
}
break;
)";
}
std::string IpcGeneratorImpl::GenServiceProcImpl(int servicep)
{
std::string ret = "";
for (int j = 0; j < serviceList_[servicep].methodCount_; j++) {
std::string tmp = ReplaceStr(SERVICE_PROC_IMPL_STRING, "#BASE_NAME#", baseName_);
tmp = ReplaceStr(tmp, "#RESPONSE_NAME#", serviceList_[servicep].responseList_[j]);
tmp = ReplaceStr(tmp, "#PACKAGE_NAME#", packageName_);
tmp = ReplaceStr(tmp, "#NUM#", std::to_string(j + 1));
ret += tmp;
}
return ret;
}
std::string IpcGeneratorImpl::GenSource()
{
std::string source_str = BASE_SOURCE_STRING;
source_str = ReplaceStr(source_str, "#HEAD_FILE_NAME#", headFileName_);
for (int i = 0; i < serviceCount_; i++) {
std::string server_class_name = serviceList_[i].serviceName_ + "Server";
source_str = ReplaceStr(source_str, "#SERVICE_CLASS_NAME#", server_class_name);
source_str = ReplaceStr(source_str, "#SERVICE_NAME#", serviceList_[i].serviceName_);
std::string client_class_name = serviceList_[i].serviceName_ + "Client";
source_str = ReplaceStr(source_str, "#CLIENT_CLASS_NAME#", client_class_name);
source_str = ReplaceStr(source_str, "#RESPONSE_IMPLEMENT#", GenSendResponseImpl(i, server_class_name));
source_str = ReplaceStr(source_str, "#CLIENT_SEND_REQUEST_PROC_FUNC#", GenOnResponseImpl(i, client_class_name));
source_str = ReplaceStr(source_str, "#SERVICE_PROTOCOL_PROC_FUNC#", GenServiceCallImpl(i, server_class_name));
source_str = ReplaceStr(source_str, "#SERVICE_PROTOCOL_PROC#", GenClientProcImpl(i));
source_str = ReplaceStr(source_str, "#SERVICE_NAME#", serviceList_[i].serviceName_);
source_str = ReplaceStr(source_str, "#CLIENT_PROTOCOL_PROC#", GenServiceProcImpl(i));
source_str =
ReplaceStr(source_str, "#CLIENT_SEND_PROTOCOL_PROC_FUNC#", GenClientRequestImpl(i, client_class_name));
}
source_str = ReplaceStr(source_str, "\t", " ");
return source_str;
}

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ipc_generator.h"
#include <iostream>
int main(int argc, char* argv[])
{
IpcGenerator generator;
return google::protobuf::compiler::PluginMain(argc, argv, &generator);
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "service_entry.h"
#include "logging.h"
#include "service_base.h"
#include "unix_socket_server.h"
ServiceEntry::ServiceEntry()
{
unixSocketServer_ = nullptr;
}
ServiceEntry::~ServiceEntry() {}
bool ServiceEntry::StartServer(const std::string& addrname)
{
CHECK_TRUE(unixSocketServer_ == nullptr, false, "Servier Already Started");
auto server = std::make_shared<UnixSocketServer>();
CHECK_TRUE(server->StartServer(addrname, *this), false, "StartServer FAIL");
unixSocketServer_ = server;
return true;
}
bool ServiceEntry::RegisterService(ServiceBase& psb)
{
CHECK_TRUE(serviceMap_.find(psb.serviceName_) == serviceMap_.end(), false, "RegisterService FAIL");
serviceMap_[psb.serviceName_] = &psb;
return true;
}
const ServiceBase* ServiceEntry::FindServiceByName(const std::string& service_name)
{
CHECK_TRUE(serviceMap_.find(service_name) != serviceMap_.end(), nullptr, "FindServiceByName FAIL %s",
service_name.c_str());
return serviceMap_[service_name];
}
namespace {
const int MS_PER_S = 1000;
const int US_PER_S = 1000000;
const int NS_PER_US = 1000;
const int NS_PER_S = 1000000000;
const int NS_PER_MS = 1000000;
} // namespace
uint64_t GetTimeMS()
{
struct timespec ts;
clock_gettime(CLOCK_BOOTTIME, &ts);
return ts.tv_sec * MS_PER_S + ts.tv_nsec / NS_PER_MS;
}
uint64_t GetTimeUS()
{
struct timespec ts;
clock_gettime(CLOCK_BOOTTIME, &ts);
return ts.tv_sec * US_PER_S + ts.tv_nsec / NS_PER_US;
}
uint64_t GetTimeNS()
{
struct timespec ts;
clock_gettime(CLOCK_BOOTTIME, &ts);
return ts.tv_sec * NS_PER_S + ts.tv_nsec;
}

View File

@ -0,0 +1,214 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "socket_context.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
#include "logging.h"
#include "securec.h"
#include "service_base.h"
#include "service_entry.h"
namespace {
const int PROTO_SIZE_MAX = 1024 * 1024;
const int MEMORY_BLOCK_UNIT = 4096;
} // namespace
SocketContext::SocketContext()
{
socketHandle_ = -1;
clientState_ = CLIENT_STAT_WORKING;
lastProcMS_ = 0;
serviceBase_ = nullptr;
}
SocketContext::~SocketContext()
{
if (socketHandle_ >= 0) {
close(socketHandle_);
socketHandle_ = -1;
}
if (recvThread_.joinable()) {
recvThread_.join();
}
}
int SocketContext::RawProtocolProc(uint32_t pnum, const int8_t* buf, const uint32_t size)
{
return -1;
}
bool ReceiveData(int sock, uint8_t* databuf, uint32_t size)
{
uint32_t p = 0;
if (sock < 0) {
return false;
}
while (p < size) {
int ret = recv(sock, &databuf[p], size - p, 0);
if (ret <= 0) {
if (ret == -1 && errno == EAGAIN) {
continue;
}
return false;
}
p += ret;
}
return true;
}
void* SocketContext::UnixSocketRecv(void* pp)
{
pthread_setname_np(pthread_self(), "UnixSocketRecv");
uint32_t bufferSize = MEMORY_BLOCK_UNIT;
SocketContext* pssr = (SocketContext*)pp;
std::vector<unsigned char> buf(bufferSize);
struct ProtocolHead* pph = (struct ProtocolHead*)buf.data();
uint32_t head_size = sizeof(struct ProtocolHead);
CHECK_TRUE(pssr->socketHandle_ != -1, nullptr, "UnixSocketRecv pssr->socketHandle_ ==-1");
struct timeval timeout = {1, 0};
CHECK_TRUE(setsockopt(pssr->socketHandle_, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == 0, nullptr,
"setsockopt %s", strerror(errno));
while (pssr->socketHandle_ >= 0) {
if (!ReceiveData(pssr->socketHandle_, buf.data(), head_size)) {
HILOG_DEBUG(LOG_CORE, "====== IPC LOST CONNECT ======");
break;
}
if (pph->protoSize > bufferSize) {
if (pph->protoSize > PROTO_SIZE_MAX) {
HILOG_ERROR(LOG_CORE, "buffer size out of range %d/%d", pph->protoSize, PROTO_SIZE_MAX);
break;
}
bufferSize = (pph->protoSize / MEMORY_BLOCK_UNIT + 1) * MEMORY_BLOCK_UNIT;
buf.resize(bufferSize);
pph = (struct ProtocolHead*)buf.data();
}
if (!ReceiveData(pssr->socketHandle_, buf.data() + head_size, pph->protoSize - head_size)) {
HILOG_DEBUG(LOG_CORE, "====== IPC LOST CONNECT ======");
break;
}
switch (pph->protoType & PROTOCOL_TYPE_FILTER) {
case PROTOCOL_TYPE_RAW:
pssr->RawProtocolProc(pph->protoType & (~PROTOCOL_TYPE_FILTER), pph->datas, pph->protoSize - head_size);
break;
case PROTOCOL_TYPE_PROTOBUF:
if (pssr->serviceBase_ != nullptr) {
pssr->serviceBase_->ProtocolProc(*pssr, pph->protoType & (~PROTOCOL_TYPE_FILTER), pph->datas,
pph->protoSize - head_size);
}
break;
default:
HILOG_ERROR(LOG_CORE, "unknown protocol %d", pph->protoType);
break;
}
}
pssr->clientState_ = CLIENT_STAT_THREAD_EXITED;
return nullptr;
}
bool SocketContext::CreateRecvThread()
{
recvThread_ = std::thread(&SocketContext::UnixSocketRecv, this);
CHECK_TRUE(recvThread_.get_id() != std::thread::id(), false, "CreateRecvThread FAIL");
return true;
}
bool SocketContext::SendRaw(uint32_t pnum, const int8_t* data, uint32_t size, int sockfd)
{
if (data == nullptr) {
return false;
}
if (sockfd == -1) {
sockfd = socketHandle_;
}
struct ProtocolHead phead;
phead.protoType = PROTOCOL_TYPE_RAW | pnum;
phead.protoSize = size + sizeof(struct ProtocolHead);
CHECK_TRUE(send(sockfd, reinterpret_cast<int8_t*>(&phead), sizeof(struct ProtocolHead), 0) != -1, false,
"SendRaw Send Head ERR :%s", strerror(errno));
CHECK_TRUE(send(sockfd, data, size, 0) != -1, false, "SendRaw Send Data ERR : %s", strerror(errno));
return true;
}
bool SocketContext::SendProtobuf(uint32_t pnum, google::protobuf::Message& pmsg)
{
int size = pmsg.ByteSizeLong();
int8_t* data = reinterpret_cast<int8_t*>(malloc(size));
if (data == nullptr) {
return false;
}
pmsg.SerializeToArray(data, size);
struct ProtocolHead phead;
phead.protoType = PROTOCOL_TYPE_PROTOBUF | pnum;
phead.protoSize = size + sizeof(struct ProtocolHead);
send(socketHandle_, reinterpret_cast<int8_t*>(&phead), sizeof(struct ProtocolHead), 0);
send(socketHandle_, data, size, 0);
free(data);
return true;
}
bool SocketContext::SendFileDescriptor(int fd)
{
struct msghdr msg = {0};
struct cmsghdr* cmsg = nullptr;
char buf[CMSG_SPACE(1 * sizeof(int))], data;
if (memset_s(buf, sizeof(buf), 0, sizeof(buf)) != EOK) {
HILOG_ERROR(LOG_CORE, "memset_s error!");
}
struct iovec io = {.iov_base = &data, .iov_len = 1};
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int) * 1);
if (memcpy_s(CMSG_DATA(cmsg), 1 * sizeof(int), &fd, 1 * sizeof(int)) != EOK) {
HILOG_ERROR(LOG_CORE, "memcpy_s error");
}
CHECK_TRUE(sendmsg(socketHandle_, &msg, 0) != -1, false, "SendFileDescriptor FAIL");
return true;
}
int SocketContext::ReceiveFileDiscriptor()
{
struct msghdr msg = {0};
struct cmsghdr* cmsg = nullptr;
char buf[CMSG_SPACE(1 * sizeof(int))], data;
struct iovec io = {.iov_base = &data, .iov_len = 1};
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
CHECK_TRUE(recvmsg(socketHandle_, &msg, 0) != -1, -1, "ReceiveFileDiscriptor FAIL");
cmsg = CMSG_FIRSTHDR(&msg);
return cmsg ? *(int*)CMSG_DATA(cmsg) : -1;
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "unix_socket_client.h"
#include <cstdio>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "logging.h"
#include "securec.h"
#include "service_base.h"
UnixSocketClient::UnixSocketClient()
{
serviceBase_ = nullptr;
socketHandle_ = -1;
}
UnixSocketClient::~UnixSocketClient() {}
bool UnixSocketClient::Connect(const std::string addrname, ServiceBase& serviceBase)
{
CHECK_TRUE(socketHandle_ == -1, false, "socketHandle_ != -1 Already Connected");
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
CHECK_TRUE(sock != -1, false, "Unix Socket Create FAIL");
struct sockaddr_un addr;
if (memset_s(&addr, sizeof(struct sockaddr_un), 0, sizeof(struct sockaddr_un)) != EOK) {
HILOG_ERROR(LOG_CORE, "memset_s error!");
}
addr.sun_family = AF_UNIX;
if (strncpy_s(addr.sun_path, UNIX_PATH_MAX, addrname.c_str(), sizeof(addr.sun_path) - 1) != EOK) {
HILOG_ERROR(LOG_CORE, "strncpy_s error!");
}
CHECK_TRUE(connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)) != -1, close(sock) != 0,
"Unix Socket Connect FAIL");
serviceBase_ = &serviceBase;
struct RawPointToService rrs;
if (strncpy_s(rrs.serviceName_, sizeof(rrs.serviceName_),
serviceBase_->serviceName_.c_str(), serviceBase_->serviceName_.size()) != EOK) {
HILOG_ERROR(LOG_CORE, "strncpy_s error!");
}
rrs.serviceName_[serviceBase_->serviceName_.size()] = 0;
CHECK_TRUE(
SendRaw(RAW_PROTOCOL_POINTTO_SERVICE, reinterpret_cast<int8_t*>(&rrs), sizeof(struct RawPointToService), sock),
close(sock) != 0, "Unix Socket SendRaw FAIL");
CHECK_TRUE(CreateRecvThread(), close(sock) != 0, "Unix Socket Create Recv Thread FAIL");
socketHandle_ = sock;
return true;
}

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "unix_socket_server.h"
#include <cstdio>
#include <pthread.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "client_map.h"
#include "logging.h"
#include "securec.h"
UnixSocketServer::UnixSocketServer()
{
sAddrName_ = "";
socketHandle_ = -1;
serviceEntry_ = nullptr;
}
UnixSocketServer::~UnixSocketServer()
{
if (socketHandle_ != 1) {
close(socketHandle_);
socketHandle_ = -1;
unlink(sAddrName_.c_str());
}
if (acceptThread_.joinable()) {
acceptThread_.join();
}
}
void* UnixSocketServer::UnixSocketAccept(void* p)
{
if (p == nullptr) {
return nullptr;
}
pthread_setname_np(pthread_self(), "UnixSocketAccept");
UnixSocketServer* puss = (UnixSocketServer*)p;
if (puss == nullptr) {
return nullptr;
}
CHECK_TRUE(puss->socketHandle_ != -1, nullptr, "Unix Socket Accept socketHandle_ == -1");
int epfd = epoll_create(1);
struct epoll_event evt;
evt.data.fd = puss->socketHandle_;
evt.events = EPOLLIN | EPOLLET;
CHECK_TRUE(epoll_ctl(epfd, EPOLL_CTL_ADD, puss->socketHandle_, &evt) != -1, nullptr, "Unix Socket Server Exit");
int nfds;
while (puss->socketHandle_ != -1) {
nfds = epoll_wait(epfd, &evt, 1, 1000); // timeout value set 1000.
if (nfds > 0) {
int clientSocket = accept(puss->socketHandle_, nullptr, nullptr);
HILOG_INFO(LOG_CORE, "Accept A Client %d", clientSocket);
ClientMap::GetInstance().PutClientSocket(clientSocket, *puss->serviceEntry_);
}
}
close(epfd);
return nullptr;
}
namespace {
const int UNIX_SOCKET_LISTEN_COUNT = 5;
}
bool UnixSocketServer::StartServer(const std::string& addrname, ServiceEntry& p)
{
CHECK_TRUE(socketHandle_ == -1, false, "StartServer FAIL socketHandle_ != -1");
struct sockaddr_un addr;
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
CHECK_TRUE(sock != -1, false, "StartServer FAIL create socket ERR : %s", strerror(errno));
if (memset_s(&addr, sizeof(struct sockaddr_un), 0, sizeof(struct sockaddr_un)) != EOK) {
HILOG_ERROR(LOG_CORE, "memset_s error!");
}
addr.sun_family = AF_UNIX;
if (strncpy_s(addr.sun_path, UNIX_PATH_MAX, addrname.c_str(), sizeof(addr.sun_path) - 1) != EOK) {
HILOG_ERROR(LOG_CORE, "strncpy_s error!");
}
unlink(addrname.c_str());
CHECK_TRUE(bind(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)) == 0, close(sock) != 0,
"StartServer FAIL bind ERR : %s", strerror(errno));
CHECK_TRUE(listen(sock, UNIX_SOCKET_LISTEN_COUNT) != -1, close(sock) != 0 && unlink(addrname.c_str()) == 0,
"StartServer FAIL listen ERR : %s", strerror(errno));
socketHandle_ = sock;
acceptThread_ = std::thread(&UnixSocketServer::UnixSocketAccept, this);
if (acceptThread_.get_id() == std::thread::id()) {
close(socketHandle_);
unlink(addrname.c_str());
HILOG_ERROR(LOG_CORE, "StartServer FAIL pthread_create ERR : %s", strerror(errno));
socketHandle_ = -1;
return false;
}
serviceEntry_ = &p;
sAddrName_ = addrname;
return true;
}

Some files were not shown because too many files have changed in this diff Show More