• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "trace_dump_pipe.h"
17 
18 #include <chrono>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <sys/file.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 
26 #include "common_define.h"
27 #include "hilog/log.h"
28 
29 namespace OHOS {
30 namespace HiviewDFX {
31 namespace Hitrace {
32 #ifdef LOG_DOMAIN
33 #undef LOG_DOMAIN
34 #define LOG_DOMAIN 0xD002D33
35 #endif
36 #ifdef LOG_TAG
37 #undef LOG_TAG
38 #define LOG_TAG "HitraceDumpPipe"
39 #endif
40 namespace {
41 const char TRACE_TASK_SUBMIT_PIPE[] = "/data/log/hitrace/trace_task";
42 const char TRACE_SYNC_RETURN_PIPE[] = "/data/log/hitrace/trace_sync_return";
43 const char TRACE_ASYNC_RETURN_PIPE[] = "/data/log/hitrace/trace_async_return";
44 const int READ_PIPE_TICK = 50;
45 const mode_t PIPE_FILE_MODE = 0666;
46 } // namespace
47 
HitraceDumpPipe(bool isParent)48 HitraceDumpPipe::HitraceDumpPipe(bool isParent)
49 {
50     isParent_ = isParent;
51     if (isParent_) {
52         taskSubmitFd_ = UniqueFd(open(TRACE_TASK_SUBMIT_PIPE, O_WRONLY));
53         if (taskSubmitFd_ < 0) {
54             HILOG_ERROR(LOG_CORE, "HitraceDumpPipe: parent open %{public}s failed, errno(%{public}d)",
55                 TRACE_TASK_SUBMIT_PIPE, errno);
56         }
57         syncRetFd_ = UniqueFd(open(TRACE_SYNC_RETURN_PIPE, O_RDONLY | O_NONBLOCK));
58         if (syncRetFd_ < 0) {
59             HILOG_ERROR(LOG_CORE, "HitraceDumpPipe: parent open %{public}s failed, errno(%{public}d)",
60                 TRACE_SYNC_RETURN_PIPE, errno);
61         }
62         asyncRetFd_ = UniqueFd(open(TRACE_ASYNC_RETURN_PIPE, O_RDONLY | O_NONBLOCK));
63         if (asyncRetFd_ < 0) {
64             HILOG_ERROR(LOG_CORE, "HitraceDumpPipe: parent open %{public}s failed, errno(%{public}d)",
65                 TRACE_ASYNC_RETURN_PIPE, errno);
66         }
67     } else {
68         taskSubmitFd_ = UniqueFd(open(TRACE_TASK_SUBMIT_PIPE, O_RDONLY | O_NONBLOCK));
69         if (taskSubmitFd_ < 0) {
70             HILOG_ERROR(LOG_CORE, "HitraceDumpPipe: child open %{public}s failed, errno(%{public}d)",
71                 TRACE_TASK_SUBMIT_PIPE, errno);
72         }
73         syncRetFd_ = UniqueFd(open(TRACE_SYNC_RETURN_PIPE, O_WRONLY));
74         if (syncRetFd_ < 0) {
75             HILOG_ERROR(LOG_CORE, "HitraceDumpPipe: child open %{public}s failed, errno(%{public}d)",
76                 TRACE_SYNC_RETURN_PIPE, errno);
77         }
78         asyncRetFd_ = UniqueFd(open(TRACE_ASYNC_RETURN_PIPE, O_WRONLY));
79         if (asyncRetFd_ < 0) {
80             HILOG_ERROR(LOG_CORE, "HitraceDumpPipe: child open %{public}s failed, errno(%{public}d)",
81                 TRACE_ASYNC_RETURN_PIPE, errno);
82         }
83     }
84 }
85 
InitTraceDumpPipe()86 bool HitraceDumpPipe::InitTraceDumpPipe()
87 {
88     if (mkfifo(TRACE_TASK_SUBMIT_PIPE, PIPE_FILE_MODE) < 0) {
89         HILOG_ERROR(LOG_CORE, "HitraceDumpPipe: create %{public}s failed, errno(%{public}d)",
90             TRACE_TASK_SUBMIT_PIPE, errno);
91         return false;
92     }
93     if (mkfifo(TRACE_SYNC_RETURN_PIPE, PIPE_FILE_MODE) < 0) {
94         HILOG_ERROR(LOG_CORE, "HitraceDumpPipe: create %{public}s failed, errno(%{public}d)",
95             TRACE_SYNC_RETURN_PIPE, errno);
96         unlink(TRACE_TASK_SUBMIT_PIPE);
97         return false;
98     }
99     if (mkfifo(TRACE_ASYNC_RETURN_PIPE, PIPE_FILE_MODE) < 0) {
100         HILOG_ERROR(LOG_CORE, "HitraceDumpPipe: create %{public}s failed, errno(%{public}d)",
101             TRACE_ASYNC_RETURN_PIPE, errno);
102         unlink(TRACE_TASK_SUBMIT_PIPE);
103         unlink(TRACE_SYNC_RETURN_PIPE);
104         return false;
105     }
106     return true;
107 }
108 
ClearTraceDumpPipe()109 void HitraceDumpPipe::ClearTraceDumpPipe()
110 {
111     unlink(TRACE_TASK_SUBMIT_PIPE);
112     unlink(TRACE_SYNC_RETURN_PIPE);
113     unlink(TRACE_ASYNC_RETURN_PIPE);
114 }
115 
CheckProcessRole(bool shouldBeParent,const char * operation) const116 bool HitraceDumpPipe::CheckProcessRole(bool shouldBeParent, const char* operation) const
117 {
118     if (isParent_ != shouldBeParent) {
119         HILOG_ERROR(LOG_CORE, "%{public}s: %{public}s process can not perform this operation.",
120             operation, shouldBeParent ? "child" : "parent");
121         return false;
122     }
123     return true;
124 }
125 
CheckFdValidity(const int fd,const char * operation,const char * pipeName) const126 bool HitraceDumpPipe::CheckFdValidity(const int fd, const char* operation, const char* pipeName) const
127 {
128     if (fd < 0) {
129         HILOG_ERROR(LOG_CORE, "%{public}s: %{public}s fd is illegal.", operation, pipeName);
130         return false;
131     }
132     return true;
133 }
134 
WriteToPipe(const int fd,const TraceDumpTask & task,const char * operation)135 bool HitraceDumpPipe::WriteToPipe(const int fd, const TraceDumpTask& task, const char* operation)
136 {
137     ssize_t ret = TEMP_FAILURE_RETRY(write(fd, &task, sizeof(task)));
138     if (ret < 0) {
139         HILOG_ERROR(LOG_CORE, "%{public}s: write pipe failed.", operation);
140         return false;
141     }
142     HILOG_INFO(LOG_CORE, "%{public}s: task submitted, task id: %{public}" PRIu64 ".", operation, task.time);
143     return true;
144 }
145 
ReadFromPipe(const int fd,TraceDumpTask & task,const int timeoutMs,const char * operation)146 bool HitraceDumpPipe::ReadFromPipe(const int fd, TraceDumpTask& task, const int timeoutMs, const char* operation)
147 {
148     fd_set readfds;
149     struct timeval tv;
150     int ret;
151     const int waitStepMs = READ_PIPE_TICK;
152     auto start = std::chrono::steady_clock::now();
153     while (true) {
154         auto now = std::chrono::steady_clock::now();
155         int elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count();
156         int remain = timeoutMs - elapsed;
157         if (remain <= 0) {
158             break;
159         }
160         int waitMs = (remain < waitStepMs) ? remain : waitStepMs;
161         FD_ZERO(&readfds);
162         FD_SET(fd, &readfds);
163         tv.tv_sec = waitMs / S_TO_MS;
164         tv.tv_usec = (waitMs % S_TO_MS) * S_TO_MS;
165         ret = select(fd + 1, &readfds, nullptr, nullptr, &tv);
166         if (ret > 0 && FD_ISSET(fd, &readfds)) {
167             ssize_t readSize = TEMP_FAILURE_RETRY(read(fd, &task, sizeof(task)));
168             if (readSize > 0) {
169                 HILOG_INFO(LOG_CORE, "%{public}s: read task done, task id: %{public}" PRIu64 ".", operation, task.time);
170                 return true;
171             }
172         } else if (ret < 0) {
173             HILOG_ERROR(LOG_CORE, "%{public}s: select error, errno: %{public}d", operation, errno);
174             return false;
175         }
176     }
177     HILOG_INFO(LOG_CORE, "%{public}s: read task timeout.", operation);
178     return false;
179 }
180 
SubmitTraceDumpTask(const TraceDumpTask & task)181 bool HitraceDumpPipe::SubmitTraceDumpTask(const TraceDumpTask& task)
182 {
183     const char* operation = "SubmitTraceDumpTask";
184     if (!CheckProcessRole(true, operation) || !CheckFdValidity(taskSubmitFd_, operation, "submit pipe")) {
185         return false;
186     }
187     return WriteToPipe(taskSubmitFd_, task, operation);
188 }
189 
ReadSyncDumpRet(const int timeout,TraceDumpTask & task)190 bool HitraceDumpPipe::ReadSyncDumpRet(const int timeout, TraceDumpTask& task)
191 {
192     const char* operation = "ReadSyncDumpRet";
193     if (!CheckProcessRole(true, operation) || !CheckFdValidity(syncRetFd_, operation, "sync return pipe")) {
194         return false;
195     }
196     return ReadFromPipe(syncRetFd_, task, timeout * S_TO_MS, operation);
197 }
198 
ReadAsyncDumpRet(const int timeout,TraceDumpTask & task)199 bool HitraceDumpPipe::ReadAsyncDumpRet(const int timeout, TraceDumpTask& task)
200 {
201     const char* operation = "ReadAsyncDumpRet";
202     if (!CheckProcessRole(true, operation) || !CheckFdValidity(asyncRetFd_, operation, "async return pipe")) {
203         return false;
204     }
205     return ReadFromPipe(asyncRetFd_, task, timeout * S_TO_MS, operation);
206 }
207 
ReadTraceTask(const int timeoutMs,TraceDumpTask & task)208 bool HitraceDumpPipe::ReadTraceTask(const int timeoutMs, TraceDumpTask& task)
209 {
210     const char* operation = "ReadTraceTask";
211     if (!CheckProcessRole(false, operation) || !CheckFdValidity(taskSubmitFd_, operation, "submit pipe")) {
212         return false;
213     }
214     return ReadFromPipe(taskSubmitFd_, task, timeoutMs, operation);
215 }
216 
WriteSyncReturn(const TraceDumpTask & task)217 bool HitraceDumpPipe::WriteSyncReturn(const TraceDumpTask& task)
218 {
219     const char* operation = "WriteSyncReturn";
220     if (!CheckProcessRole(false, operation) || !CheckFdValidity(syncRetFd_, operation, "sync return pipe")) {
221         return false;
222     }
223     return WriteToPipe(syncRetFd_, task, operation);
224 }
225 
WriteAsyncReturn(const TraceDumpTask & task)226 bool HitraceDumpPipe::WriteAsyncReturn(const TraceDumpTask& task)
227 {
228     const char* operation = "WriteAsyncReturn";
229     if (!CheckProcessRole(false, operation) || !CheckFdValidity(asyncRetFd_, operation, "async return pipe")) {
230         return false;
231     }
232     return WriteToPipe(asyncRetFd_, task, operation);
233 }
234 } // namespace Hitrace
235 } // namespace HiviewDFX
236 } // namespace OHOS