1 /*
2 * Copyright (c) 2023 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 "common_utils.h"
17
18 #include <cinttypes>
19 #include <unistd.h>
20 #include <cstdio>
21 #include <fstream>
22 #include <fcntl.h>
23 #include "cJSON.h"
24 #include "securec.h"
25
26 namespace OHOS {
27 namespace HiviewDFX {
28 namespace Hitrace {
29
CanonicalizeSpecPath(const char * src)30 std::string CanonicalizeSpecPath(const char* src)
31 {
32 if (src == nullptr || strlen(src) >= PATH_MAX) {
33 HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: %{pubilc}s failed.", src);
34 return "";
35 }
36 char resolvedPath[PATH_MAX] = { 0 };
37
38 if (access(src, F_OK) == 0) {
39 if (realpath(src, resolvedPath) == nullptr) {
40 HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: realpath %{pubilc}s failed.", src);
41 return "";
42 }
43 } else {
44 std::string fileName(src);
45 if (fileName.find("..") == std::string::npos) {
46 if (sprintf_s(resolvedPath, PATH_MAX, "%s", src) == -1) {
47 HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: sprintf_s %{pubilc}s failed.", src);
48 return "";
49 }
50 } else {
51 HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: find .. src failed.");
52 return "";
53 }
54 }
55
56 std::string res(resolvedPath);
57 return res;
58 }
59
MarkClockSync(const std::string & traceRootPath)60 bool MarkClockSync(const std::string& traceRootPath)
61 {
62 constexpr unsigned int bufferSize = 128;
63 char buffer[bufferSize] = { 0 };
64 std::string traceMarker = "trace_marker";
65 std::string resolvedPath = CanonicalizeSpecPath((traceRootPath + traceMarker).c_str());
66 int fd = open(resolvedPath.c_str(), O_WRONLY);
67 if (fd == -1) {
68 HILOG_ERROR(LOG_CORE, "MarkClockSync: oepn %{public}s fail, errno(%{public}d)", resolvedPath.c_str(), errno);
69 return false;
70 }
71
72 // write realtime_ts
73 struct timespec rts = {0, 0};
74 if (clock_gettime(CLOCK_REALTIME, &rts) == -1) {
75 HILOG_ERROR(LOG_CORE, "MarkClockSync: get realtime error, errno(%{public}d)", errno);
76 close(fd);
77 return false;
78 }
79 constexpr unsigned int nanoSeconds = 1000000000; // seconds converted to nanoseconds
80 constexpr unsigned int nanoToMill = 1000000; // millisecond converted to nanoseconds
81 int len = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1,
82 "trace_event_clock_sync: realtime_ts=%" PRId64 "\n",
83 static_cast<int64_t>((rts.tv_sec * nanoSeconds + rts.tv_nsec) / nanoToMill));
84 if (len < 0) {
85 HILOG_ERROR(LOG_CORE, "MarkClockSync: entering realtime_ts into buffer error, errno(%{public}d)", errno);
86 close(fd);
87 return false;
88 }
89
90 if (write(fd, buffer, len) < 0) {
91 HILOG_ERROR(LOG_CORE, "MarkClockSync: writing realtime error, errno(%{public}d)", errno);
92 }
93
94 // write parent_ts
95 struct timespec mts = {0, 0};
96 if (clock_gettime(CLOCK_MONOTONIC, &mts) == -1) {
97 HILOG_ERROR(LOG_CORE, "MarkClockSync: get parent_ts error, errno(%{public}d)", errno);
98 close(fd);
99 return false;
100 }
101 constexpr float nanoToSecond = 1000000000.0f; // consistent with the ftrace timestamp format
102 len = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "trace_event_clock_sync: parent_ts=%f\n",
103 static_cast<float>(((static_cast<float>(mts.tv_sec)) * nanoSeconds + mts.tv_nsec) / nanoToSecond));
104 if (len < 0) {
105 HILOG_ERROR(LOG_CORE, "MarkClockSync: entering parent_ts into buffer error, errno(%{public}d)", errno);
106 close(fd);
107 return false;
108 }
109 if (write(fd, buffer, len) < 0) {
110 HILOG_ERROR(LOG_CORE, "MarkClockSync: writing parent_ts error, errno(%{public}d)", errno);
111 }
112 close(fd);
113 return true;
114 }
115
ParseJsonFromFile(const std::string & filePath)116 static cJSON* ParseJsonFromFile(const std::string& filePath)
117 {
118 std::ifstream inFile(filePath, std::ios::in);
119 if (!inFile.is_open()) {
120 HILOG_ERROR(LOG_CORE, "ParseJsonFromFile: %{public}s is not existed.", filePath.c_str());
121 return nullptr;
122 }
123 std::string fileContent((std::istreambuf_iterator<char>(inFile)), std::istreambuf_iterator<char>());
124 cJSON* root = cJSON_Parse(fileContent.c_str());
125 if (root == nullptr) {
126 HILOG_ERROR(LOG_CORE, "ParseJsonFromFile: %{public}s is not in JSON format.", filePath.c_str());
127 }
128 inFile.close();
129 return root;
130 }
131
ParseSysFiles(cJSON * tags,TagCategory & tagCategory)132 static void ParseSysFiles(cJSON *tags, TagCategory& tagCategory)
133 {
134 cJSON *sysFiles = cJSON_GetObjectItem(tags, "sysFiles");
135 if (sysFiles != nullptr && cJSON_IsArray(sysFiles)) {
136 cJSON *sysFile = nullptr;
137 cJSON_ArrayForEach(sysFile, sysFiles) {
138 if (cJSON_IsString(sysFile)) {
139 tagCategory.sysFiles.push_back(sysFile->valuestring);
140 }
141 }
142 }
143 }
144
ParseTagCategory(cJSON * tagCategoryNode,std::map<std::string,TagCategory> & allTags)145 static bool ParseTagCategory(cJSON* tagCategoryNode, std::map<std::string, TagCategory>& allTags)
146 {
147 cJSON* tags = nullptr;
148 cJSON_ArrayForEach(tags, tagCategoryNode) {
149 if (tags == nullptr || tags->string == nullptr) {
150 continue;
151 }
152 TagCategory tagCategory;
153 cJSON* description = cJSON_GetObjectItem(tags, "description");
154 if (description != nullptr && cJSON_IsString(description)) {
155 tagCategory.description = description->valuestring;
156 }
157 cJSON* tagOffset = cJSON_GetObjectItem(tags, "tag_offset");
158 if (tagOffset != nullptr && cJSON_IsNumber(tagOffset)) {
159 tagCategory.tag = 1ULL << tagOffset->valueint;
160 }
161 cJSON* type = cJSON_GetObjectItem(tags, "type");
162 if (type != nullptr && cJSON_IsNumber(type)) {
163 tagCategory.type = type->valueint;
164 }
165 ParseSysFiles(tags, tagCategory);
166 allTags.insert(std::pair<std::string, TagCategory>(tags->string, tagCategory));
167 }
168 return true;
169 }
170
ParseTagGroups(cJSON * tagGroupsNode,std::map<std::string,std::vector<std::string>> & tagGroupTable)171 static bool ParseTagGroups(cJSON* tagGroupsNode, std::map<std::string, std::vector<std::string>> &tagGroupTable)
172 {
173 cJSON* tagGroup = nullptr;
174 cJSON_ArrayForEach(tagGroup, tagGroupsNode) {
175 if (tagGroup == nullptr || tagGroup->string == nullptr) {
176 continue;
177 }
178 std::string tagGroupName = tagGroup->string;
179 std::vector<std::string> tagList;
180 cJSON* tag = nullptr;
181 cJSON_ArrayForEach(tag, tagGroup) {
182 if (cJSON_IsString(tag)) {
183 tagList.push_back(tag->valuestring);
184 }
185 }
186 tagGroupTable.insert(std::pair<std::string, std::vector<std::string>>(tagGroupName, tagList));
187 }
188 return true;
189 }
190
ParseTagInfo(std::map<std::string,TagCategory> & allTags,std::map<std::string,std::vector<std::string>> & tagGroupTable)191 bool ParseTagInfo(std::map<std::string, TagCategory> &allTags,
192 std::map<std::string, std::vector<std::string>> &tagGroupTable)
193 {
194 std::string traceUtilsPath = "/system/etc/hiview/hitrace_utils.json";
195 cJSON* root = ParseJsonFromFile(traceUtilsPath);
196 if (root == nullptr) {
197 return false;
198 }
199 cJSON* tagCategory = cJSON_GetObjectItem(root, "tag_category");
200 if (tagCategory == nullptr) {
201 HILOG_ERROR(LOG_CORE, "ParseTagInfo: %{public}s is not contain tag_category node.", traceUtilsPath.c_str());
202 cJSON_Delete(root);
203 return false;
204 }
205 if (!ParseTagCategory(tagCategory, allTags)) {
206 cJSON_Delete(root);
207 return false;
208 }
209 cJSON* tagGroups = cJSON_GetObjectItem(root, "tag_groups");
210 if (tagGroups == nullptr) {
211 HILOG_ERROR(LOG_CORE, "ParseTagInfo: %{public}s is not contain tag_groups node.", traceUtilsPath.c_str());
212 cJSON_Delete(root);
213 return false;
214 }
215 if (!ParseTagGroups(tagGroups, tagGroupTable)) {
216 cJSON_Delete(root);
217 return false;
218 }
219 cJSON_Delete(root);
220 HILOG_INFO(LOG_CORE, "ParseTagInfo: parse done.");
221 return true;
222 }
223
IsNumber(const std::string & str)224 bool IsNumber(const std::string &str)
225 {
226 if (str.empty()) {
227 return false;
228 }
229 for (auto c : str) {
230 if (!isdigit(c)) {
231 return false;
232 }
233 }
234 return true;
235 }
236 } // Hitrace
237 } // HiviewDFX
238 } // OHOS
239