1 /*
2 * Copyright (C) 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 "hitrace_option/hitrace_option.h"
17
18 #include <fcntl.h>
19 #include <sstream>
20 #include <filesystem>
21 #include <unistd.h>
22
23 #include "hilog/log.h"
24 #include "parameters.h"
25
26 namespace OHOS {
27 namespace HiviewDFX {
28 namespace Hitrace {
29
30 #ifdef LOG_DOMAIN
31 #undef LOG_DOMAIN
32 #define LOG_DOMAIN 0xD002D33
33 #endif
34 #ifdef LOG_TAG
35 #undef LOG_TAG
36 #define LOG_TAG "HitraceOption"
37 #endif
38
39 static const char* TELEMETRY_APP_PARAM = "debug.hitrace.telemetry.app";
40 static const char* SET_EVENT_PID = "/sys/kernel/tracing/set_event_pid";
41 static const char* DEBUG_SET_EVENT_PID = "/sys/kernel/debug/tracing/set_event_pid";
42
43 class FileLock {
44 private:
45 int fd_ = -1;
46 public:
FileLock(const std::string & filename,int flags)47 explicit FileLock(const std::string& filename, int flags)
48 {
49 char canonicalPath[PATH_MAX + 1] = {0};
50 if (realpath(filename.c_str(), canonicalPath) == nullptr) {
51 HILOG_ERROR(LOG_CORE, "FileLock: %{public}s realpath failed, errno%{public}d", filename.c_str(), errno);
52 return;
53 }
54 fd_ = open(canonicalPath, flags);
55 if (fd_ == -1) {
56 HILOG_ERROR(LOG_CORE, "FileLock: %{public}s open failed, errno%{public}d", filename.c_str(), errno);
57 return;
58 }
59
60 #ifdef ENABLE_LOCK
61 if (flock(fd_, LOCK_EX) != 0) {
62 HILOG_ERROR(LOG_CORE, "FileLock: %{public}s lock failed.", filename.c_str());
63 close(fd_);
64 fd_ = -1;
65 }
66 HILOG_INFO(LOG_CORE, "FileLock: %{public}s lock succ, fd = %{public}d", filename.c_str(), fd_);
67 #endif
68 }
69
~FileLock()70 ~FileLock()
71 {
72 if (fd_ != -1) {
73 #ifdef ENABLE_LOCK
74 flock(fd_, LOCK_UN);
75 HILOG_INFO(LOG_CORE, "FileLock: %{public}d unlock succ", fd_);
76 #endif
77 close(fd_);
78 }
79 }
80
Fd()81 int Fd()
82 {
83 return fd_;
84 }
85 };
86
GetSubThreadIds(const std::string & pid)87 std::vector<std::string> GetSubThreadIds(const std::string& pid)
88 {
89 std::vector<std::string> ret;
90 std::string path = "/proc/" + pid + "/task/";
91
92 if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) {
93 for (const auto& entry : std::filesystem::directory_iterator(path)) {
94 ret.emplace_back(entry.path().filename());
95 }
96 }
97
98 return ret;
99 }
100
AppendToFile(const std::string & filename,const std::string & str)101 bool AppendToFile(const std::string& filename, const std::string& str)
102 {
103 FileLock fileLock(filename, O_RDWR);
104
105 int fd = fileLock.Fd();
106 if (fd == -1) {
107 return false;
108 }
109
110 if (write(fd, str.c_str(), str.size()) < 0) {
111 HILOG_ERROR(LOG_CORE, "AppendToFile: %{public}s write failed %{public}d", filename.c_str(), errno);
112 return false;
113 }
114 return true;
115 }
116
SetFilterAppName(const std::string & app)117 int32_t SetFilterAppName(const std::string& app)
118 {
119 bool ret = OHOS::system::SetParameter(TELEMETRY_APP_PARAM, app);
120 HILOG_INFO(LOG_CORE, "SetTelemetryAppName %{public}s ret=%{public}d", app.c_str(), ret);
121 return ret ? HITRACE_NO_ERROR : HITRACE_SET_PARAM_ERROR;
122 }
123
AddFilterPid(const pid_t pid)124 int32_t AddFilterPid(const pid_t pid)
125 {
126 std::vector<std::string> vec = { std::to_string(pid) };
127 return AddFilterPids(vec);
128 }
129
AddFilterPids(const std::vector<std::string> & pids)130 int32_t AddFilterPids(const std::vector<std::string>& pids)
131 {
132 std::stringstream ss(" ");
133 for (const auto& pid : pids) {
134 for (const auto& tid : GetSubThreadIds(pid)) {
135 ss << tid << " ";
136 }
137 }
138
139 std::string pidStr = ss.str();
140 if (AppendToFile(DEBUG_SET_EVENT_PID, pidStr) || AppendToFile(SET_EVENT_PID, pidStr)) {
141 HILOG_INFO(LOG_CORE, "AddFilterPids %{public}s success", pidStr.c_str());
142 return HITRACE_NO_ERROR;
143 }
144
145 HILOG_INFO(LOG_CORE, "AddFilterPids %{public}s fail", pidStr.c_str());
146 return HITRACE_WRITE_FILE_ERROR;
147 }
148
ClearFilterPid()149 int32_t ClearFilterPid()
150 {
151 int fd = creat(DEBUG_SET_EVENT_PID, 0);
152 if (fd != -1) {
153 close(fd);
154 HILOG_INFO(LOG_CORE, "ClearFilterPid success");
155 return HITRACE_NO_ERROR;
156 }
157
158 fd = creat(SET_EVENT_PID, 0);
159 if (fd != -1) {
160 close(fd);
161 HILOG_INFO(LOG_CORE, "ClearFilterPid success");
162 return HITRACE_NO_ERROR;
163 }
164
165 HILOG_INFO(LOG_CORE, "ClearFilterPid fail");
166 return HITRACE_WRITE_FILE_ERROR;
167 }
168
FilterAppTrace(const char * app,pid_t pid)169 void FilterAppTrace(const char* app, pid_t pid)
170 {
171 if (app == nullptr) {
172 HILOG_INFO(LOG_CORE, "FilterAppTrace: app is null");
173 return;
174 }
175 HILOG_INFO(LOG_CORE, "FilterAppTrace %{public}s %{public}d", app, pid);
176 std::string paramApp = OHOS::system::GetParameter(TELEMETRY_APP_PARAM, "");
177 if (paramApp == app) {
178 AddFilterPid(pid);
179 }
180 }
181
182 } // namespace Hitrace
183 } // namespace HiviewDFX
184 } // namespace OHOS
185