1800b99b8Sopenharmony_ci/* 2800b99b8Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License. 5800b99b8Sopenharmony_ci * You may obtain a copy of the License at 6800b99b8Sopenharmony_ci * 7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8800b99b8Sopenharmony_ci * 9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and 13800b99b8Sopenharmony_ci * limitations under the License. 14800b99b8Sopenharmony_ci */ 15800b99b8Sopenharmony_ci 16800b99b8Sopenharmony_ci#include "dfx_dump_catcher.h" 17800b99b8Sopenharmony_ci 18800b99b8Sopenharmony_ci#include <atomic> 19800b99b8Sopenharmony_ci#include <cerrno> 20800b99b8Sopenharmony_ci#include <memory> 21800b99b8Sopenharmony_ci#include <thread> 22800b99b8Sopenharmony_ci#include <vector> 23800b99b8Sopenharmony_ci 24800b99b8Sopenharmony_ci#include <dlfcn.h> 25800b99b8Sopenharmony_ci#include <poll.h> 26800b99b8Sopenharmony_ci#include <sys/syscall.h> 27800b99b8Sopenharmony_ci#include <sys/types.h> 28800b99b8Sopenharmony_ci#include <securec.h> 29800b99b8Sopenharmony_ci#include <strings.h> 30800b99b8Sopenharmony_ci 31800b99b8Sopenharmony_ci#include "backtrace_local.h" 32800b99b8Sopenharmony_ci#include "dfx_define.h" 33800b99b8Sopenharmony_ci#include "dfx_dump_res.h" 34800b99b8Sopenharmony_ci#include "dfx_kernel_stack.h" 35800b99b8Sopenharmony_ci#include "dfx_log.h" 36800b99b8Sopenharmony_ci#include "dfx_trace_dlsym.h" 37800b99b8Sopenharmony_ci#include "dfx_util.h" 38800b99b8Sopenharmony_ci#include "elapsed_time.h" 39800b99b8Sopenharmony_ci#include "faultloggerd_client.h" 40800b99b8Sopenharmony_ci#include "file_ex.h" 41800b99b8Sopenharmony_ci#include "procinfo.h" 42800b99b8Sopenharmony_ci 43800b99b8Sopenharmony_cinamespace OHOS { 44800b99b8Sopenharmony_cinamespace HiviewDFX { 45800b99b8Sopenharmony_cinamespace { 46800b99b8Sopenharmony_ci#ifdef LOG_DOMAIN 47800b99b8Sopenharmony_ci#undef LOG_DOMAIN 48800b99b8Sopenharmony_ci#define LOG_DOMAIN 0xD002D11 49800b99b8Sopenharmony_ci#endif 50800b99b8Sopenharmony_ci 51800b99b8Sopenharmony_ci#ifdef LOG_TAG 52800b99b8Sopenharmony_ci#undef LOG_TAG 53800b99b8Sopenharmony_ci#define LOG_TAG "DfxDumpCatcher" 54800b99b8Sopenharmony_ci#endif 55800b99b8Sopenharmony_cistatic const int DUMP_CATCHE_WORK_TIME_S = 60; 56800b99b8Sopenharmony_cistatic const std::string DFXDUMPCATCHER_TAG = "DfxDumpCatcher"; 57800b99b8Sopenharmony_cistatic std::string g_kernelStackInfo; 58800b99b8Sopenharmony_cistatic std::atomic_bool g_asyncThreadRunning; 59800b99b8Sopenharmony_cistatic pid_t g_kernelStackPid = 0; 60800b99b8Sopenharmony_cistatic std::condition_variable g_cv; 61800b99b8Sopenharmony_cistatic std::mutex g_kernelStackMutex; 62800b99b8Sopenharmony_cistatic constexpr int WAIT_GET_KERNEL_STACK_TIMEOUT = 1000; // 1000 : time out 1000 ms 63800b99b8Sopenharmony_ci 64800b99b8Sopenharmony_cienum DfxDumpPollRes : int32_t { 65800b99b8Sopenharmony_ci DUMP_POLL_INIT = -1, 66800b99b8Sopenharmony_ci DUMP_POLL_OK, 67800b99b8Sopenharmony_ci DUMP_POLL_FD, 68800b99b8Sopenharmony_ci DUMP_POLL_FAILED, 69800b99b8Sopenharmony_ci DUMP_POLL_TIMEOUT, 70800b99b8Sopenharmony_ci DUMP_POLL_RETURN, 71800b99b8Sopenharmony_ci}; 72800b99b8Sopenharmony_ci 73800b99b8Sopenharmony_cienum DfxDumpStatRes : int32_t { 74800b99b8Sopenharmony_ci DUMP_RES_NO_KERNELSTACK = -2, 75800b99b8Sopenharmony_ci DUMP_RES_WITH_KERNELSTACK = -1, 76800b99b8Sopenharmony_ci DUMP_RES_WITH_USERSTACK = 0, 77800b99b8Sopenharmony_ci}; 78800b99b8Sopenharmony_ci} 79800b99b8Sopenharmony_ci 80800b99b8Sopenharmony_cibool DfxDumpCatcher::DoDumpCurrTid(const size_t skipFrameNum, std::string& msg, size_t maxFrameNums) 81800b99b8Sopenharmony_ci{ 82800b99b8Sopenharmony_ci bool ret = false; 83800b99b8Sopenharmony_ci 84800b99b8Sopenharmony_ci ret = GetBacktrace(msg, skipFrameNum + 1, false, maxFrameNums); 85800b99b8Sopenharmony_ci if (!ret) { 86800b99b8Sopenharmony_ci int currTid = gettid(); 87800b99b8Sopenharmony_ci msg.append("Failed to dump curr thread:" + std::to_string(currTid) + ".\n"); 88800b99b8Sopenharmony_ci } 89800b99b8Sopenharmony_ci DFXLOGD("%{public}s :: DoDumpCurrTid :: return %{public}d.", DFXDUMPCATCHER_TAG.c_str(), ret); 90800b99b8Sopenharmony_ci return ret; 91800b99b8Sopenharmony_ci} 92800b99b8Sopenharmony_ci 93800b99b8Sopenharmony_cibool DfxDumpCatcher::DoDumpLocalTid(const int tid, std::string& msg, size_t maxFrameNums) 94800b99b8Sopenharmony_ci{ 95800b99b8Sopenharmony_ci bool ret = false; 96800b99b8Sopenharmony_ci if (tid <= 0) { 97800b99b8Sopenharmony_ci DFXLOGE("%{public}s :: DoDumpLocalTid :: return false as param error.", DFXDUMPCATCHER_TAG.c_str()); 98800b99b8Sopenharmony_ci return ret; 99800b99b8Sopenharmony_ci } 100800b99b8Sopenharmony_ci ret = GetBacktraceStringByTid(msg, tid, 0, false, maxFrameNums); 101800b99b8Sopenharmony_ci if (!ret) { 102800b99b8Sopenharmony_ci msg.append("Failed to dump thread:" + std::to_string(tid) + ".\n"); 103800b99b8Sopenharmony_ci } 104800b99b8Sopenharmony_ci DFXLOGD("%{public}s :: DoDumpLocalTid :: return %{public}d.", DFXDUMPCATCHER_TAG.c_str(), ret); 105800b99b8Sopenharmony_ci return ret; 106800b99b8Sopenharmony_ci} 107800b99b8Sopenharmony_ci 108800b99b8Sopenharmony_cibool DfxDumpCatcher::DoDumpLocalPid(int pid, std::string& msg, size_t maxFrameNums) 109800b99b8Sopenharmony_ci{ 110800b99b8Sopenharmony_ci bool ret = false; 111800b99b8Sopenharmony_ci if (pid <= 0) { 112800b99b8Sopenharmony_ci DFXLOGE("%{public}s :: DoDumpLocalPid :: return false as param error.", DFXDUMPCATCHER_TAG.c_str()); 113800b99b8Sopenharmony_ci return ret; 114800b99b8Sopenharmony_ci } 115800b99b8Sopenharmony_ci size_t skipFramNum = 5; // 5: skip 5 frame 116800b99b8Sopenharmony_ci 117800b99b8Sopenharmony_ci msg = GetStacktraceHeader(); 118800b99b8Sopenharmony_ci std::function<bool(int)> func = [&](int tid) { 119800b99b8Sopenharmony_ci if (tid <= 0) { 120800b99b8Sopenharmony_ci return false; 121800b99b8Sopenharmony_ci } 122800b99b8Sopenharmony_ci std::string threadMsg; 123800b99b8Sopenharmony_ci if (tid == gettid()) { 124800b99b8Sopenharmony_ci ret = DoDumpCurrTid(skipFramNum, threadMsg, maxFrameNums); 125800b99b8Sopenharmony_ci } else { 126800b99b8Sopenharmony_ci ret = DoDumpLocalTid(tid, threadMsg, maxFrameNums); 127800b99b8Sopenharmony_ci } 128800b99b8Sopenharmony_ci msg += threadMsg; 129800b99b8Sopenharmony_ci return ret; 130800b99b8Sopenharmony_ci }; 131800b99b8Sopenharmony_ci std::vector<int> tids; 132800b99b8Sopenharmony_ci ret = GetTidsByPidWithFunc(getpid(), tids, func); 133800b99b8Sopenharmony_ci DFXLOGD("%{public}s :: DoDumpLocalPid :: return %{public}d.", DFXDUMPCATCHER_TAG.c_str(), ret); 134800b99b8Sopenharmony_ci return ret; 135800b99b8Sopenharmony_ci} 136800b99b8Sopenharmony_ci 137800b99b8Sopenharmony_cibool DfxDumpCatcher::DoDumpRemoteLocked(int pid, int tid, std::string& msg, bool isJson, int timeout) 138800b99b8Sopenharmony_ci{ 139800b99b8Sopenharmony_ci return DoDumpCatchRemote(pid, tid, msg, isJson, timeout); 140800b99b8Sopenharmony_ci} 141800b99b8Sopenharmony_ci 142800b99b8Sopenharmony_cibool DfxDumpCatcher::DoDumpLocalLocked(int pid, int tid, std::string& msg, size_t maxFrameNums) 143800b99b8Sopenharmony_ci{ 144800b99b8Sopenharmony_ci bool ret = false; 145800b99b8Sopenharmony_ci if (tid == gettid()) { 146800b99b8Sopenharmony_ci size_t skipFramNum = 4; // 4: skip 4 frame 147800b99b8Sopenharmony_ci ret = DoDumpCurrTid(skipFramNum, msg, maxFrameNums); 148800b99b8Sopenharmony_ci } else if (tid == 0) { 149800b99b8Sopenharmony_ci ret = DoDumpLocalPid(pid, msg, maxFrameNums); 150800b99b8Sopenharmony_ci } else { 151800b99b8Sopenharmony_ci if (!IsThreadInPid(pid, tid)) { 152800b99b8Sopenharmony_ci msg.append("tid(" + std::to_string(tid) + ") is not in pid(" + std::to_string(pid) + ").\n"); 153800b99b8Sopenharmony_ci } else { 154800b99b8Sopenharmony_ci ret = DoDumpLocalTid(tid, msg, maxFrameNums); 155800b99b8Sopenharmony_ci } 156800b99b8Sopenharmony_ci } 157800b99b8Sopenharmony_ci 158800b99b8Sopenharmony_ci DFXLOGD("%{public}s :: DoDumpLocal :: ret(%{public}d).", DFXDUMPCATCHER_TAG.c_str(), ret); 159800b99b8Sopenharmony_ci return ret; 160800b99b8Sopenharmony_ci} 161800b99b8Sopenharmony_ci 162800b99b8Sopenharmony_cistatic void ReportDumpCatcherStats(int32_t pid, 163800b99b8Sopenharmony_ci uint64_t requestTime, bool ret, std::string& msg, void* retAddr) 164800b99b8Sopenharmony_ci{ 165800b99b8Sopenharmony_ci std::vector<uint8_t> buf(sizeof(struct FaultLoggerdStatsRequest), 0); 166800b99b8Sopenharmony_ci auto stat = reinterpret_cast<struct FaultLoggerdStatsRequest*>(buf.data()); 167800b99b8Sopenharmony_ci stat->type = DUMP_CATCHER; 168800b99b8Sopenharmony_ci stat->pid = pid; 169800b99b8Sopenharmony_ci stat->requestTime = requestTime; 170800b99b8Sopenharmony_ci stat->dumpCatcherFinishTime = GetTimeMilliSeconds(); 171800b99b8Sopenharmony_ci stat->result = ret ? DUMP_RES_WITH_USERSTACK : DUMP_RES_WITH_KERNELSTACK; // we need more detailed failure info 172800b99b8Sopenharmony_ci if (!ret && g_kernelStackInfo.empty()) { 173800b99b8Sopenharmony_ci stat->result = DUMP_RES_NO_KERNELSTACK; 174800b99b8Sopenharmony_ci } 175800b99b8Sopenharmony_ci size_t copyLen; 176800b99b8Sopenharmony_ci std::string processName; 177800b99b8Sopenharmony_ci ReadProcessName(pid, processName); 178800b99b8Sopenharmony_ci copyLen = std::min(sizeof(stat->targetProcess) - 1, processName.size()); 179800b99b8Sopenharmony_ci if (memcpy_s(stat->targetProcess, sizeof(stat->targetProcess) - 1, processName.c_str(), copyLen) != 0) { 180800b99b8Sopenharmony_ci DFXLOGE("%{public}s::Failed to copy target process", DFXDUMPCATCHER_TAG.c_str()); 181800b99b8Sopenharmony_ci return; 182800b99b8Sopenharmony_ci } 183800b99b8Sopenharmony_ci 184800b99b8Sopenharmony_ci if (!ret) { 185800b99b8Sopenharmony_ci copyLen = std::min(sizeof(stat->summary) - 1, msg.size()); 186800b99b8Sopenharmony_ci if (memcpy_s(stat->summary, sizeof(stat->summary) - 1, msg.c_str(), copyLen) != 0) { 187800b99b8Sopenharmony_ci DFXLOGE("%{public}s::Failed to copy dumpcatcher summary", DFXDUMPCATCHER_TAG.c_str()); 188800b99b8Sopenharmony_ci return; 189800b99b8Sopenharmony_ci } 190800b99b8Sopenharmony_ci } 191800b99b8Sopenharmony_ci 192800b99b8Sopenharmony_ci Dl_info info; 193800b99b8Sopenharmony_ci if (dladdr(retAddr, &info) != 0) { 194800b99b8Sopenharmony_ci copyLen = std::min(sizeof(stat->callerElf) - 1, strlen(info.dli_fname)); 195800b99b8Sopenharmony_ci if (memcpy_s(stat->callerElf, sizeof(stat->callerElf) - 1, info.dli_fname, copyLen) != 0) { 196800b99b8Sopenharmony_ci DFXLOGE("%{public}s::Failed to copy caller elf info", DFXDUMPCATCHER_TAG.c_str()); 197800b99b8Sopenharmony_ci return; 198800b99b8Sopenharmony_ci } 199800b99b8Sopenharmony_ci stat->offset = reinterpret_cast<uintptr_t>(retAddr) - reinterpret_cast<uintptr_t>(info.dli_fbase); 200800b99b8Sopenharmony_ci } 201800b99b8Sopenharmony_ci 202800b99b8Sopenharmony_ci std::string cmdline; 203800b99b8Sopenharmony_ci if (OHOS::LoadStringFromFile("/proc/self/cmdline", cmdline)) { 204800b99b8Sopenharmony_ci copyLen = std::min(sizeof(stat->callerProcess) - 1, cmdline.size()); 205800b99b8Sopenharmony_ci if (memcpy_s(stat->callerProcess, sizeof(stat->callerProcess) - 1, 206800b99b8Sopenharmony_ci cmdline.c_str(), copyLen) != 0) { 207800b99b8Sopenharmony_ci DFXLOGE("%{public}s::Failed to copy caller cmdline", DFXDUMPCATCHER_TAG.c_str()); 208800b99b8Sopenharmony_ci return; 209800b99b8Sopenharmony_ci } 210800b99b8Sopenharmony_ci } 211800b99b8Sopenharmony_ci 212800b99b8Sopenharmony_ci ReportDumpStats(stat); 213800b99b8Sopenharmony_ci} 214800b99b8Sopenharmony_ci 215800b99b8Sopenharmony_ciint DfxDumpCatcher::DumpCatchProcess(int pid, std::string& msg, size_t maxFrameNums, bool isJson) 216800b99b8Sopenharmony_ci{ 217800b99b8Sopenharmony_ci if (DumpCatch(pid, 0, msg, maxFrameNums, isJson)) { 218800b99b8Sopenharmony_ci return 0; 219800b99b8Sopenharmony_ci } 220800b99b8Sopenharmony_ci if (pid == g_kernelStackPid && !g_asyncThreadRunning) { 221800b99b8Sopenharmony_ci msg.append(g_kernelStackInfo); 222800b99b8Sopenharmony_ci g_kernelStackInfo.clear(); 223800b99b8Sopenharmony_ci g_kernelStackPid = 0; 224800b99b8Sopenharmony_ci return 1; 225800b99b8Sopenharmony_ci } 226800b99b8Sopenharmony_ci return -1; 227800b99b8Sopenharmony_ci} 228800b99b8Sopenharmony_ci 229800b99b8Sopenharmony_cibool DfxDumpCatcher::DumpCatch(int pid, int tid, std::string& msg, size_t maxFrameNums, bool isJson) 230800b99b8Sopenharmony_ci{ 231800b99b8Sopenharmony_ci bool ret = false; 232800b99b8Sopenharmony_ci if (pid <= 0 || tid < 0) { 233800b99b8Sopenharmony_ci DFXLOGE("%{public}s :: dump_catch :: param error.", DFXDUMPCATCHER_TAG.c_str()); 234800b99b8Sopenharmony_ci return ret; 235800b99b8Sopenharmony_ci } 236800b99b8Sopenharmony_ci std::string statusPath = StringPrintf("/proc/%d/status", pid); 237800b99b8Sopenharmony_ci if (access(statusPath.c_str(), F_OK) != 0 && errno != EACCES) { 238800b99b8Sopenharmony_ci DFXLOGE("DumpCatch:: the pid(%{public}d) process has exited, errno(%{public}d)", pid, errno); 239800b99b8Sopenharmony_ci msg.append("Result: pid(" + std::to_string(pid) + ") process has exited.\n"); 240800b99b8Sopenharmony_ci return ret; 241800b99b8Sopenharmony_ci } 242800b99b8Sopenharmony_ci DfxEnableTraceDlsym(true); 243800b99b8Sopenharmony_ci ElapsedTime counter; 244800b99b8Sopenharmony_ci std::unique_lock<std::mutex> lck(mutex_); 245800b99b8Sopenharmony_ci int currentPid = getpid(); 246800b99b8Sopenharmony_ci bool reportStat = false; 247800b99b8Sopenharmony_ci uint64_t requestTime = GetTimeMilliSeconds(); 248800b99b8Sopenharmony_ci DFXLOGW("Receive DumpCatch request for cPid:(%{public}d), pid(%{public}d), " \ 249800b99b8Sopenharmony_ci "tid:(%{public}d).", currentPid, pid, tid); 250800b99b8Sopenharmony_ci if (pid == currentPid) { 251800b99b8Sopenharmony_ci ret = DoDumpLocalLocked(pid, tid, msg, maxFrameNums); 252800b99b8Sopenharmony_ci } else { 253800b99b8Sopenharmony_ci if (maxFrameNums != DEFAULT_MAX_FRAME_NUM) { 254800b99b8Sopenharmony_ci DFXLOGI("%{public}s :: dump_catch :: maxFrameNums does not support setting " \ 255800b99b8Sopenharmony_ci "when pid is not equal to caller pid", DFXDUMPCATCHER_TAG.c_str()); 256800b99b8Sopenharmony_ci } 257800b99b8Sopenharmony_ci reportStat = true; 258800b99b8Sopenharmony_ci int timeout = (tid == 0 ? 3 : 10) * 1000; // when tid not zero, timeout is 10s 259800b99b8Sopenharmony_ci ret = DoDumpRemoteLocked(pid, tid, msg, isJson, timeout); 260800b99b8Sopenharmony_ci } 261800b99b8Sopenharmony_ci 262800b99b8Sopenharmony_ci if (reportStat) { 263800b99b8Sopenharmony_ci void* retAddr = __builtin_return_address(0); 264800b99b8Sopenharmony_ci ReportDumpCatcherStats(pid, requestTime, ret, msg, retAddr); 265800b99b8Sopenharmony_ci } 266800b99b8Sopenharmony_ci 267800b99b8Sopenharmony_ci DFXLOGW("dump_catch : pid = %{public}d, elapsed time = %{public}" PRId64 " ms, ret = %{public}d, " \ 268800b99b8Sopenharmony_ci "msgLength = %{public}zu", 269800b99b8Sopenharmony_ci pid, counter.Elapsed<std::chrono::milliseconds>(), ret, msg.size()); 270800b99b8Sopenharmony_ci DfxEnableTraceDlsym(false); 271800b99b8Sopenharmony_ci return ret; 272800b99b8Sopenharmony_ci} 273800b99b8Sopenharmony_ci 274800b99b8Sopenharmony_cibool DfxDumpCatcher::DumpCatchFd(int pid, int tid, std::string& msg, int fd, size_t maxFrameNums) 275800b99b8Sopenharmony_ci{ 276800b99b8Sopenharmony_ci bool ret = false; 277800b99b8Sopenharmony_ci ret = DumpCatch(pid, tid, msg, maxFrameNums); 278800b99b8Sopenharmony_ci if (fd > 0) { 279800b99b8Sopenharmony_ci ret = OHOS_TEMP_FAILURE_RETRY(write(fd, msg.c_str(), msg.length())); 280800b99b8Sopenharmony_ci } 281800b99b8Sopenharmony_ci return ret; 282800b99b8Sopenharmony_ci} 283800b99b8Sopenharmony_ci 284800b99b8Sopenharmony_cibool DfxDumpCatcher::DoDumpCatchRemote(int pid, int tid, std::string& msg, bool isJson, int timeout) 285800b99b8Sopenharmony_ci{ 286800b99b8Sopenharmony_ci DFX_TRACE_SCOPED_DLSYM("DoDumpCatchRemote"); 287800b99b8Sopenharmony_ci bool ret = false; 288800b99b8Sopenharmony_ci if (pid <= 0 || tid < 0) { 289800b99b8Sopenharmony_ci msg.append("Result: pid(" + std::to_string(pid) + ") param error.\n"); 290800b99b8Sopenharmony_ci DFXLOGW("%{public}s :: %{public}s :: %{public}s", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str()); 291800b99b8Sopenharmony_ci return ret; 292800b99b8Sopenharmony_ci } 293800b99b8Sopenharmony_ci pid_ = pid; 294800b99b8Sopenharmony_ci int sdkdumpRet = RequestSdkDumpJson(pid, tid, isJson, timeout); 295800b99b8Sopenharmony_ci if (sdkdumpRet != static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_PASS)) { 296800b99b8Sopenharmony_ci if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_REPEAT)) { 297800b99b8Sopenharmony_ci AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); 298800b99b8Sopenharmony_ci msg.append("Result: pid(" + std::to_string(pid) + ") process is dumping.\n"); 299800b99b8Sopenharmony_ci } else if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_REJECT)) { 300800b99b8Sopenharmony_ci msg.append("Result: pid(" + std::to_string(pid) + ") process check permission error.\n"); 301800b99b8Sopenharmony_ci } else if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_DUMP_NOPROC)) { 302800b99b8Sopenharmony_ci msg.append("Result: pid(" + std::to_string(pid) + ") process has exited.\n"); 303800b99b8Sopenharmony_ci RequestDelPipeFd(pid); 304800b99b8Sopenharmony_ci } else if (sdkdumpRet == static_cast<int>(FaultLoggerSdkDumpResp::SDK_PROCESS_CRASHED)) { 305800b99b8Sopenharmony_ci msg.append("Result: pid(" + std::to_string(pid) + ") process has been crashed.\n"); 306800b99b8Sopenharmony_ci } 307800b99b8Sopenharmony_ci DFXLOGW("%{public}s :: %{public}s :: %{public}s", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str()); 308800b99b8Sopenharmony_ci return ret; 309800b99b8Sopenharmony_ci } 310800b99b8Sopenharmony_ci 311800b99b8Sopenharmony_ci int pollRet = DoDumpRemotePid(pid, msg, isJson, timeout); 312800b99b8Sopenharmony_ci switch (pollRet) { 313800b99b8Sopenharmony_ci case DUMP_POLL_OK: 314800b99b8Sopenharmony_ci ret = true; 315800b99b8Sopenharmony_ci break; 316800b99b8Sopenharmony_ci case DUMP_POLL_TIMEOUT: { 317800b99b8Sopenharmony_ci msg.append(halfProcStatus_); 318800b99b8Sopenharmony_ci msg.append(halfProcWchan_); 319800b99b8Sopenharmony_ci break; 320800b99b8Sopenharmony_ci } 321800b99b8Sopenharmony_ci default: 322800b99b8Sopenharmony_ci if (g_kernelStackPid != pid) { // maybe not get kernel stack, try again 323800b99b8Sopenharmony_ci AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); 324800b99b8Sopenharmony_ci } 325800b99b8Sopenharmony_ci msg.append(halfProcStatus_); 326800b99b8Sopenharmony_ci msg.append(halfProcWchan_); 327800b99b8Sopenharmony_ci break; 328800b99b8Sopenharmony_ci } 329800b99b8Sopenharmony_ci DFXLOGW("%{public}s :: %{public}s :: pid(%{public}d) ret: %{public}d", DFXDUMPCATCHER_TAG.c_str(), 330800b99b8Sopenharmony_ci __func__, pid, ret); 331800b99b8Sopenharmony_ci return ret; 332800b99b8Sopenharmony_ci} 333800b99b8Sopenharmony_ci 334800b99b8Sopenharmony_ciint DfxDumpCatcher::DoDumpRemotePid(int pid, std::string& msg, bool isJson, int32_t timeout) 335800b99b8Sopenharmony_ci{ 336800b99b8Sopenharmony_ci DFX_TRACE_SCOPED_DLSYM("DoDumpRemotePid"); 337800b99b8Sopenharmony_ci int readBufFd = -1; 338800b99b8Sopenharmony_ci int readResFd = -1; 339800b99b8Sopenharmony_ci if (isJson) { 340800b99b8Sopenharmony_ci readBufFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_JSON_READ_BUF); 341800b99b8Sopenharmony_ci readResFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_JSON_READ_RES); 342800b99b8Sopenharmony_ci } else { 343800b99b8Sopenharmony_ci readBufFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_READ_BUF); 344800b99b8Sopenharmony_ci readResFd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_READ_RES); 345800b99b8Sopenharmony_ci } 346800b99b8Sopenharmony_ci DFXLOGD("read res fd: %{public}d", readResFd); 347800b99b8Sopenharmony_ci int ret = DoDumpRemotePoll(readBufFd, readResFd, timeout, msg, isJson); 348800b99b8Sopenharmony_ci // request close fds in faultloggerd 349800b99b8Sopenharmony_ci RequestDelPipeFd(pid); 350800b99b8Sopenharmony_ci if (readBufFd >= 0) { 351800b99b8Sopenharmony_ci close(readBufFd); 352800b99b8Sopenharmony_ci readBufFd = -1; 353800b99b8Sopenharmony_ci } 354800b99b8Sopenharmony_ci if (readResFd >= 0) { 355800b99b8Sopenharmony_ci close(readResFd); 356800b99b8Sopenharmony_ci readResFd = -1; 357800b99b8Sopenharmony_ci } 358800b99b8Sopenharmony_ci DFXLOGI("%{public}s :: %{public}s :: pid(%{public}d) poll ret: %{public}d", 359800b99b8Sopenharmony_ci DFXDUMPCATCHER_TAG.c_str(), __func__, pid, ret); 360800b99b8Sopenharmony_ci return ret; 361800b99b8Sopenharmony_ci} 362800b99b8Sopenharmony_ci 363800b99b8Sopenharmony_civoid DfxDumpCatcher::CollectKernelStack(pid_t pid, int waitMilliSeconds) 364800b99b8Sopenharmony_ci{ 365800b99b8Sopenharmony_ci ElapsedTime timer; 366800b99b8Sopenharmony_ci std::string kernelStackInfo; 367800b99b8Sopenharmony_ci auto finishCollect = [waitMilliSeconds]() { 368800b99b8Sopenharmony_ci if (waitMilliSeconds > 0) { 369800b99b8Sopenharmony_ci std::unique_lock<std::mutex> lock(g_kernelStackMutex); 370800b99b8Sopenharmony_ci g_asyncThreadRunning = false; 371800b99b8Sopenharmony_ci lock.unlock(); 372800b99b8Sopenharmony_ci g_cv.notify_all(); 373800b99b8Sopenharmony_ci } else { 374800b99b8Sopenharmony_ci g_asyncThreadRunning = false; 375800b99b8Sopenharmony_ci } 376800b99b8Sopenharmony_ci }; 377800b99b8Sopenharmony_ci std::string statusPath = StringPrintf("/proc/%d/status", pid); 378800b99b8Sopenharmony_ci if (access(statusPath.c_str(), F_OK) != 0) { 379800b99b8Sopenharmony_ci DFXLOGW("No process(%{public}d) status file exist!", pid); 380800b99b8Sopenharmony_ci finishCollect(); 381800b99b8Sopenharmony_ci return; 382800b99b8Sopenharmony_ci } 383800b99b8Sopenharmony_ci 384800b99b8Sopenharmony_ci std::function<bool(int)> func = [&](int tid) { 385800b99b8Sopenharmony_ci if (tid <= 0) { 386800b99b8Sopenharmony_ci return false; 387800b99b8Sopenharmony_ci } 388800b99b8Sopenharmony_ci std::string tidKernelStackInfo; 389800b99b8Sopenharmony_ci if (DfxGetKernelStack(tid, tidKernelStackInfo) == 0) { 390800b99b8Sopenharmony_ci kernelStackInfo.append(tidKernelStackInfo); 391800b99b8Sopenharmony_ci } 392800b99b8Sopenharmony_ci return true; 393800b99b8Sopenharmony_ci }; 394800b99b8Sopenharmony_ci std::vector<int> tids; 395800b99b8Sopenharmony_ci bool ret = GetTidsByPidWithFunc(pid, tids, func); 396800b99b8Sopenharmony_ci if (ret == false) { 397800b99b8Sopenharmony_ci DFXLOGE("Process(%{public}d) Get Tids fail!", pid); 398800b99b8Sopenharmony_ci finishCollect(); 399800b99b8Sopenharmony_ci return; 400800b99b8Sopenharmony_ci } 401800b99b8Sopenharmony_ci g_kernelStackPid = pid; 402800b99b8Sopenharmony_ci g_kernelStackInfo = kernelStackInfo; 403800b99b8Sopenharmony_ci finishCollect(); 404800b99b8Sopenharmony_ci DFXLOGI("finish collect all tid info for pid(%{public}d) time(%{public}" PRId64 ")ms", pid, 405800b99b8Sopenharmony_ci timer.Elapsed<std::chrono::milliseconds>()); 406800b99b8Sopenharmony_ci} 407800b99b8Sopenharmony_ci 408800b99b8Sopenharmony_civoid DfxDumpCatcher::AsyncGetAllTidKernelStack(pid_t pid, int waitMilliSeconds) 409800b99b8Sopenharmony_ci{ 410800b99b8Sopenharmony_ci ReadProcessStatus(halfProcStatus_, pid); 411800b99b8Sopenharmony_ci ReadProcessWchan(halfProcWchan_, pid, false, true); 412800b99b8Sopenharmony_ci if (g_asyncThreadRunning) { 413800b99b8Sopenharmony_ci DFXLOGI("pid(%{public}d) get kernel stack thread is running, not get pid(%{public}d)", g_kernelStackPid, pid); 414800b99b8Sopenharmony_ci return; 415800b99b8Sopenharmony_ci } 416800b99b8Sopenharmony_ci g_asyncThreadRunning = true; 417800b99b8Sopenharmony_ci g_kernelStackPid = 0; 418800b99b8Sopenharmony_ci g_kernelStackInfo.clear(); 419800b99b8Sopenharmony_ci auto func = [pid, waitMilliSeconds] { 420800b99b8Sopenharmony_ci CollectKernelStack(pid, waitMilliSeconds); 421800b99b8Sopenharmony_ci }; 422800b99b8Sopenharmony_ci if (waitMilliSeconds > 0) { 423800b99b8Sopenharmony_ci std::unique_lock<std::mutex> lock(g_kernelStackMutex); 424800b99b8Sopenharmony_ci std::thread kernelStackTask(func); 425800b99b8Sopenharmony_ci kernelStackTask.detach(); 426800b99b8Sopenharmony_ci g_cv.wait_for(lock, std::chrono::milliseconds(WAIT_GET_KERNEL_STACK_TIMEOUT), 427800b99b8Sopenharmony_ci [] {return !g_asyncThreadRunning;}); 428800b99b8Sopenharmony_ci } else { 429800b99b8Sopenharmony_ci std::thread kernelStackTask(func); 430800b99b8Sopenharmony_ci kernelStackTask.detach(); 431800b99b8Sopenharmony_ci } 432800b99b8Sopenharmony_ci} 433800b99b8Sopenharmony_ci 434800b99b8Sopenharmony_ciint DfxDumpCatcher::DoDumpRemotePoll(int bufFd, int resFd, int timeout, std::string& msg, bool isJson) 435800b99b8Sopenharmony_ci{ 436800b99b8Sopenharmony_ci DFX_TRACE_SCOPED_DLSYM("DoDumpRemotePoll"); 437800b99b8Sopenharmony_ci if (bufFd < 0 || resFd < 0) { 438800b99b8Sopenharmony_ci if (!isJson) { 439800b99b8Sopenharmony_ci msg = "Result: bufFd or resFd < 0.\n"; 440800b99b8Sopenharmony_ci } 441800b99b8Sopenharmony_ci DFXLOGE("invalid bufFd or resFd"); 442800b99b8Sopenharmony_ci return DUMP_POLL_FD; 443800b99b8Sopenharmony_ci } 444800b99b8Sopenharmony_ci int ret = DUMP_POLL_INIT; 445800b99b8Sopenharmony_ci std::string resMsg; 446800b99b8Sopenharmony_ci bool res = false; 447800b99b8Sopenharmony_ci std::string bufMsg; 448800b99b8Sopenharmony_ci struct pollfd readfds[2]; 449800b99b8Sopenharmony_ci (void)memset_s(readfds, sizeof(readfds), 0, sizeof(readfds)); 450800b99b8Sopenharmony_ci readfds[0].fd = bufFd; 451800b99b8Sopenharmony_ci readfds[0].events = POLLIN; 452800b99b8Sopenharmony_ci readfds[1].fd = resFd; 453800b99b8Sopenharmony_ci readfds[1].events = POLLIN; 454800b99b8Sopenharmony_ci int fdsSize = sizeof(readfds) / sizeof(readfds[0]); 455800b99b8Sopenharmony_ci bool bPipeConnect = false; 456800b99b8Sopenharmony_ci int remainTime = DUMPCATCHER_REMOTE_P90_TIMEOUT; 457800b99b8Sopenharmony_ci bool collectAllTidStack = false; 458800b99b8Sopenharmony_ci uint64_t startTime = GetAbsTimeMilliSeconds(); 459800b99b8Sopenharmony_ci uint64_t endTime = startTime + static_cast<uint64_t>(timeout); 460800b99b8Sopenharmony_ci while (true) { 461800b99b8Sopenharmony_ci int pollRet = poll(readfds, fdsSize, remainTime); 462800b99b8Sopenharmony_ci if (pollRet < 0 && errno == EINTR) { 463800b99b8Sopenharmony_ci uint64_t now = GetAbsTimeMilliSeconds(); 464800b99b8Sopenharmony_ci if (now >= endTime) { 465800b99b8Sopenharmony_ci ret = DUMP_POLL_TIMEOUT; 466800b99b8Sopenharmony_ci resMsg.append("Result: poll timeout.\n"); 467800b99b8Sopenharmony_ci break; 468800b99b8Sopenharmony_ci } 469800b99b8Sopenharmony_ci if (!collectAllTidStack && (remainTime == DUMPCATCHER_REMOTE_P90_TIMEOUT)) { 470800b99b8Sopenharmony_ci AsyncGetAllTidKernelStack(pid_); 471800b99b8Sopenharmony_ci collectAllTidStack = true; 472800b99b8Sopenharmony_ci } 473800b99b8Sopenharmony_ci remainTime = static_cast<int>(endTime - now); 474800b99b8Sopenharmony_ci continue; 475800b99b8Sopenharmony_ci } else if (pollRet < 0) { 476800b99b8Sopenharmony_ci ret = DUMP_POLL_FAILED; 477800b99b8Sopenharmony_ci resMsg.append("Result: poll error, errno(" + std::to_string(errno) + ")\n"); 478800b99b8Sopenharmony_ci break; 479800b99b8Sopenharmony_ci } else if (pollRet == 0) { 480800b99b8Sopenharmony_ci if (!collectAllTidStack && (remainTime == DUMPCATCHER_REMOTE_P90_TIMEOUT)) { 481800b99b8Sopenharmony_ci AsyncGetAllTidKernelStack(pid_); 482800b99b8Sopenharmony_ci remainTime = timeout - DUMPCATCHER_REMOTE_P90_TIMEOUT; 483800b99b8Sopenharmony_ci collectAllTidStack = true; 484800b99b8Sopenharmony_ci continue; 485800b99b8Sopenharmony_ci } 486800b99b8Sopenharmony_ci ret = DUMP_POLL_TIMEOUT; 487800b99b8Sopenharmony_ci resMsg.append("Result: poll timeout.\n"); 488800b99b8Sopenharmony_ci break; 489800b99b8Sopenharmony_ci } 490800b99b8Sopenharmony_ci 491800b99b8Sopenharmony_ci bool bufRet = true; 492800b99b8Sopenharmony_ci bool resRet = false; 493800b99b8Sopenharmony_ci bool eventRet = true; 494800b99b8Sopenharmony_ci for (int i = 0; i < fdsSize; ++i) { 495800b99b8Sopenharmony_ci if (!bPipeConnect && ((uint32_t)readfds[i].revents & POLLIN)) { 496800b99b8Sopenharmony_ci bPipeConnect = true; 497800b99b8Sopenharmony_ci } 498800b99b8Sopenharmony_ci if (bPipeConnect && 499800b99b8Sopenharmony_ci (((uint32_t)readfds[i].revents & POLLERR) || ((uint32_t)readfds[i].revents & POLLHUP))) { 500800b99b8Sopenharmony_ci eventRet = false; 501800b99b8Sopenharmony_ci resMsg.append("Result: poll events error.\n"); 502800b99b8Sopenharmony_ci break; 503800b99b8Sopenharmony_ci } 504800b99b8Sopenharmony_ci 505800b99b8Sopenharmony_ci if (((uint32_t)readfds[i].revents & POLLIN) != POLLIN) { 506800b99b8Sopenharmony_ci continue; 507800b99b8Sopenharmony_ci } 508800b99b8Sopenharmony_ci 509800b99b8Sopenharmony_ci if (readfds[i].fd == bufFd) { 510800b99b8Sopenharmony_ci bufRet = DoReadBuf(bufFd, bufMsg); 511800b99b8Sopenharmony_ci continue; 512800b99b8Sopenharmony_ci } 513800b99b8Sopenharmony_ci 514800b99b8Sopenharmony_ci if (readfds[i].fd == resFd) { 515800b99b8Sopenharmony_ci resRet = DoReadRes(resFd, res, resMsg); 516800b99b8Sopenharmony_ci } 517800b99b8Sopenharmony_ci } 518800b99b8Sopenharmony_ci 519800b99b8Sopenharmony_ci if ((eventRet == false) || (bufRet == false) || (resRet == true)) { 520800b99b8Sopenharmony_ci DFXLOGI("%{public}s :: %{public}s :: eventRet(%{public}d) bufRet: %{public}d resRet: %{public}d", 521800b99b8Sopenharmony_ci DFXDUMPCATCHER_TAG.c_str(), __func__, eventRet, bufRet, resRet); 522800b99b8Sopenharmony_ci ret = DUMP_POLL_RETURN; 523800b99b8Sopenharmony_ci break; 524800b99b8Sopenharmony_ci } 525800b99b8Sopenharmony_ci uint64_t now = GetAbsTimeMilliSeconds(); 526800b99b8Sopenharmony_ci if (now >= endTime) { 527800b99b8Sopenharmony_ci ret = DUMP_POLL_TIMEOUT; 528800b99b8Sopenharmony_ci resMsg.append("Result: poll timeout.\n"); 529800b99b8Sopenharmony_ci break; 530800b99b8Sopenharmony_ci } 531800b99b8Sopenharmony_ci remainTime = static_cast<int>(endTime - now); 532800b99b8Sopenharmony_ci } 533800b99b8Sopenharmony_ci 534800b99b8Sopenharmony_ci DFXLOGW("%{public}s :: %{public}s :: %{public}s", DFXDUMPCATCHER_TAG.c_str(), __func__, resMsg.c_str()); 535800b99b8Sopenharmony_ci msg = isJson && res ? bufMsg : (resMsg + bufMsg); 536800b99b8Sopenharmony_ci return res ? DUMP_POLL_OK : ret; 537800b99b8Sopenharmony_ci} 538800b99b8Sopenharmony_ci 539800b99b8Sopenharmony_cibool DfxDumpCatcher::DoReadBuf(int fd, std::string& msg) 540800b99b8Sopenharmony_ci{ 541800b99b8Sopenharmony_ci bool ret = false; 542800b99b8Sopenharmony_ci char *buffer = new char[MAX_PIPE_SIZE]; 543800b99b8Sopenharmony_ci do { 544800b99b8Sopenharmony_ci ssize_t nread = OHOS_TEMP_FAILURE_RETRY(read(fd, buffer, MAX_PIPE_SIZE)); 545800b99b8Sopenharmony_ci if (nread <= 0) { 546800b99b8Sopenharmony_ci DFXLOGW("%{public}s :: %{public}s :: read error", DFXDUMPCATCHER_TAG.c_str(), __func__); 547800b99b8Sopenharmony_ci break; 548800b99b8Sopenharmony_ci } 549800b99b8Sopenharmony_ci DFXLOGD("%{public}s :: %{public}s :: nread: %{public}zu", DFXDUMPCATCHER_TAG.c_str(), __func__, nread); 550800b99b8Sopenharmony_ci ret = true; 551800b99b8Sopenharmony_ci msg.append(buffer); 552800b99b8Sopenharmony_ci } while (false); 553800b99b8Sopenharmony_ci delete []buffer; 554800b99b8Sopenharmony_ci return ret; 555800b99b8Sopenharmony_ci} 556800b99b8Sopenharmony_ci 557800b99b8Sopenharmony_cibool DfxDumpCatcher::DoReadRes(int fd, bool &ret, std::string& msg) 558800b99b8Sopenharmony_ci{ 559800b99b8Sopenharmony_ci int32_t res = DumpErrorCode::DUMP_ESUCCESS; 560800b99b8Sopenharmony_ci ssize_t nread = OHOS_TEMP_FAILURE_RETRY(read(fd, &res, sizeof(res))); 561800b99b8Sopenharmony_ci if (nread <= 0 || nread != sizeof(res)) { 562800b99b8Sopenharmony_ci DFXLOGW("%{public}s :: %{public}s :: read error", DFXDUMPCATCHER_TAG.c_str(), __func__); 563800b99b8Sopenharmony_ci return false; 564800b99b8Sopenharmony_ci } 565800b99b8Sopenharmony_ci if (res == DumpErrorCode::DUMP_ESUCCESS) { 566800b99b8Sopenharmony_ci ret = true; 567800b99b8Sopenharmony_ci } 568800b99b8Sopenharmony_ci msg.append("Result: " + DfxDumpRes::ToString(res) + "\n"); 569800b99b8Sopenharmony_ci return true; 570800b99b8Sopenharmony_ci} 571800b99b8Sopenharmony_ci 572800b99b8Sopenharmony_cibool DfxDumpCatcher::DumpCatchMultiPid(const std::vector<int> pidV, std::string& msg) 573800b99b8Sopenharmony_ci{ 574800b99b8Sopenharmony_ci bool ret = false; 575800b99b8Sopenharmony_ci int pidSize = (int)pidV.size(); 576800b99b8Sopenharmony_ci if (pidSize <= 0) { 577800b99b8Sopenharmony_ci DFXLOGE("%{public}s :: %{public}s :: param error, pidSize(%{public}d).", 578800b99b8Sopenharmony_ci DFXDUMPCATCHER_TAG.c_str(), __func__, pidSize); 579800b99b8Sopenharmony_ci return ret; 580800b99b8Sopenharmony_ci } 581800b99b8Sopenharmony_ci 582800b99b8Sopenharmony_ci std::unique_lock<std::mutex> lck(mutex_); 583800b99b8Sopenharmony_ci int currentPid = getpid(); 584800b99b8Sopenharmony_ci int currentTid = gettid(); 585800b99b8Sopenharmony_ci DFXLOGD("%{public}s :: %{public}s :: cPid(%{public}d), cTid(%{public}d), pidSize(%{public}d).", 586800b99b8Sopenharmony_ci DFXDUMPCATCHER_TAG.c_str(), \ 587800b99b8Sopenharmony_ci __func__, currentPid, currentTid, pidSize); 588800b99b8Sopenharmony_ci 589800b99b8Sopenharmony_ci time_t startTime = time(nullptr); 590800b99b8Sopenharmony_ci if (startTime > 0) { 591800b99b8Sopenharmony_ci DFXLOGD("%{public}s :: %{public}s :: startTime(%{public}" PRId64 ").", 592800b99b8Sopenharmony_ci DFXDUMPCATCHER_TAG.c_str(), __func__, startTime); 593800b99b8Sopenharmony_ci } 594800b99b8Sopenharmony_ci 595800b99b8Sopenharmony_ci for (int i = 0; i < pidSize; i++) { 596800b99b8Sopenharmony_ci int pid = pidV[i]; 597800b99b8Sopenharmony_ci std::string pidStr; 598800b99b8Sopenharmony_ci if (DoDumpRemoteLocked(pid, 0, pidStr)) { 599800b99b8Sopenharmony_ci msg.append(pidStr + "\n"); 600800b99b8Sopenharmony_ci } else { 601800b99b8Sopenharmony_ci msg.append("Failed to dump process:" + std::to_string(pid)); 602800b99b8Sopenharmony_ci } 603800b99b8Sopenharmony_ci 604800b99b8Sopenharmony_ci time_t currentTime = time(nullptr); 605800b99b8Sopenharmony_ci if (currentTime > 0) { 606800b99b8Sopenharmony_ci DFXLOGD("%{public}s :: %{public}s :: startTime(%{public}" PRId64 "), currentTime(%{public}" PRId64 ").", 607800b99b8Sopenharmony_ci DFXDUMPCATCHER_TAG.c_str(), \ 608800b99b8Sopenharmony_ci __func__, startTime, currentTime); 609800b99b8Sopenharmony_ci if (currentTime > startTime + DUMP_CATCHE_WORK_TIME_S) { 610800b99b8Sopenharmony_ci break; 611800b99b8Sopenharmony_ci } 612800b99b8Sopenharmony_ci } 613800b99b8Sopenharmony_ci } 614800b99b8Sopenharmony_ci 615800b99b8Sopenharmony_ci DFXLOGD("%{public}s :: %{public}s :: msg(%{public}s).", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str()); 616800b99b8Sopenharmony_ci if (msg.find("Tid:") != std::string::npos) { 617800b99b8Sopenharmony_ci ret = true; 618800b99b8Sopenharmony_ci } 619800b99b8Sopenharmony_ci return ret; 620800b99b8Sopenharmony_ci} 621800b99b8Sopenharmony_ci} // namespace HiviewDFX 622800b99b8Sopenharmony_ci} // namespace OHOS 623