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