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