1 /*
2 * Copyright (c) 2023-2025 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 <sys/statvfs.h>
24 #include <sys/time.h>
25 #include <sys/utsname.h>
26
27 #include "common_define.h"
28 #include "hilog/log.h"
29 #include "parameters.h"
30 #include "securec.h"
31
32 namespace OHOS {
33 namespace HiviewDFX {
34 namespace Hitrace {
35 #ifdef LOG_DOMAIN
36 #undef LOG_DOMAIN
37 #define LOG_DOMAIN 0xD002D33
38 #endif
39 #ifdef LOG_TAG
40 #undef LOG_TAG
41 #define LOG_TAG "HitraceUtils"
42 #endif
43 namespace {
44 static const char* CPUFREQ_PREFIX = "/sys/devices/system/cpu/cpu";
45 static const char* CPUFREQ_AFTERFIX = "/cpufreq/scaling_cur_freq";
46 constexpr int DECIMAL_SCALE = 10;
47 }
48
CanonicalizeSpecPath(const char * src)49 std::string CanonicalizeSpecPath(const char* src)
50 {
51 if (src == nullptr || strlen(src) >= PATH_MAX) {
52 HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: %{pubilc}s failed.", src);
53 return "";
54 }
55 char resolvedPath[PATH_MAX] = { 0 };
56
57 if (access(src, F_OK) == 0) {
58 if (realpath(src, resolvedPath) == nullptr) {
59 HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: realpath %{pubilc}s failed.", src);
60 return "";
61 }
62 } else {
63 std::string fileName(src);
64 if (fileName.find("..") == std::string::npos) {
65 if (sprintf_s(resolvedPath, PATH_MAX, "%s", src) == -1) {
66 HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: sprintf_s %{pubilc}s failed.", src);
67 return "";
68 }
69 } else {
70 HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: find .. src failed.");
71 return "";
72 }
73 }
74
75 std::string res(resolvedPath);
76 return res;
77 }
78
MarkClockSync(const std::string & traceRootPath)79 bool MarkClockSync(const std::string& traceRootPath)
80 {
81 constexpr unsigned int bufferSize = 128;
82 char buffer[bufferSize] = { 0 };
83 std::string resolvedPath = CanonicalizeSpecPath((traceRootPath + TRACE_MARKER_NODE).c_str());
84 int fd = open(resolvedPath.c_str(), O_WRONLY);
85 if (fd == -1) {
86 HILOG_ERROR(LOG_CORE, "MarkClockSync: open %{public}s fail, errno(%{public}d)", resolvedPath.c_str(), errno);
87 return false;
88 }
89
90 // write realtime_ts
91 struct timespec rts = {0, 0};
92 if (clock_gettime(CLOCK_REALTIME, &rts) == -1) {
93 HILOG_ERROR(LOG_CORE, "MarkClockSync: get realtime error, errno(%{public}d)", errno);
94 close(fd);
95 return false;
96 }
97 constexpr unsigned int nanoSeconds = 1000000000; // seconds converted to nanoseconds
98 constexpr unsigned int nanoToMill = 1000000; // millisecond converted to nanoseconds
99 int len = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1,
100 "trace_event_clock_sync: realtime_ts=%" PRId64 "\n",
101 static_cast<int64_t>((rts.tv_sec * nanoSeconds + rts.tv_nsec) / nanoToMill));
102 if (len < 0) {
103 HILOG_ERROR(LOG_CORE, "MarkClockSync: entering realtime_ts into buffer error, errno(%{public}d)", errno);
104 close(fd);
105 return false;
106 }
107
108 if (write(fd, buffer, len) < 0) {
109 HILOG_ERROR(LOG_CORE, "MarkClockSync: writing realtime error, errno(%{public}d)", errno);
110 }
111
112 // write parent_ts
113 struct timespec mts = {0, 0};
114 if (clock_gettime(CLOCK_MONOTONIC, &mts) == -1) {
115 HILOG_ERROR(LOG_CORE, "MarkClockSync: get parent_ts error, errno(%{public}d)", errno);
116 close(fd);
117 return false;
118 }
119 constexpr float nanoToSecond = 1000000000.0f; // consistent with the ftrace timestamp format
120 len = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "trace_event_clock_sync: parent_ts=%f\n",
121 static_cast<float>(((static_cast<float>(mts.tv_sec)) * nanoSeconds + mts.tv_nsec) / nanoToSecond));
122 if (len < 0) {
123 HILOG_ERROR(LOG_CORE, "MarkClockSync: entering parent_ts into buffer error, errno(%{public}d)", errno);
124 close(fd);
125 return false;
126 }
127 if (write(fd, buffer, len) < 0) {
128 HILOG_ERROR(LOG_CORE, "MarkClockSync: writing parent_ts error, errno(%{public}d)", errno);
129 }
130 close(fd);
131 return true;
132 }
133
IsNumber(const std::string & str)134 bool IsNumber(const std::string& str)
135 {
136 if (str.empty()) {
137 return false;
138 }
139 for (auto c : str) {
140 if (!isdigit(c)) {
141 return false;
142 }
143 }
144 return true;
145 }
146
GetCpuProcessors()147 int GetCpuProcessors()
148 {
149 int processors = 0;
150 processors = sysconf(_SC_NPROCESSORS_CONF);
151 return (processors == 0) ? 1 : processors;
152 }
153
GetCurBootTime()154 uint64_t GetCurBootTime()
155 {
156 struct timespec bts = {0, 0};
157 clock_gettime(CLOCK_BOOTTIME, &bts);
158 return static_cast<uint64_t>(bts.tv_sec * S_TO_NS + bts.tv_nsec);
159 }
160
ReadCurrentCpuFrequencies(std::string & freqs)161 void ReadCurrentCpuFrequencies(std::string& freqs)
162 {
163 int cpuNum = GetCpuProcessors();
164 std::ifstream file;
165 std::string line;
166 for (int i = 0; i < cpuNum; ++i) {
167 std::string freq = "0";
168 std::string cpuFreqPath = CPUFREQ_PREFIX + std::to_string(i) + CPUFREQ_AFTERFIX;
169 file.open(cpuFreqPath);
170 if (file.is_open()) {
171 if (std::getline(file, line)) {
172 freq = line;
173 }
174 file.close();
175 }
176 freqs += "cpu_id=" + std::to_string(i) + " state=" + freq;
177 if (i != cpuNum - 1) {
178 freqs += ",";
179 }
180 }
181 }
182
SetPropertyInner(const std::string & property,const std::string & value)183 bool SetPropertyInner(const std::string& property, const std::string& value)
184 {
185 bool result = OHOS::system::SetParameter(property, value);
186 if (!result) {
187 fprintf(stderr, "Error: Failed to set %s property.\n", property.c_str());
188 }
189 return result;
190 }
191
GetPropertyInner(const std::string & property,const std::string & value)192 std::string GetPropertyInner(const std::string& property, const std::string& value)
193 {
194 return OHOS::system::GetParameter(property, value);
195 }
196
IsHmKernel()197 bool IsHmKernel()
198 {
199 bool isHM = false;
200 utsname unameBuf;
201 if ((uname(&unameBuf)) == 0) {
202 std::string osRelease = unameBuf.release;
203 isHM = osRelease.find("HongMeng") != std::string::npos;
204 }
205 return isHM;
206 }
207
IsDeveloperMode()208 bool IsDeveloperMode()
209 {
210 return OHOS::system::GetBoolParameter("const.security.developermode.state", false);
211 }
212
IsRootVersion()213 bool IsRootVersion()
214 {
215 return OHOS::system::GetBoolParameter("const.debuggable", false);
216 }
217
IsTraceMounted(std::string & traceRootPath)218 bool IsTraceMounted(std::string& traceRootPath)
219 {
220 if (access((DEBUGFS_TRACING_DIR + TRACE_MARKER_NODE).c_str(), F_OK) != -1) {
221 traceRootPath = DEBUGFS_TRACING_DIR;
222 return true;
223 }
224 if (access((TRACEFS_DIR + TRACE_MARKER_NODE).c_str(), F_OK) != -1) {
225 traceRootPath = TRACEFS_DIR;
226 return true;
227 }
228 return false;
229 }
230
GetFilePath(const std::string & fileName,const std::string & traceRootPath)231 std::string GetFilePath(const std::string& fileName, const std::string& traceRootPath)
232 {
233 return traceRootPath + fileName;
234 }
235
ReadFileInner(const std::string & filename)236 std::string ReadFileInner(const std::string& filename)
237 {
238 std::string resolvedPath = CanonicalizeSpecPath(filename.c_str());
239 std::ifstream fileIn(resolvedPath.c_str());
240 if (!fileIn.is_open()) {
241 HILOG_ERROR(LOG_CORE, "ReadFile: %{public}s open failed.", filename.c_str());
242 return "";
243 }
244 std::string str((std::istreambuf_iterator<char>(fileIn)), std::istreambuf_iterator<char>());
245 fileIn.close();
246 return str;
247 }
248
ReadFile(const std::string & filename,const std::string & traceRootPath)249 std::string ReadFile(const std::string& filename, const std::string& traceRootPath)
250 {
251 std::string filePath = GetFilePath(filename, traceRootPath);
252 return ReadFileInner(filePath);
253 }
254
IsTracingOn(const std::string & traceRootPath)255 bool IsTracingOn(const std::string& traceRootPath)
256 {
257 const std::string enable = "1";
258 if (ReadFile(TRACING_ON_NODE, traceRootPath).substr(0, enable.size()) == enable) {
259 HILOG_INFO(LOG_CORE, "tracing_on is 1.");
260 return true;
261 }
262 HILOG_INFO(LOG_CORE, "tracing_on is 0.");
263 return false;
264 }
265
StringToInt(const std::string & str,int & val)266 bool StringToInt(const std::string &str, int &val)
267 {
268 char *endPtr = nullptr;
269 errno = 0;
270 long num = std::strtol(str.c_str(), &endPtr, OHOS::HiviewDFX::Hitrace::DECIMAL_SCALE);
271 if (endPtr == str.c_str() || *endPtr != '\0' || errno != 0 || num > INT_MAX || num < INT_MIN) {
272 HILOG_ERROR(LOG_CORE, "get int failed, str: %s", str.c_str());
273 return false;
274 }
275 val = static_cast<int>(num);
276 return true;
277 }
278
StringToInt64(const std::string & str,int64_t & val)279 bool StringToInt64(const std::string &str, int64_t &val)
280 {
281 char *endPtr = nullptr;
282 errno = 0;
283 int64_t num = std::strtoll(str.c_str(), &endPtr, OHOS::HiviewDFX::Hitrace::DECIMAL_SCALE);
284 if (endPtr == str.c_str() || *endPtr != '\0' || errno != 0 || num > LLONG_MAX || num < LLONG_MIN) {
285 HILOG_ERROR(LOG_CORE, "get int64 failed, str: %s", str.c_str());
286 return false;
287 }
288 val = num;
289 return true;
290 }
291
StringToUint64(const std::string & str,uint64_t & val)292 bool StringToUint64(const std::string &str, uint64_t &val)
293 {
294 char *endPtr = nullptr;
295 errno = 0;
296 uint64_t num = std::strtoull(str.c_str(), &endPtr, OHOS::HiviewDFX::Hitrace::DECIMAL_SCALE);
297 if (endPtr == str.c_str() || *endPtr != '\0' || errno != 0 || num > ULLONG_MAX || str.c_str()[0] == '-') {
298 HILOG_ERROR(LOG_CORE, "get uint64 failed, str: %s", str.c_str());
299 return false;
300 }
301 val = num;
302 return true;
303 }
304
StringToDouble(const std::string & str,double & val)305 bool StringToDouble(const std::string &str, double &val)
306 {
307 char *endPtr = nullptr;
308 errno = 0;
309 double num = std::strtod(str.c_str(), &endPtr);
310 if (endPtr == str.c_str() || *endPtr != '\0' || errno != 0) {
311 HILOG_ERROR(LOG_CORE, "get double failed, str: %s", str.c_str());
312 return false;
313 }
314 val = num;
315 return true;
316 }
317
WriteEventFile(const std::string & srcPath,const int fd)318 void WriteEventFile(const std::string& srcPath, const int fd)
319 {
320 uint8_t buffer[PAGE_SIZE] = {0};
321 std::string srcSpecPath = CanonicalizeSpecPath(srcPath.c_str());
322 int srcFd = open(srcSpecPath.c_str(), O_RDONLY);
323 if (srcFd < 0) {
324 HILOG_ERROR(LOG_CORE, "WriteEventFile: open %{public}s failed.", srcPath.c_str());
325 return;
326 }
327 int64_t readLen = 0;
328 do {
329 int64_t len = read(srcFd, buffer, PAGE_SIZE);
330 if (len <= 0) {
331 break;
332 }
333 ssize_t writeRet = write(fd, buffer, len);
334 if (writeRet < 0) {
335 HILOG_ERROR(LOG_CORE, "WriteEventFile: write failed, err(%{public}s)", strerror(errno));
336 break;
337 }
338 readLen += len;
339 } while (true);
340 close(srcFd);
341 HILOG_INFO(LOG_CORE, "WriteEventFile end, path: %{public}s, data size: (%{public}" PRIu64 ").",
342 srcPath.c_str(), static_cast<uint64_t>(readLen));
343 }
344
GetKernelVersion()345 std::string GetKernelVersion()
346 {
347 utsname unameBuf;
348 if (uname(&unameBuf) == 0) {
349 return unameBuf.release;
350 } else {
351 HILOG_ERROR(LOG_CORE, "GetKernelVersion failed, errno: %{public}s", strerror(errno));
352 return "";
353 }
354 }
355
GetRemainingSpace(const std::string & path)356 uint64_t GetRemainingSpace(const std::string& path)
357 {
358 struct statvfs fsInfo;
359
360 if (statvfs(path.c_str(), &fsInfo) != 0) {
361 HILOG_ERROR(LOG_CORE, "GetRemainingSpace: statvfs failed, errno: %{public}d", errno);
362 return UINT64_MAX;
363 }
364
365 uint64_t ret = fsInfo.f_bavail * static_cast<uint64_t>(fsInfo.f_frsize);
366 HILOG_INFO(LOG_CORE, "GetRemainingSpace: %{public}s current remaining space %{public}" PRIu64, path.c_str(), ret);
367 return ret;
368 }
369 } // namespace Hitrace
370 } // namespace HiviewDFX
371 } // namespace OHOS
372