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 = getproctid();
87 msg.append("Failed to dump curr thread:" + std::to_string(currTid) + ".\n");
88 }
89 DFXLOG_DEBUG("%s :: DoDumpCurrTid :: return %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 DFXLOG_ERROR("%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 DFXLOG_DEBUG("%s :: DoDumpLocalTid :: return %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 DFXLOG_ERROR("%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 == getproctid()) {
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 #if defined(is_ohos) && is_ohos
133 ret = GetTidsByPidWithFunc(getprocpid(), tids, func);
134 #else
135 ret = GetTidsByPidWithFunc(getpid(), tids, func);
136 #endif
137 DFXLOG_DEBUG("%s :: DoDumpLocalPid :: return %d.", DFXDUMPCATCHER_TAG.c_str(), ret);
138 return ret;
139 }
140
DoDumpRemoteLocked(int pid,int tid,std::string & msg,bool isJson,int timeout)141 bool DfxDumpCatcher::DoDumpRemoteLocked(int pid, int tid, std::string& msg, bool isJson, int timeout)
142 {
143 return DoDumpCatchRemote(pid, tid, msg, isJson, timeout);
144 }
145
DoDumpLocalLocked(int pid,int tid,std::string & msg,size_t maxFrameNums)146 bool DfxDumpCatcher::DoDumpLocalLocked(int pid, int tid, std::string& msg, size_t maxFrameNums)
147 {
148 bool ret = false;
149 if (tid == getproctid()) {
150 size_t skipFramNum = 4; // 4: skip 4 frame
151 ret = DoDumpCurrTid(skipFramNum, msg, maxFrameNums);
152 } else if (tid == 0) {
153 ret = DoDumpLocalPid(pid, msg, maxFrameNums);
154 } else {
155 if (!IsThreadInPid(pid, tid)) {
156 msg.append("tid(" + std::to_string(tid) + ") is not in pid(" + std::to_string(pid) + ").\n");
157 } else {
158 ret = DoDumpLocalTid(tid, msg, maxFrameNums);
159 }
160 }
161
162 DFXLOG_DEBUG("%s :: DoDumpLocal :: ret(%d).", DFXDUMPCATCHER_TAG.c_str(), ret);
163 return ret;
164 }
165
DumpCatchMix(int pid,int tid,std::string & msg)166 bool DfxDumpCatcher::DumpCatchMix(int pid, int tid, std::string& msg)
167 {
168 return DoDumpCatchRemote(pid, tid, msg);
169 }
170
ReportDumpCatcherStats(int32_t pid,uint64_t requestTime,bool ret,std::string & msg,void * retAddr)171 static void ReportDumpCatcherStats(int32_t pid,
172 uint64_t requestTime, bool ret, std::string& msg, void* retAddr)
173 {
174 std::vector<uint8_t> buf(sizeof(struct FaultLoggerdStatsRequest), 0);
175 auto stat = reinterpret_cast<struct FaultLoggerdStatsRequest*>(buf.data());
176 stat->type = DUMP_CATCHER;
177 stat->pid = pid;
178 stat->requestTime = requestTime;
179 stat->dumpCatcherFinishTime = GetTimeMilliSeconds();
180 stat->result = ret ? DUMP_RES_WITH_USERSTACK : DUMP_RES_WITH_KERNELSTACK; // we need more detailed failure info
181 if (!ret && g_kernelStackInfo.empty()) {
182 stat->result = DUMP_RES_NO_KERNELSTACK;
183 }
184 size_t copyLen;
185 std::string processName;
186 ReadProcessName(pid, processName);
187 copyLen = std::min(sizeof(stat->targetProcess) - 1, processName.size());
188 if (memcpy_s(stat->targetProcess, sizeof(stat->targetProcess) - 1, processName.c_str(), copyLen) != 0) {
189 DFXLOG_ERROR("%s::Failed to copy target process", DFXDUMPCATCHER_TAG.c_str());
190 return;
191 }
192
193 if (!ret) {
194 copyLen = std::min(sizeof(stat->summary) - 1, msg.size());
195 if (memcpy_s(stat->summary, sizeof(stat->summary) - 1, msg.c_str(), copyLen) != 0) {
196 DFXLOG_ERROR("%s::Failed to copy dumpcatcher summary", DFXDUMPCATCHER_TAG.c_str());
197 return;
198 }
199 }
200
201 Dl_info info;
202 if (dladdr(retAddr, &info) != 0) {
203 copyLen = std::min(sizeof(stat->callerElf) - 1, strlen(info.dli_fname));
204 if (memcpy_s(stat->callerElf, sizeof(stat->callerElf) - 1, info.dli_fname, copyLen) != 0) {
205 DFXLOG_ERROR("%s::Failed to copy caller elf info", DFXDUMPCATCHER_TAG.c_str());
206 return;
207 }
208 stat->offset = reinterpret_cast<uintptr_t>(retAddr) - reinterpret_cast<uintptr_t>(info.dli_fbase);
209 }
210
211 std::string cmdline;
212 if (OHOS::LoadStringFromFile("/proc/self/cmdline", cmdline)) {
213 copyLen = std::min(sizeof(stat->callerProcess) - 1, cmdline.size());
214 if (memcpy_s(stat->callerProcess, sizeof(stat->callerProcess) - 1,
215 cmdline.c_str(), copyLen) != 0) {
216 DFXLOG_ERROR("%s::Failed to copy caller cmdline", DFXDUMPCATCHER_TAG.c_str());
217 return;
218 }
219 }
220
221 ReportDumpStats(stat);
222 }
223
DumpCatchProcess(int pid,std::string & msg,size_t maxFrameNums,bool isJson)224 int DfxDumpCatcher::DumpCatchProcess(int pid, std::string& msg, size_t maxFrameNums, bool isJson)
225 {
226 if (DumpCatch(pid, 0, msg, maxFrameNums, isJson)) {
227 return 0;
228 }
229 if (pid == g_kernelStackPid && !g_asyncThreadRunning) {
230 msg.append(g_kernelStackInfo);
231 g_kernelStackInfo.clear();
232 g_kernelStackPid = 0;
233 return 1;
234 }
235 return -1;
236 }
237
DumpCatch(int pid,int tid,std::string & msg,size_t maxFrameNums,bool isJson)238 bool DfxDumpCatcher::DumpCatch(int pid, int tid, std::string& msg, size_t maxFrameNums, bool isJson)
239 {
240 bool ret = false;
241 if (pid <= 0 || tid < 0) {
242 DFXLOG_ERROR("%s :: dump_catch :: param error.", DFXDUMPCATCHER_TAG.c_str());
243 return ret;
244 }
245 std::string statusPath = StringPrintf("/proc/%d/status", pid);
246 if (access(statusPath.c_str(), F_OK) != 0 && errno != EACCES) {
247 DFXLOG_ERROR("DumpCatch:: the pid(%d) process has exited, errno(%d)", pid, errno);
248 msg.append("Result: pid(" + std::to_string(pid) + ") process has exited.\n");
249 return ret;
250 }
251 DfxEnableTraceDlsym(true);
252 ElapsedTime counter;
253 std::unique_lock<std::mutex> lck(mutex_);
254 int currentPid = getprocpid();
255 bool reportStat = false;
256 uint64_t requestTime = GetTimeMilliSeconds();
257 DFXLOG_INFO("Receive DumpCatch request for cPid:(%d), pid(%d), tid:(%d).", currentPid, pid, tid);
258 if (pid == currentPid) {
259 ret = DoDumpLocalLocked(pid, tid, msg, maxFrameNums);
260 } else {
261 if (maxFrameNums != DEFAULT_MAX_FRAME_NUM) {
262 DFXLOG_INFO("%s :: dump_catch :: maxFrameNums does not support setting when pid is not equal to caller pid",
263 DFXDUMPCATCHER_TAG.c_str());
264 }
265 reportStat = true;
266 int timeout = (tid == 0 ? 3 : 10) * 1000; // when tid not zero, timeout is 10s
267 ret = DoDumpRemoteLocked(pid, tid, msg, isJson, timeout);
268 }
269
270 if (reportStat) {
271 void* retAddr = __builtin_return_address(0);
272 ReportDumpCatcherStats(pid, requestTime, ret, msg, retAddr);
273 }
274
275 DFXLOG_INFO("dump_catch : pid = %d, elapsed time = %ld ms, ret = %d, msgLength = %zu",
276 pid, counter.Elapsed<std::chrono::milliseconds>(), ret, msg.size());
277 DfxEnableTraceDlsym(false);
278 return ret;
279 }
280
DumpCatchFd(int pid,int tid,std::string & msg,int fd,size_t maxFrameNums)281 bool DfxDumpCatcher::DumpCatchFd(int pid, int tid, std::string& msg, int fd, size_t maxFrameNums)
282 {
283 bool ret = false;
284 ret = DumpCatch(pid, tid, msg, maxFrameNums);
285 if (fd > 0) {
286 ret = OHOS_TEMP_FAILURE_RETRY(write(fd, msg.c_str(), msg.length()));
287 }
288 return ret;
289 }
290
DoDumpCatchRemote(int pid,int tid,std::string & msg,bool isJson,int timeout)291 bool DfxDumpCatcher::DoDumpCatchRemote(int pid, int tid, std::string& msg, bool isJson, int timeout)
292 {
293 DFX_TRACE_SCOPED_DLSYM("DoDumpCatchRemote");
294 bool ret = false;
295 if (pid <= 0 || tid < 0) {
296 msg.append("Result: pid(" + std::to_string(pid) + ") param error.\n");
297 DFXLOG_WARN("%s :: %s :: %s", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str());
298 return ret;
299 }
300 pid_ = pid;
301 int sdkdumpRet = RequestSdkDumpJson(pid, tid, isJson, timeout);
302 if (sdkdumpRet != static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_PASS)) {
303 if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_REPEAT)) {
304 AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT);
305 msg.append("Result: pid(" + std::to_string(pid) + ") process is dumping.\n");
306 } else if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_REJECT)) {
307 msg.append("Result: pid(" + std::to_string(pid) + ") process check permission error.\n");
308 } else if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_NOPROC)) {
309 msg.append("Result: pid(" + std::to_string(pid) + ") process has exited.\n");
310 RequestDelPipeFd(pid);
311 } else if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_PROCESS_CRASHED)) {
312 msg.append("Result: pid(" + std::to_string(pid) + ") process has been crashed.\n");
313 }
314 DFXLOG_WARN("%s :: %s :: %s", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str());
315 return ret;
316 }
317
318 int pollRet = DoDumpRemotePid(pid, msg, isJson, timeout);
319 switch (pollRet) {
320 case DUMP_POLL_OK:
321 ret = true;
322 break;
323 case DUMP_POLL_TIMEOUT: {
324 msg.append(halfProcStatus_);
325 msg.append(halfProcWchan_);
326 break;
327 }
328 default:
329 if (g_kernelStackPid != pid) { // maybe not get kernel stack, try again
330 AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT);
331 }
332 msg.append(halfProcStatus_);
333 msg.append(halfProcWchan_);
334 break;
335 }
336 DFXLOG_INFO("%s :: %s :: pid(%d) ret: %d", DFXDUMPCATCHER_TAG.c_str(), __func__, pid, ret);
337 return ret;
338 }
339
DoDumpRemotePid(int pid,std::string & msg,bool isJson,int32_t timeout)340 int DfxDumpCatcher::DoDumpRemotePid(int pid, std::string& msg, bool isJson, int32_t timeout)
341 {
342 DFX_TRACE_SCOPED_DLSYM("DoDumpRemotePid");
343 int readBufFd = -1;
344 int readResFd = -1;
345 if (isJson) {
346 readBufFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_JSON_READ_BUF);
347 readResFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_JSON_READ_RES);
348 } else {
349 readBufFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_READ_BUF);
350 readResFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_READ_RES);
351 }
352 DFXLOG_DEBUG("read res fd: %d", readResFd);
353 int ret = DoDumpRemotePoll(readBufFd, readResFd, timeout, msg, isJson);
354 // request close fds in faultloggerd
355 RequestDelPipeFd(pid);
356 if (readBufFd >= 0) {
357 close(readBufFd);
358 readBufFd = -1;
359 }
360 if (readResFd >= 0) {
361 close(readResFd);
362 readResFd = -1;
363 }
364 DFXLOG_INFO("%s :: %s :: pid(%d) poll ret: %d", DFXDUMPCATCHER_TAG.c_str(), __func__, pid, ret);
365 return ret;
366 }
367
CollectKernelStack(pid_t pid,int waitMilliSeconds)368 void DfxDumpCatcher::CollectKernelStack(pid_t pid, int waitMilliSeconds)
369 {
370 ElapsedTime timer;
371 std::string kernelStackInfo;
372 auto finishCollect = [waitMilliSeconds]() {
373 if (waitMilliSeconds > 0) {
374 std::unique_lock<std::mutex> lock(g_kernelStackMutex);
375 g_asyncThreadRunning = false;
376 lock.unlock();
377 g_cv.notify_all();
378 } else {
379 g_asyncThreadRunning = false;
380 }
381 };
382 std::string statusPath = StringPrintf("/proc/%d/status", pid);
383 if (access(statusPath.c_str(), F_OK) != 0) {
384 DFXLOG_WARN("No process(%d) status file exist!", pid);
385 finishCollect();
386 return;
387 }
388 std::vector<int> tids = {};
389 std::vector<int> nstids = {};
390 if (GetTidsByPid(pid, tids, nstids) == false) {
391 DFXLOG_ERROR("Process(%d) Get Tids fail!", pid);
392 finishCollect();
393 return;
394 }
395 g_kernelStackPid = pid;
396 for (int tid : tids) {
397 std::string tidKernelStackInfo;
398 if (DfxGetKernelStack(tid, tidKernelStackInfo) == 0) {
399 kernelStackInfo.append(tidKernelStackInfo);
400 }
401 }
402 DFXLOG_INFO("finish collect all tid info for pid(%d) time(%lld)ms", pid,
403 timer.Elapsed<std::chrono::milliseconds>());
404 g_kernelStackInfo = kernelStackInfo;
405 finishCollect();
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 DFXLOG_INFO("pid(%d) get kernel stack thread is running, not get pid(%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 DFXLOG_ERROR("%s", "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 DFXLOG_INFO("%s :: %s :: eventRet(%d) bufRet: %d resRet: %d", DFXDUMPCATCHER_TAG.c_str(), __func__,
521 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 DFXLOG_INFO("%s :: %s :: %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 DFXLOG_WARN("%s :: %s :: read error", DFXDUMPCATCHER_TAG.c_str(), __func__);
547 break;
548 }
549 DFXLOG_DEBUG("%s :: %s :: nread: %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 DFXLOG_WARN("%s :: %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 DFXLOG_ERROR("%s :: %s :: param error, pidSize(%d).", DFXDUMPCATCHER_TAG.c_str(), __func__, pidSize);
578 return ret;
579 }
580
581 std::unique_lock<std::mutex> lck(mutex_);
582 #if defined(is_ohos) && is_ohos
583 int currentPid = getprocpid();
584 int currentTid = getproctid();
585 #else
586 int currentPid = getpid();
587 int currentTid = gettid();
588 #endif
589 DFXLOG_DEBUG("%s :: %s :: cPid(%d), cTid(%d), pidSize(%d).", DFXDUMPCATCHER_TAG.c_str(), \
590 __func__, currentPid, currentTid, pidSize);
591
592 time_t startTime = time(nullptr);
593 if (startTime > 0) {
594 DFXLOG_DEBUG("%s :: %s :: startTime(%" PRId64 ").", DFXDUMPCATCHER_TAG.c_str(), __func__, startTime);
595 }
596
597 for (int i = 0; i < pidSize; i++) {
598 int pid = pidV[i];
599 std::string pidStr;
600 if (DoDumpRemoteLocked(pid, 0, pidStr)) {
601 msg.append(pidStr + "\n");
602 } else {
603 msg.append("Failed to dump process:" + std::to_string(pid));
604 }
605
606 time_t currentTime = time(nullptr);
607 if (currentTime > 0) {
608 DFXLOG_DEBUG("%s :: %s :: startTime(%" PRId64 "), currentTime(%" PRId64 ").", DFXDUMPCATCHER_TAG.c_str(), \
609 __func__, startTime, currentTime);
610 if (currentTime > startTime + DUMP_CATCHE_WORK_TIME_S) {
611 break;
612 }
613 }
614 }
615
616 DFXLOG_DEBUG("%s :: %s :: msg(%s).", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str());
617 if (msg.find("Tid:") != std::string::npos) {
618 ret = true;
619 }
620 return ret;
621 }
622 } // namespace HiviewDFX
623 } // namespace OHOS
624