1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License.
5800b99b8Sopenharmony_ci * You may obtain a copy of the License at
6800b99b8Sopenharmony_ci *
7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8800b99b8Sopenharmony_ci *
9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and
13800b99b8Sopenharmony_ci * limitations under the License.
14800b99b8Sopenharmony_ci */
15800b99b8Sopenharmony_ci
16800b99b8Sopenharmony_ci#include "cppcrash_reporter.h"
17800b99b8Sopenharmony_ci
18800b99b8Sopenharmony_ci#include <cinttypes>
19800b99b8Sopenharmony_ci#include <dlfcn.h>
20800b99b8Sopenharmony_ci#include <fcntl.h>
21800b99b8Sopenharmony_ci#include <map>
22800b99b8Sopenharmony_ci#include <string>
23800b99b8Sopenharmony_ci#include "dfx_define.h"
24800b99b8Sopenharmony_ci#include "dfx_logger.h"
25800b99b8Sopenharmony_ci#include "dfx_process.h"
26800b99b8Sopenharmony_ci#include "dfx_signal.h"
27800b99b8Sopenharmony_ci#include "dfx_thread.h"
28800b99b8Sopenharmony_ci#include "faultlogger_client_msg.h"
29800b99b8Sopenharmony_ci#ifndef HISYSEVENT_DISABLE
30800b99b8Sopenharmony_ci#include "hisysevent.h"
31800b99b8Sopenharmony_ci#endif
32800b99b8Sopenharmony_ci
33800b99b8Sopenharmony_cistatic const char FOUNDATION_PROCESS_NAME[] = "foundation";
34800b99b8Sopenharmony_cistatic const char HIVIEW_PROCESS_NAME[] = "/system/bin/hiview";
35800b99b8Sopenharmony_cistatic const char REGS_KEY_WORD[] = "Registers:\n";
36800b99b8Sopenharmony_ci#ifndef HISYSEVENT_DISABLE
37800b99b8Sopenharmony_cistatic const char KILL_REASON_CPP_CRASH[] = "Kill Reason:Cpp Crash";
38800b99b8Sopenharmony_ci#endif
39800b99b8Sopenharmony_ci
40800b99b8Sopenharmony_ciusing RecordAppExitReason = int (*)(int reason, const char *exitMsg);
41800b99b8Sopenharmony_ci
42800b99b8Sopenharmony_cinamespace OHOS {
43800b99b8Sopenharmony_cinamespace HiviewDFX {
44800b99b8Sopenharmony_ci
45800b99b8Sopenharmony_cibool CppCrashReporter::Format()
46800b99b8Sopenharmony_ci{
47800b99b8Sopenharmony_ci    if (process_ == nullptr) {
48800b99b8Sopenharmony_ci        return false;
49800b99b8Sopenharmony_ci    }
50800b99b8Sopenharmony_ci
51800b99b8Sopenharmony_ci    cmdline_ = process_->processInfo_.processName;
52800b99b8Sopenharmony_ci    pid_ = process_->processInfo_.pid;
53800b99b8Sopenharmony_ci    uid_ = process_->processInfo_.uid;
54800b99b8Sopenharmony_ci    reason_ = process_->reason;
55800b99b8Sopenharmony_ci    auto msg = process_->GetFatalMessage();
56800b99b8Sopenharmony_ci    if (!msg.empty()) {
57800b99b8Sopenharmony_ci        stack_ = "LastFatalMessage:" + msg + "\n";
58800b99b8Sopenharmony_ci    }
59800b99b8Sopenharmony_ci    std::shared_ptr<DfxThread> thread = dumpMode_ == FUSION_MODE ? process_->keyThread_ : process_->vmThread_;
60800b99b8Sopenharmony_ci    if (thread != nullptr) {
61800b99b8Sopenharmony_ci        std::string threadInfo = thread->ToString();
62800b99b8Sopenharmony_ci        auto iterator = threadInfo.begin();
63800b99b8Sopenharmony_ci        while (iterator != threadInfo.end() && *iterator != '\n') {
64800b99b8Sopenharmony_ci            if (isdigit(*iterator)) {
65800b99b8Sopenharmony_ci                iterator = threadInfo.erase(iterator);
66800b99b8Sopenharmony_ci            } else {
67800b99b8Sopenharmony_ci                iterator++;
68800b99b8Sopenharmony_ci            }
69800b99b8Sopenharmony_ci        }
70800b99b8Sopenharmony_ci        stack_ += threadInfo;
71800b99b8Sopenharmony_ci
72800b99b8Sopenharmony_ci        // regs
73800b99b8Sopenharmony_ci        registers_ = GetRegsString(process_->regs_);
74800b99b8Sopenharmony_ci    }
75800b99b8Sopenharmony_ci    return true;
76800b99b8Sopenharmony_ci}
77800b99b8Sopenharmony_ci
78800b99b8Sopenharmony_civoid CppCrashReporter::ReportToHiview()
79800b99b8Sopenharmony_ci{
80800b99b8Sopenharmony_ci    if (!Format()) {
81800b99b8Sopenharmony_ci        DFXLOGW("Failed to format crash report.");
82800b99b8Sopenharmony_ci        return;
83800b99b8Sopenharmony_ci    }
84800b99b8Sopenharmony_ci    if (process_->processInfo_.processName.find(HIVIEW_PROCESS_NAME) != std::string::npos) {
85800b99b8Sopenharmony_ci        DFXLOGW("Failed to report, hiview is crashed.");
86800b99b8Sopenharmony_ci        return;
87800b99b8Sopenharmony_ci    }
88800b99b8Sopenharmony_ci
89800b99b8Sopenharmony_ci    void* handle = dlopen("libfaultlogger.z.so", RTLD_LAZY | RTLD_NODELETE);
90800b99b8Sopenharmony_ci    if (handle == nullptr) {
91800b99b8Sopenharmony_ci        DFXLOGW("Failed to dlopen libfaultlogger, %{public}s\n", dlerror());
92800b99b8Sopenharmony_ci        return;
93800b99b8Sopenharmony_ci    }
94800b99b8Sopenharmony_ci
95800b99b8Sopenharmony_ci    auto addFaultLog = reinterpret_cast<void (*)(FaultDFXLOGIInner*)>(dlsym(handle, "AddFaultLog"));
96800b99b8Sopenharmony_ci    if (addFaultLog == nullptr) {
97800b99b8Sopenharmony_ci        DFXLOGW("Failed to dlsym AddFaultLog, %{public}s\n", dlerror());
98800b99b8Sopenharmony_ci        dlclose(handle);
99800b99b8Sopenharmony_ci        return;
100800b99b8Sopenharmony_ci    }
101800b99b8Sopenharmony_ci
102800b99b8Sopenharmony_ci    FaultDFXLOGIInner info;
103800b99b8Sopenharmony_ci    info.time = time_;
104800b99b8Sopenharmony_ci    info.id = uid_;
105800b99b8Sopenharmony_ci    info.pid = pid_;
106800b99b8Sopenharmony_ci    info.pipeFd = WriteCppCrashInfoByPipe();
107800b99b8Sopenharmony_ci    info.faultLogType = 2; // 2 : CPP_CRASH_TYPE
108800b99b8Sopenharmony_ci    info.module = cmdline_;
109800b99b8Sopenharmony_ci    info.reason = reason_;
110800b99b8Sopenharmony_ci    info.summary = stack_;
111800b99b8Sopenharmony_ci    info.registers = registers_;
112800b99b8Sopenharmony_ci    addFaultLog(&info);
113800b99b8Sopenharmony_ci    DFXLOGI("Finish report fault to FaultLogger %{public}s(%{public}d,%{public}d)", cmdline_.c_str(), pid_, uid_);
114800b99b8Sopenharmony_ci    dlclose(handle);
115800b99b8Sopenharmony_ci}
116800b99b8Sopenharmony_ci
117800b99b8Sopenharmony_ci// read fd will be closed after transfering to hiview
118800b99b8Sopenharmony_ciint32_t CppCrashReporter::WriteCppCrashInfoByPipe()
119800b99b8Sopenharmony_ci{
120800b99b8Sopenharmony_ci    size_t sz = cppCrashInfo_.size();
121800b99b8Sopenharmony_ci    if (sz > MAX_PIPE_SIZE) {
122800b99b8Sopenharmony_ci        DFXLOGE("the size of json string is greater than max pipe size, do not report");
123800b99b8Sopenharmony_ci        return -1;
124800b99b8Sopenharmony_ci    }
125800b99b8Sopenharmony_ci    int pipeFd[2] = {-1, -1};
126800b99b8Sopenharmony_ci    if (pipe(pipeFd) != 0) {
127800b99b8Sopenharmony_ci        DFXLOGE("Failed to create pipe.");
128800b99b8Sopenharmony_ci        return -1;
129800b99b8Sopenharmony_ci    }
130800b99b8Sopenharmony_ci    if (fcntl(pipeFd[PIPE_READ], F_SETPIPE_SZ, sz) < 0 ||
131800b99b8Sopenharmony_ci        fcntl(pipeFd[PIPE_WRITE], F_SETPIPE_SZ, sz) < 0) {
132800b99b8Sopenharmony_ci        DFXLOGE("[%{public}d]: failed to set pipe size.", __LINE__);
133800b99b8Sopenharmony_ci        return -1;
134800b99b8Sopenharmony_ci    }
135800b99b8Sopenharmony_ci    if (fcntl(pipeFd[PIPE_READ], F_GETFL) < 0) {
136800b99b8Sopenharmony_ci        DFXLOGE("[%{public}d]: failed to set pipe size.", __LINE__);
137800b99b8Sopenharmony_ci        return -1;
138800b99b8Sopenharmony_ci    } else {
139800b99b8Sopenharmony_ci        uint32_t flags = static_cast<uint32_t>(fcntl(pipeFd[PIPE_READ], F_GETFL));
140800b99b8Sopenharmony_ci        flags |= O_NONBLOCK;
141800b99b8Sopenharmony_ci        if (fcntl(pipeFd[PIPE_READ], F_SETFL, flags) < 0) {
142800b99b8Sopenharmony_ci            DFXLOGE("Failed to set pipe flag.");
143800b99b8Sopenharmony_ci            return -1;
144800b99b8Sopenharmony_ci        }
145800b99b8Sopenharmony_ci    }
146800b99b8Sopenharmony_ci    ssize_t realWriteSize = -1;
147800b99b8Sopenharmony_ci    realWriteSize = OHOS_TEMP_FAILURE_RETRY(write(pipeFd[PIPE_WRITE], cppCrashInfo_.c_str(), sz));
148800b99b8Sopenharmony_ci    close(pipeFd[PIPE_WRITE]);
149800b99b8Sopenharmony_ci    if (static_cast<ssize_t>(cppCrashInfo_.size()) != realWriteSize) {
150800b99b8Sopenharmony_ci        DFXLOGE("Failed to write pipe. realWriteSize %{public}zd, json size %{public}zd", realWriteSize, sz);
151800b99b8Sopenharmony_ci        close(pipeFd[PIPE_READ]);
152800b99b8Sopenharmony_ci        return -1;
153800b99b8Sopenharmony_ci    }
154800b99b8Sopenharmony_ci    return pipeFd[PIPE_READ];
155800b99b8Sopenharmony_ci}
156800b99b8Sopenharmony_ci
157800b99b8Sopenharmony_civoid CppCrashReporter::ReportToAbilityManagerService()
158800b99b8Sopenharmony_ci{
159800b99b8Sopenharmony_ci    if (process_->processInfo_.processName.find(FOUNDATION_PROCESS_NAME) != std::string::npos) {
160800b99b8Sopenharmony_ci        DFXLOGW("Do not to report to AbilityManagerService, foundation is crashed.");
161800b99b8Sopenharmony_ci        return;
162800b99b8Sopenharmony_ci    }
163800b99b8Sopenharmony_ci
164800b99b8Sopenharmony_ci    void* handle = dlopen("libability_manager_c.z.so", RTLD_LAZY | RTLD_NODELETE);
165800b99b8Sopenharmony_ci    if (handle == nullptr) {
166800b99b8Sopenharmony_ci        DFXLOGW("Failed to dlopen libabilityms, %{public}s\n", dlerror());
167800b99b8Sopenharmony_ci        return;
168800b99b8Sopenharmony_ci    }
169800b99b8Sopenharmony_ci
170800b99b8Sopenharmony_ci    RecordAppExitReason recordAppExitReason = (RecordAppExitReason)dlsym(handle, "RecordAppExitReason");
171800b99b8Sopenharmony_ci    if (recordAppExitReason == nullptr) {
172800b99b8Sopenharmony_ci        DFXLOGW("Failed to dlsym RecordAppExitReason, %{public}s\n", dlerror());
173800b99b8Sopenharmony_ci        dlclose(handle);
174800b99b8Sopenharmony_ci        return;
175800b99b8Sopenharmony_ci    }
176800b99b8Sopenharmony_ci
177800b99b8Sopenharmony_ci    // defined in interfaces/inner_api/ability_manager/include/ability_state.h
178800b99b8Sopenharmony_ci    const int cppCrashExitReason = 2;
179800b99b8Sopenharmony_ci    recordAppExitReason(cppCrashExitReason, reason_.c_str());
180800b99b8Sopenharmony_ci    dlclose(handle);
181800b99b8Sopenharmony_ci#ifndef HISYSEVENT_DISABLE
182800b99b8Sopenharmony_ci    int result = HiSysEventWrite(HiSysEvent::Domain::FRAMEWORK, "PROCESS_KILL", HiSysEvent::EventType::FAULT,
183800b99b8Sopenharmony_ci        "PID", pid_, "PROCESS_NAME", cmdline_.c_str(), "MSG", KILL_REASON_CPP_CRASH);
184800b99b8Sopenharmony_ci    DFXLOGW("hisysevent write result=%{public}d, send event [FRAMEWORK,PROCESS_KILL], pid=%{public}d,"
185800b99b8Sopenharmony_ci        " processName=%{public}s, msg=%{public}s", result, pid_, cmdline_.c_str(), KILL_REASON_CPP_CRASH);
186800b99b8Sopenharmony_ci#endif
187800b99b8Sopenharmony_ci}
188800b99b8Sopenharmony_ci
189800b99b8Sopenharmony_cistd::string CppCrashReporter::GetRegsString(std::shared_ptr<DfxRegs> regs)
190800b99b8Sopenharmony_ci{
191800b99b8Sopenharmony_ci    std::string regsString = "";
192800b99b8Sopenharmony_ci    if (regs == nullptr) {
193800b99b8Sopenharmony_ci        return regsString;
194800b99b8Sopenharmony_ci    }
195800b99b8Sopenharmony_ci    regsString = regs->PrintRegs();
196800b99b8Sopenharmony_ci    // if start with 'Registers:\n', need remove
197800b99b8Sopenharmony_ci    if (regsString.find(REGS_KEY_WORD) == 0) {
198800b99b8Sopenharmony_ci        regsString = regsString.substr(strlen(REGS_KEY_WORD));
199800b99b8Sopenharmony_ci    }
200800b99b8Sopenharmony_ci    return regsString;
201800b99b8Sopenharmony_ci}
202800b99b8Sopenharmony_ci} // namespace HiviewDFX
203800b99b8Sopenharmony_ci} // namespace OHOS
204