1 /*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "trace_json_parser.h"
17
18 #include <cinttypes>
19 #include <unistd.h>
20 #include <cstdio>
21 #include <fstream>
22 #include <fcntl.h>
23 #include <sstream>
24
25 #include "common_define.h"
26 #include "cJSON.h"
27 #include "hilog/log.h"
28
29 namespace OHOS {
30 namespace HiviewDFX {
31 namespace Hitrace {
32 #ifdef LOG_DOMAIN
33 #undef LOG_DOMAIN
34 #define LOG_DOMAIN 0xD002D33
35 #endif
36 #ifdef LOG_TAG
37 #undef LOG_TAG
38 #define LOG_TAG "HitraceUtils"
39 #endif
40 namespace {
41 const std::string HTIRACE_TAG_CONFIG_FILE = "/system/etc/hiview/hitrace_utils.json";
42
ParseEnablePath(cJSON * tagNode,TraceTag & tag)43 void ParseEnablePath(cJSON *tagNode, TraceTag& tag)
44 {
45 cJSON *enablePathNode = cJSON_GetObjectItem(tagNode, "enable_path");
46 if (enablePathNode != nullptr && cJSON_IsArray(enablePathNode)) {
47 cJSON *pathItem = nullptr;
48 cJSON_ArrayForEach(pathItem, enablePathNode) {
49 if (cJSON_IsString(pathItem)) {
50 tag.enablePath.push_back(pathItem->valuestring);
51 }
52 }
53 }
54 }
55
ParseFormatPath(cJSON * tagNode,TraceTag & tag)56 void ParseFormatPath(cJSON *tagNode, TraceTag& tag)
57 {
58 cJSON *formatPathNode = cJSON_GetObjectItem(tagNode, "format_path");
59 if (formatPathNode != nullptr && cJSON_IsArray(formatPathNode)) {
60 cJSON *pathItem = nullptr;
61 cJSON_ArrayForEach(pathItem, formatPathNode) {
62 if (cJSON_IsString(pathItem)) {
63 tag.formatPath.push_back(pathItem->valuestring);
64 }
65 }
66 }
67 }
68
ParseJsonFromFile(const std::string & filePath)69 cJSON* ParseJsonFromFile(const std::string& filePath)
70 {
71 std::ifstream inFile(filePath, std::ios::in);
72 if (!inFile.is_open()) {
73 HILOG_ERROR(LOG_CORE, "ParseJsonFromFile: %{public}s is not existed.", filePath.c_str());
74 return nullptr;
75 }
76 std::string fileContent((std::istreambuf_iterator<char>(inFile)), std::istreambuf_iterator<char>());
77 cJSON* rootNode = cJSON_Parse(fileContent.c_str());
78 if (rootNode == nullptr) {
79 HILOG_ERROR(LOG_CORE, "ParseJsonFromFile: %{public}s is not in JSON format.", filePath.c_str());
80 }
81 inFile.close();
82 return rootNode;
83 }
84
ParseTagCategory(cJSON * jsonNode,bool parseEnable,bool parseFmt,std::map<std::string,TraceTag> & tagInfos)85 bool ParseTagCategory(cJSON* jsonNode, bool parseEnable, bool parseFmt, std::map<std::string, TraceTag>& tagInfos)
86 {
87 cJSON* tagCategoryNode = cJSON_GetObjectItem(jsonNode, "tag_category");
88 if (tagCategoryNode == nullptr) {
89 HILOG_ERROR(LOG_CORE, "TraceJsonParser: tag_category json node not found.");
90 return false;
91 }
92 cJSON* tagNode = nullptr;
93 cJSON_ArrayForEach(tagNode, tagCategoryNode) {
94 if (tagNode == nullptr || tagNode->string == nullptr) {
95 continue;
96 }
97 // when base info has been parsed, only try to parse particial trace infos.
98 if (tagInfos.find(tagNode->string) != tagInfos.end()) {
99 if (parseEnable) {
100 ParseEnablePath(tagNode, tagInfos[tagNode->string]);
101 }
102 if (parseFmt) {
103 ParseFormatPath(tagNode, tagInfos[tagNode->string]);
104 }
105 continue;
106 }
107 TraceTag tag;
108 cJSON* description = cJSON_GetObjectItem(tagNode, "description");
109 if (description != nullptr && cJSON_IsString(description)) {
110 tag.description = description->valuestring;
111 }
112 cJSON* tagOffset = cJSON_GetObjectItem(tagNode, "tag_offset");
113 if (tagOffset != nullptr && cJSON_IsNumber(tagOffset)) {
114 tag.tag = 1ULL << tagOffset->valueint;
115 }
116 cJSON* type = cJSON_GetObjectItem(tagNode, "type");
117 if (type != nullptr && cJSON_IsNumber(type)) {
118 tag.type = static_cast<TraceType>(type->valueint);
119 }
120 if (parseEnable) {
121 ParseEnablePath(tagNode, tag);
122 }
123 if (parseFmt) {
124 ParseFormatPath(tagNode, tag);
125 }
126 tagInfos.insert(std::pair<std::string, TraceTag>(tagNode->string, tag));
127 }
128 return true;
129 }
130
ParseBaseFormatPath(cJSON * jsonNode,std::vector<std::string> & baseTraceFormats)131 bool ParseBaseFormatPath(cJSON* jsonNode, std::vector<std::string>& baseTraceFormats)
132 {
133 cJSON* baseTraceFormatsNode = cJSON_GetObjectItem(jsonNode, "base_format_path");
134 if (baseTraceFormatsNode == nullptr) {
135 HILOG_ERROR(LOG_CORE, "ParseTraceJson: base_format_path json node not found.");
136 return false;
137 }
138 if (cJSON_IsArray(baseTraceFormatsNode)) {
139 cJSON *formatItem = nullptr;
140 cJSON_ArrayForEach(formatItem, baseTraceFormatsNode) {
141 if (cJSON_IsString(formatItem)) {
142 baseTraceFormats.push_back(formatItem->valuestring);
143 }
144 }
145 }
146 return true;
147 }
148
ParseTagGroups(cJSON * jsonNode,std::map<std::string,std::vector<std::string>> & tagGroups)149 bool ParseTagGroups(cJSON* jsonNode, std::map<std::string, std::vector<std::string>>& tagGroups)
150 {
151 cJSON* tagGroupsNode = cJSON_GetObjectItem(jsonNode, "tag_groups");
152 if (tagGroupsNode == nullptr) {
153 HILOG_ERROR(LOG_CORE, "ParseTraceJson: tag_groups json node not found.");
154 return false;
155 }
156 cJSON* tagGroupNode = nullptr;
157 cJSON_ArrayForEach(tagGroupNode, tagGroupsNode) {
158 if (tagGroupNode == nullptr || tagGroupNode->string == nullptr) {
159 continue;
160 }
161 std::string tagGroupName = tagGroupNode->string;
162 std::vector<std::string> tagList;
163 cJSON* tagNameNode = nullptr;
164 cJSON_ArrayForEach(tagNameNode, tagGroupNode) {
165 if (cJSON_IsString(tagNameNode)) {
166 tagList.push_back(tagNameNode->valuestring);
167 }
168 }
169 tagGroups.insert(std::pair<std::string, std::vector<std::string>>(tagGroupName, tagList));
170 }
171 return true;
172 }
173
ParseTraceBufSz(cJSON * jsonNode,int & bufSz)174 bool ParseTraceBufSz(cJSON* jsonNode, int& bufSz)
175 {
176 cJSON* bufSzNode = cJSON_GetObjectItem(jsonNode, "snapshot_buffer_kb");
177 if (bufSzNode == nullptr) {
178 HILOG_ERROR(LOG_CORE, "ParseTraceJson: snapshot_buffer_kb json node not found.");
179 return false;
180 }
181 if (!cJSON_IsNumber(bufSzNode)) {
182 HILOG_ERROR(LOG_CORE, "ParseTraceJson: snapshot_buffer_kb item is illegal.");
183 return false;
184 }
185 bufSz = bufSzNode->valueint;
186 return true;
187 }
188
ParseTraceFileAge(cJSON * jsonNode,const std::string & jsonLabel,bool & agingSwitcher)189 bool ParseTraceFileAge(cJSON* jsonNode, const std::string& jsonLabel, bool& agingSwitcher)
190 {
191 cJSON* agingNode = cJSON_GetObjectItem(jsonNode, jsonLabel.c_str());
192 if (agingNode == nullptr) {
193 HILOG_ERROR(LOG_CORE, "ParseTraceJson: %{public}s json node not found.", jsonLabel.c_str());
194 return false;
195 }
196 if (!cJSON_IsNumber(agingNode)) {
197 HILOG_ERROR(LOG_CORE, "ParseTraceJson: %{public}s item is illegal.", jsonLabel.c_str());
198 return false;
199 }
200 agingSwitcher = agingNode->valueint == 0 ? false : true;
201 return true;
202 }
203
UpdateParseItem(const uint8_t parseItem)204 uint8_t UpdateParseItem(const uint8_t parseItem)
205 {
206 uint8_t retParseItem = parseItem;
207 if ((parseItem & TRACE_TAG_ENABLE_INFO) > 0 || (parseItem & TRACE_TAG_FORMAT_INFO) > 0 ||
208 (parseItem & TRACE_TAG_GROUP_INFO) > 0) {
209 retParseItem |= TRACE_TAG_BASE_INFO;
210 }
211 return retParseItem;
212 }
213 }
214
ParseTraceJson(const uint8_t policy)215 bool TraceJsonParser::ParseTraceJson(const uint8_t policy)
216 {
217 if ((policy & parserState_) == policy) {
218 HILOG_INFO(LOG_CORE, "ParseTraceJson: Parser policy(%{public}d) already done.", policy);
219 return true;
220 }
221
222 uint8_t needParseItem = UpdateParseItem(policy);
223 needParseItem &= (~parserState_);
224
225 cJSON* rootNode = ParseJsonFromFile(HTIRACE_TAG_CONFIG_FILE);
226 if (rootNode == nullptr) {
227 return false;
228 }
229
230 if ((needParseItem & TRACE_SNAPSHOT_BUFSZ) > 0 && ParseTraceBufSz(rootNode, snapshotBufSzKb_)) {
231 parserState_ |= TRACE_SNAPSHOT_BUFSZ;
232 }
233 if ((needParseItem & TRACE_SNAPSHOT_FILE_AGE) > 0 &&
234 ParseTraceFileAge(rootNode, "snapshot_file_aging", snapshotFileAge_)) {
235 parserState_ |= TRACE_SNAPSHOT_FILE_AGE;
236 }
237
238 bool needParseTagEnableInfo = (needParseItem & TRACE_TAG_ENABLE_INFO) > 0;
239 bool needParseTagFmtInfo = (needParseItem & TRACE_TAG_FORMAT_INFO) > 0;
240 if ((needParseItem & TRACE_TAG_BASE_INFO) > 0 || needParseTagEnableInfo || needParseTagFmtInfo) {
241 if (ParseTagCategory(rootNode, needParseTagEnableInfo, needParseTagFmtInfo, traceTagInfos_)) {
242 parserState_ |= TRACE_TAG_BASE_INFO;
243 if (needParseTagEnableInfo) {
244 parserState_ |= TRACE_TAG_ENABLE_INFO;
245 }
246 }
247 }
248
249 if (needParseTagFmtInfo && ParseBaseFormatPath(rootNode, baseTraceFormats_)) {
250 parserState_ |= TRACE_TAG_FORMAT_INFO;
251 }
252
253 if ((needParseItem & TRACE_TAG_GROUP_INFO) > 0 && ParseTagGroups(rootNode, tagGroups_)) {
254 parserState_ |= TRACE_TAG_GROUP_INFO;
255 }
256
257 cJSON_Delete(rootNode);
258 HILOG_INFO(LOG_CORE, "ParseTraceJson: parse done, input policy(%{public}u), parser state(%{public}u)",
259 policy, parserState_);
260 return (policy & parserState_) == policy;
261 }
262 } // namespace HiTrace
263 } // namespace HiviewDFX
264 } // namespace OHOS