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
16 #include "reporter.h"
17
18 #include <dlfcn.h>
19 #include <fcntl.h>
20 #include <string>
21 #include "dfx_define.h"
22
23 #include "dfx_log.h"
24 #include "dfx_process.h"
25 #include "dfx_signal.h"
26 #include "dfx_thread.h"
27 #include "faultlogger_client_msg.h"
28 #ifndef HISYSEVENT_DISABLE
29 #include "hisysevent.h"
30 #endif
31
32 const char* const FOUNDATION_PROCESS_NAME = "foundation";
33 const char* const HIVIEW_PROCESS_NAME = "/system/bin/hiview";
34 const char* const REGS_KEY_WORD = "Registers:\n";
35 #ifndef HISYSEVENT_DISABLE
36 const char* const KILL_REASON_CPP_CRASH = "Kill Reason:Cpp Crash";
37 #endif
38
39 using RecordAppExitReason = int (*)(int reason, const char *exitMsg);
40
41 namespace OHOS {
42 namespace HiviewDFX {
SysEventReporter(const ProcessDumpType & processDumpType)43 SysEventReporter::SysEventReporter(const ProcessDumpType& processDumpType)
44 {
45 if (processDumpType == ProcessDumpType::DUMP_TYPE_CPP_CRASH) {
46 reporter_ = std::make_shared<CppCrashReporter>();
47 } else if (processDumpType >= ProcessDumpType::DUMP_TYPE_FDSAN
48 && processDumpType <= ProcessDumpType::DUMP_TYPE_BADFD) {
49 reporter_ = std::make_shared<AddrSanitizerReporter>();
50 }
51 }
Report(DfxProcess & process,const ProcessDumpRequest & request)52 void SysEventReporter::Report(DfxProcess& process, const ProcessDumpRequest &request)
53 {
54 if (reporter_ != nullptr) {
55 reporter_->Report(process, request);
56 }
57 }
58
Report(DfxProcess & process,const ProcessDumpRequest & request)59 void CppCrashReporter::Report(DfxProcess& process, const ProcessDumpRequest &request)
60 {
61 if (process.GetProcessInfo().processName.find(HIVIEW_PROCESS_NAME) == std::string::npos) {
62 ReportToHiview(process, request);
63 } else {
64 DFXLOGW("Do not to report to hiview, because hiview is crashed.");
65 }
66 if (process.GetProcessInfo().processName.find(FOUNDATION_PROCESS_NAME) == std::string::npos) {
67 ReportToAbilityManagerService(process);
68 } else {
69 DFXLOGW("Do not to report to AbilityManagerService, because foundation is crashed.");
70 }
71 }
72
ReportToHiview(DfxProcess & process,const ProcessDumpRequest & request)73 void CppCrashReporter::ReportToHiview(DfxProcess& process, const ProcessDumpRequest &request)
74 {
75 void* handle = dlopen("libfaultlogger.z.so", RTLD_LAZY | RTLD_NODELETE);
76 if (handle == nullptr) {
77 DFXLOGW("Failed to dlopen libfaultlogger, %{public}s\n", dlerror());
78 dlerror();
79 return;
80 }
81 auto addFaultLog = reinterpret_cast<void (*)(FaultDFXLOGIInner*)>(dlsym(handle, "AddFaultLog"));
82 if (addFaultLog == nullptr) {
83 DFXLOGW("Failed to dlsym AddFaultLog, %{public}s\n", dlerror());
84 dlerror();
85 dlclose(handle);
86 return;
87 }
88 FaultDFXLOGIInner info;
89 info.time = request.timeStamp;
90 info.id = process.GetProcessInfo().uid;
91 info.pid = process.GetProcessInfo().pid;
92 SmartFd fdRead = TranferCrashInfoToHiview(process.GetCrashInfoJson());
93 info.pipeFd = fdRead.GetFd(); // free after addFaultLog
94 info.faultLogType = 2; // 2 : CPP_CRASH_TYPE
95 info.logFileCutoffSizeBytes = process.GetCrashLogConfig().logFileCutoffSizeBytes;
96 info.module = process.GetProcessInfo().processName;
97 info.reason = process.GetReason();
98 info.registers = GetRegsString(process.GetFaultThreadRegisters());
99 info.summary = GetSummary(process);
100 addFaultLog(&info);
101 DFXLOGI("Finish report fault to FaultLogger %{public}s(%{public}d,%{public}d)",
102 info.module.c_str(), info.pid, info.id);
103 dlclose(handle);
104 }
105
GetSummary(DfxProcess & process)106 std::string CppCrashReporter::GetSummary(DfxProcess& process)
107 {
108 std::string summary;
109 auto msg = process.GetFatalMessage();
110 if (!msg.empty()) {
111 summary += ("LastFatalMessage:" + msg + "\n");
112 }
113 if (process.GetKeyThread() == nullptr) {
114 DFXLOGE("Failed to get key thread!");
115 return summary;
116 }
117 bool needPrintTid = false;
118 std::string threadInfo = process.GetKeyThread()->ToString(needPrintTid);
119 auto iterator = threadInfo.begin();
120 while (iterator != threadInfo.end() && *iterator != '\n') {
121 if (isdigit(*iterator)) {
122 iterator = threadInfo.erase(iterator);
123 } else {
124 iterator++;
125 }
126 }
127 summary += threadInfo;
128 return summary;
129 }
130
131 // read fd will be closed after transfering to hiview
TranferCrashInfoToHiview(const std::string & cppCrashInfo)132 SmartFd CppCrashReporter::TranferCrashInfoToHiview(const std::string& cppCrashInfo)
133 {
134 size_t crashInfoSize = cppCrashInfo.size();
135 if (crashInfoSize > MAX_PIPE_SIZE) {
136 DFXLOGE("the size of json string is greater than max pipe size, do not report");
137 return {};
138 }
139 int pipeFd[PIPE_NUM_SZ] = {-1, -1};
140 if (pipe2(pipeFd, O_NONBLOCK) != 0) {
141 DFXLOGE("Failed to create pipe.");
142 return {};
143 }
144 SmartFd writeFd(pipeFd[PIPE_WRITE]);
145 SmartFd readFd(pipeFd[PIPE_READ]);
146 if (fcntl(readFd.GetFd(), F_SETPIPE_SZ, crashInfoSize) < 0 ||
147 fcntl(writeFd.GetFd(), F_SETPIPE_SZ, crashInfoSize) < 0) {
148 DFXLOGE("[%{public}d]: failed to set pipe size.", __LINE__);
149 return {};
150 }
151 ssize_t realWriteSize = -1;
152 realWriteSize = OHOS_TEMP_FAILURE_RETRY(write(writeFd.GetFd(), cppCrashInfo.c_str(), crashInfoSize));
153 if (static_cast<ssize_t>(crashInfoSize) != realWriteSize) {
154 DFXLOGE("Failed to write pipe. realWriteSize %{public}zd, json size %{public}zd", realWriteSize, crashInfoSize);
155 return {};
156 }
157 return readFd;
158 }
159
ReportToAbilityManagerService(const DfxProcess & process)160 void CppCrashReporter::ReportToAbilityManagerService(const DfxProcess& process)
161 {
162 void* handle = dlopen("libability_manager_c.z.so", RTLD_LAZY | RTLD_NODELETE);
163 if (handle == nullptr) {
164 DFXLOGW("Failed to dlopen libabilityms, %{public}s\n", dlerror());
165 return;
166 }
167
168 RecordAppExitReason recordAppExitReason = (RecordAppExitReason)dlsym(handle, "RecordAppExitReason");
169 if (recordAppExitReason == nullptr) {
170 DFXLOGW("Failed to dlsym RecordAppExitReason, %{public}s\n", dlerror());
171 dlclose(handle);
172 return;
173 }
174
175 // defined in interfaces/inner_api/ability_manager/include/ability_state.h
176 const int cppCrashExitReason = 2;
177 recordAppExitReason(cppCrashExitReason, process.GetReason().c_str());
178 dlclose(handle);
179 #ifndef HISYSEVENT_DISABLE
180 int result = HiSysEventWrite(HiSysEvent::Domain::FRAMEWORK, "PROCESS_KILL", HiSysEvent::EventType::FAULT,
181 "PID", process.GetProcessInfo().pid, "PROCESS_NAME", process.GetProcessInfo().processName.c_str(),
182 "MSG", KILL_REASON_CPP_CRASH);
183 DFXLOGW("hisysevent write result=%{public}d, send event [FRAMEWORK,PROCESS_KILL], pid=%{public}d,"
184 " processName=%{public}s, msg=%{public}s", result, process.GetProcessInfo().pid,
185 process.GetProcessInfo().processName.c_str(), KILL_REASON_CPP_CRASH);
186 #endif
187 }
188
GetRegsString(std::shared_ptr<DfxRegs> regs)189 std::string CppCrashReporter::GetRegsString(std::shared_ptr<DfxRegs> regs)
190 {
191 std::string regsString = "";
192 if (regs == nullptr) {
193 return regsString;
194 }
195 regsString = regs->PrintRegs();
196 // if start with 'Registers:\n', need remove
197 if (regsString.find(REGS_KEY_WORD) == 0) {
198 regsString = regsString.substr(strlen(REGS_KEY_WORD));
199 }
200 return regsString;
201 }
202
Report(DfxProcess & process,const ProcessDumpRequest & request)203 void AddrSanitizerReporter::Report(DfxProcess& process, const ProcessDumpRequest &request)
204 {
205 #ifndef HISYSEVENT_DISABLE
206 std::string reason = process.GetReason().empty() ? "DEBUG SIGNAL" : process.GetReason();
207 std::string summary;
208 if (process.GetKeyThread() != nullptr) {
209 bool needPrintTid = false;
210 summary = process.GetKeyThread()->ToString(needPrintTid);
211 }
212 HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::RELIABILITY, "ADDR_SANITIZER",
213 OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
214 "MODULE", request.processName,
215 "PID", request.pid,
216 "UID", request.uid,
217 "HAPPEN_TIME", request.timeStamp,
218 "REASON", reason,
219 "SUMMARY", summary);
220 DFXLOGI("%{public}s", "Report ADDR_SANITIZER event done.");
221 #else
222 DFXLOGW("%{public}s", "Not supported for ADDR_SANITIZER reporting.");
223 #endif
224 }
225 } // namespace HiviewDFX
226 } // namespace OHOS
227