1 /*
2 * Copyright (c) 2021-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_formatter.h"
16
17 #include <cstdint>
18 #include <fstream>
19 #include <functional>
20 #include <string>
21 #include <sstream>
22 #include <unordered_map>
23 #include <vector>
24 #include <unistd.h>
25
26 #include "parameters.h"
27
28 #include "constants.h"
29 #include "faultlog_info.h"
30 #include "faultlog_util.h"
31 #include "file_util.h"
32 #include "string_util.h"
33
34 namespace OHOS {
35 namespace HiviewDFX {
36 namespace FaultLogger {
37 namespace {
38
39 struct SectionLog {
40 const char* sectionName;
41 const char* logName;
42 };
43
44 const SectionLog DEVICE_INFO = {FaultKey::DEVICE_INFO, "Device info:"};
45 const SectionLog BUILD_INFO = {FaultKey::BUILD_INFO, "Build info:"};
46 const SectionLog MODULE_NAME = {FaultKey::MODULE_NAME, "Module name:"};
47 const SectionLog PROCESS_NAME = {FaultKey::P_NAME, "Process name:"};
48 const SectionLog MODULE_PID = {FaultKey::MODULE_PID, "Pid:"};
49 const SectionLog MODULE_UID = {FaultKey::MODULE_UID, "Uid:"};
50 const SectionLog MODULE_VERSION = {FaultKey::MODULE_VERSION, "Version:"};
51 const SectionLog FAULT_TYPE = {FaultKey::FAULT_TYPE, "Fault type:"};
52 const SectionLog SYS_VM_TYPE = {FaultKey::SYS_VM_TYPE, "SYSVMTYPE:"};
53 const SectionLog APP_VM_TYPE = {FaultKey::APP_VM_TYPE, "APPVMTYPE:"};
54 const SectionLog FOREGROUND = {FaultKey::FOREGROUND, "Foreground:"};
55 const SectionLog LIFETIME = {FaultKey::LIFETIME, "Up time:"};
56 const SectionLog REASON = {FaultKey::REASON, "Reason:"};
57 const SectionLog FAULT_MESSAGE = {FaultKey::FAULT_MESSAGE, "Fault message:"};
58 const SectionLog STACKTRACE = {FaultKey::STACKTRACE, "Selected stacktrace:\n"};
59 const SectionLog ROOT_CAUSE = {FaultKey::ROOT_CAUSE, "Blocked chain:\n"};
60 const SectionLog MSG_QUEUE_INFO = {FaultKey::MSG_QUEUE_INFO, "Message queue info:\n"};
61 const SectionLog BINDER_TRANSACTION_INFO = {
62 FaultKey::BINDER_TRANSACTION_INFO, "Binder transaction info:\n"
63 };
64 const SectionLog PROCESS_STACKTRACE = {FaultKey::PROCESS_STACKTRACE, "Process stacktrace:\n"};
65 const SectionLog OTHER_THREAD_INFO = {FaultKey::OTHER_THREAD_INFO, "Other thread info:\n"};
66 const SectionLog KEY_THREAD_INFO = {FaultKey::KEY_THREAD_INFO, "Fault thread info:\n"};
67 const SectionLog KEY_THREAD_REGISTERS = {FaultKey::KEY_THREAD_REGISTERS, "Registers:\n"};
68 const SectionLog MEMORY_USAGE = {FaultKey::MEMORY_USAGE, "Memory Usage:\n"};
69 const SectionLog CPU_USAGE = {FaultKey::CPU_USAGE, "CPU Usage:"};
70 const SectionLog TRACE_ID = {FaultKey::TRACE_ID, "Trace-Id:"};
71 const SectionLog SUMMARY = {FaultKey::SUMMARY, "Summary:\n"};
72 const SectionLog TIMESTAMP = {FaultKey::TIMESTAMP, "Timestamp:"};
73 const SectionLog MEMORY_NEAR_REGISTERS = {FaultKey::MEMORY_NEAR_REGISTERS, "Memory near registers:\n"};
74 const SectionLog PRE_INSTALL = {FaultKey::PRE_INSTALL, "PreInstalled:"};
75 const SectionLog VERSION_CODE = {FaultKey::VERSION_CODE, "VersionCode:"};
76 const SectionLog FINGERPRINT = {FaultKey::FINGERPRINT, "Fingerprint:"};
77 const SectionLog APPEND_ORIGIN_LOG = {FaultKey::APPEND_ORIGIN_LOG, ""};
78 const SectionLog PROCESS_RSS_MEMINFO = {FaultKey::PROCESS_RSS_MEMINFO, ""};
79 const SectionLog DEVICE_MEMINFO = {FaultKey::DEVICE_MEMINFO, ""};
80 const SectionLog PAGE_SWITCH_HISTORY = {FaultKey::PAGE_SWITCH_HISTORY, "Page switch history:\n"};
81
GetCppCrashSectionLogs()82 std::vector<SectionLog> GetCppCrashSectionLogs()
83 {
84 std::vector<SectionLog> info = {
85 DEVICE_INFO, BUILD_INFO, FINGERPRINT, MODULE_NAME, MODULE_VERSION, VERSION_CODE,
86 PRE_INSTALL, FOREGROUND, PAGE_SWITCH_HISTORY, APPEND_ORIGIN_LOG, MODULE_PID, MODULE_UID, FAULT_TYPE,
87 SYS_VM_TYPE, APP_VM_TYPE, REASON, FAULT_MESSAGE, TRACE_ID, PROCESS_NAME, KEY_THREAD_INFO,
88 SUMMARY, KEY_THREAD_REGISTERS, OTHER_THREAD_INFO, MEMORY_NEAR_REGISTERS
89 };
90 return info;
91 }
92
GetJsCrashSectionLogs()93 std::vector<SectionLog> GetJsCrashSectionLogs()
94 {
95 std::vector<SectionLog> info = {
96 DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, VERSION_CODE,
97 PRE_INSTALL, FOREGROUND, MODULE_PID, MODULE_UID, FAULT_TYPE, FAULT_MESSAGE, SYS_VM_TYPE,
98 APP_VM_TYPE, LIFETIME, PROCESS_RSS_MEMINFO, DEVICE_MEMINFO, PAGE_SWITCH_HISTORY, REASON, TRACE_ID, SUMMARY
99 };
100 return info;
101 }
102
GetCjCrashSectionLogs()103 std::vector<SectionLog> GetCjCrashSectionLogs()
104 {
105 std::vector<SectionLog> info = {
106 DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, VERSION_CODE,
107 PRE_INSTALL, FOREGROUND, MODULE_PID, MODULE_UID, FAULT_TYPE, FAULT_MESSAGE, SYS_VM_TYPE,
108 APP_VM_TYPE, LIFETIME, PROCESS_RSS_MEMINFO, DEVICE_MEMINFO, REASON, TRACE_ID, SUMMARY
109 };
110 return info;
111 }
112
GetAppFreezeSectionLogs()113 std::vector<SectionLog> GetAppFreezeSectionLogs()
114 {
115 std::vector<SectionLog> info = {
116 DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, VERSION_CODE,
117 PRE_INSTALL, FOREGROUND, MODULE_PID, MODULE_UID, FAULT_TYPE, SYS_VM_TYPE,
118 APP_VM_TYPE, REASON, TRACE_ID, CPU_USAGE, MEMORY_USAGE, ROOT_CAUSE, STACKTRACE,
119 MSG_QUEUE_INFO, BINDER_TRANSACTION_INFO, PROCESS_STACKTRACE, SUMMARY, PAGE_SWITCH_HISTORY
120 };
121 return info;
122 }
123
GetSysFreezeSectionLogs()124 std::vector<SectionLog> GetSysFreezeSectionLogs()
125 {
126 std::vector<SectionLog> info = {
127 DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, FOREGROUND,
128 MODULE_PID, MODULE_UID, FAULT_TYPE, SYS_VM_TYPE, APP_VM_TYPE, REASON,
129 TRACE_ID, CPU_USAGE, MEMORY_USAGE, ROOT_CAUSE, STACKTRACE,
130 MSG_QUEUE_INFO, BINDER_TRANSACTION_INFO, PROCESS_STACKTRACE, SUMMARY
131 };
132 return info;
133 }
134
GetSysWarningSectionLogs()135 std::vector<SectionLog> GetSysWarningSectionLogs()
136 {
137 std::vector<SectionLog> info = {
138 DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, FOREGROUND,
139 MODULE_PID, MODULE_UID, FAULT_TYPE, SYS_VM_TYPE, APP_VM_TYPE, REASON,
140 TRACE_ID, CPU_USAGE, MEMORY_USAGE, ROOT_CAUSE, STACKTRACE,
141 MSG_QUEUE_INFO, BINDER_TRANSACTION_INFO, PROCESS_STACKTRACE, SUMMARY
142 };
143 return info;
144 }
145
GetRustPanicSectionLogs()146 std::vector<SectionLog> GetRustPanicSectionLogs()
147 {
148 std::vector<SectionLog> info = {
149 DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, MODULE_PID,
150 MODULE_UID, FAULT_TYPE, FAULT_MESSAGE, APP_VM_TYPE, REASON, SUMMARY
151 };
152 return info;
153 }
154
GetAddrSanitizerSectionLogs()155 std::vector<SectionLog> GetAddrSanitizerSectionLogs()
156 {
157 std::vector<SectionLog> info = {
158 DEVICE_INFO, BUILD_INFO, FINGERPRINT, APPEND_ORIGIN_LOG, TIMESTAMP, MODULE_NAME,
159 MODULE_VERSION, MODULE_PID, MODULE_UID, FAULT_TYPE, FAULT_MESSAGE, APP_VM_TYPE, REASON,
160 SUMMARY
161 };
162 return info;
163 }
164 }
165
GetLogParseSections(int32_t logType)166 std::vector<SectionLog> GetLogParseSections(int32_t logType)
167 {
168 std::unordered_map<int32_t, std::function<decltype(GetCppCrashSectionLogs)>> table = {
169 {FaultLogType::CPP_CRASH, GetCppCrashSectionLogs},
170 {FaultLogType::JS_CRASH, GetJsCrashSectionLogs},
171 {FaultLogType::CJ_ERROR, GetCjCrashSectionLogs},
172 {FaultLogType::APP_FREEZE, GetAppFreezeSectionLogs},
173 {FaultLogType::SYS_FREEZE, GetSysFreezeSectionLogs},
174 {FaultLogType::SYS_WARNING, GetSysWarningSectionLogs},
175 {FaultLogType::RUST_PANIC, GetRustPanicSectionLogs},
176 {FaultLogType::ADDR_SANITIZER, GetAddrSanitizerSectionLogs},
177 };
178 if (auto iter = table.find(logType); iter != table.end()) {
179 return iter->second();
180 }
181 return {};
182 }
183
ParseFaultLogLine(const std::vector<SectionLog> & parseList,const std::string & line,const std::string & multline,std::string & multlineName,FaultLogInfo & info)184 bool ParseFaultLogLine(const std::vector<SectionLog>& parseList, const std::string& line,
185 const std::string& multline, std::string& multlineName, FaultLogInfo& info)
186 {
187 for (const auto &item : parseList) {
188 if (strlen(item.logName) <= 1) {
189 continue;
190 }
191 std::string sectionHead = item.logName;
192 sectionHead = sectionHead.back() == '\n' ? sectionHead.substr(0, sectionHead.size() - 1) : sectionHead;
193 if (line.find(sectionHead) == std::string::npos) {
194 continue;
195 }
196 if (!line.empty() && line.at(line.size() - 1) == ':') {
197 if ((item.sectionName != multlineName) && (!multline.empty())) {
198 info.sectionMap[multlineName] = multline;
199 }
200 multlineName = item.sectionName;
201 } else {
202 info.sectionMap[item.sectionName] = line.substr(line.find_first_of(":") + 1);
203 }
204 return false;
205 }
206 return true;
207 }
208
WriteStackTraceFromLog(int32_t fd,const std::string & pidStr,const std::string & path)209 bool WriteStackTraceFromLog(int32_t fd, const std::string& pidStr, const std::string& path)
210 {
211 std::string realPath;
212 if (!FileUtil::PathToRealPath(path, realPath)) {
213 FileUtil::SaveStringToFd(fd, "Log file not exist.\n");
214 return false;
215 }
216
217 std::ifstream logFile(realPath);
218 std::string line;
219 bool startWrite = false;
220 while (std::getline(logFile, line)) {
221 if (!logFile.good()) {
222 break;
223 }
224
225 if (line.empty()) {
226 continue;
227 }
228
229 if ((line.find("----- pid") != std::string::npos) &&
230 (line.find(pidStr) != std::string::npos)) {
231 startWrite = true;
232 }
233
234 if ((line.find("----- end") != std::string::npos) &&
235 (line.find(pidStr) != std::string::npos)) {
236 FileUtil::SaveStringToFd(fd, line + "\n");
237 break;
238 }
239
240 if (startWrite) {
241 FileUtil::SaveStringToFd(fd, line + "\n");
242 }
243 }
244 return true;
245 }
246
WriteDfxLogToFile(int32_t fd)247 void WriteDfxLogToFile(int32_t fd)
248 {
249 std::string dfxStr = std::string("Generated by HiviewDFX@OpenHarmony\n");
250 std::string sepStr = std::string("================================================================\n");
251 FileUtil::SaveStringToFd(fd, dfxStr);
252 FileUtil::SaveStringToFd(fd, sepStr);
253 }
254
WriteFaultLogToFile(int32_t fd,int32_t logType,const std::map<std::string,std::string> & sections)255 void WriteFaultLogToFile(int32_t fd, int32_t logType, const std::map<std::string, std::string>& sections)
256 {
257 auto seq = GetLogParseSections(logType);
258 for (const auto &item : seq) {
259 auto iter = sections.find(item.sectionName);
260 if (iter == sections.end() || iter->second.empty()) {
261 continue;
262 }
263 auto value = iter->second;
264 std::string keyStr = item.sectionName;
265 if (keyStr.find(APPEND_ORIGIN_LOG.sectionName) != std::string::npos && WriteLogToFile(fd, value, sections)) {
266 break;
267 }
268
269 // Does not require adding an identifier header for Summary section
270 if (keyStr.find(SUMMARY.sectionName) == std::string::npos) {
271 FileUtil::SaveStringToFd(fd, item.logName);
272 }
273
274 if (value.back() != '\n') {
275 value.append("\n");
276 }
277 FileUtil::SaveStringToFd(fd, value);
278 }
279
280 if (auto logIter = sections.find("KEYLOGFILE"); logIter != sections.end() && !logIter->second.empty()) {
281 if (auto pidIter = sections.find(FaultKey::MODULE_PID); pidIter != sections.end()) {
282 FileUtil::SaveStringToFd(fd, "Additional Logs:\n");
283 WriteStackTraceFromLog(fd, pidIter->second, logIter->second);
284 }
285 }
286 }
287
UpdateFaultLogInfoFromTempFile(FaultLogInfo & info)288 static void UpdateFaultLogInfoFromTempFile(FaultLogInfo& info)
289 {
290 if (!info.module.empty()) {
291 return;
292 }
293
294 StringUtil::ConvertStringTo<int32_t>(info.sectionMap[MODULE_UID.sectionName], info.id);
295 info.module = info.sectionMap[PROCESS_NAME.sectionName];
296 info.reason = info.sectionMap[REASON.sectionName];
297 info.summary = info.sectionMap[KEY_THREAD_INFO.sectionName];
298 info.registers = info.sectionMap[KEY_THREAD_REGISTERS.sectionName];
299 info.otherThreadInfo = info.sectionMap[OTHER_THREAD_INFO.sectionName];
300 size_t removeStartPos = info.summary.find("Tid:");
301 size_t removeEndPos = info.summary.find("Name:");
302 if (removeStartPos != std::string::npos && removeEndPos != std::string::npos) {
303 auto iterator = info.summary.begin() + removeEndPos;
304 while (iterator != info.summary.end() && *iterator != '\n') {
305 if (isdigit(*iterator)) {
306 iterator = info.summary.erase(iterator);
307 } else {
308 iterator++;
309 }
310 }
311 info.summary.replace(removeStartPos, removeEndPos - removeStartPos + 1, "Thread n");
312 }
313 }
314
ParseCppCrashFromFile(const std::string & path)315 FaultLogInfo ParseCppCrashFromFile(const std::string& path)
316 {
317 auto fileName = FileUtil::ExtractFileName(path);
318 FaultLogInfo info = ExtractInfoFromTempFile(fileName);
319 auto parseList = GetLogParseSections(info.faultLogType);
320 std::ifstream logFile(path);
321 std::string line;
322 std::string multline;
323 std::string multlineName;
324 while (std::getline(logFile, line)) {
325 if (!logFile.good()) {
326 break;
327 }
328
329 if (line.empty()) {
330 continue;
331 }
332
333 if (ParseFaultLogLine(parseList, line, multline, multlineName, info)) {
334 multline.append(line).append("\n");
335 } else {
336 multline.clear();
337 }
338 }
339
340 if (!multline.empty() && !multlineName.empty()) {
341 info.sectionMap[multlineName] = multline;
342 }
343 UpdateFaultLogInfoFromTempFile(info);
344 return info;
345 }
346
JumpBuildInfo(int32_t fd,std::ifstream & logFile)347 void JumpBuildInfo(int32_t fd, std::ifstream& logFile)
348 {
349 std::string line;
350 if (std::getline(logFile, line)) {
351 if (line.find("Build info:") != std::string::npos) {
352 return;
353 }
354 }
355 FileUtil::SaveStringToFd(fd, line + "\n");
356 }
357
WriteLogToFile(int32_t fd,const std::string & path,const std::map<std::string,std::string> & sections)358 bool WriteLogToFile(int32_t fd, const std::string& path, const std::map<std::string, std::string>& sections)
359 {
360 if ((fd < 0) || path.empty()) {
361 return false;
362 }
363
364 std::string line;
365 std::ifstream logFile(path);
366 JumpBuildInfo(fd, logFile);
367
368 bool hasFindRssInfo = false;
369 while (std::getline(logFile, line)) {
370 if (logFile.eof()) {
371 break;
372 }
373 if (!logFile.good()) {
374 return false;
375 }
376 FileUtil::SaveStringToFd(fd, line);
377 FileUtil::SaveStringToFd(fd, "\n");
378 if (!hasFindRssInfo && line.find("Process Memory(kB):") != std::string::npos &&
379 sections.find("DEVICE_MEMINFO") != sections.end()) {
380 FileUtil::SaveStringToFd(fd, sections.at("DEVICE_MEMINFO"));
381 FileUtil::SaveStringToFd(fd, "\n");
382 hasFindRssInfo = true;
383 }
384 }
385 return true;
386 }
387
IsFaultLogLimit()388 bool IsFaultLogLimit()
389 {
390 std::string isDev = OHOS::system::GetParameter("const.security.developermode.state", "");
391 std::string isBeta = OHOS::system::GetParameter("const.logsystem.versiontype", "");
392 if ((isDev == "true") || (isBeta == "beta")) {
393 return false;
394 }
395 return true;
396 }
397 } // namespace FaultLogger
398 } // namespace HiviewDFX
399 } // namespace OHOS
400