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
24 #include "common_define.h"
25 #include "cJSON.h"
26 #include "hilog/log.h"
27
28 #include "common_utils.h"
29
30 namespace OHOS {
31 namespace HiviewDFX {
32 namespace Hitrace {
33 #ifdef LOG_DOMAIN
34 #undef LOG_DOMAIN
35 #define LOG_DOMAIN 0xD002D33
36 #endif
37 #ifdef LOG_TAG
38 #undef LOG_TAG
39 #define LOG_TAG "HitraceUtils"
40 #endif
41 namespace {
42 static const char* HTIRACE_UTILS_JSON = "/system/etc/hiview/hitrace_utils.json";
43 static const char* PRODUCT_CONFIG_JSON = "/sys_prod/etc/hiview/hitrace/hitrace_param.json";
44
45 constexpr int DEFAULT_SNAPSHOT_BUFFER_SIZE_KB = 12 * 1024;
46 constexpr int HM_DEFAULT_SNAPSHOT_BUFFER_SIZE_KB = 144 * 1024;
47
48 constexpr uint32_t DEFAULT_RECORD_FILE_NUMBER_LIMIT = 15;
49
50 constexpr uint32_t DEFAULT_SNAPSHOT_FILE_NUMBER_LIMIT = 20;
51
GetInt64FromJson(cJSON * jsonNode,const std::string & key,int64_t & value)52 bool GetInt64FromJson(cJSON* jsonNode, const std::string& key, int64_t& value)
53 {
54 cJSON* item = cJSON_GetObjectItem(jsonNode, key.c_str());
55 if (item == nullptr) {
56 HILOG_ERROR(LOG_CORE, "GetInt64FromJson: [%{public}s] not found.", key.c_str());
57 return false;
58 }
59 if (!cJSON_IsNumber(item)) {
60 HILOG_ERROR(LOG_CORE, "GetInt64FromJson: [%{public}s] item is illegal.", key.c_str());
61 return false;
62 }
63 value = static_cast<int64_t>(item->valueint);
64 return true;
65 }
66
GetIntFromJson(cJSON * jsonNode,const std::string & key,int & value)67 bool GetIntFromJson(cJSON* jsonNode, const std::string& key, int& value)
68 {
69 cJSON* item = cJSON_GetObjectItem(jsonNode, key.c_str());
70 if (item == nullptr) {
71 HILOG_ERROR(LOG_CORE, "GetIntFromJson: [%{public}s] not found.", key.c_str());
72 return false;
73 }
74 if (!cJSON_IsNumber(item)) {
75 HILOG_ERROR(LOG_CORE, "GetIntFromJson: [%{public}s] item is illegal.", key.c_str());
76 return false;
77 }
78 value = item->valueint;
79 return true;
80 }
81
GetStringFromJsonVector(cJSON * jsonNode,const std::string & key,std::vector<std::string> & vec)82 void GetStringFromJsonVector(cJSON *jsonNode, const std::string& key, std::vector<std::string>& vec)
83 {
84 cJSON* node = cJSON_GetObjectItem(jsonNode, key.c_str());
85 if (node != nullptr && cJSON_IsArray(node)) {
86 cJSON *item = nullptr;
87 cJSON_ArrayForEach(item, node) {
88 if (cJSON_IsString(item)) {
89 vec.push_back(item->valuestring);
90 }
91 }
92 }
93 }
94
ParseJsonFromFile(const std::string & filePath)95 cJSON* ParseJsonFromFile(const std::string& filePath)
96 {
97 std::ifstream inFile(filePath, std::ios::in);
98 if (!inFile.is_open()) {
99 HILOG_ERROR(LOG_CORE, "ParseJsonFromFile: %{public}s is not existed.", filePath.c_str());
100 return nullptr;
101 }
102 std::string fileContent((std::istreambuf_iterator<char>(inFile)), std::istreambuf_iterator<char>());
103 cJSON* rootNode = cJSON_Parse(fileContent.c_str());
104 if (rootNode == nullptr) {
105 HILOG_ERROR(LOG_CORE, "ParseJsonFromFile: %{public}s is not in JSON format.", filePath.c_str());
106 }
107 inFile.close();
108 return rootNode;
109 }
110
ParseTagCategory(cJSON * jsonNode,std::map<std::string,TraceTag> & tagInfos)111 bool ParseTagCategory(cJSON* jsonNode, std::map<std::string, TraceTag>& tagInfos)
112 {
113 cJSON* tagCategoryNode = cJSON_GetObjectItem(jsonNode, "tag_category");
114 if (tagCategoryNode == nullptr) {
115 HILOG_ERROR(LOG_CORE, "TraceJsonParser: tag_category json node not found.");
116 return false;
117 }
118 cJSON* tagNode = nullptr;
119 cJSON_ArrayForEach(tagNode, tagCategoryNode) {
120 if (tagNode == nullptr || tagNode->string == nullptr) {
121 continue;
122 }
123 // when base info has been parsed, only try to parse particial trace infos.
124 if (tagInfos.find(tagNode->string) != tagInfos.end()) {
125 GetStringFromJsonVector(tagNode, "enable_path", tagInfos[tagNode->string].enablePath);
126 GetStringFromJsonVector(tagNode, "format_path", tagInfos[tagNode->string].formatPath);
127 continue;
128 }
129 TraceTag tag;
130 cJSON* description = cJSON_GetObjectItem(tagNode, "description");
131 if (description != nullptr && cJSON_IsString(description)) {
132 tag.description = description->valuestring;
133 }
134 cJSON* tagOffset = cJSON_GetObjectItem(tagNode, "tag_offset");
135 if (tagOffset != nullptr && cJSON_IsNumber(tagOffset)) {
136 tag.tag = 1ULL << tagOffset->valueint;
137 }
138 cJSON* type = cJSON_GetObjectItem(tagNode, "type");
139
140 if (type != nullptr && cJSON_IsNumber(type)) {
141 tag.type = static_cast<TraceType>(type->valueint);
142 }
143 GetStringFromJsonVector(tagNode, "enable_path", tag.enablePath);
144 GetStringFromJsonVector(tagNode, "format_path", tag.formatPath);
145 tagInfos.insert(std::pair<std::string, TraceTag>(tagNode->string, tag));
146 }
147 return true;
148 }
149
ParseTagGroups(cJSON * jsonNode,std::map<std::string,std::vector<std::string>> & tagGroups)150 bool ParseTagGroups(cJSON* jsonNode, std::map<std::string, std::vector<std::string>>& tagGroups)
151 {
152 cJSON* tagGroupsNode = cJSON_GetObjectItem(jsonNode, "tag_groups");
153 if (tagGroupsNode == nullptr) {
154 HILOG_ERROR(LOG_CORE, "ParseTraceJson: tag_groups json node not found.");
155 return false;
156 }
157 cJSON* tagGroupNode = nullptr;
158 cJSON_ArrayForEach(tagGroupNode, tagGroupsNode) {
159 if (tagGroupNode == nullptr || tagGroupNode->string == nullptr) {
160 continue;
161 }
162 std::string tagGroupName = tagGroupNode->string;
163 std::vector<std::string> tagList;
164 cJSON* tagNameNode = nullptr;
165 cJSON_ArrayForEach(tagNameNode, tagGroupNode) {
166 if (cJSON_IsString(tagNameNode)) {
167 tagList.push_back(tagNameNode->valuestring);
168 }
169 }
170 tagGroups.insert(std::pair<std::string, std::vector<std::string>>(tagGroupName, tagList));
171 }
172 return true;
173 }
174 }
175
Instance()176 TraceJsonParser& TraceJsonParser::Instance()
177 {
178 static TraceJsonParser parser(HTIRACE_UTILS_JSON, PRODUCT_CONFIG_JSON);
179 return parser;
180 }
181
TraceJsonParser(const std::string & hitraceUtilsJson,const std::string & productConfigJson)182 TraceJsonParser::TraceJsonParser(const std::string& hitraceUtilsJson, const std::string& productConfigJson)
183 {
184 InitSnapshotDefaultBufferSize();
185 InitAgeingParam();
186
187 ParseHitraceUtilsJson(hitraceUtilsJson);
188 ParseProductConfigJson(productConfigJson);
189
190 PrintParseResult();
191 }
192
ParseHitraceUtilsJson(const std::string & hitraceUtilsJson)193 void TraceJsonParser::ParseHitraceUtilsJson(const std::string& hitraceUtilsJson)
194 {
195 cJSON* hitraceUtilsJsonRoot = ParseJsonFromFile(hitraceUtilsJson);
196 if (hitraceUtilsJsonRoot == nullptr) {
197 HILOG_ERROR(LOG_CORE, "ParseTraceJson: open %{public}s fail", hitraceUtilsJson.c_str());
198 } else {
199 ParseTagCategory(hitraceUtilsJsonRoot, traceTagInfos_);
200 GetStringFromJsonVector(hitraceUtilsJsonRoot, "base_format_path", baseTraceFormats_);
201 ParseTagGroups(hitraceUtilsJsonRoot, tagGroups_);
202
203 int value = 0;
204 if (GetIntFromJson(hitraceUtilsJsonRoot, "snapshot_file_aging", value)) {
205 snapShotAgeingParam_.rootEnable = (value != 0);
206 }
207 if (GetIntFromJson(hitraceUtilsJsonRoot, "record_file_aging", value)) {
208 recordAgeingParam_.rootEnable = (value != 0);
209 }
210 if (GetIntFromJson(hitraceUtilsJsonRoot, "snapshot_buffer_kb", value) && value != 0) {
211 snapshotBufSzKb_ = value;
212 }
213 }
214 cJSON_Delete(hitraceUtilsJsonRoot);
215 }
216
ParseProductConfigJson(const std::string & productConfigJson)217 void TraceJsonParser::ParseProductConfigJson(const std::string& productConfigJson)
218 {
219 cJSON* productConfigJsonRoot = ParseJsonFromFile(productConfigJson);
220 if (productConfigJsonRoot == nullptr) {
221 HILOG_DEBUG(LOG_CORE, "ParseTraceJson: open %{public}s fail", productConfigJson.c_str());
222 } else {
223 GetInt64FromJson(productConfigJsonRoot, "record_file_kb_size", recordAgeingParam_.fileSizeKbLimit);
224 GetInt64FromJson(productConfigJsonRoot, "snapshot_file_kb_size", snapShotAgeingParam_.fileSizeKbLimit);
225 GetIntFromJson(productConfigJsonRoot, "default_buffer_kb_size", snapshotBufSzKb_);
226
227 int tRootAgeingEnable = -1;
228 if (GetIntFromJson(productConfigJsonRoot, "root_ageing_enable", tRootAgeingEnable)) {
229 bool enable = (tRootAgeingEnable != 0);
230 snapShotAgeingParam_.rootEnable = enable;
231 recordAgeingParam_.rootEnable = enable;
232 }
233 }
234
235 cJSON_Delete(productConfigJsonRoot);
236 }
237
GetAgeingParam(TraceDumpType type) const238 const AgeingParam& TraceJsonParser::GetAgeingParam(TraceDumpType type) const
239 {
240 if (type == TraceDumpType::TRACE_RECORDING) {
241 return recordAgeingParam_;
242 }
243 if (type == TraceDumpType::TRACE_SNAPSHOT) {
244 return snapShotAgeingParam_;
245 }
246
247 static AgeingParam defaultParam;
248 return defaultParam;
249 }
250
InitSnapshotDefaultBufferSize()251 void TraceJsonParser::InitSnapshotDefaultBufferSize()
252 {
253 snapshotBufSzKb_ = DEFAULT_SNAPSHOT_BUFFER_SIZE_KB;
254
255 if (IsHmKernel()) {
256 snapshotBufSzKb_ = HM_DEFAULT_SNAPSHOT_BUFFER_SIZE_KB;
257 }
258
259 #if defined(SNAPSHOT_TRACEBUFFER_SIZE) && (SNAPSHOT_TRACEBUFFER_SIZE != 0)
260 snapshotBufSzKb_ = SNAPSHOT_TRACEBUFFER_SIZE;
261 #endif
262 }
263
InitAgeingParam()264 void TraceJsonParser::InitAgeingParam()
265 {
266 // record file number limit
267 recordAgeingParam_.fileNumberLimit = DEFAULT_RECORD_FILE_NUMBER_LIMIT;
268 #if defined(RECORD_FILE_LIMIT) && (RECORD_FILE_LIMIT != 0)
269 recordAgeingParam_.fileNumberLimit = RECORD_FILE_LIMIT;
270 #endif
271
272 // snapshot file number limit
273 snapShotAgeingParam_.fileNumberLimit = DEFAULT_SNAPSHOT_FILE_NUMBER_LIMIT;
274 #if defined(SNAPSHOT_FILE_LIMIT) && (SNAPSHOT_FILE_LIMIT != 0)
275 snapShotAgeingParam_.fileNumberLimit = SNAPSHOT_FILE_LIMIT;
276 #endif
277 }
278
PrintParseResult()279 void TraceJsonParser::PrintParseResult()
280 {
281 HILOG_INFO(LOG_CORE, "PrintParseResult snap:[%{public}d %{public}" PRId64" %{public}" PRId64 "] "
282 "reco:[%{public}d %{public}" PRId64 " %{public}" PRId64 "] bufsz:[%{public}d]",
283 snapShotAgeingParam_.rootEnable, snapShotAgeingParam_.fileNumberLimit, snapShotAgeingParam_.fileSizeKbLimit,
284 recordAgeingParam_.rootEnable, recordAgeingParam_.fileNumberLimit, recordAgeingParam_.fileSizeKbLimit,
285 snapshotBufSzKb_);
286 }
287
288 } // namespace HiTrace
289 } // namespace HiviewDFX
290 } // namespace OHOS