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