1 /*
2 * Copyright (c) 2021-2024 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
16 #include "crash_validator.h"
17
18 #include <csignal>
19 #include <cstdio>
20 #include <memory>
21 #include <set>
22
23 #include "hisysevent.h"
24 #include "hiview_logger.h"
25 #include "plugin_factory.h"
26 #include "time_util.h"
27
28 namespace OHOS {
29 namespace HiviewDFX {
30 static const int CHECK_TIME = 15;
31
32 REGISTER(CrashValidator);
33 DEFINE_LOG_LABEL(0xD002D11, "HiView-CrashValidator");
CrashValidator()34 CrashValidator::CrashValidator() : hasLoaded_(false)
35 {
36 }
37
~CrashValidator()38 CrashValidator::~CrashValidator() {}
39
OnLoad()40 void CrashValidator::OnLoad()
41 {
42 if (GetHiviewContext() == nullptr) {
43 HIVIEW_LOGE("hiview context is null");
44 return;
45 }
46 InitWorkLoop();
47 GetHiviewContext()->AppendPluginToPipeline("CrashValidator", "faultloggerPipeline");
48 HIVIEW_LOGI("crash validator load");
49 hasLoaded_ = true;
50 }
51
OnUnload()52 void CrashValidator::OnUnload()
53 {
54 HIVIEW_LOGI("crash validator unload");
55 }
56
IsInterestedPipelineEvent(std::shared_ptr<Event> event)57 bool CrashValidator::IsInterestedPipelineEvent(std::shared_ptr<Event> event)
58 {
59 if (!hasLoaded_ || event == nullptr) {
60 return false;
61 }
62
63 if (event->eventName_ != "PROCESS_EXIT" &&
64 event->eventName_ != "CPP_CRASH" &&
65 event->eventName_ != "CPP_CRASH_EXCEPTION") {
66 return false;
67 }
68
69 return true;
70 }
71
Convert2SysEvent(std::shared_ptr<Event>& event)72 std::shared_ptr<SysEvent> CrashValidator::Convert2SysEvent(std::shared_ptr<Event>& event)
73 {
74 if (event == nullptr) {
75 HIVIEW_LOGE("event is null");
76 return nullptr;
77 }
78 if (event->messageType_ != Event::MessageType::SYS_EVENT) {
79 HIVIEW_LOGE("receive out of sys event type");
80 return nullptr;
81 }
82 std::shared_ptr<SysEvent> sysEvent = Event::DownCastTo<SysEvent>(event);
83 if (sysEvent == nullptr) {
84 HIVIEW_LOGE("sysevent is null");
85 }
86 return sysEvent;
87 }
88
89 /* use hiview shared workloop as our workloop */
InitWorkLoop()90 void CrashValidator::InitWorkLoop()
91 {
92 workLoop_ = GetHiviewContext()->GetSharedWorkLoop();
93 }
94
95 /* check process event map empty or not. if empty, clear crash and crash exception maps */
CheckProcessMapEmpty()96 bool CrashValidator::CheckProcessMapEmpty()
97 {
98 if (processExitEvents_.empty()) {
99 HIVIEW_LOGI("exit processes empty");
100 cppCrashEvents_.clear();
101 cppCrashExceptionEvents_.clear();
102 return true;
103 }
104
105 return false;
106 }
107
108 /* only process exit with status !=0 will trigger this func be called */
MatchEvent(int32_t pid)109 bool CrashValidator::MatchEvent(int32_t pid)
110 {
111 std::lock_guard<std::mutex> lock(mutex_);
112
113 if (CheckProcessMapEmpty()) {
114 return false;
115 }
116
117 if (processExitEvents_.find(pid) == processExitEvents_.end()) {
118 HIVIEW_LOGE("process(pid = %d) does not in process exit map", pid);
119 return false;
120 }
121
122 if (cppCrashExceptionEvents_.find(pid) != cppCrashExceptionEvents_.end()) {
123 ReportMatchEvent("CPP_CRASH_EXCEPTION_MATCHED", cppCrashExceptionEvents_[pid]);
124 cppCrashExceptionEvents_.erase(pid);
125 } else if (cppCrashEvents_.find(pid) != cppCrashEvents_.end()) {
126 ReportMatchEvent("CPP_CRASH_MATCHED", cppCrashEvents_[pid]);
127 cppCrashEvents_.erase(pid);
128 } else {
129 ReportDisMatchEvent(processExitEvents_[pid]);
130 }
131 processExitEvents_.erase(pid);
132 CheckProcessMapEmpty();
133 return true;
134 }
135
136 /* process exit、 crash exception、 crash events insert into each map */
AddEventToMap(int32_t pid, std::shared_ptr<SysEvent> sysEvent)137 void CrashValidator::AddEventToMap(int32_t pid, std::shared_ptr<SysEvent> sysEvent)
138 {
139 int64_t happendTime = sysEvent->GetEventIntValue("time_");
140 std::lock_guard<std::mutex> lock(mutex_);
141
142 if ((sysEvent->eventName_ == "PROCESS_EXIT")) {
143 processExitEvents_.try_emplace(pid, sysEvent);
144 } else if (sysEvent->eventName_ == "CPP_CRASH") {
145 if ((cppCrashEvents_.find(pid) == cppCrashEvents_.end()) ||
146 (cppCrashEvents_[pid]->GetEventIntValue("time_") - happendTime > 0)) {
147 cppCrashEvents_[pid] = sysEvent;
148 }
149 } else {
150 if ((cppCrashExceptionEvents_.find(pid) == cppCrashExceptionEvents_.end()) ||
151 (cppCrashExceptionEvents_[pid]->GetEventIntValue("time_") - happendTime > 0)) {
152 cppCrashExceptionEvents_[pid] = sysEvent;
153 }
154 }
155 }
156
IsNormalExitEvent(std::shared_ptr<SysEvent> sysEvent)157 static bool IsNormalExitEvent(std::shared_ptr<SysEvent> sysEvent)
158 {
159 std::set<int32_t> crashSet = { SIGILL, SIGABRT, SIGBUS, SIGFPE,
160 SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP };
161 int32_t status = sysEvent->GetEventIntValue("STATUS");
162 int32_t exitSigno = WTERMSIG(status);
163 if (crashSet.count(exitSigno)) {
164 return false;
165 }
166
167 return true;
168 }
169
OnEvent(std::shared_ptr<Event>& event)170 bool CrashValidator::OnEvent(std::shared_ptr<Event>& event)
171 {
172 if (!hasLoaded_ || event == nullptr) {
173 HIVIEW_LOGE("crash validator not ready");
174 return false;
175 }
176 if (event->rawData_ == nullptr) {
177 return false;
178 }
179
180 std::shared_ptr<SysEvent> sysEvent = Convert2SysEvent(event);
181 if (sysEvent == nullptr) {
182 return false;
183 }
184
185 if ((sysEvent->eventName_ == "PROCESS_EXIT") && IsNormalExitEvent(sysEvent)) {
186 return true;
187 }
188
189 int32_t pid = sysEvent->GetEventIntValue("PID");
190 AddEventToMap(pid, sysEvent);
191 if (sysEvent->eventName_ == "PROCESS_EXIT") {
192 workLoop_->AddTimerEvent(nullptr, nullptr, [this, pid] {
193 MatchEvent(pid);
194 }, CHECK_TIME, false);
195 int32_t status = sysEvent->GetEventIntValue("STATUS");
196 int32_t exitSigno = WTERMSIG(status);
197 HIVIEW_LOGI("Add MatchEvent task, process pid = %{public}d, name = %{public}s, exitSigno = %{public}d",
198 pid, sysEvent->GetEventValue("PROCESS_NAME").c_str(), exitSigno);
199 }
200
201 return true;
202 }
203
ReportMatchEvent(std::string eventName, std::shared_ptr<SysEvent> sysEvent)204 void CrashValidator::ReportMatchEvent(std::string eventName, std::shared_ptr<SysEvent> sysEvent)
205 {
206 std::string summary;
207 std::string processName;
208
209 if (sysEvent == nullptr) {
210 HIVIEW_LOGE("report match sysEvent is null");
211 return;
212 }
213
214 if (eventName == "CPP_CRASH_MATCHED") {
215 summary = sysEvent->GetEventValue("SUMMARY");
216 processName = sysEvent->GetEventValue("MODULE");
217 } else if (eventName == "CPP_CRASH_EXCEPTION_MATCHED") {
218 summary = sysEvent->GetEventValue("ERROR_MSG");
219 processName = sysEvent->GetEventValue("PROCESS_NAME");
220 }
221
222 HiSysEventWrite(
223 HiSysEvent::Domain::RELIABILITY,
224 eventName,
225 HiSysEvent::EventType::FAULT,
226 "PROCESS_NAME", processName,
227 "PID", sysEvent->GetEventIntValue("PID"),
228 "UID", sysEvent->GetEventIntValue("UID"),
229 "HAPPEN_TIME", sysEvent->GetEventIntValue("HAPPEN_TIME"),
230 "SUMMARY", summary);
231 }
232
ReportDisMatchEvent(std::shared_ptr<SysEvent> sysEvent)233 void CrashValidator::ReportDisMatchEvent(std::shared_ptr<SysEvent> sysEvent)
234 {
235 if (sysEvent == nullptr) {
236 HIVIEW_LOGE("report dismatch sysEvent is null");
237 return;
238 }
239
240 HiSysEventWrite(
241 HiSysEvent::Domain::RELIABILITY,
242 "CPP_CRASH_DISMATCH",
243 HiSysEvent::EventType::FAULT,
244 "PROCESS_NAME", sysEvent->GetEventValue("PROCESS_NAME"),
245 "PID", sysEvent->GetEventIntValue("PID"),
246 "UID", sysEvent->GetEventIntValue("UID"));
247 }
248
249 }
250 }
251