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