• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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