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 28namespace OHOS { 29namespace HiviewDFX { 30static const int CHECK_TIME = 15; 31 32REGISTER(CrashValidator); 33DEFINE_LOG_LABEL(0xD002D11, "HiView-CrashValidator"); 34CrashValidator::CrashValidator() : hasLoaded_(false) 35{ 36} 37 38CrashValidator::~CrashValidator() {} 39 40void 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 52void CrashValidator::OnUnload() 53{ 54 HIVIEW_LOGI("crash validator unload"); 55} 56 57bool 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 72std::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 */ 90void 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 */ 96bool 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 */ 109bool 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 */ 137void 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 157static 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 170bool 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 204void 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 233void 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