1 /*
2  * Copyright (c) 2021-2024 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 "dfx_dump_catcher.h"
17 
18 #include <atomic>
19 #include <cerrno>
20 #include <memory>
21 #include <thread>
22 #include <vector>
23 
24 #include <dlfcn.h>
25 #include <poll.h>
26 #include <sys/syscall.h>
27 #include <sys/types.h>
28 #include <securec.h>
29 #include <strings.h>
30 
31 #include "backtrace_local.h"
32 #include "dfx_define.h"
33 #include "dfx_dump_res.h"
34 #include "dfx_kernel_stack.h"
35 #include "dfx_log.h"
36 #include "dfx_trace_dlsym.h"
37 #include "dfx_util.h"
38 #include "elapsed_time.h"
39 #include "faultloggerd_client.h"
40 #include "file_ex.h"
41 #include "procinfo.h"
42 
43 namespace OHOS {
44 namespace HiviewDFX {
45 namespace {
46 #ifdef LOG_DOMAIN
47 #undef LOG_DOMAIN
48 #define LOG_DOMAIN 0xD002D11
49 #endif
50 
51 #ifdef LOG_TAG
52 #undef LOG_TAG
53 #define LOG_TAG "DfxDumpCatcher"
54 #endif
55 static const int DUMP_CATCHE_WORK_TIME_S = 60;
56 static const std::string DFXDUMPCATCHER_TAG = "DfxDumpCatcher";
57 static std::string g_kernelStackInfo;
58 static std::atomic_bool g_asyncThreadRunning;
59 static pid_t g_kernelStackPid = 0;
60 static std::condition_variable g_cv;
61 static std::mutex g_kernelStackMutex;
62 static constexpr int WAIT_GET_KERNEL_STACK_TIMEOUT = 1000; // 1000 : time out 1000 ms
63 
64 enum DfxDumpPollRes : int32_t {
65     DUMP_POLL_INIT = -1,
66     DUMP_POLL_OK,
67     DUMP_POLL_FD,
68     DUMP_POLL_FAILED,
69     DUMP_POLL_TIMEOUT,
70     DUMP_POLL_RETURN,
71 };
72 
73 enum DfxDumpStatRes : int32_t {
74     DUMP_RES_NO_KERNELSTACK = -2,
75     DUMP_RES_WITH_KERNELSTACK = -1,
76     DUMP_RES_WITH_USERSTACK = 0,
77 };
78 }
79 
DoDumpCurrTid(const size_t skipFrameNum, std::string& msg, size_t maxFrameNums)80 bool DfxDumpCatcher::DoDumpCurrTid(const size_t skipFrameNum, std::string& msg, size_t maxFrameNums)
81 {
82     bool ret = false;
83 
84     ret = GetBacktrace(msg, skipFrameNum + 1, false, maxFrameNums);
85     if (!ret) {
86         int currTid = gettid();
87         msg.append("Failed to dump curr thread:" + std::to_string(currTid) + ".\n");
88     }
89     DFXLOGD("%{public}s :: DoDumpCurrTid :: return %{public}d.", DFXDUMPCATCHER_TAG.c_str(), ret);
90     return ret;
91 }
92 
DoDumpLocalTid(const int tid, std::string& msg, size_t maxFrameNums)93 bool DfxDumpCatcher::DoDumpLocalTid(const int tid, std::string& msg, size_t maxFrameNums)
94 {
95     bool ret = false;
96     if (tid <= 0) {
97         DFXLOGE("%{public}s :: DoDumpLocalTid :: return false as param error.", DFXDUMPCATCHER_TAG.c_str());
98         return ret;
99     }
100     ret = GetBacktraceStringByTid(msg, tid, 0, false, maxFrameNums);
101     if (!ret) {
102         msg.append("Failed to dump thread:" + std::to_string(tid) + ".\n");
103     }
104     DFXLOGD("%{public}s :: DoDumpLocalTid :: return %{public}d.", DFXDUMPCATCHER_TAG.c_str(), ret);
105     return ret;
106 }
107 
DoDumpLocalPid(int pid, std::string& msg, size_t maxFrameNums)108 bool DfxDumpCatcher::DoDumpLocalPid(int pid, std::string& msg, size_t maxFrameNums)
109 {
110     bool ret = false;
111     if (pid <= 0) {
112         DFXLOGE("%{public}s :: DoDumpLocalPid :: return false as param error.", DFXDUMPCATCHER_TAG.c_str());
113         return ret;
114     }
115     size_t skipFramNum = 5; // 5: skip 5 frame
116 
117     msg = GetStacktraceHeader();
118     std::function<bool(int)> func = [&](int tid) {
119         if (tid <= 0) {
120             return false;
121         }
122         std::string threadMsg;
123         if (tid == gettid()) {
124             ret = DoDumpCurrTid(skipFramNum, threadMsg, maxFrameNums);
125         } else {
126             ret = DoDumpLocalTid(tid, threadMsg, maxFrameNums);
127         }
128         msg += threadMsg;
129         return ret;
130     };
131     std::vector<int> tids;
132     ret = GetTidsByPidWithFunc(getpid(), tids, func);
133     DFXLOGD("%{public}s :: DoDumpLocalPid :: return %{public}d.", DFXDUMPCATCHER_TAG.c_str(), ret);
134     return ret;
135 }
136 
DoDumpRemoteLocked(int pid, int tid, std::string& msg, bool isJson, int timeout)137 bool DfxDumpCatcher::DoDumpRemoteLocked(int pid, int tid, std::string& msg, bool isJson, int timeout)
138 {
139     return DoDumpCatchRemote(pid, tid, msg, isJson, timeout);
140 }
141 
DoDumpLocalLocked(int pid, int tid, std::string& msg, size_t maxFrameNums)142 bool DfxDumpCatcher::DoDumpLocalLocked(int pid, int tid, std::string& msg, size_t maxFrameNums)
143 {
144     bool ret = false;
145     if (tid == gettid()) {
146         size_t skipFramNum = 4; // 4: skip 4 frame
147         ret = DoDumpCurrTid(skipFramNum, msg, maxFrameNums);
148     } else if (tid == 0) {
149         ret = DoDumpLocalPid(pid, msg, maxFrameNums);
150     } else {
151         if (!IsThreadInPid(pid, tid)) {
152             msg.append("tid(" + std::to_string(tid) + ") is not in pid(" + std::to_string(pid) + ").\n");
153         } else {
154             ret = DoDumpLocalTid(tid, msg, maxFrameNums);
155         }
156     }
157 
158     DFXLOGD("%{public}s :: DoDumpLocal :: ret(%{public}d).", DFXDUMPCATCHER_TAG.c_str(), ret);
159     return ret;
160 }
161 
ReportDumpCatcherStats(int32_t pid, uint64_t requestTime, bool ret, std::string& msg, void* retAddr)162 static void ReportDumpCatcherStats(int32_t pid,
163     uint64_t requestTime, bool ret, std::string& msg, void* retAddr)
164 {
165     std::vector<uint8_t> buf(sizeof(struct FaultLoggerdStatsRequest), 0);
166     auto stat = reinterpret_cast<struct FaultLoggerdStatsRequest*>(buf.data());
167     stat->type = DUMP_CATCHER;
168     stat->pid = pid;
169     stat->requestTime = requestTime;
170     stat->dumpCatcherFinishTime = GetTimeMilliSeconds();
171     stat->result = ret ? DUMP_RES_WITH_USERSTACK : DUMP_RES_WITH_KERNELSTACK; // we need more detailed failure info
172     if (!ret && g_kernelStackInfo.empty()) {
173         stat->result = DUMP_RES_NO_KERNELSTACK;
174     }
175     size_t copyLen;
176     std::string processName;
177     ReadProcessName(pid, processName);
178     copyLen = std::min(sizeof(stat->targetProcess) - 1, processName.size());
179     if (memcpy_s(stat->targetProcess, sizeof(stat->targetProcess) - 1, processName.c_str(), copyLen) != 0) {
180         DFXLOGE("%{public}s::Failed to copy target process", DFXDUMPCATCHER_TAG.c_str());
181         return;
182     }
183 
184     if (!ret) {
185         copyLen = std::min(sizeof(stat->summary) - 1, msg.size());
186         if (memcpy_s(stat->summary, sizeof(stat->summary) - 1, msg.c_str(), copyLen) != 0) {
187             DFXLOGE("%{public}s::Failed to copy dumpcatcher summary", DFXDUMPCATCHER_TAG.c_str());
188             return;
189         }
190     }
191 
192     Dl_info info;
193     if (dladdr(retAddr, &info) != 0) {
194         copyLen = std::min(sizeof(stat->callerElf) - 1, strlen(info.dli_fname));
195         if (memcpy_s(stat->callerElf, sizeof(stat->callerElf) - 1, info.dli_fname, copyLen) != 0) {
196             DFXLOGE("%{public}s::Failed to copy caller elf info", DFXDUMPCATCHER_TAG.c_str());
197             return;
198         }
199         stat->offset = reinterpret_cast<uintptr_t>(retAddr) - reinterpret_cast<uintptr_t>(info.dli_fbase);
200     }
201 
202     std::string cmdline;
203     if (OHOS::LoadStringFromFile("/proc/self/cmdline", cmdline)) {
204         copyLen = std::min(sizeof(stat->callerProcess) - 1, cmdline.size());
205         if (memcpy_s(stat->callerProcess, sizeof(stat->callerProcess) - 1,
206             cmdline.c_str(), copyLen) != 0) {
207             DFXLOGE("%{public}s::Failed to copy caller cmdline", DFXDUMPCATCHER_TAG.c_str());
208             return;
209         }
210     }
211 
212     ReportDumpStats(stat);
213 }
214 
DumpCatchProcess(int pid, std::string& msg, size_t maxFrameNums, bool isJson)215 int DfxDumpCatcher::DumpCatchProcess(int pid, std::string& msg, size_t maxFrameNums, bool isJson)
216 {
217     if (DumpCatch(pid, 0, msg, maxFrameNums, isJson)) {
218         return 0;
219     }
220     if (pid == g_kernelStackPid && !g_asyncThreadRunning) {
221         msg.append(g_kernelStackInfo);
222         g_kernelStackInfo.clear();
223         g_kernelStackPid = 0;
224         return 1;
225     }
226     return -1;
227 }
228 
DumpCatch(int pid, int tid, std::string& msg, size_t maxFrameNums, bool isJson)229 bool DfxDumpCatcher::DumpCatch(int pid, int tid, std::string& msg, size_t maxFrameNums, bool isJson)
230 {
231     bool ret = false;
232     if (pid <= 0 || tid < 0) {
233         DFXLOGE("%{public}s :: dump_catch :: param error.", DFXDUMPCATCHER_TAG.c_str());
234         return ret;
235     }
236     std::string statusPath = StringPrintf("/proc/%d/status", pid);
237     if (access(statusPath.c_str(), F_OK) != 0 && errno != EACCES) {
238         DFXLOGE("DumpCatch:: the pid(%{public}d) process has exited, errno(%{public}d)", pid, errno);
239         msg.append("Result: pid(" + std::to_string(pid) + ") process has exited.\n");
240         return ret;
241     }
242     DfxEnableTraceDlsym(true);
243     ElapsedTime counter;
244     std::unique_lock<std::mutex> lck(mutex_);
245     int currentPid = getpid();
246     bool reportStat = false;
247     uint64_t requestTime = GetTimeMilliSeconds();
248     DFXLOGW("Receive DumpCatch request for cPid:(%{public}d), pid(%{public}d), " \
249         "tid:(%{public}d).", currentPid, pid, tid);
250     if (pid == currentPid) {
251         ret = DoDumpLocalLocked(pid, tid, msg, maxFrameNums);
252     } else {
253         if (maxFrameNums != DEFAULT_MAX_FRAME_NUM) {
254             DFXLOGI("%{public}s :: dump_catch :: maxFrameNums does not support setting " \
255                 "when pid is not equal to caller pid", DFXDUMPCATCHER_TAG.c_str());
256         }
257         reportStat = true;
258         int timeout = (tid == 0 ? 3 : 10) * 1000; // when tid not zero, timeout is 10s
259         ret = DoDumpRemoteLocked(pid, tid, msg, isJson, timeout);
260     }
261 
262     if (reportStat) {
263         void* retAddr = __builtin_return_address(0);
264         ReportDumpCatcherStats(pid, requestTime, ret, msg, retAddr);
265     }
266 
267     DFXLOGW("dump_catch : pid = %{public}d, elapsed time = %{public}" PRId64 " ms, ret = %{public}d, " \
268         "msgLength = %{public}zu",
269         pid, counter.Elapsed<std::chrono::milliseconds>(), ret, msg.size());
270     DfxEnableTraceDlsym(false);
271     return ret;
272 }
273 
DumpCatchFd(int pid, int tid, std::string& msg, int fd, size_t maxFrameNums)274 bool DfxDumpCatcher::DumpCatchFd(int pid, int tid, std::string& msg, int fd, size_t maxFrameNums)
275 {
276     bool ret = false;
277     ret = DumpCatch(pid, tid, msg, maxFrameNums);
278     if (fd > 0) {
279         ret = OHOS_TEMP_FAILURE_RETRY(write(fd, msg.c_str(), msg.length()));
280     }
281     return ret;
282 }
283 
DoDumpCatchRemote(int pid, int tid, std::string& msg, bool isJson, int timeout)284 bool DfxDumpCatcher::DoDumpCatchRemote(int pid, int tid, std::string& msg, bool isJson, int timeout)
285 {
286     DFX_TRACE_SCOPED_DLSYM("DoDumpCatchRemote");
287     bool ret = false;
288     if (pid <= 0 || tid < 0) {
289         msg.append("Result: pid(" + std::to_string(pid) + ") param error.\n");
290         DFXLOGW("%{public}s :: %{public}s :: %{public}s", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str());
291         return ret;
292     }
293     pid_ = pid;
294     int sdkdumpRet = RequestSdkDumpJson(pid, tid, isJson, timeout);
295     if (sdkdumpRet != static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_PASS)) {
296         if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_REPEAT)) {
297             AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT);
298             msg.append("Result: pid(" + std::to_string(pid) + ") process is dumping.\n");
299         } else if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_REJECT)) {
300             msg.append("Result: pid(" + std::to_string(pid) + ") process check permission error.\n");
301         } else if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_NOPROC)) {
302             msg.append("Result: pid(" + std::to_string(pid) + ") process has exited.\n");
303             RequestDelPipeFd(pid);
304         } else if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_PROCESS_CRASHED)) {
305             msg.append("Result: pid(" + std::to_string(pid) + ") process has been crashed.\n");
306         }
307         DFXLOGW("%{public}s :: %{public}s :: %{public}s", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str());
308         return ret;
309     }
310 
311     int pollRet = DoDumpRemotePid(pid, msg, isJson, timeout);
312     switch (pollRet) {
313         case DUMP_POLL_OK:
314             ret = true;
315             break;
316         case DUMP_POLL_TIMEOUT: {
317             msg.append(halfProcStatus_);
318             msg.append(halfProcWchan_);
319             break;
320         }
321         default:
322             if (g_kernelStackPid != pid) { // maybe not get kernel stack, try again
323                 AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT);
324             }
325             msg.append(halfProcStatus_);
326             msg.append(halfProcWchan_);
327             break;
328     }
329     DFXLOGW("%{public}s :: %{public}s :: pid(%{public}d) ret: %{public}d", DFXDUMPCATCHER_TAG.c_str(),
330         __func__, pid, ret);
331     return ret;
332 }
333 
DoDumpRemotePid(int pid, std::string& msg, bool isJson, int32_t timeout)334 int DfxDumpCatcher::DoDumpRemotePid(int pid, std::string& msg, bool isJson, int32_t timeout)
335 {
336     DFX_TRACE_SCOPED_DLSYM("DoDumpRemotePid");
337     int readBufFd = -1;
338     int readResFd = -1;
339     if (isJson) {
340         readBufFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_JSON_READ_BUF);
341         readResFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_JSON_READ_RES);
342     } else {
343         readBufFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_READ_BUF);
344         readResFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_READ_RES);
345     }
346     DFXLOGD("read res fd: %{public}d", readResFd);
347     int ret = DoDumpRemotePoll(readBufFd, readResFd, timeout, msg, isJson);
348     // request close fds in faultloggerd
349     RequestDelPipeFd(pid);
350     if (readBufFd >= 0) {
351         close(readBufFd);
352         readBufFd = -1;
353     }
354     if (readResFd >= 0) {
355         close(readResFd);
356         readResFd = -1;
357     }
358     DFXLOGI("%{public}s :: %{public}s :: pid(%{public}d) poll ret: %{public}d",
359         DFXDUMPCATCHER_TAG.c_str(), __func__, pid, ret);
360     return ret;
361 }
362 
CollectKernelStack(pid_t pid, int waitMilliSeconds)363 void DfxDumpCatcher::CollectKernelStack(pid_t pid, int waitMilliSeconds)
364 {
365     ElapsedTime timer;
366     std::string kernelStackInfo;
367     auto finishCollect = [waitMilliSeconds]() {
368         if (waitMilliSeconds > 0) {
369             std::unique_lock<std::mutex> lock(g_kernelStackMutex);
370             g_asyncThreadRunning = false;
371             lock.unlock();
372             g_cv.notify_all();
373         } else {
374             g_asyncThreadRunning = false;
375         }
376     };
377     std::string statusPath = StringPrintf("/proc/%d/status", pid);
378     if (access(statusPath.c_str(), F_OK) != 0) {
379         DFXLOGW("No process(%{public}d) status file exist!", pid);
380         finishCollect();
381         return;
382     }
383 
384     std::function<bool(int)> func = [&](int tid) {
385         if (tid <= 0) {
386             return false;
387         }
388         std::string tidKernelStackInfo;
389         if (DfxGetKernelStack(tid, tidKernelStackInfo) == 0) {
390             kernelStackInfo.append(tidKernelStackInfo);
391         }
392         return true;
393     };
394     std::vector<int> tids;
395     bool ret = GetTidsByPidWithFunc(pid, tids, func);
396     if (ret == false) {
397         DFXLOGE("Process(%{public}d) Get Tids fail!", pid);
398         finishCollect();
399         return;
400     }
401     g_kernelStackPid = pid;
402     g_kernelStackInfo = kernelStackInfo;
403     finishCollect();
404     DFXLOGI("finish collect all tid info for pid(%{public}d) time(%{public}" PRId64 ")ms", pid,
405         timer.Elapsed<std::chrono::milliseconds>());
406 }
407 
AsyncGetAllTidKernelStack(pid_t pid, int waitMilliSeconds)408 void DfxDumpCatcher::AsyncGetAllTidKernelStack(pid_t pid, int waitMilliSeconds)
409 {
410     ReadProcessStatus(halfProcStatus_, pid);
411     ReadProcessWchan(halfProcWchan_, pid, false, true);
412     if (g_asyncThreadRunning) {
413         DFXLOGI("pid(%{public}d) get kernel stack thread is running, not get pid(%{public}d)", g_kernelStackPid, pid);
414         return;
415     }
416     g_asyncThreadRunning = true;
417     g_kernelStackPid = 0;
418     g_kernelStackInfo.clear();
419     auto func = [pid, waitMilliSeconds] {
420         CollectKernelStack(pid, waitMilliSeconds);
421     };
422     if (waitMilliSeconds > 0) {
423         std::unique_lock<std::mutex> lock(g_kernelStackMutex);
424         std::thread kernelStackTask(func);
425         kernelStackTask.detach();
426         g_cv.wait_for(lock, std::chrono::milliseconds(WAIT_GET_KERNEL_STACK_TIMEOUT),
427             [] {return !g_asyncThreadRunning;});
428     } else {
429         std::thread kernelStackTask(func);
430         kernelStackTask.detach();
431     }
432 }
433 
DoDumpRemotePoll(int bufFd, int resFd, int timeout, std::string& msg, bool isJson)434 int DfxDumpCatcher::DoDumpRemotePoll(int bufFd, int resFd, int timeout, std::string& msg, bool isJson)
435 {
436     DFX_TRACE_SCOPED_DLSYM("DoDumpRemotePoll");
437     if (bufFd < 0 || resFd < 0) {
438         if (!isJson) {
439             msg = "Result: bufFd or resFd < 0.\n";
440         }
441         DFXLOGE("invalid bufFd or resFd");
442         return DUMP_POLL_FD;
443     }
444     int ret = DUMP_POLL_INIT;
445     std::string resMsg;
446     bool res = false;
447     std::string bufMsg;
448     struct pollfd readfds[2];
449     (void)memset_s(readfds, sizeof(readfds), 0, sizeof(readfds));
450     readfds[0].fd = bufFd;
451     readfds[0].events = POLLIN;
452     readfds[1].fd = resFd;
453     readfds[1].events = POLLIN;
454     int fdsSize = sizeof(readfds) / sizeof(readfds[0]);
455     bool bPipeConnect = false;
456     int remainTime = DUMPCATCHER_REMOTE_P90_TIMEOUT;
457     bool collectAllTidStack = false;
458     uint64_t startTime = GetAbsTimeMilliSeconds();
459     uint64_t endTime = startTime + static_cast<uint64_t>(timeout);
460     while (true) {
461         int pollRet = poll(readfds, fdsSize, remainTime);
462         if (pollRet < 0 && errno == EINTR) {
463             uint64_t now = GetAbsTimeMilliSeconds();
464             if (now >= endTime) {
465                 ret = DUMP_POLL_TIMEOUT;
466                 resMsg.append("Result: poll timeout.\n");
467                 break;
468             }
469             if (!collectAllTidStack && (remainTime == DUMPCATCHER_REMOTE_P90_TIMEOUT)) {
470                 AsyncGetAllTidKernelStack(pid_);
471                 collectAllTidStack = true;
472             }
473             remainTime = static_cast<int>(endTime - now);
474             continue;
475         } else if (pollRet < 0) {
476             ret = DUMP_POLL_FAILED;
477             resMsg.append("Result: poll error, errno(" + std::to_string(errno) + ")\n");
478             break;
479         } else if (pollRet == 0) {
480             if (!collectAllTidStack && (remainTime == DUMPCATCHER_REMOTE_P90_TIMEOUT)) {
481                 AsyncGetAllTidKernelStack(pid_);
482                 remainTime = timeout - DUMPCATCHER_REMOTE_P90_TIMEOUT;
483                 collectAllTidStack = true;
484                 continue;
485             }
486             ret = DUMP_POLL_TIMEOUT;
487             resMsg.append("Result: poll timeout.\n");
488             break;
489         }
490 
491         bool bufRet = true;
492         bool resRet = false;
493         bool eventRet = true;
494         for (int i = 0; i < fdsSize; ++i) {
495             if (!bPipeConnect && ((uint32_t)readfds[i].revents & POLLIN)) {
496                 bPipeConnect = true;
497             }
498             if (bPipeConnect &&
499                 (((uint32_t)readfds[i].revents & POLLERR) || ((uint32_t)readfds[i].revents & POLLHUP))) {
500                 eventRet = false;
501                 resMsg.append("Result: poll events error.\n");
502                 break;
503             }
504 
505             if (((uint32_t)readfds[i].revents & POLLIN) != POLLIN) {
506                 continue;
507             }
508 
509             if (readfds[i].fd == bufFd) {
510                 bufRet = DoReadBuf(bufFd, bufMsg);
511                 continue;
512             }
513 
514             if (readfds[i].fd == resFd) {
515                 resRet = DoReadRes(resFd, res, resMsg);
516             }
517         }
518 
519         if ((eventRet == false) || (bufRet == false) || (resRet == true)) {
520             DFXLOGI("%{public}s :: %{public}s :: eventRet(%{public}d) bufRet: %{public}d resRet: %{public}d",
521                 DFXDUMPCATCHER_TAG.c_str(), __func__, eventRet, bufRet, resRet);
522             ret = DUMP_POLL_RETURN;
523             break;
524         }
525         uint64_t now = GetAbsTimeMilliSeconds();
526         if (now >= endTime) {
527             ret = DUMP_POLL_TIMEOUT;
528             resMsg.append("Result: poll timeout.\n");
529             break;
530         }
531         remainTime = static_cast<int>(endTime - now);
532     }
533 
534     DFXLOGW("%{public}s :: %{public}s :: %{public}s", DFXDUMPCATCHER_TAG.c_str(), __func__, resMsg.c_str());
535     msg = isJson && res ? bufMsg : (resMsg + bufMsg);
536     return res ? DUMP_POLL_OK : ret;
537 }
538 
DoReadBuf(int fd, std::string& msg)539 bool DfxDumpCatcher::DoReadBuf(int fd, std::string& msg)
540 {
541     bool ret = false;
542     char *buffer = new char[MAX_PIPE_SIZE];
543     do {
544         ssize_t nread = OHOS_TEMP_FAILURE_RETRY(read(fd, buffer, MAX_PIPE_SIZE));
545         if (nread <= 0) {
546             DFXLOGW("%{public}s :: %{public}s :: read error", DFXDUMPCATCHER_TAG.c_str(), __func__);
547             break;
548         }
549         DFXLOGD("%{public}s :: %{public}s :: nread: %{public}zu", DFXDUMPCATCHER_TAG.c_str(), __func__, nread);
550         ret = true;
551         msg.append(buffer);
552     } while (false);
553     delete []buffer;
554     return ret;
555 }
556 
DoReadRes(int fd, bool &ret, std::string& msg)557 bool DfxDumpCatcher::DoReadRes(int fd, bool &ret, std::string& msg)
558 {
559     int32_t res = DumpErrorCode::DUMP_ESUCCESS;
560     ssize_t nread = OHOS_TEMP_FAILURE_RETRY(read(fd, &res, sizeof(res)));
561     if (nread <= 0 || nread != sizeof(res)) {
562         DFXLOGW("%{public}s :: %{public}s :: read error", DFXDUMPCATCHER_TAG.c_str(), __func__);
563         return false;
564     }
565     if (res == DumpErrorCode::DUMP_ESUCCESS) {
566         ret = true;
567     }
568     msg.append("Result: " + DfxDumpRes::ToString(res) + "\n");
569     return true;
570 }
571 
DumpCatchMultiPid(const std::vector<int> pidV, std::string& msg)572 bool DfxDumpCatcher::DumpCatchMultiPid(const std::vector<int> pidV, std::string& msg)
573 {
574     bool ret = false;
575     int pidSize = (int)pidV.size();
576     if (pidSize <= 0) {
577         DFXLOGE("%{public}s :: %{public}s :: param error, pidSize(%{public}d).",
578             DFXDUMPCATCHER_TAG.c_str(), __func__, pidSize);
579         return ret;
580     }
581 
582     std::unique_lock<std::mutex> lck(mutex_);
583     int currentPid = getpid();
584     int currentTid = gettid();
585     DFXLOGD("%{public}s :: %{public}s :: cPid(%{public}d), cTid(%{public}d), pidSize(%{public}d).",
586         DFXDUMPCATCHER_TAG.c_str(), \
587         __func__, currentPid, currentTid, pidSize);
588 
589     time_t startTime = time(nullptr);
590     if (startTime > 0) {
591         DFXLOGD("%{public}s :: %{public}s :: startTime(%{public}" PRId64 ").",
592             DFXDUMPCATCHER_TAG.c_str(), __func__, startTime);
593     }
594 
595     for (int i = 0; i < pidSize; i++) {
596         int pid = pidV[i];
597         std::string pidStr;
598         if (DoDumpRemoteLocked(pid, 0, pidStr)) {
599             msg.append(pidStr + "\n");
600         } else {
601             msg.append("Failed to dump process:" + std::to_string(pid));
602         }
603 
604         time_t currentTime = time(nullptr);
605         if (currentTime > 0) {
606             DFXLOGD("%{public}s :: %{public}s :: startTime(%{public}" PRId64 "), currentTime(%{public}" PRId64 ").",
607                 DFXDUMPCATCHER_TAG.c_str(), \
608                 __func__, startTime, currentTime);
609             if (currentTime > startTime + DUMP_CATCHE_WORK_TIME_S) {
610                 break;
611             }
612         }
613     }
614 
615     DFXLOGD("%{public}s :: %{public}s :: msg(%{public}s).", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str());
616     if (msg.find("Tid:") != std::string::npos) {
617         ret = true;
618     }
619     return ret;
620 }
621 } // namespace HiviewDFX
622 } // namespace OHOS
623