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