• 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_processor_base.h"
16 
17 #include "constants.h"
18 #include "dfx_define.h"
19 #include "faultlog_bundle_util.h"
20 #include "faultlog_formatter.h"
21 #include "faultlog_hilog_helper.h"
22 #include "faultlog_util.h"
23 #include "hisysevent.h"
24 #include "hiview_logger.h"
25 #include "log_analyzer.h"
26 #include "page_history_manager.h"
27 #include "parameter_ex.h"
28 #include "process_status.h"
29 #include "string_util.h"
30 
31 namespace OHOS {
32 namespace HiviewDFX {
33 using namespace FaultLogger;
34 DEFINE_LOG_LABEL(0xD002D11, "Faultlogger");
35 using namespace FaultlogHilogHelper;
36 
37 namespace {
GetSummaryFromSectionMap(int32_t type,const std::map<std::string,std::string> & maps)38 std::string GetSummaryFromSectionMap(int32_t type, const std::map<std::string, std::string>& maps)
39 {
40     std::string key = "";
41     switch (type) {
42         case CPP_CRASH:
43             key = FaultKey::KEY_THREAD_INFO;
44             break;
45         default:
46             break;
47     }
48 
49     if (key.empty()) {
50         return "";
51     }
52 
53     auto value = maps.find(key);
54     if (value == maps.end()) {
55         return "";
56     }
57     return value->second;
58 }
59 
IsFaultTypeSupport(const FaultLogInfo & info)60 bool IsFaultTypeSupport(const FaultLogInfo& info)
61 {
62     if ((info.faultLogType <= FaultLogType::ALL) || (info.faultLogType > FaultLogType::CJ_ERROR)) {
63         HIVIEW_LOGW("Unsupported fault type");
64         return false;
65     }
66     return true;
67 }
68 
IsSnapshot(const FaultLogInfo & info)69 bool IsSnapshot(const FaultLogInfo& info)
70 {
71     if (info.reason.find("CppCrashKernelSnapshot") != std::string::npos) {
72         HIVIEW_LOGI("Skip cpp crash kernel snapshot fault %{public}d", info.pid);
73         return true;
74     }
75     return false;
76 }
77 
IsFaultByIpc(const FaultLogInfo & info)78 bool IsFaultByIpc(const FaultLogInfo& info)
79 {
80     return info.faultLogType == FaultLogType::CPP_CRASH ||
81         info.faultLogType == FaultLogType::SYS_FREEZE ||
82         info.faultLogType == FaultLogType::SYS_WARNING ||
83         info.faultLogType == FaultLogType::APP_FREEZE;
84 }
85 } // namespace
86 
AddFaultLog(FaultLogInfo & info,const std::shared_ptr<EventLoop> & workLoop,const std::shared_ptr<FaultLogManager> & faultLogManager)87 void FaultLogProcessorBase::AddFaultLog(FaultLogInfo& info, const std::shared_ptr<EventLoop>& workLoop,
88     const std::shared_ptr<FaultLogManager>& faultLogManager)
89 {
90     workLoop_ = workLoop;
91     faultLogManager_ = faultLogManager;
92     if (!IsFaultTypeSupport(info) || IsSnapshot(info)) {
93         return;
94     }
95 
96     ProcessFaultLog(info);
97 
98     if (!IsFaultByIpc(info)) {
99         return;
100     }
101     SaveFaultInfoToRawDb(info);
102     ReportEventToAppEvent(info);
103     DoFaultLogLimit(info);
104 }
105 
VerifyModule(FaultLogInfo & info)106 bool FaultLogProcessorBase::VerifyModule(FaultLogInfo& info)
107 {
108     if (!IsValidPath(info.logPath)) {
109         HIVIEW_LOGE("The log path is incorrect, and the current log path is: %{public}s.", info.logPath.c_str());
110         return false;
111     }
112     HIVIEW_LOGI("Start saving Faultlog of Process:%{public}d, Name:%{public}s, Reason:%{public}s.",
113         info.pid, info.module.c_str(), info.reason.c_str());
114     info.sectionMap["PROCESS_NAME"] = info.module; // save process name
115     // Non system processes use UID to pass events to applications
116     if (!IsSystemProcess(info.module, info.id) && info.sectionMap["SCBPROCESS"] != "Yes") {
117         std::string appName = GetApplicationNameById(info.id);
118         if (!appName.empty() && !ExtractSubMoudleName(info.module)) {
119             info.module = appName; // if bundle name is not empty, replace module name by it.
120         }
121     }
122 
123     HIVIEW_LOGD("nameProc %{public}s", info.module.c_str());
124     if ((info.module.empty()) ||
125         (info.faultLogType != FaultLogType::ADDR_SANITIZER && !IsModuleNameValid(info.module))) {
126         HIVIEW_LOGW("Invalid module name %{public}s", info.module.c_str());
127         return false;
128     }
129     return true;
130 }
131 
ProcessFaultLog(FaultLogInfo & info)132 void FaultLogProcessorBase::ProcessFaultLog(FaultLogInfo& info)
133 {
134     if (!VerifyModule(info)) {
135         return;
136     }
137     // step1: add common info: uid module name, pid, reason, summary etc
138     AddCommonInfo(info);
139     // step2: add specific info: need implement in derived class
140     AddSpecificInfo(info);
141     // step3: generate fault log file
142     SaveFaultLogToFile(info);
143     PrintFaultLogInfo(info);
144 }
145 
SaveFaultLogToFile(FaultLogInfo & info)146 void FaultLogProcessorBase::SaveFaultLogToFile(FaultLogInfo& info)
147 {
148     if (info.dumpLogToFaultlogger && faultLogManager_) {
149         faultLogManager_->SaveFaultLogToFile(info);
150     }
151 }
152 
DoFaultLogLimit(const FaultLogInfo & info)153 void FaultLogProcessorBase::DoFaultLogLimit(const FaultLogInfo& info)
154 {
155     bool isNeedLimitFile = (info.dumpLogToFaultlogger && ((info.faultLogType == FaultLogType::CPP_CRASH) ||
156         (info.faultLogType == FaultLogType::APP_FREEZE)) && IsFaultLogLimit());
157     if (isNeedLimitFile) {
158         DoFaultLogLimit(info.logPath, info.faultLogType);
159     }
160 }
161 
SaveFaultInfoToRawDb(FaultLogInfo & info)162 void FaultLogProcessorBase::SaveFaultInfoToRawDb(FaultLogInfo& info)
163 {
164     if (faultLogManager_) {
165         faultLogManager_->SaveFaultInfoToRawDb(info);
166     }
167 }
168 
AddCommonInfo(FaultLogInfo & info)169 void FaultLogProcessorBase::AddCommonInfo(FaultLogInfo& info)
170 {
171     info.sectionMap[FaultKey::DEVICE_INFO] = Parameter::GetString("const.product.name", "Unknown");
172     if (info.sectionMap.find(FaultKey::BUILD_INFO) == info.sectionMap.end()) {
173         info.sectionMap[FaultKey::BUILD_INFO] = Parameter::GetString("const.product.software.version", "Unknown");
174     }
175     info.sectionMap[FaultKey::MODULE_UID] = std::to_string(info.id);
176     info.sectionMap[FaultKey::MODULE_PID] = std::to_string(info.pid);
177     info.module = RegulateModuleNameIfNeed(info.module);
178     info.sectionMap[FaultKey::MODULE_NAME] = info.module;
179     AddBundleInfo(info);
180     AddForegroundInfo(info);
181 
182     if (info.reason.empty()) {
183         info.reason = info.sectionMap[FaultKey::REASON];
184     } else {
185         info.sectionMap[FaultKey::REASON] = info.reason;
186     }
187 
188     if (info.summary.empty()) {
189         info.summary = GetSummaryFromSectionMap(info.faultLogType, info.sectionMap);
190     } else {
191         info.sectionMap[FaultKey::SUMMARY] = info.summary;
192     }
193 
194     UpdateTerminalThreadStack(info);
195 
196     // parse fingerprint by summary or temp log for native crash
197     AnalysisFaultlog(info, info.parsedLogInfo);
198     info.sectionMap.insert(info.parsedLogInfo.begin(), info.parsedLogInfo.end());
199     info.parsedLogInfo.clear();
200     // Internal reserved fields, avoid illegal privilege escalation to access files
201     info.sectionMap.erase(FaultKey::APPEND_ORIGIN_LOG);
202 }
203 
AddBundleInfo(FaultLogInfo & info)204 void FaultLogProcessorBase::AddBundleInfo(FaultLogInfo& info)
205 {
206     DfxBundleInfo bundleInfo;
207     if (info.id < MIN_APP_USERID || !GetDfxBundleInfo(info.module, bundleInfo)) {
208         return;
209     }
210 
211     if (!bundleInfo.versionName.empty()) {
212         info.sectionMap[FaultKey::MODULE_VERSION] = bundleInfo.versionName;
213         info.sectionMap[FaultKey::VERSION_CODE] = std::to_string(bundleInfo.versionCode);
214     }
215 
216     info.sectionMap[FaultKey::PRE_INSTALL] = bundleInfo.isPreInstalled ? "Yes" : "No";
217 }
218 
AddForegroundInfo(FaultLogInfo & info)219 void FaultLogProcessorBase::AddForegroundInfo(FaultLogInfo& info)
220 {
221     if (!info.sectionMap[FaultKey::FOREGROUND].empty() || info.id < MIN_APP_USERID) {
222         return;
223     }
224 
225     if (UCollectUtil::ProcessStatus::GetInstance().GetProcessState(info.pid) == UCollectUtil::FOREGROUND) {
226         info.sectionMap[FaultKey::FOREGROUND] = "Yes";
227     } else if (UCollectUtil::ProcessStatus::GetInstance().GetProcessState(info.pid) == UCollectUtil::BACKGROUND) {
228         int64_t lastFgTime = static_cast<int64_t>(UCollectUtil::ProcessStatus::GetInstance()
229                                                   .GetProcessLastForegroundTime(info.pid));
230         info.sectionMap[FaultKey::FOREGROUND] = lastFgTime > info.time ? "Yes" : "No";
231     }
232 }
233 
UpdateTerminalThreadStack(FaultLogInfo & info)234 void FaultLogProcessorBase::UpdateTerminalThreadStack(FaultLogInfo& info)
235 {
236     auto threadStack = GetStrValFromMap(info.sectionMap, "TERMINAL_THREAD_STACK");
237     if (threadStack.empty()) {
238         return;
239     }
240     // Replace the '\n' in the string with a line break character
241     info.parsedLogInfo["TERMINAL_THREAD_STACK"] = StringUtil::ReplaceStr(threadStack, "\\n", "\n");
242 }
243 
PrintFaultLogInfo(const FaultLogInfo & info)244 void FaultLogProcessorBase::PrintFaultLogInfo(const FaultLogInfo& info)
245 {
246     HIVIEW_LOGI("\nSave Faultlog of Process:%{public}d\n"
247         "ModuleName:%{public}s\n"
248         "Reason:%{public}s\n",
249         info.pid, info.module.c_str(), info.reason.c_str());
250 }
251 
ReadLogFile(const std::string & logPath) const252 std::string FaultLogProcessorBase::ReadLogFile(const std::string& logPath) const
253 {
254     std::ifstream logReadFile(logPath);
255     if (!logReadFile.is_open()) {
256         return "";
257     }
258     return std::string(std::istreambuf_iterator<char>(logReadFile), std::istreambuf_iterator<char>());
259 }
260 
WriteLogFile(const std::string & logPath,const std::string & content) const261 void FaultLogProcessorBase::WriteLogFile(const std::string& logPath, const std::string& content) const
262 {
263     std::ofstream logWriteFile(logPath, std::ios::out | std::ios::trunc);
264     if (!logWriteFile.is_open()) {
265         HIVIEW_LOGE("Failed to open log file: %{public}s", logPath.c_str());
266         return;
267     }
268     logWriteFile << content;
269     if (!logWriteFile.good()) {
270         HIVIEW_LOGE("Failed to write content to log file: %{public}s", logPath.c_str());
271     }
272     logWriteFile.close();
273 }
274 
GetProcMemInfo(FaultLogInfo & info)275 void FaultLogProcessorBase::GetProcMemInfo(FaultLogInfo& info)
276 {
277     if (!info.sectionMap["START_BOOT_SCAN"].empty()) {
278         return;
279     }
280 
281     std::ifstream meminfoStream("/proc/meminfo");
282     if (meminfoStream) {
283         constexpr int decimalBase = 10;
284         unsigned long long totalMem = 0; // row 1
285         unsigned long long freeMem = 0; // row 2
286         unsigned long long availMem = 0; // row 3
287         std::string meminfoLine;
288         std::getline(meminfoStream, meminfoLine);
289         totalMem = strtoull(GetDigtStrArr(meminfoLine).front().c_str(), nullptr, decimalBase);
290         std::getline(meminfoStream, meminfoLine);
291         freeMem = strtoull(GetDigtStrArr(meminfoLine).front().c_str(), nullptr, decimalBase);
292         std::getline(meminfoStream, meminfoLine);
293         availMem = strtoull(GetDigtStrArr(meminfoLine).front().c_str(), nullptr, decimalBase);
294         meminfoStream.close();
295         info.sectionMap["DEVICE_MEMINFO"] = "Device Memory(kB): Total " + std::to_string(totalMem) +
296             ", Free " + std::to_string(freeMem) + ", Available " + std::to_string(availMem);
297     } else {
298         HIVIEW_LOGE("Fail to open /proc/meminfo");
299     }
300 }
301 
GetDigtStrArr(const std::string & target)302 std::list<std::string> FaultLogProcessorBase::GetDigtStrArr(const std::string &target)
303 {
304     std::list<std::string> ret;
305     std::string temp = "";
306     for (size_t i = 0, len = target.size(); i < len; i++) {
307         if (target[i] >= '0' && target[i] <= '9') {
308             temp += target[i];
309             continue;
310         }
311         if (temp.size() != 0) {
312             ret.push_back(temp);
313             temp = "";
314         }
315     }
316     if (temp.size() != 0) {
317         ret.push_back(temp);
318     }
319     ret.push_back("0");
320     return ret;
321 }
322 
AddPagesHistory(FaultLogInfo & info) const323 void FaultLogProcessorBase::AddPagesHistory(FaultLogInfo& info) const
324 {
325     if (info.id < MIN_APP_USERID) {
326         return;
327     }
328     auto trace = PageHistoryManager::GetInstance().GetPageHistory(info.module, info.pid);
329     if (!trace.empty()) {
330         info.sectionMap[FaultKey::PAGE_SWITCH_HISTORY] = std::move(trace);
331     }
332 }
333 } // namespace HiviewDFX
334 } // namespace OHOS
335