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 "dfx_ring_buffer_wrapper.h"
17
18#include <securec.h>
19#include <unistd.h>
20
21#include "dfx_define.h"
22#include "dfx_logger.h"
23
24namespace OHOS {
25namespace HiviewDFX {
26static const int32_t INVALID_FD = -1;
27static const int32_t UNUSED_FD = -2;
28const int BACK_TRACE_RING_BUFFER_PRINT_WAIT_TIME_MS = 10;
29std::condition_variable DfxRingBufferWrapper::printCV_;
30std::mutex DfxRingBufferWrapper::printMutex_;
31
32DfxRingBufferWrapper &DfxRingBufferWrapper::GetInstance()
33{
34    static DfxRingBufferWrapper ins;
35    return ins;
36}
37
38void DfxRingBufferWrapper::LoopPrintRingBuffer()
39{
40    if (DfxRingBufferWrapper::GetInstance().writeFunc_ == nullptr) {
41        DfxRingBufferWrapper::GetInstance().writeFunc_ = DfxRingBufferWrapper::DefaultWrite;
42    }
43
44    std::unique_lock<std::mutex> lck(printMutex_);
45    while (true) {
46        auto available = DfxRingBufferWrapper::GetInstance().ringBuffer_.Available();
47        auto item = DfxRingBufferWrapper::GetInstance().ringBuffer_.Read(available);
48
49        if (available != 0) {
50            if (item.At(0).empty()) {
51                DfxRingBufferWrapper::GetInstance().ringBuffer_.Skip(item.Length());
52                continue;
53            }
54
55            for (unsigned int i = 0; i < item.Length(); i++) {
56                DfxRingBufferWrapper::GetInstance().writeFunc_(DfxRingBufferWrapper::GetInstance().fd_, \
57                    item.At(i).c_str(), item.At(i).length());
58            }
59            DfxRingBufferWrapper::GetInstance().ringBuffer_.Skip(item.Length());
60        } else {
61            if (DfxRingBufferWrapper::GetInstance().hasFinished_) {
62                DFXLOGD("%{public}s :: print finished, exit loop.\n", __func__);
63                break;
64            }
65
66            printCV_.wait_for(lck, std::chrono::milliseconds(BACK_TRACE_RING_BUFFER_PRINT_WAIT_TIME_MS));
67        }
68    }
69}
70
71void DfxRingBufferWrapper::AppendMsg(const std::string& msg)
72{
73    if (writeFunc_ == nullptr) {
74        writeFunc_ = DfxRingBufferWrapper::DefaultWrite;
75    }
76    writeFunc_(fd_, msg.c_str(), msg.length());
77}
78
79int DfxRingBufferWrapper::AppendBuf(const char *format, ...)
80{
81    int ret = -1;
82    char buf[LINE_BUF_SIZE] = {0};
83    va_list args;
84    va_start(args, format);
85    ret = vsnprintf_s(buf, sizeof(buf), sizeof(buf) - 1, format, args);
86    va_end(args);
87    if (ret < 0) {
88        DFXLOGE("%{public}s :: vsnprintf_s failed, line: %{public}d.", __func__, __LINE__);
89    }
90
91    AppendMsg(std::string(buf));
92    return ret;
93}
94
95static std::vector<std::string> SplitDumpInfo(const std::string& dumpInfo, const std::string& sepator)
96{
97    std::vector<std::string> result;
98    if (dumpInfo.empty() || sepator.empty()) {
99        return result;
100    }
101    size_t begin = 0;
102    size_t pos = dumpInfo.find(sepator, begin);
103    while (pos != std::string::npos) {
104        result.push_back(dumpInfo.substr(begin, pos - begin));
105
106        begin = pos + sepator.size();
107        pos = dumpInfo.find(sepator, begin);
108    }
109    if (begin < dumpInfo.size()) {
110        result.push_back(dumpInfo.substr(begin));
111    }
112    return result;
113}
114
115void DfxRingBufferWrapper::AppendBaseInfo(const std::string& info)
116{
117    crashBaseInfo_.emplace_back(info);
118}
119
120void DfxRingBufferWrapper::PrintBaseInfo()
121{
122    if (crashBaseInfo_.empty()) {
123        DFXLOGE("crash base info is empty");
124    }
125    for (const auto& item : crashBaseInfo_) {
126        std::vector<std::string> itemVec = SplitDumpInfo(item, "\n");
127        for (size_t i = 0; i < itemVec.size(); i++) {
128            DFXLOGI("%{public}s", itemVec[i].c_str());
129        }
130    }
131}
132
133void DfxRingBufferWrapper::StartThread()
134{
135    hasFinished_ = false;
136}
137
138void DfxRingBufferWrapper::StopThread()
139{
140    if (fd_ != INVALID_FD) {
141        close(fd_);
142    }
143    fd_ = INVALID_FD;
144}
145
146void DfxRingBufferWrapper::SetWriteBufFd(int32_t fd)
147{
148    fd_ = fd;
149    if (fd_ < 0) {
150        DFXLOGW("%{public}s :: Failed to set fd.\n", __func__);
151    }
152}
153
154void DfxRingBufferWrapper::SetWriteFunc(RingBufferWriteFunc func)
155{
156    writeFunc_ = func;
157}
158
159int DfxRingBufferWrapper::DefaultWrite(int32_t fd, const char *buf, const int len)
160{
161    if (buf == nullptr) {
162        return -1;
163    }
164    WriteLog(UNUSED_FD, "%s", buf);
165    if (fd > 0) {
166        return OHOS_TEMP_FAILURE_RETRY(write(fd, buf, len));
167    }
168    return 0;
169}
170} // namespace HiviewDFX
171} // namespace OHOS
172