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