• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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