1/*
2 * Copyright (c) 2021-2023 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#include "faultlog_manager.h"
16
17#include <cstdint>
18#include <memory>
19#include <mutex>
20#include <string>
21#include <vector>
22
23#include <fcntl.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <unistd.h>
27
28#include "defines.h"
29#include "file_util.h"
30#include "log_store_ex.h"
31#include "hiview_logger.h"
32#include "time_util.h"
33
34#include "faultlog_database.h"
35#include "faultlog_formatter.h"
36#include "faultlog_info.h"
37#include "faultlog_util.h"
38
39namespace OHOS {
40namespace HiviewDFX {
41namespace {
42constexpr char DEFAULT_FAULTLOG_FOLDER[] = "/data/log/faultlog/faultlogger/";
43constexpr int32_t MAX_FAULT_LOG_PER_HAP = 10;
44}
45
46DEFINE_LOG_LABEL(0xD002D11, "FaultLogManager");
47LogStoreEx::LogFileFilter CreateLogFileFilter(time_t time, int32_t id, int32_t faultLogType, const std::string& module)
48{
49    LogStoreEx::LogFileFilter filter = [time, id, faultLogType, module](const LogFile &file) {
50        FaultLogInfo info = ExtractInfoFromFileName(file.name_);
51        if (info.time <= time) {
52            return false;
53        }
54
55        if ((id != -1) && (info.id != id)) {
56            return false;
57        }
58
59        if ((faultLogType != 0) && (info.faultLogType != faultLogType)) {
60            return false;
61        }
62
63        if ((!module.empty()) && (info.module != module)) {
64            return false;
65        }
66        return true;
67    };
68    return filter;
69}
70
71FaultLogManager::~FaultLogManager()
72{
73    if (faultLogDb_ != nullptr) {
74        delete faultLogDb_;
75        faultLogDb_ = nullptr;
76    }
77}
78
79int32_t FaultLogManager::CreateTempFaultLogFile(time_t time, int32_t id, int32_t faultType,
80    const std::string &module) const
81{
82    FaultLogInfo info;
83    info.time = time;
84    info.id = id;
85    info.faultLogType = faultType;
86    info.module = module;
87    auto fileName = GetFaultLogName(info);
88    return store_->CreateLogFile(fileName);
89}
90
91void FaultLogManager::Init()
92{
93    store_ = std::make_unique<LogStoreEx>(DEFAULT_FAULTLOG_FOLDER, true);
94    LogStoreEx::LogFileComparator comparator = [](const LogFile &lhs, const LogFile &rhs) {
95        FaultLogInfo lhsInfo = ExtractInfoFromFileName(lhs.name_);
96        FaultLogInfo rhsInfo = ExtractInfoFromFileName(rhs.name_);
97        return lhsInfo.time > rhsInfo.time;
98    };
99    store_->SetLogFileComparator(comparator);
100    store_->Init();
101    faultLogDb_ = new FaultLogDatabase(looper_);
102}
103
104std::string FaultLogManager::SaveFaultLogToFile(FaultLogInfo &info) const
105{
106    auto fileName = GetFaultLogName(info);
107    std::string filePath = std::string(DEFAULT_FAULTLOG_FOLDER) + fileName;
108    if (FileUtil::FileExists(filePath)) {
109        HIVIEW_LOGI("logfile %{public}s already exist.", filePath.c_str());
110        return "";
111    }
112    auto fd = store_->CreateLogFile(fileName);
113    if (fd < 0) {
114        return "";
115    }
116
117    FaultLogger::WriteDfxLogToFile(fd);
118    FaultLogger::WriteFaultLogToFile(fd, info.faultLogType, info.sectionMap);
119    FaultLogger::WriteLogToFile(fd, info.logPath);
120    if (info.sectionMap.count("HILOG") == 1) {
121        FileUtil::SaveStringToFd(fd, "\nHiLog:\n");
122        FileUtil::SaveStringToFd(fd, info.sectionMap["HILOG"]);
123    }
124    FaultLogger::LimitCppCrashLog(fd, info.faultLogType);
125    close(fd);
126
127    std::string logFile = info.logPath;
128    if (logFile != "" && FileUtil::FileExists(logFile)) {
129        if (!FileUtil::RemoveFile(logFile)) {
130            HIVIEW_LOGW("remove logFile %{public}s failed.", logFile.c_str());
131        } else {
132            HIVIEW_LOGI("remove logFile %{public}s.", logFile.c_str());
133        }
134    }
135    store_->ClearSameLogFilesIfNeeded(CreateLogFileFilter(0, info.id, info.faultLogType, info.module),
136        MAX_FAULT_LOG_PER_HAP);
137    info.logPath = std::string(DEFAULT_FAULTLOG_FOLDER) + fileName;
138    HIVIEW_LOGI("create log %{public}s", fileName.c_str());
139    return fileName;
140}
141
142std::list<FaultLogInfo> FaultLogManager::GetFaultInfoList(const std::string& module,
143    int32_t id, int32_t faultType, int32_t maxNum) const
144{
145    std::list<FaultLogInfo> ret;
146    if (faultLogDb_ != nullptr) {
147        ret = faultLogDb_->GetFaultInfoList(module, id, faultType, maxNum);
148        HIVIEW_LOGI("Find %{public}zu fault records for uid:%{public}d type:%{public}d",
149            ret.size(), id, faultType);
150    }
151    return ret;
152}
153
154void FaultLogManager::SaveFaultInfoToRawDb(FaultLogInfo& info) const
155{
156    if (faultLogDb_ != nullptr) {
157        faultLogDb_->SaveFaultLogInfo(info);
158    }
159}
160
161void FaultLogManager::ReduceLogFileListSize(std::list<std::string> &infoVec, int32_t maxNum) const
162{
163    if ((maxNum < 0) || (infoVec.size() <= static_cast<uint32_t>(maxNum))) {
164        return;
165    }
166
167    auto begin = infoVec.begin();
168    std::advance(begin, maxNum);
169    infoVec.erase(begin, infoVec.end());
170}
171
172std::list<std::string> FaultLogManager::GetFaultLogFileList(const std::string &module, time_t time, int32_t id,
173                                                            int32_t faultType, int32_t maxNum) const
174{
175    LogStoreEx::LogFileFilter filter = CreateLogFileFilter(time, id, faultType, module);
176    auto vec = store_->GetLogFiles(filter);
177    std::list<std::string> ret;
178    std::transform(vec.begin(), vec.end(), std::back_inserter(ret), [](const LogFile &file) { return file.path_; });
179    ReduceLogFileListSize(ret, maxNum);
180    return ret;
181}
182
183bool FaultLogManager::GetFaultLogContent(const std::string &name, std::string &content) const
184{
185    auto path = std::string(DEFAULT_FAULTLOG_FOLDER) + name;
186    return FileUtil::LoadStringFromFile(path, content);
187}
188
189bool FaultLogManager::IsProcessedFault(int32_t pid, int32_t uid, int32_t faultType)
190{
191    if (faultLogDb_ == nullptr) {
192        return false;
193    }
194
195    return faultLogDb_->IsFaultExist(pid, uid, faultType);
196}
197} // namespace HiviewDFX
198} // namespace OHOS
199