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_cppcrash.h"
16
17 #include <chrono>
18 #include <ctime>
19 #include <fstream>
20
21 #include "crash_exception.h"
22 #include "constants.h"
23 #include "dfx_define.h"
24 #include "faultlog_bundle_util.h"
25 #include "faultlog_formatter.h"
26 #include "faultlog_util.h"
27 #include "file_util.h"
28 #include "hisysevent.h"
29 #include "hiview_logger.h"
30 #include "parameter_ex.h"
31
32 namespace OHOS {
33 namespace HiviewDFX {
34 DEFINE_LOG_LABEL(0xD002D11, "Faultlogger");
35 using namespace FaultLogger;
36
37 namespace {
38 const int DFX_HILOG_TIMESTAMP_LEN = 18;
39 const int DFX_HILOG_TIMESTAMP_START_YEAR = 1900;
40 const int DFX_HILOG_TIMESTAMP_MILLISEC_NUM = 3;
41 const int DFX_HILOG_TIMESTAMP_DECIMAL = 10;
42 const int64_t DFX_HILOG_TIMESTAMP_THOUSAND = 1000;
43 }
44
GetLastLineHilogTime(const std::string & lastLineHilog) const45 int64_t FaultLogCppCrash::GetLastLineHilogTime(const std::string& lastLineHilog) const
46 {
47 if (lastLineHilog.length() < DFX_HILOG_TIMESTAMP_LEN) {
48 HIVIEW_LOGE("GetLastLineHilogTime invalid length last line");
49 return -1;
50 }
51 std::string lastLineHilogTimeStr = lastLineHilog.substr(0, DFX_HILOG_TIMESTAMP_LEN);
52 // get year of the current time
53 std::time_t nowTt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
54 std::tm* nowTm = std::localtime(&nowTt);
55 if (!nowTm) {
56 HIVIEW_LOGE("GetLastLineHilogTime tm is null");
57 return -1;
58 }
59 // add year for time format
60 lastLineHilogTimeStr = std::to_string(nowTm->tm_year + DFX_HILOG_TIMESTAMP_START_YEAR) +
61 "-" + lastLineHilogTimeStr;
62 // format last line hilog time
63 std::tm lastLineHilogTm = {0};
64 std::istringstream ss(lastLineHilogTimeStr);
65 ss >> std::get_time(&lastLineHilogTm, "%Y-%m-%d %H:%M:%S");
66 if (ss.fail()) {
67 HIVIEW_LOGE("GetLastLineHilogTime get time fail");
68 return -1;
69 }
70 std::time_t lastLineHilogTt = std::mktime(&lastLineHilogTm);
71 int64_t lastLineHilogTime = static_cast<int64_t>(lastLineHilogTt);
72 // format time from second to milliseconds
73 size_t dotPos = lastLineHilogTimeStr.find_last_of('.');
74 long milliseconds = 0;
75 if (dotPos != std::string::npos && dotPos + DFX_HILOG_TIMESTAMP_MILLISEC_NUM < lastLineHilogTimeStr.size()) {
76 std::string millisecStr = lastLineHilogTimeStr.substr(dotPos + 1, DFX_HILOG_TIMESTAMP_MILLISEC_NUM);
77 milliseconds = strtol(millisecStr.c_str(), nullptr, DFX_HILOG_TIMESTAMP_DECIMAL);
78 }
79 lastLineHilogTime = lastLineHilogTime * DFX_HILOG_TIMESTAMP_THOUSAND + static_cast<int64_t>(milliseconds);
80 return lastLineHilogTime;
81 }
82
CheckHilogTime(FaultLogInfo & info)83 void FaultLogCppCrash::CheckHilogTime(FaultLogInfo& info)
84 {
85 if (!Parameter::IsBetaVersion()) {
86 return;
87 }
88 // drop last line tail '\n'
89 size_t hilogLen = info.sectionMap[FaultKey::HILOG].length();
90 if (hilogLen <= 1) {
91 HIVIEW_LOGE("Hilog length does not meet expectations, hilogLen: %{public}zu", hilogLen);
92 return;
93 }
94 if (hilogLen > 0 && info.sectionMap[FaultKey::HILOG][hilogLen - 1] == '\n') {
95 hilogLen--;
96 }
97 size_t pos = info.sectionMap[FaultKey::HILOG].rfind('\n', hilogLen - 1);
98 if (pos == std::string::npos) {
99 HIVIEW_LOGE("CheckHilogTime get last line hilog fail");
100 return;
101 }
102 // get last hilog time
103 std::string lastLineHilog = info.sectionMap[FaultKey::HILOG].substr(pos + 1);
104 int64_t lastLineHilogTime = GetLastLineHilogTime(lastLineHilog);
105 if (lastLineHilogTime < 0) {
106 return;
107 }
108 // check time invalid
109 if (lastLineHilogTime < info.time) {
110 info.sectionMap["INVAILED_HILOG_TIME"] = "true";
111 HIVIEW_LOGW("Hilog Time: %{public}" PRId64 ", Crash Time %{public}" PRId64 ".", lastLineHilogTime, info.time);
112 }
113 }
114
ReadStackFromPipe(const FaultLogInfo & info) const115 std::string FaultLogCppCrash::ReadStackFromPipe(const FaultLogInfo& info) const
116 {
117 if (info.pipeFd == nullptr || *(info.pipeFd) == -1) {
118 HIVIEW_LOGE("invalid fd");
119 return "";
120 }
121 std::vector<char> buffer(MAX_PIPE_SIZE + 1);
122 ssize_t nread = TEMP_FAILURE_RETRY(read(*info.pipeFd, buffer.data(), MAX_PIPE_SIZE));
123 if (nread <= 0) {
124 HIVIEW_LOGE("read pipe failed errno %{public}d", errno);
125 return "";
126 }
127 return std::string(buffer.data(), nread);
128 }
129
FillStackInfo(const FaultLogInfo & info,std::string & stackInfoOriginal) const130 Json::Value FaultLogCppCrash::FillStackInfo(const FaultLogInfo& info, std::string& stackInfoOriginal) const
131 {
132 Json::Reader reader;
133 Json::Value stackInfoObj;
134 if (!reader.parse(stackInfoOriginal, stackInfoObj)) {
135 HIVIEW_LOGE("parse stackInfo failed");
136 return stackInfoObj;
137 }
138 stackInfoObj["bundle_name"] = info.module;
139 Json::Value externalLog;
140 externalLog.append(info.logPath);
141 stackInfoObj["external_log"] = externalLog;
142 if (info.sectionMap.count(FaultKey::MODULE_VERSION) == 1) {
143 stackInfoObj["bundle_version"] = info.sectionMap.at(FaultKey::MODULE_VERSION);
144 }
145 if (info.sectionMap.count(FaultKey::FOREGROUND) == 1) {
146 stackInfoObj["foreground"] = info.sectionMap.at(FaultKey::FOREGROUND) == "Yes";
147 }
148 if (info.sectionMap.count(FaultKey::FINGERPRINT) == 1) {
149 stackInfoObj["uuid"] = info.sectionMap.at(FaultKey::FINGERPRINT);
150 }
151 if (info.sectionMap.count(FaultKey::HILOG) == 1) {
152 stackInfoObj["hilog"] = ParseHilogToJson(info.sectionMap.at(FaultKey::HILOG));
153 }
154 return stackInfoObj;
155 }
156
GetStackInfo(const FaultLogInfo & info) const157 std::string FaultLogCppCrash::GetStackInfo(const FaultLogInfo& info) const
158 {
159 std::string stackInfoOriginal = ReadStackFromPipe(info);
160 if (stackInfoOriginal.empty()) {
161 HIVIEW_LOGE("read stack from pipe failed");
162 return "";
163 }
164
165 auto stackInfoObj = FillStackInfo(info, stackInfoOriginal);
166 return Json::FastWriter().write(stackInfoObj);
167 }
168
ReportCppCrashToAppEvent(const FaultLogInfo & info) const169 void FaultLogCppCrash::ReportCppCrashToAppEvent(const FaultLogInfo& info) const
170 {
171 std::string stackInfo = GetStackInfo(info);
172 if (stackInfo.empty()) {
173 HIVIEW_LOGE("stackInfo is empty");
174 return;
175 }
176 HIVIEW_LOGI("report cppcrash to appevent, pid:%{public}d len:%{public}zu", info.pid, stackInfo.length());
177 #ifdef UNIT_TEST
178 std::string outputFilePath = "/data/test_cppcrash_info_" + std::to_string(info.pid);
179 WriteLogFile(outputFilePath, stackInfo + "\n");
180 #endif
181 EventPublish::GetInstance().PushEvent(info.id, APP_CRASH_TYPE, HiSysEvent::EventType::FAULT, stackInfo,
182 info.logFileCutoffSizeBytes);
183 }
184
AddCppCrashInfo(FaultLogInfo & info)185 void FaultLogCppCrash::AddCppCrashInfo(FaultLogInfo& info)
186 {
187 if (!info.registers.empty()) {
188 info.sectionMap[FaultKey::KEY_THREAD_REGISTERS] = info.registers;
189 }
190
191 AddPagesHistory(info);
192
193 FaultLogProcessorBase::GetProcMemInfo(info);
194 info.sectionMap[FaultKey::APPEND_ORIGIN_LOG] = GetCppCrashTempLogName(info);
195 std::string path = FAULTLOG_FAULT_HILOG_FOLDER + std::to_string(info.pid) +
196 "-" + std::to_string(info.id) + "-" + std::to_string(info.time);
197 std::string hilogSnapShot;
198 if (FileUtil::LoadStringFromFile(path, hilogSnapShot)) {
199 info.sectionMap[FaultKey::HILOG] = hilogSnapShot;
200 return;
201 }
202
203 std::string hilogGetByCmd = GetHilogByPid(info.pid);
204 if (FileUtil::LoadStringFromFile(path, hilogSnapShot)) {
205 info.sectionMap[FaultKey::HILOG] = hilogSnapShot;
206 } else {
207 info.sectionMap[FaultKey::HILOG] = hilogGetByCmd;
208 info.sectionMap["INVAILED_HILOG_TIME"] = "false";
209 CheckHilogTime(info);
210 }
211 }
212
CheckFaultLogAsync(const FaultLogInfo & info)213 void FaultLogCppCrash::CheckFaultLogAsync(const FaultLogInfo& info)
214 {
215 if (workLoop_ != nullptr) {
216 auto task = [info] {
217 CheckFaultLog(info);
218 };
219 workLoop_->AddTimerEvent(nullptr, nullptr, task, 0, false);
220 }
221 }
222
CheckFaultLog(const FaultLogInfo & info)223 bool FaultLogCppCrash::CheckFaultLog(const FaultLogInfo& info)
224 {
225 int32_t err = CrashExceptionCode::CRASH_ESUCCESS;
226 if (!CheckFaultSummaryValid(info.summary)) {
227 err = CrashExceptionCode::CRASH_LOG_ESUMMARYLOS;
228 }
229 ReportCrashException(info.module, info.pid, info.id, err);
230
231 return (err == CrashExceptionCode::CRASH_ESUCCESS);
232 }
233
AddSpecificInfo(FaultLogInfo & info)234 void FaultLogCppCrash::AddSpecificInfo(FaultLogInfo& info)
235 {
236 AddCppCrashInfo(info);
237 }
238
ReportEventToAppEvent(const FaultLogInfo & info)239 bool FaultLogCppCrash::ReportEventToAppEvent(const FaultLogInfo& info)
240 {
241 if (IsSystemProcess(info.module, info.id) || !info.reportToAppEvent) {
242 return false;
243 }
244 CheckFaultLogAsync(info);
245 ReportCppCrashToAppEvent(info);
246 return true;
247 }
248
DoFaultLogLimit(const std::string & logPath,int32_t faultType) const249 void FaultLogCppCrash::DoFaultLogLimit(const std::string& logPath, int32_t faultType) const
250 {
251 std::string readContent = ReadLogFile(logPath);
252 if (!TruncateLogIfExceedsLimit(readContent)) {
253 return;
254 }
255 WriteLogFile(logPath, readContent);
256 }
257
RemoveHiLogSection(std::string & readContent) const258 bool FaultLogCppCrash::RemoveHiLogSection(std::string& readContent) const
259 {
260 size_t pos = readContent.find("HiLog:");
261 if (pos == std::string::npos) {
262 HIVIEW_LOGW("No Hilog Found In Crash Log");
263 return false;
264 }
265 readContent.resize(pos);
266 return true;
267 }
268
TruncateLogIfExceedsLimit(std::string & readContent) const269 bool FaultLogCppCrash::TruncateLogIfExceedsLimit(std::string& readContent) const
270 {
271 constexpr size_t maxLogSize = 1024 * 1024;
272 auto fileLen = readContent.length();
273 if (fileLen <= maxLogSize) {
274 return false;
275 }
276
277 readContent.resize(maxLogSize);
278 readContent += "\n[truncated]";
279 return true;
280 }
281 } // namespace HiviewDFX
282 } // namespace OHOS
283