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
43namespace OHOS {
44namespace HiviewDFX {
45namespace {
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
55static const int DUMP_CATCHE_WORK_TIME_S = 60;
56static const std::string DFXDUMPCATCHER_TAG = "DfxDumpCatcher";
57static std::string g_kernelStackInfo;
58static std::atomic_bool g_asyncThreadRunning;
59static pid_t g_kernelStackPid = 0;
60static std::condition_variable g_cv;
61static std::mutex g_kernelStackMutex;
62static constexpr int WAIT_GET_KERNEL_STACK_TIMEOUT = 1000; // 1000 : time out 1000 ms
63
64enum 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
73enum DfxDumpStatRes : int32_t {
74    DUMP_RES_NO_KERNELSTACK = -2,
75    DUMP_RES_WITH_KERNELSTACK = -1,
76    DUMP_RES_WITH_USERSTACK = 0,
77};
78}
79
80bool 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
93bool 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
108bool 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
137bool DfxDumpCatcher::DoDumpRemoteLocked(int pid, int tid, std::string& msg, bool isJson, int timeout)
138{
139    return DoDumpCatchRemote(pid, tid, msg, isJson, timeout);
140}
141
142bool 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
162static 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
215int 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
229bool 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
274bool 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
284bool 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
334int 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
363void 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
408void 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
434int 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
539bool 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
557bool 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
572bool 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