1/* 2 * Copyright (C) 2021 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#include "open_stacktrace_catcher.h" 16 17#include <ctime> 18#include <string> 19 20#include "common_utils.h" 21#include "file_util.h" 22#include "log_catcher_utils.h" 23#include "hiview_logger.h" 24#include "securec.h" 25#include <sys/wait.h> 26#include <unistd.h> 27 28namespace OHOS { 29namespace HiviewDFX { 30namespace { 31 static const inline int SLEEP_TIME_US = 100000; 32 static const inline int MAX_RETRY_COUNT = 10; 33} 34DEFINE_LOG_LABEL(0xD002D01, "EventLogger-OpenStacktraceCatcher"); 35OpenStacktraceCatcher::OpenStacktraceCatcher() : EventLogCatcher() 36{ 37 name_ = "OpenStacktraceCatcher"; 38} 39 40bool OpenStacktraceCatcher::Initialize(const std::string& packageNam, int pid, int intParam) 41{ 42 if (pid <= 0 && packageNam.length() == 0) { 43 description_ = "OpenStacktraceCatcher -- pid is null, packageName is null\n"; 44 return false; 45 } 46 packageName_ = packageNam; 47 if (pid > 0) { 48 pid_ = pid; 49 } else { 50 pid_ = CommonUtils::GetPidByName(packageNam); 51 } 52 53 if (pid_ <= 0) { 54 description_ = "OpenStacktraceCatcher -- packageName is " + packageName_ + " pid is null\n"; 55 return false; 56 } 57 58 if (packageName_.length() == 0) { 59 packageName_ = "(null)"; 60 } 61 62 description_ = "OpenStacktraceCatcher -- pid==" + std::to_string(pid_) + " packageName is " + packageName_ + "\n"; 63 return EventLogCatcher::Initialize(packageName_, pid_, intParam); 64}; 65 66// may block, run in another thread 67int OpenStacktraceCatcher::Catch(int fd, int jsonFd) 68{ 69 if (pid_ <= 0) { 70 return 0; 71 } 72 int originSize = GetFdSize(fd); 73 74#ifdef DUMP_STACK_IN_PROCESS 75 LogCatcherUtils::DumpStacktrace(fd, pid_); 76#else 77 ForkAndDumpStackTrace(fd); 78#endif 79 logSize_ = GetFdSize(fd) - originSize; 80 return logSize_; 81} 82 83inline void OpenStacktraceCatcher::WaitChildPid(pid_t pid) 84{ 85 int retryCount = 0; 86 while (retryCount < MAX_RETRY_COUNT) { 87 if (waitpid(pid, NULL, WNOHANG) != 0) { 88 break; 89 } 90 retryCount++; 91 usleep(SLEEP_TIME_US); 92 } 93} 94 95int32_t OpenStacktraceCatcher::ForkAndDumpStackTrace(int32_t fd) 96{ 97 int pid = -1; 98 int leftTimeMicroSecond = 30000000; // 30000000us 99 if ((pid = fork()) < 0) { 100 HIVIEW_LOGE("Fork error, err:%{public}d", errno); 101 return 0; 102 } 103 104 if (pid == 0) { 105 auto newFd = dup(fd); 106 int ret = LogCatcherUtils::DumpStacktrace(newFd, pid_); 107 HIVIEW_LOGD("LogCatcherUtils::DumpStacktrace ret %{public}d", ret); 108 close(newFd); 109 _exit(ret); 110 } 111 112 while (true) { 113 int status = 0; 114 pid_t p = waitpid(pid, &status, WNOHANG); 115 if (p < 0) { 116 HIVIEW_LOGW("Waitpid return p=%{public}d, err:%{public}d", p, errno); 117 return -1; 118 } 119 120 if (p == pid) { 121 HIVIEW_LOGD("Dump process exited status is %{public}d", status); 122 return WEXITSTATUS(status); 123 } 124 125 if (needStop_ || leftTimeMicroSecond <= 0) { 126 HIVIEW_LOGW("Dump stacktrace timeout, killing pid %{public}d.", pid); 127 std::string str = "Dump stacktrace timeout, Catch for " + std::to_string(pid_); 128 FileUtil::SaveStringToFd(fd, str); 129 kill(pid, SIGKILL); 130 WaitChildPid(pid); 131 return -1; 132 } 133 134 usleep(SLEEP_TIME_US); // poll every 0.1 sec 135 leftTimeMicroSecond -= SLEEP_TIME_US; 136 } 137} 138} // namespace HiviewDFX 139} // namespace OHOS 140