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