1 /*
2 * Copyright (c) 2025 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_bootscan.h"
16
17 #include "constants.h"
18 #include "event_publish.h"
19 #include "faultlog_formatter.h"
20 #include "faultlog_util.h"
21 #include "faultlog_processor_factory.h"
22 #include "file_util.h"
23 #include "hisysevent.h"
24 #include "hiview_logger.h"
25 #include "sanitizer_telemetry.h"
26
27 namespace OHOS {
28 namespace HiviewDFX {
29 DEFINE_LOG_LABEL(0xD002D11, "Faultlogger");
30
31 namespace {
32 constexpr time_t FORTYEIGHT_HOURS = 48 * 60 * 60;
33 }
34 using namespace FaultLogger;
35
IsCrashType(const std::string & file)36 bool FaultLogBootScan::IsCrashType(const std::string& file)
37 {
38 // if file type is not cppcrash, skip!
39 if (file.find("cppcrash") == std::string::npos) {
40 HIVIEW_LOGI("Skip this file(%{public}s) that the type is not cppcrash.", file.c_str());
41 return false;
42 }
43 return true;
44 }
45
IsInValidTime(const std::string & file,const time_t & now)46 bool FaultLogBootScan::IsInValidTime(const std::string& file, const time_t& now)
47 {
48 time_t lastAccessTime = GetFileLastAccessTimeStamp(file);
49 if (now < lastAccessTime) {
50 HIVIEW_LOGI("Skip this file(%{public}s) that current time may be incorrect.", file.c_str());
51 return false;
52 }
53 if (now - lastAccessTime > FORTYEIGHT_HOURS) {
54 HIVIEW_LOGI("Skip this file(%{public}s) that were created 48 hours ago.", file.c_str());
55 return false;
56 }
57 return true;
58 }
59
IsCrashTempBigFile(const std::string & file)60 bool FaultLogBootScan::IsCrashTempBigFile(const std::string& file)
61 {
62 constexpr uint64_t tempMaxFileSize = 1024 * 1024 * 5;
63 auto fileSize = FileUtil::GetFileSize(file);
64 if (fileSize > tempMaxFileSize) {
65 HIVIEW_LOGI("Skip this file(%{public}s) that file size(%{public}" PRIu64 ") exceeds limit.",
66 file.c_str(), fileSize);
67 FileUtil::RemoveFile(file);
68 return true;
69 }
70 return false;
71 }
72
IsEmptyStack(const std::string & file,const FaultLogInfo & info)73 bool FaultLogBootScan::IsEmptyStack(const std::string& file, const FaultLogInfo& info)
74 {
75 if (info.summary.find("#00") == std::string::npos) {
76 HIVIEW_LOGI("Skip this file(%{public}s) which stack is empty.", file.c_str());
77 HiSysEventWrite(HiSysEvent::Domain::RELIABILITY, "CPP_CRASH_NO_LOG", HiSysEvent::EventType::FAULT,
78 FaultKey::MODULE_PID, info.pid,
79 FaultKey::MODULE_UID, info.id,
80 "PROCESS_NAME", info.module,
81 FaultKey::HAPPEN_TIME, std::to_string(info.time)
82 );
83 if (remove(file.c_str()) != 0) {
84 HIVIEW_LOGE("Failed to remove file(%{public}s) which stack is empty", file.c_str());
85 }
86 return true;
87 }
88 return false;
89 }
90
IsReported(const FaultLogInfo & info)91 bool FaultLogBootScan::IsReported(const FaultLogInfo& info)
92 {
93 if (faultLogManager_->IsProcessedFault(info.pid, info.id, info.faultLogType)) {
94 HIVIEW_LOGI("Skip processed fault.(%{public}d:%{public}d) ", info.pid, info.id);
95 return true;
96 }
97 return false;
98 }
99
StartBootScan()100 void FaultLogBootScan::StartBootScan()
101 {
102 std::vector<std::string> files;
103 time_t now = time(nullptr);
104 FileUtil::GetDirFiles(FAULTLOG_TEMP_FOLDER, files);
105 for (const auto& file : files) {
106 if (!IsCrashType(file) || !IsInValidTime(file, now) || IsCrashTempBigFile(file)) {
107 continue;
108 }
109
110 auto info = ParseCppCrashFromFile(file);
111 if (IsEmptyStack(file, info) || IsReported(info)) {
112 continue;
113 }
114 FaultLogProcessorFactory factory;
115 auto processor = factory.CreateFaultLogProcessor(static_cast<FaultLogType>(info.faultLogType));
116 if (processor) {
117 info.sectionMap["START_BOOT_SCAN"] = "true";
118 processor->AddFaultLog(info, workLoop_, faultLogManager_);
119 }
120 }
121 }
122
AddBootScanEvent()123 void FaultLogBootScan::AddBootScanEvent()
124 {
125 if (workLoop_ == nullptr) {
126 HIVIEW_LOGE("workLoop_ is nullptr.");
127 return;
128 }
129 // some crash happened before hiview start, ensure every crash event is added into eventdb
130 auto task = [this] {
131 StartBootScan();
132 };
133 workLoop_->AddTimerEvent(nullptr, nullptr, task, 60, false); // delay 60 seconds
134 }
135
FaultLogBootScan(std::shared_ptr<EventLoop> workLoop,std::shared_ptr<FaultLogManager> faultLogManager)136 FaultLogBootScan::FaultLogBootScan(std::shared_ptr<EventLoop> workLoop,
137 std::shared_ptr<FaultLogManager> faultLogManager) : workLoop_(workLoop), faultLogManager_(faultLogManager)
138 {
139 AddListenerInfo(Event::MessageType::PLUGIN_MAINTENANCE);
140 AddListenerInfo(Event::TELEMETRY_EVENT);
141 }
142
OnUnorderedEvent(const Event & msg)143 void FaultLogBootScan::OnUnorderedEvent(const Event& msg)
144 {
145 if (msg.messageType_ == Event::TELEMETRY_EVENT) {
146 SanitizerTelemetry sanitizerTelemetry;
147 sanitizerTelemetry.OnUnorderedEvent(msg);
148 }
149 #ifndef UNITTEST
150 if (msg.messageType_ != Event::MessageType::PLUGIN_MAINTENANCE ||
151 msg.eventId_ != Event::EventId::PLUGIN_LOADED) {
152 HIVIEW_LOGE("messageType_(%{public}u), eventId_(%{public}u).", msg.messageType_, msg.eventId_);
153 return;
154 }
155 AddBootScanEvent();
156 #endif
157 }
158
GetListenerName()159 std::string FaultLogBootScan::GetListenerName()
160 {
161 return "Faultlogger";
162 }
163 } // namespace HiviewDFX
164 } // namespace OHOS
165