1 /*
2 * Copyright (c) 2022 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 "crash_validator.h"
16
17
18 #include <csignal>
19 #include <iostream>
20
21 #include <fcntl.h>
22 #include <hisysevent.h>
23 #include <securec.h>
24
25 #include "plugin_factory.h"
26 #include "logger.h"
27 #include "sys_event.h"
28
29 namespace OHOS {
30 namespace HiviewDFX {
31 REGISTER(CrashValidator);
32 DEFINE_LOG_TAG("CrashValidator");
33 namespace {
34 constexpr char EVENT_CPP_CRASH[] = "CPP_CRASH";
35 constexpr char KEY_PROCESS_EXIT[] = "PROCESS_EXIT";
36 constexpr char KEY_NAME[] = "PROCESS_NAME";
37 constexpr char KEY_PID[] = "PID";
38 constexpr char KEY_UID[] = "UID";
39 constexpr char KEY_STATUS[] = "STATUS";
40 constexpr char KEY_LOG_PATH[] = "LOG_PATH";
41 constexpr char KEY_MODULE[] = "MODULE";
42 constexpr char INIT_LOG_PATTERN[] = "SigHandler, SIGCHLD received, ";
43 constexpr char KEY_NO_LOG_EVENT_NAME[] = "CPP_CRASH_NO_LOG";
44 constexpr char KEY_HAPPEN_TIME[] = "HAPPEN_TIME";
45 constexpr int32_t LOG_SIZE = 1024;
46 constexpr uint64_t MAX_LOG_GENERATE_TIME = 600; // 600 seconds
47 constexpr int32_t KMSG_SIZE = 2049;
48 }
CrashValidator()49 CrashValidator::CrashValidator() : stopReadKmsg_(false), totalEventCount_(0),
50 normalEventCount_(0), kmsgReaderThread_(nullptr)
51 {
52 name_ = "CrashValidator";
53 }
54
~CrashValidator()55 CrashValidator::~CrashValidator()
56 {
57 if (kmsgReaderThread_ != nullptr) {
58 kmsgReaderThread_ = nullptr;
59 }
60 }
61
GetListenerName()62 std::string CrashValidator::GetListenerName()
63 {
64 return name_;
65 }
66
ReadyToLoad()67 bool CrashValidator::ReadyToLoad()
68 {
69 return true;
70 }
71
CanProcessEvent(std::shared_ptr<Event> event)72 bool CrashValidator::CanProcessEvent(std::shared_ptr<Event> event)
73 {
74 return false;
75 }
76
PrintEvents(int fd,const std::vector<CrashEvent> & events)77 void CrashValidator::PrintEvents(int fd, const std::vector<CrashEvent>& events)
78 {
79 std::vector<CrashEvent>::const_iterator it = events.begin();
80 while (it != events.end()) {
81 dprintf(fd, "Module:%s Time:%" PRIu64 " Pid:%" PRIu64 " Uid:%" PRIu64 " HasLog:%d\n",
82 it->name.c_str(),
83 static_cast<uint64_t>(it->time),
84 static_cast<uint64_t>(it->pid),
85 static_cast<uint64_t>(it->uid),
86 it->isCppCrash);
87 it++;
88 }
89 }
90
Dump(int fd,const std::vector<std::string> & cmds)91 void CrashValidator::Dump(int fd, const std::vector<std::string>& cmds)
92 {
93 dprintf(fd, "Summary:\n");
94 dprintf(fd, "Total Signaled Process:%d\n", totalEventCount_);
95 dprintf(fd, "Total CppCrash Count:%d\n", normalEventCount_);
96 if (totalEventCount_ > 0) {
97 dprintf(fd, "CppCrash detect rate:%d%%\n",
98 (normalEventCount_ * 100) / totalEventCount_); // 100 : percent ratio
99 }
100
101 std::lock_guard<std::mutex> lock(lock_);
102 if (!noLogEvents_.empty()) {
103 dprintf(fd, "No CppCrash Log Events(%zu):\n", noLogEvents_.size());
104 PrintEvents(fd, noLogEvents_);
105 }
106
107 if (!pendingEvents_.empty()) {
108 dprintf(fd, "Pending CppCrash Log Events(%zu):\n", pendingEvents_.size());
109 PrintEvents(fd, pendingEvents_);
110 }
111
112 if (!matchedEvents_.empty()) {
113 dprintf(fd, "Matched Events(%zu):\n", matchedEvents_.size());
114 PrintEvents(fd, matchedEvents_);
115 }
116 }
117
OnEvent(std::shared_ptr<Event> & event)118 bool CrashValidator::OnEvent(std::shared_ptr<Event>& event)
119 {
120 OnUnorderedEvent(*(event.get()));
121 return true;
122 }
123
OnUnorderedEvent(const Event & event)124 void CrashValidator::OnUnorderedEvent(const Event &event)
125 {
126 if (GetHiviewContext() == nullptr) {
127 HIVIEW_LOGE("failed to get context.");
128 return;
129 }
130
131 std::lock_guard<std::mutex> lock(lock_);
132 Event& eventRef = const_cast<Event&>(event);
133 SysEvent& sysEvent = static_cast<SysEvent&>(eventRef);
134 if (eventRef.eventName_ == EVENT_CPP_CRASH) {
135 HandleCppCrashEvent(sysEvent);
136 } else if (eventRef.eventName_ == KEY_PROCESS_EXIT) {
137 HandleProcessExitEvent(sysEvent);
138 }
139 }
140
RemoveSimilarEvent(const CrashEvent & event)141 bool CrashValidator::RemoveSimilarEvent(const CrashEvent& event)
142 {
143 std::vector<CrashEvent>::iterator it = pendingEvents_.begin();
144 while (it != pendingEvents_.end()) {
145 if (it->uid == event.uid && it->pid == event.pid) {
146 it = pendingEvents_.erase(it);
147 normalEventCount_++;
148 return true;
149 } else {
150 ++it;
151 }
152 }
153 return false;
154 }
155
HandleCppCrashEvent(SysEvent & sysEvent)156 void CrashValidator::HandleCppCrashEvent(SysEvent& sysEvent)
157 {
158 CrashEvent crashEvent;
159 crashEvent.isCppCrash = true;
160 crashEvent.time = sysEvent.happenTime_;
161 crashEvent.uid = sysEvent.GetEventIntValue(KEY_UID);
162 crashEvent.pid = sysEvent.GetEventIntValue(KEY_PID);
163 crashEvent.path = sysEvent.GetEventValue(KEY_LOG_PATH);
164 crashEvent.name = sysEvent.GetEventValue(KEY_MODULE);
165 HIVIEW_LOGI("CrashValidator Plugin is handling CPPCRASH event [PID : %{public}d]\n", crashEvent.pid);
166 if (!RemoveSimilarEvent(crashEvent)) {
167 pendingEvents_.push_back(crashEvent);
168 }
169 }
170
HandleProcessExitEvent(SysEvent & sysEvent)171 void CrashValidator::HandleProcessExitEvent(SysEvent& sysEvent)
172 {
173 CrashEvent crashEvent;
174 crashEvent.isCppCrash = false;
175 crashEvent.time = sysEvent.happenTime_;
176 crashEvent.pid = sysEvent.GetEventIntValue(KEY_PID);
177 crashEvent.uid = sysEvent.GetEventIntValue(KEY_UID);
178 crashEvent.name = sysEvent.GetEventValue(KEY_NAME);
179 int status = static_cast<int>(sysEvent.GetEventIntValue(KEY_STATUS));
180 if (!WIFSIGNALED(status)) {
181 return;
182 }
183
184 int interestedSignalList[] = {
185 SIGABRT, SIGBUS, SIGFPE, SIGILL,
186 SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP };
187 bool shouldGenerateCppCrash = false;
188 for (size_t i = 0; i < sizeof(interestedSignalList) / sizeof(interestedSignalList[0]); i++) {
189 if (interestedSignalList[i] == WTERMSIG(status)) {
190 shouldGenerateCppCrash = true;
191 break;
192 }
193 }
194
195 if (!shouldGenerateCppCrash) {
196 return;
197 }
198
199 HIVIEW_LOGI("Process Exit Name:%{public}s Time:%{public}llu Pid:%{public}d Uid:%{public}d status:%{public}d\n",
200 crashEvent.name.c_str(),
201 static_cast<unsigned long long>(crashEvent.time),
202 crashEvent.pid,
203 crashEvent.uid,
204 status);
205 totalEventCount_++;
206 if (!RemoveSimilarEvent(crashEvent)) {
207 pendingEvents_.push_back(crashEvent);
208 }
209 }
210
CheckOutOfDateEvents()211 void CrashValidator::CheckOutOfDateEvents()
212 {
213 std::vector<CrashEvent>::iterator it = pendingEvents_.begin();
214 while (it != pendingEvents_.end()) {
215 uint64_t now = time(nullptr);
216 uint64_t eventTime = it->time;
217 if (eventTime > now) {
218 eventTime = eventTime / 1000; // 1000 : convert to second
219 }
220
221 if (now > eventTime && now - eventTime < MAX_LOG_GENERATE_TIME) {
222 it++;
223 continue;
224 }
225
226 if (!it->isCppCrash) {
227 HiSysEvent::Write("RELIABILITY", KEY_NO_LOG_EVENT_NAME, HiSysEvent::EventType::FAULT,
228 KEY_NAME, it->name,
229 KEY_PID, it->pid,
230 KEY_UID, it->uid,
231 KEY_HAPPEN_TIME, it->time);
232 noLogEvents_.push_back(*it);
233 } else {
234 totalEventCount_++;
235 normalEventCount_++;
236 }
237 it = pendingEvents_.erase(it);
238 }
239 }
240
ReadServiceCrashStatus()241 void CrashValidator::ReadServiceCrashStatus()
242 {
243 char kmsg[KMSG_SIZE];
244 int fd = open("/dev/kmsg", O_RDONLY | O_NONBLOCK);
245 if (fd == -1) {
246 HIVIEW_LOGE("Failed to open /dev/kmsg.");
247 return;
248 }
249 lseek(fd, 0, 3); // 3 : SEEK_DATA
250 while (true) {
251 ssize_t len;
252 if (-1 == (len = read(fd, kmsg, sizeof(kmsg))) && errno == EPIPE) {
253 continue;
254 }
255 if (len == -1 && errno == EINVAL) {
256 HIVIEW_LOGE("Failed to read kmsg");
257 close(fd);
258 return;
259 }
260 if (len < 1) {
261 continue;
262 }
263 kmsg[len] = 0;
264 if (stopReadKmsg_) {
265 break;
266 }
267 std::string line = kmsg;
268 auto pos = line.find(INIT_LOG_PATTERN);
269 if (pos == std::string::npos) {
270 continue;
271 }
272 std::string formatedLog = line.substr(pos + strlen(INIT_LOG_PATTERN));
273 char name[LOG_SIZE] {0};
274 int pid;
275 int uid;
276 int status;
277 int ret = sscanf_s(formatedLog.c_str(), "Service:%s pid:%d uid:%d status:%d",
278 name, sizeof(name), &pid, &uid, &status);
279 if (ret <= 0) {
280 HIVIEW_LOGI("Failed to parse kmsg:%{public}s.", formatedLog.c_str());
281 continue;
282 }
283
284 HIVIEW_LOGI("report PROCESS_EXIT event[name : %{public}s pid : %{public}d]", name, pid);
285
286 HiSysEvent::Write(HiSysEvent::Domain::STARTUP, KEY_PROCESS_EXIT, HiSysEvent::EventType::BEHAVIOR,
287 KEY_NAME, name, KEY_PID, pid, KEY_UID, uid, KEY_STATUS, status);
288 }
289 close(fd);
290 }
291
ValidateLogContent(const CrashEvent & event)292 bool CrashValidator::ValidateLogContent(const CrashEvent& event)
293 {
294 // check later
295 return true;
296 }
297
OnLoad()298 void CrashValidator::OnLoad()
299 {
300 kmsgReaderThread_ = std::make_unique<std::thread>(&CrashValidator::ReadServiceCrashStatus, this);
301 kmsgReaderThread_->detach();
302 AddListenerInfo(Event::MessageType::SYS_EVENT, EVENT_CPP_CRASH);
303 AddListenerInfo(Event::MessageType::SYS_EVENT, KEY_PROCESS_EXIT);
304 GetHiviewContext()->RegisterUnorderedEventListener(
305 std::static_pointer_cast<CrashValidator>(shared_from_this()));
306 GetHiviewContext()->AppendPluginToPipeline(GetName(), "SysEventPipeline");
307 }
308
OnUnload()309 void CrashValidator::OnUnload()
310 {
311 stopReadKmsg_ = true;
312 totalEventCount_ = 0;
313 normalEventCount_ = 0;
314 pendingEvents_.clear();
315 noLogEvents_.clear();
316 matchedEvents_.clear();
317 }
318 } // namespace HiviewDFX
319 } // namespace OHOS
320