• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 "cppcrash_reporter.h"
17 
18 #include <cinttypes>
19 #include <dlfcn.h>
20 #include <fcntl.h>
21 #include <map>
22 #include <sstream>
23 #include <string>
24 #include "dfx_define.h"
25 #include "dfx_logger.h"
26 #include "dfx_process.h"
27 #include "dfx_signal.h"
28 #include "dfx_thread.h"
29 #ifndef HISYSEVENT_DISABLE
30 #include "hisysevent.h"
31 #endif
32 
33 struct FaultLogInfoInner {
34     uint64_t time {0};
35     uint32_t id {0};
36     int32_t pid {-1};
37     int32_t pipeFd {-1};
38     int32_t faultLogType {0};
39     std::string module;
40     std::string reason;
41     std::string summary;
42     std::string logPath;
43     std::string registers;
44     std::map<std::string, std::string> sectionMaps;
45 };
46 static const char FOUNDATION_PROCESS_NAME[] = "foundation";
47 static const char HIVIEW_PROCESS_NAME[] = "/system/bin/hiview";
48 static const char REGS_KEY_WORD[] = "Registers:\n";
49 #ifndef HISYSEVENT_DISABLE
50 static const char KILL_REASON_CPP_CRASH[] = "Kill Reason:Cpp Crash";
51 #endif
52 
53 using AddFaultLog = void (*)(FaultLogInfoInner* info);
54 using RecordAppExitReason = int (*)(int reason, const char *exitMsg);
55 
56 namespace OHOS {
57 namespace HiviewDFX {
58 
Format()59 bool CppCrashReporter::Format()
60 {
61     if (process_ == nullptr) {
62         return false;
63     }
64 
65     cmdline_ = process_->processInfo_.processName;
66     pid_ = process_->processInfo_.pid;
67     uid_ = process_->processInfo_.uid;
68     reason_ = process_->reason;
69     auto msg = process_->GetFatalMessage();
70     if (!msg.empty()) {
71         stack_ = "LastFatalMessage:" + msg + "\n";
72     }
73     std::shared_ptr<DfxThread> thread = dumpMode_ == FUSION_MODE ? process_->keyThread_ : process_->vmThread_;
74     if (thread != nullptr) {
75         std::string threadInfo = thread->ToString();
76         auto iterator = threadInfo.begin();
77         while (iterator != threadInfo.end() && *iterator != '\n') {
78             if (isdigit(*iterator)) {
79                 iterator = threadInfo.erase(iterator);
80             } else {
81                 iterator++;
82             }
83         }
84         stack_ += threadInfo;
85 
86         // regs
87         registers_ = GetRegsString(thread);
88     }
89     return true;
90 }
91 
ReportToHiview()92 void CppCrashReporter::ReportToHiview()
93 {
94     if (!Format()) {
95         DFXLOG_WARN("%s", "Failed to format crash report.");
96         return;
97     }
98     if (process_->processInfo_.processName.find(HIVIEW_PROCESS_NAME) != std::string::npos) {
99         DFXLOG_WARN("%s", "Failed to report, hiview is crashed.");
100         return;
101     }
102 
103     void* handle = dlopen("libfaultlogger.z.so", RTLD_LAZY | RTLD_NODELETE);
104     if (handle == nullptr) {
105         DFXLOG_WARN("Failed to dlopen libfaultlogger, %s\n", dlerror());
106         return;
107     }
108 
109     AddFaultLog addFaultLog = (AddFaultLog)dlsym(handle, "AddFaultLog");
110     if (addFaultLog == nullptr) {
111         DFXLOG_WARN("Failed to dlsym AddFaultLog, %s\n", dlerror());
112         dlclose(handle);
113         return;
114     }
115 
116     FaultLogInfoInner info;
117     info.time = time_;
118     info.id = uid_;
119     info.pid = pid_;
120     info.pipeFd = WriteCppCrashInfoByPipe();
121     info.faultLogType = 2; // 2 : CPP_CRASH_TYPE
122     info.module = cmdline_;
123     info.reason = reason_;
124     info.summary = stack_;
125     info.registers = registers_;
126     addFaultLog(&info);
127     DFXLOG_INFO("Finish report fault to FaultLogger %s(%d,%d)", cmdline_.c_str(), pid_, uid_);
128     dlclose(handle);
129 }
130 
131 // read fd will be closed after transfering to hiview
WriteCppCrashInfoByPipe()132 int32_t CppCrashReporter::WriteCppCrashInfoByPipe()
133 {
134     size_t sz = cppCrashInfo_.size();
135     if (sz > MAX_PIPE_SIZE) {
136         DFXLOG_ERROR("the size of json string is greater than max pipe size, do not report");
137         return -1;
138     }
139     int pipeFd[2] = {-1, -1};
140     if (pipe(pipeFd) != 0) {
141         DFXLOG_ERROR("Failed to create pipe.");
142         return -1;
143     }
144     if (fcntl(pipeFd[PIPE_READ], F_SETPIPE_SZ, sz) < 0 ||
145         fcntl(pipeFd[PIPE_WRITE], F_SETPIPE_SZ, sz) < 0) {
146         DFXLOG_ERROR("Failed to set pipe size.");
147         return -1;
148     }
149     if (fcntl(pipeFd[PIPE_READ], F_GETFL) < 0) {
150         DFXLOG_ERROR("Failed to set pipe size.");
151         return -1;
152     } else {
153         uint32_t flags = static_cast<uint32_t>(fcntl(pipeFd[PIPE_READ], F_GETFL));
154         flags |= O_NONBLOCK;
155         if (fcntl(pipeFd[PIPE_READ], F_SETFL, flags) < 0) {
156             DFXLOG_ERROR("Failed to set pipe flag.");
157             return -1;
158         }
159     }
160     ssize_t realWriteSize = -1;
161     realWriteSize = OHOS_TEMP_FAILURE_RETRY(write(pipeFd[PIPE_WRITE], cppCrashInfo_.c_str(), sz));
162     close(pipeFd[PIPE_WRITE]);
163     if (static_cast<ssize_t>(cppCrashInfo_.size()) != realWriteSize) {
164         DFXLOG_ERROR("Failed to write pipe. realWriteSize %zd, json size %zd", realWriteSize, sz);
165         close(pipeFd[PIPE_READ]);
166         return -1;
167     }
168     return pipeFd[PIPE_READ];
169 }
170 
ReportToAbilityManagerService()171 void CppCrashReporter::ReportToAbilityManagerService()
172 {
173     if (process_->processInfo_.processName.find(FOUNDATION_PROCESS_NAME) != std::string::npos) {
174         DFXLOG_WARN("%s", "Do not to report to AbilityManagerService, foundation is crashed.");
175         return;
176     }
177 
178     void* handle = dlopen("libability_manager_c.z.so", RTLD_LAZY | RTLD_NODELETE);
179     if (handle == nullptr) {
180         DFXLOG_WARN("Failed to dlopen libabilityms, %s\n", dlerror());
181         return;
182     }
183 
184     RecordAppExitReason recordAppExitReason = (RecordAppExitReason)dlsym(handle, "RecordAppExitReason");
185     if (recordAppExitReason == nullptr) {
186         DFXLOG_WARN("Failed to dlsym RecordAppExitReason, %s\n", dlerror());
187         dlclose(handle);
188         return;
189     }
190 
191     // defined in interfaces/inner_api/ability_manager/include/ability_state.h
192     const int cppCrashExitReason = 2;
193     recordAppExitReason(cppCrashExitReason, reason_.c_str());
194     dlclose(handle);
195 #ifndef HISYSEVENT_DISABLE
196     int result = HiSysEventWrite(HiSysEvent::Domain::FRAMEWORK, "PROCESS_KILL", HiSysEvent::EventType::FAULT,
197         "PID", pid_, "PROCESS_NAME", cmdline_.c_str(), "MSG", KILL_REASON_CPP_CRASH);
198     DFXLOG_INFO("hisysevent write result=%d, send event [FRAMEWORK,PROCESS_KILL], pid=%d processName=%s, msg=%s",
199         result, pid_, cmdline_.c_str(), KILL_REASON_CPP_CRASH);
200 #endif
201 }
202 
GetRegsString(std::shared_ptr<DfxThread> thread)203 std::string CppCrashReporter::GetRegsString(std::shared_ptr<DfxThread> thread)
204 {
205     std::string regsString = "";
206     if (thread == nullptr) {
207         return regsString;
208     }
209     std::shared_ptr<DfxRegs> regs = thread->GetThreadRegs();
210     if (regs == nullptr) {
211         return regsString;
212     }
213     regsString = regs->PrintRegs();
214     // if start with 'Registers:\n', need remove
215     if (regsString.find(REGS_KEY_WORD) == 0) {
216         regsString = regsString.substr(strlen(REGS_KEY_WORD));
217     }
218     return regsString;
219 }
220 } // namespace HiviewDFX
221 } // namespace OHOS
222