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 if (access(statusPath.c_str(), F_OK) != 0 && errno != EACCES) {
264 DFXLOG_ERROR("DumpCatch:: the pid(%d) process has exited, errno(%d)", pid, errno);
265 msg.append("Result: pid(" + std::to_string(pid) + ") process has exited.\n");
266 return ret;
267 }
268 }
269 DfxEnableTraceDlsym(true);
270 ElapsedTime counter;
271 std::unique_lock<std::mutex> lck(mutex_);
272 int currentPid = getprocpid();
273 bool reportStat = false;
274 uint64_t requestTime = GetTimeMilliSeconds();
275 DFXLOG_INFO("Receive DumpCatch request for cPid:(%d), pid(%d), tid:(%d).", currentPid, pid, tid);
276 if (pid == currentPid) {
277 ret = DoDumpLocalLocked(pid, tid, msg, maxFrameNums);
278 } else {
279 if (maxFrameNums != DEFAULT_MAX_FRAME_NUM) {
280 DFXLOG_INFO("%s :: dump_catch :: maxFrameNums does not support setting when pid is not equal to caller pid",
281 DFXDUMPCATCHER_TAG.c_str());
282 }
283 reportStat = true;
284 int timeout = (tid == 0 ? 3 : 10) * 1000; // when tid not zero, timeout is 10s
285 ret = DoDumpRemoteLocked(pid, tid, msg, isJson, timeout);
286 }
287
288 if (reportStat) {
289 void* retAddr = __builtin_return_address(0);
290 ReportDumpCatcherStats(pid, requestTime, ret, msg, retAddr);
291 }
292
293 DFXLOG_INFO("dump_catch : pid = %d, elapsed time = %ld ms, ret = %d, msgLength = %zu",
294 pid, counter.Elapsed<std::chrono::milliseconds>(), ret, msg.size());
295 DfxEnableTraceDlsym(false);
296 return ret;
297 }
298
DumpCatchFd(int pid,int tid,std::string & msg,int fd,size_t maxFrameNums)299 bool DfxDumpCatcher::DumpCatchFd(int pid, int tid, std::string& msg, int fd, size_t maxFrameNums)
300 {
301 bool ret = false;
302 ret = DumpCatch(pid, tid, msg, maxFrameNums);
303 if (fd > 0) {
304 ret = OHOS_TEMP_FAILURE_RETRY(write(fd, msg.c_str(), msg.length()));
305 }
306 return ret;
307 }
308
DoDumpCatchRemote(int pid,int tid,std::string & msg,bool isJson,int timeout)309 bool DfxDumpCatcher::DoDumpCatchRemote(int pid, int tid, std::string& msg, bool isJson, int timeout)
310 {
311 DFX_TRACE_SCOPED_DLSYM("DoDumpCatchRemote");
312 bool ret = false;
313 if (pid <= 0 || tid < 0) {
314 msg.append("Result: pid(" + std::to_string(pid) + ") param error.\n");
315 DFXLOG_WARN("%s :: %s :: %s", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str());
316 return ret;
317 }
318 pid_ = pid;
319 int sdkdumpRet = RequestSdkDumpJson(pid, tid, isJson, timeout);
320 if (sdkdumpRet != static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_PASS)) {
321 if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_REPEAT)) {
322 AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT);
323 msg.append("Result: pid(" + std::to_string(pid) + ") process is dumping.\n");
324 } else if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_REJECT)) {
325 msg.append("Result: pid(" + std::to_string(pid) + ") process check permission error.\n");
326 } else if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_NOPROC)) {
327 msg.append("Result: pid(" + std::to_string(pid) + ") process has exited.\n");
328 RequestDelPipeFd(pid);
329 } else if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_PROCESS_CRASHED)) {
330 msg.append("Result: pid(" + std::to_string(pid) + ") process has been crashed.\n");
331 }
332 DFXLOG_WARN("%s :: %s :: %s", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str());
333 return ret;
334 }
335
336 int pollRet = DoDumpRemotePid(pid, msg, isJson, timeout);
337 switch (pollRet) {
338 case DUMP_POLL_OK:
339 ret = true;
340 break;
341 case DUMP_POLL_TIMEOUT: {
342 msg.append(halfProcStatus_);
343 msg.append(halfProcWchan_);
344 break;
345 }
346 default:
347 if (g_kernelStackPid != pid) { // maybe not get kernel stack, try again
348 AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT);
349 }
350 msg.append(halfProcStatus_);
351 msg.append(halfProcWchan_);
352 break;
353 }
354 DFXLOG_INFO("%s :: %s :: pid(%d) ret: %d", DFXDUMPCATCHER_TAG.c_str(), __func__, pid, ret);
355 return ret;
356 }
357
DoDumpRemotePid(int pid,std::string & msg,bool isJson,int32_t timeout)358 int DfxDumpCatcher::DoDumpRemotePid(int pid, std::string& msg, bool isJson, int32_t timeout)
359 {
360 DFX_TRACE_SCOPED_DLSYM("DoDumpRemotePid");
361 int readBufFd = -1;
362 int readResFd = -1;
363 if (isJson) {
364 readBufFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_JSON_READ_BUF);
365 readResFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_JSON_READ_RES);
366 } else {
367 readBufFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_READ_BUF);
368 readResFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_READ_RES);
369 }
370 DFXLOG_DEBUG("read res fd: %d", readResFd);
371 int ret = DoDumpRemotePoll(readBufFd, readResFd, timeout, msg, isJson);
372 // request close fds in faultloggerd
373 RequestDelPipeFd(pid);
374 if (readBufFd >= 0) {
375 close(readBufFd);
376 readBufFd = -1;
377 }
378 if (readResFd >= 0) {
379 close(readResFd);
380 readResFd = -1;
381 }
382 DFXLOG_INFO("%s :: %s :: pid(%d) poll ret: %d", DFXDUMPCATCHER_TAG.c_str(), __func__, pid, ret);
383 return ret;
384 }
385
CollectKernelStack(pid_t pid,int waitMilliSeconds)386 void DfxDumpCatcher::CollectKernelStack(pid_t pid, int waitMilliSeconds)
387 {
388 ElapsedTime timer;
389 std::string kernelStackInfo;
390 auto finishCollect = [waitMilliSeconds]() {
391 if (waitMilliSeconds > 0) {
392 std::unique_lock<std::mutex> lock(g_kernelStackMutex);
393 g_asyncThreadRunning = false;
394 lock.unlock();
395 g_cv.notify_all();
396 } else {
397 g_asyncThreadRunning = false;
398 }
399 };
400 std::string statusPath = StringPrintf("/proc/%d/status", pid);
401 if (access(statusPath.c_str(), F_OK) != 0) {
402 DFXLOG_WARN("No process(%d) status file exist!", pid);
403 finishCollect();
404 return;
405 }
406 std::vector<int> tids = {};
407 std::vector<int> nstids = {};
408 if (GetTidsByPid(pid, tids, nstids) == false) {
409 DFXLOG_ERROR("Process(%d) Get Tids fail!", pid);
410 finishCollect();
411 return;
412 }
413 g_kernelStackPid = pid;
414 for (int tid : tids) {
415 std::string tidKernelStackInfo;
416 if (DfxGetKernelStack(tid, tidKernelStackInfo) == 0) {
417 kernelStackInfo.append(tidKernelStackInfo);
418 }
419 }
420 DFXLOG_INFO("finish collect all tid info for pid(%d) time(%lld)ms", pid,
421 timer.Elapsed<std::chrono::milliseconds>());
422 g_kernelStackInfo = kernelStackInfo;
423 finishCollect();
424 }
425
AsyncGetAllTidKernelStack(pid_t pid,int waitMilliSeconds)426 void DfxDumpCatcher::AsyncGetAllTidKernelStack(pid_t pid, int waitMilliSeconds)
427 {
428 ReadProcessStatus(halfProcStatus_, pid);
429 ReadProcessWchan(halfProcWchan_, pid, false, true);
430 if (g_asyncThreadRunning) {
431 DFXLOG_INFO("pid(%d) get kernel stack thread is running, not get pid(%d)", g_kernelStackPid, pid);
432 return;
433 }
434 g_asyncThreadRunning = true;
435 g_kernelStackPid = 0;
436 g_kernelStackInfo.clear();
437 auto func = [pid, waitMilliSeconds] {
438 CollectKernelStack(pid, waitMilliSeconds);
439 };
440 if (waitMilliSeconds > 0) {
441 std::unique_lock<std::mutex> lock(g_kernelStackMutex);
442 std::thread kernelStackTask(func);
443 kernelStackTask.detach();
444 g_cv.wait_for(lock, std::chrono::milliseconds(WAIT_GET_KERNEL_STACK_TIMEOUT),
445 [] {return !g_asyncThreadRunning;});
446 } else {
447 std::thread kernelStackTask(func);
448 kernelStackTask.detach();
449 }
450 }
451
DoDumpRemotePoll(int bufFd,int resFd,int timeout,std::string & msg,bool isJson)452 int DfxDumpCatcher::DoDumpRemotePoll(int bufFd, int resFd, int timeout, std::string& msg, bool isJson)
453 {
454 DFX_TRACE_SCOPED_DLSYM("DoDumpRemotePoll");
455 if (bufFd < 0 || resFd < 0) {
456 if (!isJson) {
457 msg = "Result: bufFd or resFd < 0.\n";
458 }
459 DFXLOG_ERROR("%s", "invalid bufFd or resFd");
460 return DUMP_POLL_FD;
461 }
462 int ret = DUMP_POLL_INIT;
463 std::string resMsg;
464 bool res = false;
465 std::string bufMsg;
466 struct pollfd readfds[2];
467 (void)memset_s(readfds, sizeof(readfds), 0, sizeof(readfds));
468 readfds[0].fd = bufFd;
469 readfds[0].events = POLLIN;
470 readfds[1].fd = resFd;
471 readfds[1].events = POLLIN;
472 int fdsSize = sizeof(readfds) / sizeof(readfds[0]);
473 bool bPipeConnect = false;
474 int remainTime = DUMPCATCHER_REMOTE_P90_TIMEOUT;
475 bool collectAllTidStack = false;
476 uint64_t startTime = GetAbsTimeMilliSeconds();
477 uint64_t endTime = startTime + static_cast<uint64_t>(timeout);
478 while (true) {
479 int pollRet = poll(readfds, fdsSize, remainTime);
480 if (pollRet < 0 && errno == EINTR) {
481 uint64_t now = GetAbsTimeMilliSeconds();
482 if (now >= endTime) {
483 ret = DUMP_POLL_TIMEOUT;
484 resMsg.append("Result: poll timeout.\n");
485 break;
486 }
487 if (!collectAllTidStack && (remainTime == DUMPCATCHER_REMOTE_P90_TIMEOUT)) {
488 AsyncGetAllTidKernelStack(pid_);
489 collectAllTidStack = true;
490 }
491 remainTime = static_cast<int>(endTime - now);
492 continue;
493 } else if (pollRet < 0) {
494 ret = DUMP_POLL_FAILED;
495 resMsg.append("Result: poll error, errno(" + std::to_string(errno) + ")\n");
496 break;
497 } else if (pollRet == 0) {
498 if (!collectAllTidStack && (remainTime == DUMPCATCHER_REMOTE_P90_TIMEOUT)) {
499 AsyncGetAllTidKernelStack(pid_);
500 remainTime = timeout - DUMPCATCHER_REMOTE_P90_TIMEOUT;
501 collectAllTidStack = true;
502 continue;
503 }
504 ret = DUMP_POLL_TIMEOUT;
505 resMsg.append("Result: poll timeout.\n");
506 break;
507 }
508
509 bool bufRet = true;
510 bool resRet = false;
511 bool eventRet = true;
512 for (int i = 0; i < fdsSize; ++i) {
513 if (!bPipeConnect && ((uint32_t)readfds[i].revents & POLLIN)) {
514 bPipeConnect = true;
515 }
516 if (bPipeConnect &&
517 (((uint32_t)readfds[i].revents & POLLERR) || ((uint32_t)readfds[i].revents & POLLHUP))) {
518 eventRet = false;
519 resMsg.append("Result: poll events error.\n");
520 break;
521 }
522
523 if (((uint32_t)readfds[i].revents & POLLIN) != POLLIN) {
524 continue;
525 }
526
527 if (readfds[i].fd == bufFd) {
528 bufRet = DoReadBuf(bufFd, bufMsg);
529 continue;
530 }
531
532 if (readfds[i].fd == resFd) {
533 resRet = DoReadRes(resFd, res, resMsg);
534 }
535 }
536
537 if ((eventRet == false) || (bufRet == false) || (resRet == true)) {
538 DFXLOG_INFO("%s :: %s :: eventRet(%d) bufRet: %d resRet: %d", DFXDUMPCATCHER_TAG.c_str(), __func__,
539 eventRet, bufRet, resRet);
540 ret = DUMP_POLL_RETURN;
541 break;
542 }
543 uint64_t now = GetAbsTimeMilliSeconds();
544 if (now >= endTime) {
545 ret = DUMP_POLL_TIMEOUT;
546 resMsg.append("Result: poll timeout.\n");
547 break;
548 }
549 remainTime = static_cast<int>(endTime - now);
550 }
551
552 DFXLOG_INFO("%s :: %s :: %s", DFXDUMPCATCHER_TAG.c_str(), __func__, resMsg.c_str());
553 msg = isJson && res ? bufMsg : (resMsg + bufMsg);
554 return res ? DUMP_POLL_OK : ret;
555 }
556
DoReadBuf(int fd,std::string & msg)557 bool DfxDumpCatcher::DoReadBuf(int fd, std::string& msg)
558 {
559 bool ret = false;
560 char *buffer = new char[MAX_PIPE_SIZE];
561 do {
562 ssize_t nread = OHOS_TEMP_FAILURE_RETRY(read(fd, buffer, MAX_PIPE_SIZE));
563 if (nread <= 0) {
564 DFXLOG_WARN("%s :: %s :: read error", DFXDUMPCATCHER_TAG.c_str(), __func__);
565 break;
566 }
567 DFXLOG_DEBUG("%s :: %s :: nread: %zu", DFXDUMPCATCHER_TAG.c_str(), __func__, nread);
568 ret = true;
569 msg.append(buffer);
570 } while (false);
571 delete []buffer;
572 return ret;
573 }
574
DoReadRes(int fd,bool & ret,std::string & msg)575 bool DfxDumpCatcher::DoReadRes(int fd, bool &ret, std::string& msg)
576 {
577 int32_t res = DumpErrorCode::DUMP_ESUCCESS;
578 ssize_t nread = OHOS_TEMP_FAILURE_RETRY(read(fd, &res, sizeof(res)));
579 if (nread <= 0 || nread != sizeof(res)) {
580 DFXLOG_WARN("%s :: %s :: read error", DFXDUMPCATCHER_TAG.c_str(), __func__);
581 return false;
582 }
583 if (res == DumpErrorCode::DUMP_ESUCCESS) {
584 ret = true;
585 }
586 msg.append("Result: " + DfxDumpRes::ToString(res) + "\n");
587 return true;
588 }
589
DumpCatchMultiPid(const std::vector<int> pidV,std::string & msg)590 bool DfxDumpCatcher::DumpCatchMultiPid(const std::vector<int> pidV, std::string& msg)
591 {
592 bool ret = false;
593 int pidSize = (int)pidV.size();
594 if (pidSize <= 0) {
595 DFXLOG_ERROR("%s :: %s :: param error, pidSize(%d).", DFXDUMPCATCHER_TAG.c_str(), __func__, pidSize);
596 return ret;
597 }
598
599 std::unique_lock<std::mutex> lck(mutex_);
600 #if defined(is_ohos) && is_ohos
601 int currentPid = getprocpid();
602 int currentTid = getproctid();
603 #else
604 int currentPid = getpid();
605 int currentTid = gettid();
606 #endif
607 DFXLOG_DEBUG("%s :: %s :: cPid(%d), cTid(%d), pidSize(%d).", DFXDUMPCATCHER_TAG.c_str(), \
608 __func__, currentPid, currentTid, pidSize);
609
610 time_t startTime = time(nullptr);
611 if (startTime > 0) {
612 DFXLOG_DEBUG("%s :: %s :: startTime(%" PRId64 ").", DFXDUMPCATCHER_TAG.c_str(), __func__, startTime);
613 }
614
615 for (int i = 0; i < pidSize; i++) {
616 int pid = pidV[i];
617 std::string pidStr;
618 if (DoDumpRemoteLocked(pid, 0, pidStr)) {
619 msg.append(pidStr + "\n");
620 } else {
621 msg.append("Failed to dump process:" + std::to_string(pid));
622 }
623
624 time_t currentTime = time(nullptr);
625 if (currentTime > 0) {
626 DFXLOG_DEBUG("%s :: %s :: startTime(%" PRId64 "), currentTime(%" PRId64 ").", DFXDUMPCATCHER_TAG.c_str(), \
627 __func__, startTime, currentTime);
628 if (currentTime > startTime + DUMP_CATCHE_WORK_TIME_S) {
629 break;
630 }
631 }
632 }
633
634 DFXLOG_DEBUG("%s :: %s :: msg(%s).", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str());
635 if (msg.find("Tid:") != std::string::npos) {
636 ret = true;
637 }
638 return ret;
639 }
640 } // namespace HiviewDFX
641 } // namespace OHOS
642