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