1b0e7dd80Sopenharmony_ci/*
2b0e7dd80Sopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3b0e7dd80Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4b0e7dd80Sopenharmony_ci * you may not use this file except in compliance with the License.
5b0e7dd80Sopenharmony_ci * You may obtain a copy of the License at
6b0e7dd80Sopenharmony_ci *
7b0e7dd80Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8b0e7dd80Sopenharmony_ci *
9b0e7dd80Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10b0e7dd80Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11b0e7dd80Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12b0e7dd80Sopenharmony_ci * See the License for the specific language governing permissions and
13b0e7dd80Sopenharmony_ci * limitations under the License.
14b0e7dd80Sopenharmony_ci */
15b0e7dd80Sopenharmony_ci
16b0e7dd80Sopenharmony_ci#include "common_utils.h"
17b0e7dd80Sopenharmony_ci
18b0e7dd80Sopenharmony_ci#include <cinttypes>
19b0e7dd80Sopenharmony_ci#include <unistd.h>
20b0e7dd80Sopenharmony_ci#include <cstdio>
21b0e7dd80Sopenharmony_ci#include <fstream>
22b0e7dd80Sopenharmony_ci#include <fcntl.h>
23b0e7dd80Sopenharmony_ci#include <sstream>
24b0e7dd80Sopenharmony_ci#include "cJSON.h"
25b0e7dd80Sopenharmony_ci#include "securec.h"
26b0e7dd80Sopenharmony_ci
27b0e7dd80Sopenharmony_cinamespace OHOS {
28b0e7dd80Sopenharmony_cinamespace HiviewDFX {
29b0e7dd80Sopenharmony_cinamespace Hitrace {
30b0e7dd80Sopenharmony_cinamespace {
31b0e7dd80Sopenharmony_ciconst std::string CPUFREQ_PREFIX = "/sys/devices/system/cpu/cpu";
32b0e7dd80Sopenharmony_ciconst std::string CPUFREQ_AFTERFIX = "/cpufreq/scaling_cur_freq";
33b0e7dd80Sopenharmony_ci}
34b0e7dd80Sopenharmony_ci
35b0e7dd80Sopenharmony_cistd::string CanonicalizeSpecPath(const char* src)
36b0e7dd80Sopenharmony_ci{
37b0e7dd80Sopenharmony_ci    if (src == nullptr || strlen(src) >= PATH_MAX) {
38b0e7dd80Sopenharmony_ci        HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: %{pubilc}s failed.", src);
39b0e7dd80Sopenharmony_ci        return "";
40b0e7dd80Sopenharmony_ci    }
41b0e7dd80Sopenharmony_ci    char resolvedPath[PATH_MAX] = { 0 };
42b0e7dd80Sopenharmony_ci
43b0e7dd80Sopenharmony_ci    if (access(src, F_OK) == 0) {
44b0e7dd80Sopenharmony_ci        if (realpath(src, resolvedPath) == nullptr) {
45b0e7dd80Sopenharmony_ci            HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: realpath %{pubilc}s failed.", src);
46b0e7dd80Sopenharmony_ci            return "";
47b0e7dd80Sopenharmony_ci        }
48b0e7dd80Sopenharmony_ci    } else {
49b0e7dd80Sopenharmony_ci        std::string fileName(src);
50b0e7dd80Sopenharmony_ci        if (fileName.find("..") == std::string::npos) {
51b0e7dd80Sopenharmony_ci            if (sprintf_s(resolvedPath, PATH_MAX, "%s", src) == -1) {
52b0e7dd80Sopenharmony_ci                HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: sprintf_s %{pubilc}s failed.", src);
53b0e7dd80Sopenharmony_ci                return "";
54b0e7dd80Sopenharmony_ci            }
55b0e7dd80Sopenharmony_ci        } else {
56b0e7dd80Sopenharmony_ci            HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: find .. src failed.");
57b0e7dd80Sopenharmony_ci            return "";
58b0e7dd80Sopenharmony_ci        }
59b0e7dd80Sopenharmony_ci    }
60b0e7dd80Sopenharmony_ci
61b0e7dd80Sopenharmony_ci    std::string res(resolvedPath);
62b0e7dd80Sopenharmony_ci    return res;
63b0e7dd80Sopenharmony_ci}
64b0e7dd80Sopenharmony_ci
65b0e7dd80Sopenharmony_cibool MarkClockSync(const std::string& traceRootPath)
66b0e7dd80Sopenharmony_ci{
67b0e7dd80Sopenharmony_ci    constexpr unsigned int bufferSize = 128;
68b0e7dd80Sopenharmony_ci    char buffer[bufferSize] = { 0 };
69b0e7dd80Sopenharmony_ci    std::string traceMarker = "trace_marker";
70b0e7dd80Sopenharmony_ci    std::string resolvedPath = CanonicalizeSpecPath((traceRootPath + traceMarker).c_str());
71b0e7dd80Sopenharmony_ci    int fd = open(resolvedPath.c_str(), O_WRONLY);
72b0e7dd80Sopenharmony_ci    if (fd == -1) {
73b0e7dd80Sopenharmony_ci        HILOG_ERROR(LOG_CORE, "MarkClockSync: oepn %{public}s fail, errno(%{public}d)", resolvedPath.c_str(), errno);
74b0e7dd80Sopenharmony_ci        return false;
75b0e7dd80Sopenharmony_ci    }
76b0e7dd80Sopenharmony_ci
77b0e7dd80Sopenharmony_ci    // write realtime_ts
78b0e7dd80Sopenharmony_ci    struct timespec rts = {0, 0};
79b0e7dd80Sopenharmony_ci    if (clock_gettime(CLOCK_REALTIME, &rts) == -1) {
80b0e7dd80Sopenharmony_ci        HILOG_ERROR(LOG_CORE, "MarkClockSync: get realtime error, errno(%{public}d)", errno);
81b0e7dd80Sopenharmony_ci        close(fd);
82b0e7dd80Sopenharmony_ci        return false;
83b0e7dd80Sopenharmony_ci    }
84b0e7dd80Sopenharmony_ci    constexpr unsigned int nanoSeconds = 1000000000; // seconds converted to nanoseconds
85b0e7dd80Sopenharmony_ci    constexpr unsigned int nanoToMill = 1000000; // millisecond converted to nanoseconds
86b0e7dd80Sopenharmony_ci    int len = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1,
87b0e7dd80Sopenharmony_ci        "trace_event_clock_sync: realtime_ts=%" PRId64 "\n",
88b0e7dd80Sopenharmony_ci        static_cast<int64_t>((rts.tv_sec * nanoSeconds + rts.tv_nsec) / nanoToMill));
89b0e7dd80Sopenharmony_ci    if (len < 0) {
90b0e7dd80Sopenharmony_ci        HILOG_ERROR(LOG_CORE, "MarkClockSync: entering realtime_ts into buffer error, errno(%{public}d)", errno);
91b0e7dd80Sopenharmony_ci        close(fd);
92b0e7dd80Sopenharmony_ci        return false;
93b0e7dd80Sopenharmony_ci    }
94b0e7dd80Sopenharmony_ci
95b0e7dd80Sopenharmony_ci    if (write(fd, buffer, len) < 0) {
96b0e7dd80Sopenharmony_ci        HILOG_ERROR(LOG_CORE, "MarkClockSync: writing realtime error, errno(%{public}d)", errno);
97b0e7dd80Sopenharmony_ci    }
98b0e7dd80Sopenharmony_ci
99b0e7dd80Sopenharmony_ci    // write parent_ts
100b0e7dd80Sopenharmony_ci    struct timespec mts = {0, 0};
101b0e7dd80Sopenharmony_ci    if (clock_gettime(CLOCK_MONOTONIC, &mts) == -1) {
102b0e7dd80Sopenharmony_ci        HILOG_ERROR(LOG_CORE, "MarkClockSync: get parent_ts error, errno(%{public}d)", errno);
103b0e7dd80Sopenharmony_ci        close(fd);
104b0e7dd80Sopenharmony_ci        return false;
105b0e7dd80Sopenharmony_ci    }
106b0e7dd80Sopenharmony_ci    constexpr float nanoToSecond = 1000000000.0f; // consistent with the ftrace timestamp format
107b0e7dd80Sopenharmony_ci    len = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "trace_event_clock_sync: parent_ts=%f\n",
108b0e7dd80Sopenharmony_ci        static_cast<float>(((static_cast<float>(mts.tv_sec)) * nanoSeconds + mts.tv_nsec) / nanoToSecond));
109b0e7dd80Sopenharmony_ci    if (len < 0) {
110b0e7dd80Sopenharmony_ci        HILOG_ERROR(LOG_CORE, "MarkClockSync: entering parent_ts into buffer error, errno(%{public}d)", errno);
111b0e7dd80Sopenharmony_ci        close(fd);
112b0e7dd80Sopenharmony_ci        return false;
113b0e7dd80Sopenharmony_ci    }
114b0e7dd80Sopenharmony_ci    if (write(fd, buffer, len) < 0) {
115b0e7dd80Sopenharmony_ci        HILOG_ERROR(LOG_CORE, "MarkClockSync: writing parent_ts error, errno(%{public}d)", errno);
116b0e7dd80Sopenharmony_ci    }
117b0e7dd80Sopenharmony_ci    close(fd);
118b0e7dd80Sopenharmony_ci    return true;
119b0e7dd80Sopenharmony_ci}
120b0e7dd80Sopenharmony_ci
121b0e7dd80Sopenharmony_cistatic cJSON* ParseJsonFromFile(const std::string& filePath)
122b0e7dd80Sopenharmony_ci{
123b0e7dd80Sopenharmony_ci    std::ifstream inFile(filePath, std::ios::in);
124b0e7dd80Sopenharmony_ci    if (!inFile.is_open()) {
125b0e7dd80Sopenharmony_ci        HILOG_ERROR(LOG_CORE, "ParseJsonFromFile: %{public}s is not existed.", filePath.c_str());
126b0e7dd80Sopenharmony_ci        return nullptr;
127b0e7dd80Sopenharmony_ci    }
128b0e7dd80Sopenharmony_ci    std::string fileContent((std::istreambuf_iterator<char>(inFile)), std::istreambuf_iterator<char>());
129b0e7dd80Sopenharmony_ci    cJSON* root = cJSON_Parse(fileContent.c_str());
130b0e7dd80Sopenharmony_ci    if (root == nullptr) {
131b0e7dd80Sopenharmony_ci        HILOG_ERROR(LOG_CORE, "ParseJsonFromFile: %{public}s is not in JSON format.", filePath.c_str());
132b0e7dd80Sopenharmony_ci    }
133b0e7dd80Sopenharmony_ci    inFile.close();
134b0e7dd80Sopenharmony_ci    return root;
135b0e7dd80Sopenharmony_ci}
136b0e7dd80Sopenharmony_ci
137b0e7dd80Sopenharmony_cistatic void ParseSysFiles(cJSON *tags, TagCategory& tagCategory)
138b0e7dd80Sopenharmony_ci{
139b0e7dd80Sopenharmony_ci    cJSON *sysFiles = cJSON_GetObjectItem(tags, "sysFiles");
140b0e7dd80Sopenharmony_ci    if (sysFiles != nullptr && cJSON_IsArray(sysFiles)) {
141b0e7dd80Sopenharmony_ci        cJSON *sysFile = nullptr;
142b0e7dd80Sopenharmony_ci        cJSON_ArrayForEach(sysFile, sysFiles) {
143b0e7dd80Sopenharmony_ci            if (cJSON_IsString(sysFile)) {
144b0e7dd80Sopenharmony_ci                tagCategory.sysFiles.push_back(sysFile->valuestring);
145b0e7dd80Sopenharmony_ci            }
146b0e7dd80Sopenharmony_ci        }
147b0e7dd80Sopenharmony_ci    }
148b0e7dd80Sopenharmony_ci}
149b0e7dd80Sopenharmony_ci
150b0e7dd80Sopenharmony_cistatic bool ParseTagCategory(cJSON* tagCategoryNode, std::map<std::string, TagCategory>& allTags)
151b0e7dd80Sopenharmony_ci{
152b0e7dd80Sopenharmony_ci    cJSON* tags = nullptr;
153b0e7dd80Sopenharmony_ci    cJSON_ArrayForEach(tags, tagCategoryNode) {
154b0e7dd80Sopenharmony_ci        if (tags == nullptr || tags->string == nullptr) {
155b0e7dd80Sopenharmony_ci            continue;
156b0e7dd80Sopenharmony_ci        }
157b0e7dd80Sopenharmony_ci        TagCategory tagCategory;
158b0e7dd80Sopenharmony_ci        cJSON* description = cJSON_GetObjectItem(tags, "description");
159b0e7dd80Sopenharmony_ci        if (description != nullptr && cJSON_IsString(description)) {
160b0e7dd80Sopenharmony_ci            tagCategory.description = description->valuestring;
161b0e7dd80Sopenharmony_ci        }
162b0e7dd80Sopenharmony_ci        cJSON* tagOffset = cJSON_GetObjectItem(tags, "tag_offset");
163b0e7dd80Sopenharmony_ci        if (tagOffset != nullptr && cJSON_IsNumber(tagOffset)) {
164b0e7dd80Sopenharmony_ci            tagCategory.tag = 1ULL << tagOffset->valueint;
165b0e7dd80Sopenharmony_ci        }
166b0e7dd80Sopenharmony_ci        cJSON* type = cJSON_GetObjectItem(tags, "type");
167b0e7dd80Sopenharmony_ci        if (type != nullptr && cJSON_IsNumber(type)) {
168b0e7dd80Sopenharmony_ci            tagCategory.type = type->valueint;
169b0e7dd80Sopenharmony_ci        }
170b0e7dd80Sopenharmony_ci        ParseSysFiles(tags, tagCategory);
171b0e7dd80Sopenharmony_ci        allTags.insert(std::pair<std::string, TagCategory>(tags->string, tagCategory));
172b0e7dd80Sopenharmony_ci    }
173b0e7dd80Sopenharmony_ci    return true;
174b0e7dd80Sopenharmony_ci}
175b0e7dd80Sopenharmony_ci
176b0e7dd80Sopenharmony_cistatic bool ParseTagGroups(cJSON* tagGroupsNode, std::map<std::string, std::vector<std::string>> &tagGroupTable)
177b0e7dd80Sopenharmony_ci{
178b0e7dd80Sopenharmony_ci    cJSON* tagGroup = nullptr;
179b0e7dd80Sopenharmony_ci    cJSON_ArrayForEach(tagGroup, tagGroupsNode) {
180b0e7dd80Sopenharmony_ci        if (tagGroup == nullptr || tagGroup->string == nullptr) {
181b0e7dd80Sopenharmony_ci            continue;
182b0e7dd80Sopenharmony_ci        }
183b0e7dd80Sopenharmony_ci        std::string tagGroupName = tagGroup->string;
184b0e7dd80Sopenharmony_ci        std::vector<std::string> tagList;
185b0e7dd80Sopenharmony_ci        cJSON* tag = nullptr;
186b0e7dd80Sopenharmony_ci        cJSON_ArrayForEach(tag, tagGroup) {
187b0e7dd80Sopenharmony_ci            if (cJSON_IsString(tag)) {
188b0e7dd80Sopenharmony_ci                tagList.push_back(tag->valuestring);
189b0e7dd80Sopenharmony_ci            }
190b0e7dd80Sopenharmony_ci        }
191b0e7dd80Sopenharmony_ci        tagGroupTable.insert(std::pair<std::string, std::vector<std::string>>(tagGroupName, tagList));
192b0e7dd80Sopenharmony_ci    }
193b0e7dd80Sopenharmony_ci    return true;
194b0e7dd80Sopenharmony_ci}
195b0e7dd80Sopenharmony_ci
196b0e7dd80Sopenharmony_cibool ParseTagInfo(std::map<std::string, TagCategory> &allTags,
197b0e7dd80Sopenharmony_ci                  std::map<std::string, std::vector<std::string>> &tagGroupTable)
198b0e7dd80Sopenharmony_ci{
199b0e7dd80Sopenharmony_ci    std::string traceUtilsPath = "/system/etc/hiview/hitrace_utils.json";
200b0e7dd80Sopenharmony_ci    cJSON* root = ParseJsonFromFile(traceUtilsPath);
201b0e7dd80Sopenharmony_ci    if (root == nullptr) {
202b0e7dd80Sopenharmony_ci        return false;
203b0e7dd80Sopenharmony_ci    }
204b0e7dd80Sopenharmony_ci    cJSON* tagCategory = cJSON_GetObjectItem(root, "tag_category");
205b0e7dd80Sopenharmony_ci    if (tagCategory == nullptr) {
206b0e7dd80Sopenharmony_ci        HILOG_ERROR(LOG_CORE, "ParseTagInfo: %{public}s is not contain tag_category node.", traceUtilsPath.c_str());
207b0e7dd80Sopenharmony_ci        cJSON_Delete(root);
208b0e7dd80Sopenharmony_ci        return false;
209b0e7dd80Sopenharmony_ci    }
210b0e7dd80Sopenharmony_ci    if (!ParseTagCategory(tagCategory, allTags)) {
211b0e7dd80Sopenharmony_ci        cJSON_Delete(root);
212b0e7dd80Sopenharmony_ci        return false;
213b0e7dd80Sopenharmony_ci    }
214b0e7dd80Sopenharmony_ci    cJSON* tagGroups = cJSON_GetObjectItem(root, "tag_groups");
215b0e7dd80Sopenharmony_ci    if (tagGroups == nullptr) {
216b0e7dd80Sopenharmony_ci        HILOG_ERROR(LOG_CORE, "ParseTagInfo: %{public}s is not contain tag_groups node.", traceUtilsPath.c_str());
217b0e7dd80Sopenharmony_ci        cJSON_Delete(root);
218b0e7dd80Sopenharmony_ci        return false;
219b0e7dd80Sopenharmony_ci    }
220b0e7dd80Sopenharmony_ci    if (!ParseTagGroups(tagGroups, tagGroupTable)) {
221b0e7dd80Sopenharmony_ci        cJSON_Delete(root);
222b0e7dd80Sopenharmony_ci        return false;
223b0e7dd80Sopenharmony_ci    }
224b0e7dd80Sopenharmony_ci    cJSON_Delete(root);
225b0e7dd80Sopenharmony_ci    HILOG_INFO(LOG_CORE, "ParseTagInfo: parse done.");
226b0e7dd80Sopenharmony_ci    return true;
227b0e7dd80Sopenharmony_ci}
228b0e7dd80Sopenharmony_ci
229b0e7dd80Sopenharmony_cibool IsNumber(const std::string &str)
230b0e7dd80Sopenharmony_ci{
231b0e7dd80Sopenharmony_ci    if (str.empty()) {
232b0e7dd80Sopenharmony_ci        return false;
233b0e7dd80Sopenharmony_ci    }
234b0e7dd80Sopenharmony_ci    for (auto c : str) {
235b0e7dd80Sopenharmony_ci        if (!isdigit(c)) {
236b0e7dd80Sopenharmony_ci            return false;
237b0e7dd80Sopenharmony_ci        }
238b0e7dd80Sopenharmony_ci    }
239b0e7dd80Sopenharmony_ci    return true;
240b0e7dd80Sopenharmony_ci}
241b0e7dd80Sopenharmony_ci
242b0e7dd80Sopenharmony_ciint GetCpuProcessors()
243b0e7dd80Sopenharmony_ci{
244b0e7dd80Sopenharmony_ci    int processors = 0;
245b0e7dd80Sopenharmony_ci    processors = sysconf(_SC_NPROCESSORS_CONF);
246b0e7dd80Sopenharmony_ci    return (processors == 0) ? 1 : processors;
247b0e7dd80Sopenharmony_ci}
248b0e7dd80Sopenharmony_ci
249b0e7dd80Sopenharmony_civoid ReadCurrentCpuFrequencies(std::string& freqs)
250b0e7dd80Sopenharmony_ci{
251b0e7dd80Sopenharmony_ci    int cpuNum = GetCpuProcessors();
252b0e7dd80Sopenharmony_ci    std::ifstream file;
253b0e7dd80Sopenharmony_ci    std::string line;
254b0e7dd80Sopenharmony_ci    for (int i = 0; i < cpuNum; ++i) {
255b0e7dd80Sopenharmony_ci        std::string freq = "0";
256b0e7dd80Sopenharmony_ci        std::string cpuFreqPath = CPUFREQ_PREFIX + std::to_string(i) + CPUFREQ_AFTERFIX;
257b0e7dd80Sopenharmony_ci        file.open(cpuFreqPath);
258b0e7dd80Sopenharmony_ci        if (file.is_open()) {
259b0e7dd80Sopenharmony_ci            if (std::getline(file, line)) {
260b0e7dd80Sopenharmony_ci                std::istringstream iss(line);
261b0e7dd80Sopenharmony_ci                iss >> freq;
262b0e7dd80Sopenharmony_ci            }
263b0e7dd80Sopenharmony_ci            file.close();
264b0e7dd80Sopenharmony_ci        }
265b0e7dd80Sopenharmony_ci        freqs += "cpu_id=" + std::to_string(i) + " state=" + freq;
266b0e7dd80Sopenharmony_ci        if (i != cpuNum - 1) {
267b0e7dd80Sopenharmony_ci            freqs += ",";
268b0e7dd80Sopenharmony_ci        }
269b0e7dd80Sopenharmony_ci    }
270b0e7dd80Sopenharmony_ci}
271b0e7dd80Sopenharmony_ci} // namespace Hitrace
272b0e7dd80Sopenharmony_ci} // namespace HiviewDFX
273b0e7dd80Sopenharmony_ci} // namespace OHOS
274