1/* 2 * Copyright (c) 2021 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#include "faultlog_database.h" 16 17#include <algorithm> 18#include <cinttypes> 19#include <list> 20#include <mutex> 21#include <string> 22 23#include "faultlog_info.h" 24#include "faultlog_util.h" 25#include "hisysevent.h" 26#include "hiview_global.h" 27#include "hiview_logger.h" 28#include "log_analyzer.h" 29#include "string_util.h" 30#include "sys_event_dao.h" 31#include "time_util.h" 32 33#include "decoded/decoded_event.h" 34 35using namespace std; 36namespace OHOS { 37namespace HiviewDFX { 38DEFINE_LOG_LABEL(0xD002D11, "FaultLogDatabase"); 39namespace { 40static const std::vector<std::string> QUERY_ITEMS = { 41 "time_", "name_", "uid_", "pid_", "MODULE", "REASON", "SUMMARY", "LOG_PATH", "FAULT_TYPE" 42}; 43static const std::string LOG_PATH_BASE = "/data/log/faultlog/faultlogger/"; 44bool ParseFaultLogInfoFromJson(std::shared_ptr<EventRaw::RawData> rawData, FaultLogInfo& info) 45{ 46 if (rawData == nullptr) { 47 HIVIEW_LOGE("raw data of sys event is null."); 48 return false; 49 } 50 auto sysEvent = std::make_unique<SysEvent>("FaultLogDatabase", nullptr, rawData); 51 constexpr string::size_type FIRST_200_BYTES = 200; 52 HIVIEW_LOGI("parse FaultLogInfo from %{public}s.", sysEvent->AsJsonStr().substr(0, FIRST_200_BYTES).c_str()); 53 constexpr int64_t DEFAULT_INT_VALUE = 0; 54 info.time = static_cast<int64_t>(std::atoll(sysEvent->GetEventValue("HAPPEN_TIME").c_str())); 55 if (info.time == DEFAULT_INT_VALUE) { 56 info.time = sysEvent->GetEventIntValue("HAPPEN_TIME") != DEFAULT_INT_VALUE? 57 sysEvent->GetEventIntValue("HAPPEN_TIME") : sysEvent->GetEventIntValue("time_"); 58 } 59 info.pid = sysEvent->GetEventIntValue("PID") != DEFAULT_INT_VALUE ? 60 sysEvent->GetEventIntValue("PID") : sysEvent->GetEventIntValue("pid_"); 61 62 info.id = sysEvent->GetEventIntValue("UID") != DEFAULT_INT_VALUE ? 63 sysEvent->GetEventIntValue("UID") : sysEvent->GetEventIntValue("uid_"); 64 info.faultLogType = std::atoi(sysEvent->GetEventValue("FAULT_TYPE").c_str()); 65 info.module = sysEvent->GetEventValue("MODULE"); 66 info.reason = sysEvent->GetEventValue("REASON"); 67 info.summary = StringUtil::UnescapeJsonStringValue(sysEvent->GetEventValue("SUMMARY")); 68 info.logPath = LOG_PATH_BASE + GetFaultLogName(info); 69 return true; 70} 71} 72 73FaultLogDatabase::FaultLogDatabase(const std::shared_ptr<EventLoop>& eventLoop) : eventLoop_(eventLoop) {} 74 75void FaultLogDatabase::SaveFaultLogInfo(FaultLogInfo& info) 76{ 77 std::lock_guard<std::mutex> lock(mutex_); 78 if (info.faultLogType == FaultLogType::SYS_FREEZE) { 79 AnalysisFaultlog(info, info.parsedLogInfo); 80 for (const auto& logInfo : info.parsedLogInfo) { 81 info.sectionMap[logInfo.first] = logInfo.second; 82 } 83 info.parsedLogInfo.clear(); 84 } 85 if (!eventLoop_) { 86 HIVIEW_LOGE("eventLoop_ is not inited."); 87 return; 88 } 89 auto task = [info] () mutable { 90 HiSysEventWrite( 91 HiSysEvent::Domain::RELIABILITY, 92 GetFaultNameByType(info.faultLogType, false), 93 HiSysEvent::EventType::FAULT, 94 "FAULT_TYPE", std::to_string(info.faultLogType), 95 "PID", info.pid, 96 "UID", info.id, 97 "MODULE", info.module, 98 "REASON", info.reason, 99 "SUMMARY", info.summary, 100 "LOG_PATH", info.logPath, 101 "VERSION", info.sectionMap.find("VERSION") != info.sectionMap.end() ? info.sectionMap.at("VERSION") : "", 102 "PRE_INSTALL", info.sectionMap["PRE_INSTALL"], 103 "FOREGROUND", info.sectionMap["FOREGROUND"], 104 "HAPPEN_TIME", info.time, 105 "HITRACE_TIME", info.sectionMap.find("HITRACE_TIME") != info.sectionMap.end() ? 106 info.sectionMap.at("HITRACE_TIME") : "", 107 "SYSRQ_TIME", info.sectionMap.find("SYSRQ_TIME") != info.sectionMap.end() ? 108 info.sectionMap.at("SYSRQ_TIME") : "", 109 "PNAME", info.sectionMap["PROCESS_NAME"].empty() ? "/" : info.sectionMap["PROCESS_NAME"], 110 "FIRST_FRAME", info.sectionMap["FIRST_FRAME"].empty() ? "/" : info.sectionMap["FIRST_FRAME"], 111 "SECOND_FRAME", info.sectionMap["SECOND_FRAME"].empty() ? "/" : info.sectionMap["SECOND_FRAME"], 112 "LAST_FRAME", info.sectionMap["LAST_FRAME"].empty() ? "/" : info.sectionMap["LAST_FRAME"], 113 "FINGERPRINT", info.sectionMap["fingerPrint"].empty() ? "/" : info.sectionMap["fingerPrint"], 114 "STACK", info.sectionMap["STACK"].empty() ? "" : info.sectionMap["STACK"] 115 ); 116 }; 117 constexpr int delayTime = 2; 118 eventLoop_->AddTimerEvent(nullptr, nullptr, task, delayTime, false); 119} 120 121std::list<std::shared_ptr<EventStore::SysEventQuery>> CreateQueries( 122 int32_t faultType, EventStore::Cond upperCaseCond, EventStore::Cond lowerCaseCond) 123{ 124 std::list<std::shared_ptr<EventStore::SysEventQuery>> queries; 125 if (faultType == FaultLogType::JS_CRASH || faultType == FaultLogType::ALL) { 126 std::vector<std::string> faultNames = { "JS_ERROR" }; 127 std::vector<std::string> domains = { HiSysEvent::Domain::ACE, HiSysEvent::Domain::AAFWK }; 128 for (std::string domain : domains) { 129 auto query = EventStore::SysEventDao::BuildQuery(domain, faultNames); 130 if (query == nullptr) { 131 continue; 132 } 133 query->And(lowerCaseCond); 134 query->Select(QUERY_ITEMS).Order("time_", false); 135 queries.push_back(query); 136 } 137 } 138 if (faultType != FaultLogType::JS_CRASH) { 139 std::string faultName = GetFaultNameByType(faultType, false); 140 std::vector<std::vector<std::string>> faultNames = { {faultName} }; 141 if (faultType == FaultLogType::ALL) { 142 faultNames = { {"CPP_CRASH"}, {"APP_FREEZE"}}; 143 } 144 for (auto name : faultNames) { 145 auto query = EventStore::SysEventDao::BuildQuery(HiSysEvent::Domain::RELIABILITY, name); 146 if (query == nullptr) { 147 continue; 148 } 149 query->And(upperCaseCond); 150 query->Select(QUERY_ITEMS).Order("time_", false); 151 queries.push_back(query); 152 } 153 } 154 return queries; 155} 156 157std::list<FaultLogInfo> FaultLogDatabase::GetFaultInfoList(const std::string& module, int32_t id, 158 int32_t faultType, int32_t maxNum) 159{ 160 std::lock_guard<std::mutex> lock(mutex_); 161 std::list<FaultLogInfo> queryResult; 162 if (faultType < FaultLogType::ALL || faultType > FaultLogType::APP_FREEZE) { 163 HIVIEW_LOGE("Unsupported fault type, please check it!"); 164 return queryResult; 165 } 166 EventStore::Cond hiviewUidCond("uid_", EventStore::Op::EQ, static_cast<int64_t>(getuid())); 167 EventStore::Cond uidUpperCond = hiviewUidCond.And("UID", EventStore::Op::EQ, id); 168 EventStore::Cond uidLowerCond("uid_", EventStore::Op::EQ, id); 169 auto queries = CreateQueries(faultType, uidUpperCond, uidLowerCond); 170 for (auto query : queries) { 171 if (id != 0) { 172 query->And("MODULE", EventStore::Op::EQ, module); 173 } 174 EventStore::ResultSet resultSet = query->Execute(maxNum); 175 while (resultSet.HasNext()) { 176 auto it = resultSet.Next(); 177 FaultLogInfo info; 178 if (!ParseFaultLogInfoFromJson(it->rawData_, info)) { 179 HIVIEW_LOGI("Failed to parse FaultLogInfo from queryResult."); 180 continue; 181 } 182 queryResult.push_back(info); 183 } 184 } 185 if (queries.size() > 1) { 186 queryResult.sort( 187 [](const FaultLogInfo& a, const FaultLogInfo& b) { 188 return a.time > b.time; 189 }); 190 if (queryResult.size() > static_cast<size_t>(maxNum)) { 191 queryResult.resize(maxNum); 192 } 193 } 194 195 return queryResult; 196} 197 198bool FaultLogDatabase::IsFaultExist(int32_t pid, int32_t uid, int32_t faultType) 199{ 200 std::lock_guard<std::mutex> lock(mutex_); 201 if (faultType < FaultLogType::ALL || faultType > FaultLogType::RUST_PANIC) { 202 HIVIEW_LOGE("Unsupported fault type, please check it!"); 203 return false; 204 } 205 EventStore::Cond hiviewUidCond("uid_", EventStore::Op::EQ, static_cast<int64_t>(getuid())); 206 EventStore::Cond pidUpperCond = hiviewUidCond.And("PID", EventStore::Op::EQ, pid). 207 And("UID", EventStore::Op::EQ, uid); 208 EventStore::Cond pidLowerCond("pid_", EventStore::Op::EQ, pid); 209 pidLowerCond = pidLowerCond.And("uid_", EventStore::Op::EQ, uid); 210 auto queries = CreateQueries(faultType, pidUpperCond, pidLowerCond); 211 for (auto query : queries) { 212 if (query->Execute(1).HasNext()) { 213 return true; 214 } 215 } 216 return false; 217} 218} // namespace HiviewDFX 219} // namespace OHOS 220