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