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_processor_base.h"
16
17 #include "constants.h"
18 #include "dfx_define.h"
19 #include "faultlog_bundle_util.h"
20 #include "faultlog_formatter.h"
21 #include "faultlog_hilog_helper.h"
22 #include "faultlog_util.h"
23 #include "hisysevent.h"
24 #include "hiview_logger.h"
25 #include "log_analyzer.h"
26 #include "page_history_manager.h"
27 #include "parameter_ex.h"
28 #include "process_status.h"
29 #include "string_util.h"
30
31 namespace OHOS {
32 namespace HiviewDFX {
33 using namespace FaultLogger;
34 DEFINE_LOG_LABEL(0xD002D11, "Faultlogger");
35 using namespace FaultlogHilogHelper;
36
37 namespace {
GetSummaryFromSectionMap(int32_t type,const std::map<std::string,std::string> & maps)38 std::string GetSummaryFromSectionMap(int32_t type, const std::map<std::string, std::string>& maps)
39 {
40 std::string key = "";
41 switch (type) {
42 case CPP_CRASH:
43 key = FaultKey::KEY_THREAD_INFO;
44 break;
45 default:
46 break;
47 }
48
49 if (key.empty()) {
50 return "";
51 }
52
53 auto value = maps.find(key);
54 if (value == maps.end()) {
55 return "";
56 }
57 return value->second;
58 }
59
IsFaultTypeSupport(const FaultLogInfo & info)60 bool IsFaultTypeSupport(const FaultLogInfo& info)
61 {
62 if ((info.faultLogType <= FaultLogType::ALL) || (info.faultLogType > FaultLogType::CJ_ERROR)) {
63 HIVIEW_LOGW("Unsupported fault type");
64 return false;
65 }
66 return true;
67 }
68
IsSnapshot(const FaultLogInfo & info)69 bool IsSnapshot(const FaultLogInfo& info)
70 {
71 if (info.reason.find("CppCrashKernelSnapshot") != std::string::npos) {
72 HIVIEW_LOGI("Skip cpp crash kernel snapshot fault %{public}d", info.pid);
73 return true;
74 }
75 return false;
76 }
77
IsFaultByIpc(const FaultLogInfo & info)78 bool IsFaultByIpc(const FaultLogInfo& info)
79 {
80 return info.faultLogType == FaultLogType::CPP_CRASH ||
81 info.faultLogType == FaultLogType::SYS_FREEZE ||
82 info.faultLogType == FaultLogType::SYS_WARNING ||
83 info.faultLogType == FaultLogType::APP_FREEZE;
84 }
85 } // namespace
86
AddFaultLog(FaultLogInfo & info,const std::shared_ptr<EventLoop> & workLoop,const std::shared_ptr<FaultLogManager> & faultLogManager)87 void FaultLogProcessorBase::AddFaultLog(FaultLogInfo& info, const std::shared_ptr<EventLoop>& workLoop,
88 const std::shared_ptr<FaultLogManager>& faultLogManager)
89 {
90 workLoop_ = workLoop;
91 faultLogManager_ = faultLogManager;
92 if (!IsFaultTypeSupport(info) || IsSnapshot(info)) {
93 return;
94 }
95
96 ProcessFaultLog(info);
97
98 if (!IsFaultByIpc(info)) {
99 return;
100 }
101 SaveFaultInfoToRawDb(info);
102 ReportEventToAppEvent(info);
103 DoFaultLogLimit(info);
104 }
105
VerifyModule(FaultLogInfo & info)106 bool FaultLogProcessorBase::VerifyModule(FaultLogInfo& info)
107 {
108 if (!IsValidPath(info.logPath)) {
109 HIVIEW_LOGE("The log path is incorrect, and the current log path is: %{public}s.", info.logPath.c_str());
110 return false;
111 }
112 HIVIEW_LOGI("Start saving Faultlog of Process:%{public}d, Name:%{public}s, Reason:%{public}s.",
113 info.pid, info.module.c_str(), info.reason.c_str());
114 info.sectionMap["PROCESS_NAME"] = info.module; // save process name
115 // Non system processes use UID to pass events to applications
116 if (!IsSystemProcess(info.module, info.id) && info.sectionMap["SCBPROCESS"] != "Yes") {
117 std::string appName = GetApplicationNameById(info.id);
118 if (!appName.empty() && !ExtractSubMoudleName(info.module)) {
119 info.module = appName; // if bundle name is not empty, replace module name by it.
120 }
121 }
122
123 HIVIEW_LOGD("nameProc %{public}s", info.module.c_str());
124 if ((info.module.empty()) ||
125 (info.faultLogType != FaultLogType::ADDR_SANITIZER && !IsModuleNameValid(info.module))) {
126 HIVIEW_LOGW("Invalid module name %{public}s", info.module.c_str());
127 return false;
128 }
129 return true;
130 }
131
ProcessFaultLog(FaultLogInfo & info)132 void FaultLogProcessorBase::ProcessFaultLog(FaultLogInfo& info)
133 {
134 if (!VerifyModule(info)) {
135 return;
136 }
137 // step1: add common info: uid module name, pid, reason, summary etc
138 AddCommonInfo(info);
139 // step2: add specific info: need implement in derived class
140 AddSpecificInfo(info);
141 // step3: generate fault log file
142 SaveFaultLogToFile(info);
143 PrintFaultLogInfo(info);
144 }
145
SaveFaultLogToFile(FaultLogInfo & info)146 void FaultLogProcessorBase::SaveFaultLogToFile(FaultLogInfo& info)
147 {
148 if (info.dumpLogToFaultlogger && faultLogManager_) {
149 faultLogManager_->SaveFaultLogToFile(info);
150 }
151 }
152
DoFaultLogLimit(const FaultLogInfo & info)153 void FaultLogProcessorBase::DoFaultLogLimit(const FaultLogInfo& info)
154 {
155 bool isNeedLimitFile = (info.dumpLogToFaultlogger && ((info.faultLogType == FaultLogType::CPP_CRASH) ||
156 (info.faultLogType == FaultLogType::APP_FREEZE)) && IsFaultLogLimit());
157 if (isNeedLimitFile) {
158 DoFaultLogLimit(info.logPath, info.faultLogType);
159 }
160 }
161
SaveFaultInfoToRawDb(FaultLogInfo & info)162 void FaultLogProcessorBase::SaveFaultInfoToRawDb(FaultLogInfo& info)
163 {
164 if (faultLogManager_) {
165 faultLogManager_->SaveFaultInfoToRawDb(info);
166 }
167 }
168
AddCommonInfo(FaultLogInfo & info)169 void FaultLogProcessorBase::AddCommonInfo(FaultLogInfo& info)
170 {
171 info.sectionMap[FaultKey::DEVICE_INFO] = Parameter::GetString("const.product.name", "Unknown");
172 if (info.sectionMap.find(FaultKey::BUILD_INFO) == info.sectionMap.end()) {
173 info.sectionMap[FaultKey::BUILD_INFO] = Parameter::GetString("const.product.software.version", "Unknown");
174 }
175 info.sectionMap[FaultKey::MODULE_UID] = std::to_string(info.id);
176 info.sectionMap[FaultKey::MODULE_PID] = std::to_string(info.pid);
177 info.module = RegulateModuleNameIfNeed(info.module);
178 info.sectionMap[FaultKey::MODULE_NAME] = info.module;
179 AddBundleInfo(info);
180 AddForegroundInfo(info);
181
182 if (info.reason.empty()) {
183 info.reason = info.sectionMap[FaultKey::REASON];
184 } else {
185 info.sectionMap[FaultKey::REASON] = info.reason;
186 }
187
188 if (info.summary.empty()) {
189 info.summary = GetSummaryFromSectionMap(info.faultLogType, info.sectionMap);
190 } else {
191 info.sectionMap[FaultKey::SUMMARY] = info.summary;
192 }
193
194 UpdateTerminalThreadStack(info);
195
196 // parse fingerprint by summary or temp log for native crash
197 AnalysisFaultlog(info, info.parsedLogInfo);
198 info.sectionMap.insert(info.parsedLogInfo.begin(), info.parsedLogInfo.end());
199 info.parsedLogInfo.clear();
200 // Internal reserved fields, avoid illegal privilege escalation to access files
201 info.sectionMap.erase(FaultKey::APPEND_ORIGIN_LOG);
202 }
203
AddBundleInfo(FaultLogInfo & info)204 void FaultLogProcessorBase::AddBundleInfo(FaultLogInfo& info)
205 {
206 DfxBundleInfo bundleInfo;
207 if (info.id < MIN_APP_USERID || !GetDfxBundleInfo(info.module, bundleInfo)) {
208 return;
209 }
210
211 if (!bundleInfo.versionName.empty()) {
212 info.sectionMap[FaultKey::MODULE_VERSION] = bundleInfo.versionName;
213 info.sectionMap[FaultKey::VERSION_CODE] = std::to_string(bundleInfo.versionCode);
214 }
215
216 info.sectionMap[FaultKey::PRE_INSTALL] = bundleInfo.isPreInstalled ? "Yes" : "No";
217 }
218
AddForegroundInfo(FaultLogInfo & info)219 void FaultLogProcessorBase::AddForegroundInfo(FaultLogInfo& info)
220 {
221 if (!info.sectionMap[FaultKey::FOREGROUND].empty() || info.id < MIN_APP_USERID) {
222 return;
223 }
224
225 if (UCollectUtil::ProcessStatus::GetInstance().GetProcessState(info.pid) == UCollectUtil::FOREGROUND) {
226 info.sectionMap[FaultKey::FOREGROUND] = "Yes";
227 } else if (UCollectUtil::ProcessStatus::GetInstance().GetProcessState(info.pid) == UCollectUtil::BACKGROUND) {
228 int64_t lastFgTime = static_cast<int64_t>(UCollectUtil::ProcessStatus::GetInstance()
229 .GetProcessLastForegroundTime(info.pid));
230 info.sectionMap[FaultKey::FOREGROUND] = lastFgTime > info.time ? "Yes" : "No";
231 }
232 }
233
UpdateTerminalThreadStack(FaultLogInfo & info)234 void FaultLogProcessorBase::UpdateTerminalThreadStack(FaultLogInfo& info)
235 {
236 auto threadStack = GetStrValFromMap(info.sectionMap, "TERMINAL_THREAD_STACK");
237 if (threadStack.empty()) {
238 return;
239 }
240 // Replace the '\n' in the string with a line break character
241 info.parsedLogInfo["TERMINAL_THREAD_STACK"] = StringUtil::ReplaceStr(threadStack, "\\n", "\n");
242 }
243
PrintFaultLogInfo(const FaultLogInfo & info)244 void FaultLogProcessorBase::PrintFaultLogInfo(const FaultLogInfo& info)
245 {
246 HIVIEW_LOGI("\nSave Faultlog of Process:%{public}d\n"
247 "ModuleName:%{public}s\n"
248 "Reason:%{public}s\n",
249 info.pid, info.module.c_str(), info.reason.c_str());
250 }
251
ReadLogFile(const std::string & logPath) const252 std::string FaultLogProcessorBase::ReadLogFile(const std::string& logPath) const
253 {
254 std::ifstream logReadFile(logPath);
255 if (!logReadFile.is_open()) {
256 return "";
257 }
258 return std::string(std::istreambuf_iterator<char>(logReadFile), std::istreambuf_iterator<char>());
259 }
260
WriteLogFile(const std::string & logPath,const std::string & content) const261 void FaultLogProcessorBase::WriteLogFile(const std::string& logPath, const std::string& content) const
262 {
263 std::ofstream logWriteFile(logPath, std::ios::out | std::ios::trunc);
264 if (!logWriteFile.is_open()) {
265 HIVIEW_LOGE("Failed to open log file: %{public}s", logPath.c_str());
266 return;
267 }
268 logWriteFile << content;
269 if (!logWriteFile.good()) {
270 HIVIEW_LOGE("Failed to write content to log file: %{public}s", logPath.c_str());
271 }
272 logWriteFile.close();
273 }
274
GetProcMemInfo(FaultLogInfo & info)275 void FaultLogProcessorBase::GetProcMemInfo(FaultLogInfo& info)
276 {
277 if (!info.sectionMap["START_BOOT_SCAN"].empty()) {
278 return;
279 }
280
281 std::ifstream meminfoStream("/proc/meminfo");
282 if (meminfoStream) {
283 constexpr int decimalBase = 10;
284 unsigned long long totalMem = 0; // row 1
285 unsigned long long freeMem = 0; // row 2
286 unsigned long long availMem = 0; // row 3
287 std::string meminfoLine;
288 std::getline(meminfoStream, meminfoLine);
289 totalMem = strtoull(GetDigtStrArr(meminfoLine).front().c_str(), nullptr, decimalBase);
290 std::getline(meminfoStream, meminfoLine);
291 freeMem = strtoull(GetDigtStrArr(meminfoLine).front().c_str(), nullptr, decimalBase);
292 std::getline(meminfoStream, meminfoLine);
293 availMem = strtoull(GetDigtStrArr(meminfoLine).front().c_str(), nullptr, decimalBase);
294 meminfoStream.close();
295 info.sectionMap["DEVICE_MEMINFO"] = "Device Memory(kB): Total " + std::to_string(totalMem) +
296 ", Free " + std::to_string(freeMem) + ", Available " + std::to_string(availMem);
297 } else {
298 HIVIEW_LOGE("Fail to open /proc/meminfo");
299 }
300 }
301
GetDigtStrArr(const std::string & target)302 std::list<std::string> FaultLogProcessorBase::GetDigtStrArr(const std::string &target)
303 {
304 std::list<std::string> ret;
305 std::string temp = "";
306 for (size_t i = 0, len = target.size(); i < len; i++) {
307 if (target[i] >= '0' && target[i] <= '9') {
308 temp += target[i];
309 continue;
310 }
311 if (temp.size() != 0) {
312 ret.push_back(temp);
313 temp = "";
314 }
315 }
316 if (temp.size() != 0) {
317 ret.push_back(temp);
318 }
319 ret.push_back("0");
320 return ret;
321 }
322
AddPagesHistory(FaultLogInfo & info) const323 void FaultLogProcessorBase::AddPagesHistory(FaultLogInfo& info) const
324 {
325 if (info.id < MIN_APP_USERID) {
326 return;
327 }
328 auto trace = PageHistoryManager::GetInstance().GetPageHistory(info.module, info.pid);
329 if (!trace.empty()) {
330 info.sectionMap[FaultKey::PAGE_SWITCH_HISTORY] = std::move(trace);
331 }
332 }
333 } // namespace HiviewDFX
334 } // namespace OHOS
335