1800b99b8Sopenharmony_ci/* 2800b99b8Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License. 5800b99b8Sopenharmony_ci * You may obtain a copy of the License at 6800b99b8Sopenharmony_ci * 7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8800b99b8Sopenharmony_ci * 9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and 13800b99b8Sopenharmony_ci * limitations under the License. 14800b99b8Sopenharmony_ci */ 15800b99b8Sopenharmony_ci#include "crash_validator.h" 16800b99b8Sopenharmony_ci 17800b99b8Sopenharmony_ci#include <cinttypes> 18800b99b8Sopenharmony_ci#include <csignal> 19800b99b8Sopenharmony_ci#ifdef HISYSEVENT_ENABLE 20800b99b8Sopenharmony_ci#include <fcntl.h> 21800b99b8Sopenharmony_ci#include <hisysevent.h> 22800b99b8Sopenharmony_ci#include <securec.h> 23800b99b8Sopenharmony_ci#include <unistd.h> 24800b99b8Sopenharmony_ci 25800b99b8Sopenharmony_ci#include "hisysevent_manager.h" 26800b99b8Sopenharmony_ci 27800b99b8Sopenharmony_cinamespace OHOS { 28800b99b8Sopenharmony_cinamespace HiviewDFX { 29800b99b8Sopenharmony_cinamespace { 30800b99b8Sopenharmony_ciconstexpr char EVENT_CPP_CRASH[] = "CPP_CRASH"; 31800b99b8Sopenharmony_ciconstexpr char KEY_PROCESS_EXIT[] = "PROCESS_EXIT"; 32800b99b8Sopenharmony_ciconstexpr char KEY_NAME[] = "PROCESS_NAME"; 33800b99b8Sopenharmony_ciconstexpr char KEY_PID[] = "PID"; 34800b99b8Sopenharmony_ciconstexpr char KEY_UID[] = "UID"; 35800b99b8Sopenharmony_ciconstexpr char KEY_STATUS[] = "STATUS"; 36800b99b8Sopenharmony_ciconstexpr char KEY_LOG_PATH[] = "LOG_PATH"; 37800b99b8Sopenharmony_ciconstexpr char KEY_MODULE[] = "MODULE"; 38800b99b8Sopenharmony_ciconstexpr char INIT_LOG_PATTERN[] = "Service warning "; 39800b99b8Sopenharmony_ciconstexpr char KEY_NO_LOG_EVENT_NAME[] = "CPP_CRASH_NO_LOG"; 40800b99b8Sopenharmony_ciconstexpr char KEY_HAPPEN_TIME[] = "HAPPEN_TIME"; 41800b99b8Sopenharmony_ciconstexpr int32_t LOG_SIZE = 1024; 42800b99b8Sopenharmony_ciconstexpr uint64_t MAX_LOG_GENERATE_TIME = 600; // 600 seconds 43800b99b8Sopenharmony_ciconstexpr int32_t KMSG_SIZE = 2049; 44800b99b8Sopenharmony_ci} 45800b99b8Sopenharmony_ciCrashValidator::CrashValidator() : stopReadKmsg_(false), totalEventCount_(0), 46800b99b8Sopenharmony_ci normalEventCount_(0), kmsgReaderThread_(nullptr) 47800b99b8Sopenharmony_ci{ 48800b99b8Sopenharmony_ci} 49800b99b8Sopenharmony_ci 50800b99b8Sopenharmony_ciCrashValidator::~CrashValidator() 51800b99b8Sopenharmony_ci{ 52800b99b8Sopenharmony_ci if (kmsgReaderThread_ != nullptr) { 53800b99b8Sopenharmony_ci kmsgReaderThread_ = nullptr; 54800b99b8Sopenharmony_ci } 55800b99b8Sopenharmony_ci} 56800b99b8Sopenharmony_ci 57800b99b8Sopenharmony_civoid CrashValidator::OnEvent(std::shared_ptr<HiviewDFX::HiSysEventRecord> sysEvent) 58800b99b8Sopenharmony_ci{ 59800b99b8Sopenharmony_ci std::lock_guard<std::mutex> lock(lock_); 60800b99b8Sopenharmony_ci if (sysEvent == nullptr) { 61800b99b8Sopenharmony_ci return; 62800b99b8Sopenharmony_ci } 63800b99b8Sopenharmony_ci auto domain = sysEvent->GetDomain(); 64800b99b8Sopenharmony_ci auto eventName = sysEvent->GetEventName(); 65800b99b8Sopenharmony_ci if (eventName == EVENT_CPP_CRASH) { 66800b99b8Sopenharmony_ci HandleCppCrashEvent(sysEvent); 67800b99b8Sopenharmony_ci } else if (eventName == KEY_PROCESS_EXIT) { 68800b99b8Sopenharmony_ci HandleProcessExitEvent(sysEvent); 69800b99b8Sopenharmony_ci } 70800b99b8Sopenharmony_ci} 71800b99b8Sopenharmony_ci 72800b99b8Sopenharmony_civoid CrashValidator::OnServiceDied() 73800b99b8Sopenharmony_ci{ 74800b99b8Sopenharmony_ci printf("SysEventServiceDied?.\n"); 75800b99b8Sopenharmony_ci} 76800b99b8Sopenharmony_ci 77800b99b8Sopenharmony_cibool CrashValidator::InitSysEventListener() 78800b99b8Sopenharmony_ci{ 79800b99b8Sopenharmony_ci std::vector<ListenerRule> sysRules; 80800b99b8Sopenharmony_ci sysRules.emplace_back("RELIABILITY", "CPP_CRASH"); 81800b99b8Sopenharmony_ci sysRules.emplace_back("STARTUP", "PROCESS_EXIT"); 82800b99b8Sopenharmony_ci if (HiSysEventManager::AddListener(shared_from_this(), sysRules) != 0) { 83800b99b8Sopenharmony_ci return false; 84800b99b8Sopenharmony_ci } 85800b99b8Sopenharmony_ci 86800b99b8Sopenharmony_ci kmsgReaderThread_ = std::make_unique<std::thread>([this] { 87800b99b8Sopenharmony_ci ReadServiceCrashStatus(); 88800b99b8Sopenharmony_ci }); 89800b99b8Sopenharmony_ci kmsgReaderThread_->detach(); 90800b99b8Sopenharmony_ci return true; 91800b99b8Sopenharmony_ci} 92800b99b8Sopenharmony_ci 93800b99b8Sopenharmony_civoid CrashValidator::RemoveSysEventListener() 94800b99b8Sopenharmony_ci{ 95800b99b8Sopenharmony_ci int32_t result = HiSysEventManager::RemoveListener(shared_from_this()); 96800b99b8Sopenharmony_ci printf("remove listener result: %d\n", result); 97800b99b8Sopenharmony_ci} 98800b99b8Sopenharmony_ci 99800b99b8Sopenharmony_civoid CrashValidator::PrintEvents(int fd, const std::vector<CrashEvent>& events, bool isMatched) 100800b99b8Sopenharmony_ci{ 101800b99b8Sopenharmony_ci std::vector<CrashEvent>::const_iterator it = events.begin(); 102800b99b8Sopenharmony_ci while (it != events.end()) { 103800b99b8Sopenharmony_ci if (isMatched) { 104800b99b8Sopenharmony_ci dprintf(fd, "Module:%s Time:%" PRIu64 " Pid:%" PRIu64 " Uid:%" PRIu64 "\n", 105800b99b8Sopenharmony_ci it->name.c_str(), 106800b99b8Sopenharmony_ci static_cast<uint64_t>(it->time), 107800b99b8Sopenharmony_ci static_cast<uint64_t>(it->pid), 108800b99b8Sopenharmony_ci static_cast<uint64_t>(it->uid)); 109800b99b8Sopenharmony_ci } else { 110800b99b8Sopenharmony_ci dprintf(fd, "Module:%s Time:%" PRIu64 " Pid:%" PRIu64 " Uid:%" PRIu64 " HasLog:%d\n", 111800b99b8Sopenharmony_ci it->name.c_str(), 112800b99b8Sopenharmony_ci static_cast<uint64_t>(it->time), 113800b99b8Sopenharmony_ci static_cast<uint64_t>(it->pid), 114800b99b8Sopenharmony_ci static_cast<uint64_t>(it->uid), 115800b99b8Sopenharmony_ci it->isCppCrash); 116800b99b8Sopenharmony_ci } 117800b99b8Sopenharmony_ci ++it; 118800b99b8Sopenharmony_ci } 119800b99b8Sopenharmony_ci} 120800b99b8Sopenharmony_ci 121800b99b8Sopenharmony_civoid CrashValidator::Dump(int fd) 122800b99b8Sopenharmony_ci{ 123800b99b8Sopenharmony_ci dprintf(fd, "Summary:\n"); 124800b99b8Sopenharmony_ci dprintf(fd, "Total Signaled Process:%d\n", totalEventCount_); 125800b99b8Sopenharmony_ci dprintf(fd, "Total CppCrash Count:%d\n", normalEventCount_); 126800b99b8Sopenharmony_ci if (totalEventCount_ > 0) { 127800b99b8Sopenharmony_ci dprintf(fd, "CppCrash detect rate:%d%%\n", 128800b99b8Sopenharmony_ci (normalEventCount_ * 100) / totalEventCount_); // 100 : percent ratio 129800b99b8Sopenharmony_ci } 130800b99b8Sopenharmony_ci 131800b99b8Sopenharmony_ci std::lock_guard<std::mutex> lock(lock_); 132800b99b8Sopenharmony_ci if (!noLogEvents_.empty()) { 133800b99b8Sopenharmony_ci dprintf(fd, "No CppCrash Log Events(%zu):\n", noLogEvents_.size()); 134800b99b8Sopenharmony_ci PrintEvents(fd, noLogEvents_, false); 135800b99b8Sopenharmony_ci } 136800b99b8Sopenharmony_ci 137800b99b8Sopenharmony_ci if (!pendingEvents_.empty()) { 138800b99b8Sopenharmony_ci dprintf(fd, "Pending CppCrash Log Events(%zu):\n", pendingEvents_.size()); 139800b99b8Sopenharmony_ci PrintEvents(fd, pendingEvents_, false); 140800b99b8Sopenharmony_ci } 141800b99b8Sopenharmony_ci 142800b99b8Sopenharmony_ci if (!matchedEvents_.empty()) { 143800b99b8Sopenharmony_ci dprintf(fd, "Matched Events(%zu):\n", matchedEvents_.size()); 144800b99b8Sopenharmony_ci PrintEvents(fd, matchedEvents_, true); 145800b99b8Sopenharmony_ci } 146800b99b8Sopenharmony_ci} 147800b99b8Sopenharmony_ci 148800b99b8Sopenharmony_cibool CrashValidator::RemoveSimilarEvent(const CrashEvent& event) 149800b99b8Sopenharmony_ci{ 150800b99b8Sopenharmony_ci for (const auto& matchedEvent : matchedEvents_) { 151800b99b8Sopenharmony_ci if (matchedEvent.pid == event.pid && matchedEvent.uid == event.uid) { 152800b99b8Sopenharmony_ci return true; 153800b99b8Sopenharmony_ci } 154800b99b8Sopenharmony_ci } 155800b99b8Sopenharmony_ci std::vector<CrashEvent>::iterator it = pendingEvents_.begin(); 156800b99b8Sopenharmony_ci while (it != pendingEvents_.end()) { 157800b99b8Sopenharmony_ci if (it->uid == event.uid && it->pid == event.pid) { 158800b99b8Sopenharmony_ci if (it->isCppCrash != event.isCppCrash) { 159800b99b8Sopenharmony_ci it = pendingEvents_.erase(it); 160800b99b8Sopenharmony_ci normalEventCount_++; 161800b99b8Sopenharmony_ci matchedEvents_.push_back(event); 162800b99b8Sopenharmony_ci } 163800b99b8Sopenharmony_ci return true; 164800b99b8Sopenharmony_ci } else { 165800b99b8Sopenharmony_ci ++it; 166800b99b8Sopenharmony_ci } 167800b99b8Sopenharmony_ci } 168800b99b8Sopenharmony_ci return false; 169800b99b8Sopenharmony_ci} 170800b99b8Sopenharmony_ci 171800b99b8Sopenharmony_civoid CrashValidator::HandleCppCrashEvent(std::shared_ptr<HiviewDFX::HiSysEventRecord> sysEvent) 172800b99b8Sopenharmony_ci{ 173800b99b8Sopenharmony_ci if (sysEvent == nullptr) { 174800b99b8Sopenharmony_ci return; 175800b99b8Sopenharmony_ci } 176800b99b8Sopenharmony_ci CrashEvent crashEvent; 177800b99b8Sopenharmony_ci crashEvent.isCppCrash = true; 178800b99b8Sopenharmony_ci sysEvent->GetParamValue(KEY_HAPPEN_TIME, crashEvent.time); 179800b99b8Sopenharmony_ci sysEvent->GetParamValue(KEY_UID, crashEvent.uid); 180800b99b8Sopenharmony_ci sysEvent->GetParamValue(KEY_PID, crashEvent.pid); 181800b99b8Sopenharmony_ci sysEvent->GetParamValue(KEY_LOG_PATH, crashEvent.path); 182800b99b8Sopenharmony_ci sysEvent->GetParamValue(KEY_MODULE, crashEvent.name); 183800b99b8Sopenharmony_ci printf("CPPCRASH:[Pid:%" PRIi64 " Uid:%" PRIi64 " Module:%s]\n", 184800b99b8Sopenharmony_ci crashEvent.pid, crashEvent.uid, crashEvent.name.c_str()); 185800b99b8Sopenharmony_ci if (!RemoveSimilarEvent(crashEvent)) { 186800b99b8Sopenharmony_ci totalEventCount_++; 187800b99b8Sopenharmony_ci pendingEvents_.push_back(crashEvent); 188800b99b8Sopenharmony_ci } 189800b99b8Sopenharmony_ci} 190800b99b8Sopenharmony_ci 191800b99b8Sopenharmony_civoid CrashValidator::HandleProcessExitEvent(std::shared_ptr<HiviewDFX::HiSysEventRecord> sysEvent) 192800b99b8Sopenharmony_ci{ 193800b99b8Sopenharmony_ci if (sysEvent == nullptr) { 194800b99b8Sopenharmony_ci return; 195800b99b8Sopenharmony_ci } 196800b99b8Sopenharmony_ci int64_t status64 = 0; 197800b99b8Sopenharmony_ci sysEvent->GetParamValue(KEY_STATUS, status64); 198800b99b8Sopenharmony_ci int32_t status = static_cast<int32_t>(status64); 199800b99b8Sopenharmony_ci if (!WIFSIGNALED(status) && !WIFEXITED(status)) { 200800b99b8Sopenharmony_ci return; 201800b99b8Sopenharmony_ci } 202800b99b8Sopenharmony_ci 203800b99b8Sopenharmony_ci CrashEvent crashEvent; 204800b99b8Sopenharmony_ci crashEvent.isCppCrash = false; 205800b99b8Sopenharmony_ci crashEvent.time = sysEvent->GetTime(); 206800b99b8Sopenharmony_ci sysEvent->GetParamValue(KEY_UID, crashEvent.uid); 207800b99b8Sopenharmony_ci sysEvent->GetParamValue(KEY_PID, crashEvent.pid); 208800b99b8Sopenharmony_ci sysEvent->GetParamValue(KEY_NAME, crashEvent.name); 209800b99b8Sopenharmony_ci int exitSigno = WTERMSIG(status); 210800b99b8Sopenharmony_ci // crash in pid namespace exit signo is zero, instead of use exit status code. 211800b99b8Sopenharmony_ci if (exitSigno == 0) { 212800b99b8Sopenharmony_ci exitSigno = WEXITSTATUS(status); 213800b99b8Sopenharmony_ci } 214800b99b8Sopenharmony_ci 215800b99b8Sopenharmony_ci int interestedSignalList[] = { 216800b99b8Sopenharmony_ci SIGABRT, SIGBUS, SIGFPE, SIGILL, 217800b99b8Sopenharmony_ci SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP }; 218800b99b8Sopenharmony_ci bool shouldGenerateCppCrash = false; 219800b99b8Sopenharmony_ci for (size_t i = 0; i < sizeof(interestedSignalList) / sizeof(interestedSignalList[0]); i++) { 220800b99b8Sopenharmony_ci if (interestedSignalList[i] == exitSigno) { 221800b99b8Sopenharmony_ci shouldGenerateCppCrash = true; 222800b99b8Sopenharmony_ci break; 223800b99b8Sopenharmony_ci } 224800b99b8Sopenharmony_ci } 225800b99b8Sopenharmony_ci 226800b99b8Sopenharmony_ci if (!shouldGenerateCppCrash) { 227800b99b8Sopenharmony_ci return; 228800b99b8Sopenharmony_ci } 229800b99b8Sopenharmony_ci 230800b99b8Sopenharmony_ci printf("Process Exit Name:%s Time:%llu [Pid:%" PRIi64 " Uid:%" PRIi64 "] status:%d\n", 231800b99b8Sopenharmony_ci crashEvent.name.c_str(), 232800b99b8Sopenharmony_ci static_cast<unsigned long long>(crashEvent.time), 233800b99b8Sopenharmony_ci crashEvent.pid, 234800b99b8Sopenharmony_ci crashEvent.uid, 235800b99b8Sopenharmony_ci status); 236800b99b8Sopenharmony_ci if (!RemoveSimilarEvent(crashEvent)) { 237800b99b8Sopenharmony_ci totalEventCount_++; 238800b99b8Sopenharmony_ci pendingEvents_.push_back(crashEvent); 239800b99b8Sopenharmony_ci } 240800b99b8Sopenharmony_ci} 241800b99b8Sopenharmony_ci 242800b99b8Sopenharmony_civoid CrashValidator::CheckOutOfDateEvents() 243800b99b8Sopenharmony_ci{ 244800b99b8Sopenharmony_ci std::vector<CrashEvent>::iterator it = pendingEvents_.begin(); 245800b99b8Sopenharmony_ci while (it != pendingEvents_.end()) { 246800b99b8Sopenharmony_ci uint64_t now = time(nullptr); 247800b99b8Sopenharmony_ci uint64_t eventTime = it->time; 248800b99b8Sopenharmony_ci if (eventTime > now) { 249800b99b8Sopenharmony_ci eventTime = eventTime / 1000; // 1000 : convert to second 250800b99b8Sopenharmony_ci } 251800b99b8Sopenharmony_ci 252800b99b8Sopenharmony_ci if (now > eventTime && now - eventTime < MAX_LOG_GENERATE_TIME) { 253800b99b8Sopenharmony_ci ++it; 254800b99b8Sopenharmony_ci continue; 255800b99b8Sopenharmony_ci } 256800b99b8Sopenharmony_ci 257800b99b8Sopenharmony_ci if (!it->isCppCrash) { 258800b99b8Sopenharmony_ci HiSysEventWrite(HiSysEvent::Domain::RELIABILITY, KEY_NO_LOG_EVENT_NAME, HiSysEvent::EventType::FAULT, 259800b99b8Sopenharmony_ci KEY_NAME, it->name, 260800b99b8Sopenharmony_ci KEY_PID, it->pid, 261800b99b8Sopenharmony_ci KEY_UID, it->uid, 262800b99b8Sopenharmony_ci KEY_HAPPEN_TIME, it->time); 263800b99b8Sopenharmony_ci noLogEvents_.push_back(*it); 264800b99b8Sopenharmony_ci } else { 265800b99b8Sopenharmony_ci totalEventCount_++; 266800b99b8Sopenharmony_ci normalEventCount_++; 267800b99b8Sopenharmony_ci } 268800b99b8Sopenharmony_ci it = pendingEvents_.erase(it); 269800b99b8Sopenharmony_ci } 270800b99b8Sopenharmony_ci} 271800b99b8Sopenharmony_ci 272800b99b8Sopenharmony_civoid CrashValidator::ReadServiceCrashStatus() 273800b99b8Sopenharmony_ci{ 274800b99b8Sopenharmony_ci char kmsg[KMSG_SIZE]; 275800b99b8Sopenharmony_ci int fd = open("/dev/kmsg", O_RDONLY | O_NONBLOCK); 276800b99b8Sopenharmony_ci if (fd == -1) { 277800b99b8Sopenharmony_ci printf("Failed to open /dev/kmsg.\n"); 278800b99b8Sopenharmony_ci return; 279800b99b8Sopenharmony_ci } 280800b99b8Sopenharmony_ci lseek(fd, 0, 3); // 3 : SEEK_DATA 281800b99b8Sopenharmony_ci while (true) { 282800b99b8Sopenharmony_ci ssize_t len; 283800b99b8Sopenharmony_ci if (((len = read(fd, kmsg, sizeof(kmsg))) == -1) && errno == EPIPE) { 284800b99b8Sopenharmony_ci continue; 285800b99b8Sopenharmony_ci } 286800b99b8Sopenharmony_ci if (len == -1 && errno == EINVAL) { 287800b99b8Sopenharmony_ci printf("Failed to read kmsg\n"); 288800b99b8Sopenharmony_ci close(fd); 289800b99b8Sopenharmony_ci return; 290800b99b8Sopenharmony_ci } 291800b99b8Sopenharmony_ci if (len < 1) { 292800b99b8Sopenharmony_ci continue; 293800b99b8Sopenharmony_ci } 294800b99b8Sopenharmony_ci kmsg[len] = 0; 295800b99b8Sopenharmony_ci if (stopReadKmsg_) { 296800b99b8Sopenharmony_ci break; 297800b99b8Sopenharmony_ci } 298800b99b8Sopenharmony_ci std::string line = kmsg; 299800b99b8Sopenharmony_ci auto pos = line.find(INIT_LOG_PATTERN); 300800b99b8Sopenharmony_ci if (pos == std::string::npos) { 301800b99b8Sopenharmony_ci continue; 302800b99b8Sopenharmony_ci } 303800b99b8Sopenharmony_ci std::string formattedLog = line.substr(pos + strlen(INIT_LOG_PATTERN)); 304800b99b8Sopenharmony_ci char name[LOG_SIZE] {0}; 305800b99b8Sopenharmony_ci int pid; 306800b99b8Sopenharmony_ci int uid; 307800b99b8Sopenharmony_ci int status; 308800b99b8Sopenharmony_ci int ret = sscanf_s(formattedLog.c_str(), "%[^,], SIGCHLD received, pid:%d uid:%d status:%d.", 309800b99b8Sopenharmony_ci name, sizeof(name), &pid, &uid, &status); 310800b99b8Sopenharmony_ci if (ret <= 0) { 311800b99b8Sopenharmony_ci printf("Failed to parse kmsg:%s", formattedLog.c_str()); 312800b99b8Sopenharmony_ci continue; 313800b99b8Sopenharmony_ci } 314800b99b8Sopenharmony_ci 315800b99b8Sopenharmony_ci printf("Kernel:%s", formattedLog.c_str()); 316800b99b8Sopenharmony_ci HiSysEventWrite(HiSysEvent::Domain::STARTUP, KEY_PROCESS_EXIT, HiSysEvent::EventType::BEHAVIOR, 317800b99b8Sopenharmony_ci KEY_NAME, name, KEY_PID, pid, KEY_UID, uid, KEY_STATUS, status); 318800b99b8Sopenharmony_ci } 319800b99b8Sopenharmony_ci close(fd); 320800b99b8Sopenharmony_ci} 321800b99b8Sopenharmony_ci 322800b99b8Sopenharmony_cibool CrashValidator::ValidateLogContent(const CrashEvent& event) 323800b99b8Sopenharmony_ci{ 324800b99b8Sopenharmony_ci // check later 325800b99b8Sopenharmony_ci return true; 326800b99b8Sopenharmony_ci} 327800b99b8Sopenharmony_ci} // namespace HiviewDFX 328800b99b8Sopenharmony_ci} // namespace OHOS 329800b99b8Sopenharmony_ci#endif 330