1020a203aSopenharmony_ci/*
2020a203aSopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3020a203aSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4020a203aSopenharmony_ci * you may not use this file except in compliance with the License.
5020a203aSopenharmony_ci * You may obtain a copy of the License at
6020a203aSopenharmony_ci *
7020a203aSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8020a203aSopenharmony_ci *
9020a203aSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10020a203aSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11020a203aSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12020a203aSopenharmony_ci * See the License for the specific language governing permissions and
13020a203aSopenharmony_ci * limitations under the License.
14020a203aSopenharmony_ci */
15020a203aSopenharmony_ci#include "tbox.h"
16020a203aSopenharmony_ci
17020a203aSopenharmony_ci#include <unistd.h>
18020a203aSopenharmony_ci
19020a203aSopenharmony_ci#include <regex>
20020a203aSopenharmony_ci#include "calc_fingerprint.h"
21020a203aSopenharmony_ci#include "file_util.h"
22020a203aSopenharmony_ci#include "log_parse.h"
23020a203aSopenharmony_ci#include "securec.h"
24020a203aSopenharmony_ci#include "string_util.h"
25020a203aSopenharmony_ci#include "time_util.h"
26020a203aSopenharmony_ci
27020a203aSopenharmony_ciusing namespace std;
28020a203aSopenharmony_cinamespace OHOS {
29020a203aSopenharmony_cinamespace HiviewDFX {
30020a203aSopenharmony_ciDEFINE_LOG_TAG("Tbox");
31020a203aSopenharmony_ci
32020a203aSopenharmony_ciconst string Tbox::ARRAY_STR = "ARRAY :";
33020a203aSopenharmony_ciconst string Tbox::CAUSEDBY_HEADER = "Caused by:";
34020a203aSopenharmony_ciconst string Tbox::SUPPRESSED_HEADER = "Suppressed:";
35020a203aSopenharmony_ci
36020a203aSopenharmony_ciTbox::Tbox()
37020a203aSopenharmony_ci{
38020a203aSopenharmony_ci}
39020a203aSopenharmony_ci
40020a203aSopenharmony_ciTbox::~Tbox()
41020a203aSopenharmony_ci{
42020a203aSopenharmony_ci}
43020a203aSopenharmony_ci
44020a203aSopenharmony_cistring Tbox::CalcFingerPrint(const string& val, size_t mask, int mode)
45020a203aSopenharmony_ci{
46020a203aSopenharmony_ci    char hash[HAS_LEN] = {'0'};
47020a203aSopenharmony_ci    int err = -1;
48020a203aSopenharmony_ci    switch (mode) {
49020a203aSopenharmony_ci        case FP_FILE:
50020a203aSopenharmony_ci            err = CalcFingerprint::CalcFileSha(val, hash, sizeof(hash));
51020a203aSopenharmony_ci            break;
52020a203aSopenharmony_ci        case FP_BUFFER:
53020a203aSopenharmony_ci            err = CalcFingerprint::CalcBufferSha(val, val.size(), hash, sizeof(hash));
54020a203aSopenharmony_ci            break;
55020a203aSopenharmony_ci        default:
56020a203aSopenharmony_ci            break;
57020a203aSopenharmony_ci    }
58020a203aSopenharmony_ci
59020a203aSopenharmony_ci    if (err != 0) {
60020a203aSopenharmony_ci        // if file not exist, API will return ENOENT
61020a203aSopenharmony_ci        HIVIEW_LOGE("ProcessedEvent: calc fingerprint failed, err is %{public}d.", err);
62020a203aSopenharmony_ci    }
63020a203aSopenharmony_ci    return string(hash);
64020a203aSopenharmony_ci}
65020a203aSopenharmony_ci
66020a203aSopenharmony_cibool Tbox::GetPartial(const string& src, const string& res, string& des)
67020a203aSopenharmony_ci{
68020a203aSopenharmony_ci    des = "";
69020a203aSopenharmony_ci    regex reNew(res);
70020a203aSopenharmony_ci    smatch result;
71020a203aSopenharmony_ci    if (regex_search(src, result, reNew)) {
72020a203aSopenharmony_ci        for (size_t i = 1; i < result.size(); ++i) {
73020a203aSopenharmony_ci            if (!result.str(i).empty()) {
74020a203aSopenharmony_ci                des = string(result.str(i));
75020a203aSopenharmony_ci                break;
76020a203aSopenharmony_ci            }
77020a203aSopenharmony_ci        }
78020a203aSopenharmony_ci        return true;
79020a203aSopenharmony_ci    }
80020a203aSopenharmony_ci    return false;
81020a203aSopenharmony_ci}
82020a203aSopenharmony_ci
83020a203aSopenharmony_cibool Tbox::IsCallStack(string& line)
84020a203aSopenharmony_ci{
85020a203aSopenharmony_ci    if (regex_search(line, regex("^\\s+at (.*)\\(.*")) ||
86020a203aSopenharmony_ci        regex_search(line, regex("^\\s*at .*")) ||
87020a203aSopenharmony_ci        regex_search(line, regex("^\\s+- (.*)\\(.*")) ||
88020a203aSopenharmony_ci        regex_search(line, regex("\\s+#\\d+")) ||
89020a203aSopenharmony_ci        regex_search(line, regex("[0-9a-zA-Z_]+\\+0x[0-9a-f]+/0x[0-9a-f]+")) ||
90020a203aSopenharmony_ci        regex_search(line, regex("#\\d+")) ||
91020a203aSopenharmony_ci        regex_search(line, regex("\\.*"))) {
92020a203aSopenharmony_ci        return true;
93020a203aSopenharmony_ci    }
94020a203aSopenharmony_ci    return false;
95020a203aSopenharmony_ci}
96020a203aSopenharmony_ci
97020a203aSopenharmony_cibool Tbox::HasCausedBy(const string& line)
98020a203aSopenharmony_ci{
99020a203aSopenharmony_ci    if ((line.find(CAUSEDBY_HEADER) != string::npos) ||
100020a203aSopenharmony_ci        (line.find(SUPPRESSED_HEADER) != string::npos)) {
101020a203aSopenharmony_ci        return true;
102020a203aSopenharmony_ci    }
103020a203aSopenharmony_ci    return false;
104020a203aSopenharmony_ci}
105020a203aSopenharmony_ci
106020a203aSopenharmony_ci/*
107020a203aSopenharmony_ci * format1:  com.ohos.launcher:extension
108020a203aSopenharmony_ci * format2:  #06 pc 00000000000bb328  /system/lib/libart.so (__epoll_pwait+8)
109020a203aSopenharmony_ci */
110020a203aSopenharmony_cistring Tbox::GetStackName(string line)
111020a203aSopenharmony_ci{
112020a203aSopenharmony_ci    string stackname = UNKNOWN_STR;
113020a203aSopenharmony_ci    if (IsCallStack(line)) {
114020a203aSopenharmony_ci        stackname = line;
115020a203aSopenharmony_ci        string str;
116020a203aSopenharmony_ci        if (GetPartial(line, "^\\s+at (.*)\\).*", str) ||
117020a203aSopenharmony_ci            GetPartial(line, "^\\s*at (.*)", str) || // for jsCrash
118020a203aSopenharmony_ci            GetPartial(line, "#\\d+ pc [0-9a-f]+ (.*\\+\\d+)\\)", str) ||
119020a203aSopenharmony_ci            GetPartial(line, "#\\d+ pc [0-9a-f]+ (.*)", str) ||
120020a203aSopenharmony_ci            GetPartial(line, "([0-9a-zA-Z_]+\\+0x[0-9a-f]+/0x[0-9a-f]+)", str)) {
121020a203aSopenharmony_ci            stackname = str;
122020a203aSopenharmony_ci        } else if (GetPartial(line, "^\\s+- (.*)\\(.*", str)) {
123020a203aSopenharmony_ci            size_t ret = str.find_last_of("+");
124020a203aSopenharmony_ci            if (ret != string::npos) {
125020a203aSopenharmony_ci                str.replace(ret, string::npos, ")\0");
126020a203aSopenharmony_ci                stackname = str;
127020a203aSopenharmony_ci            } else {
128020a203aSopenharmony_ci                stackname = UNKNOWN_STR;
129020a203aSopenharmony_ci            }
130020a203aSopenharmony_ci        }
131020a203aSopenharmony_ci        regex re("(.+?)-(.+)==(.+)");
132020a203aSopenharmony_ci        stackname = regex_replace(stackname, re, "$1$3");
133020a203aSopenharmony_ci    }
134020a203aSopenharmony_ci    return stackname;
135020a203aSopenharmony_ci}
136020a203aSopenharmony_ci
137020a203aSopenharmony_civoid Tbox::FilterTrace(std::map<std::string, std::string>& eventInfo, string eventType)
138020a203aSopenharmony_ci{
139020a203aSopenharmony_ci    auto iterEndStack = eventInfo.find(PARAMETER_ENDSTACK);
140020a203aSopenharmony_ci    if (eventInfo.empty() || iterEndStack == eventInfo.end() || iterEndStack->second.empty()) {
141020a203aSopenharmony_ci        return;
142020a203aSopenharmony_ci    }
143020a203aSopenharmony_ci    std::vector<std::string> trace;
144020a203aSopenharmony_ci    LogParse logparse;
145020a203aSopenharmony_ci    std::string block = logparse.GetFilterTrace(iterEndStack->second, trace, eventType);
146020a203aSopenharmony_ci    eventInfo[PARAMETER_ENDSTACK] = block;
147020a203aSopenharmony_ci    eventInfo["FINGERPRINT"] = Tbox::CalcFingerPrint(block, 0, FP_BUFFER);
148020a203aSopenharmony_ci    std::stack<std::string> stackTop = logparse.GetStackTop(trace, 3);  // 3 : first/second/last frame
149020a203aSopenharmony_ci    logparse.SetFrame(stackTop, eventInfo);
150020a203aSopenharmony_ci}
151020a203aSopenharmony_ci
152020a203aSopenharmony_cibool Tbox::WaitForDoneFile(const std::string& file, unsigned int timeout)
153020a203aSopenharmony_ci{
154020a203aSopenharmony_ci    uint64_t remainedTime = timeout * NS_PER_SECOND;
155020a203aSopenharmony_ci    while (remainedTime > 0) {
156020a203aSopenharmony_ci        if (FileUtil::FileExists(file)) {
157020a203aSopenharmony_ci            HIVIEW_LOGD("Done file exist: %{public}s", file.c_str());
158020a203aSopenharmony_ci            return true;
159020a203aSopenharmony_ci        }
160020a203aSopenharmony_ci        uint64_t startTime = TimeUtil::GetNanoTime();
161020a203aSopenharmony_ci        sleep(1);
162020a203aSopenharmony_ci        uint64_t duration = TimeUtil::GetNanoTime() - startTime;
163020a203aSopenharmony_ci        remainedTime = (remainedTime > duration) ? (remainedTime - duration) : 0;
164020a203aSopenharmony_ci    }
165020a203aSopenharmony_ci    return false;
166020a203aSopenharmony_ci}
167020a203aSopenharmony_ci
168020a203aSopenharmony_ciint64_t Tbox::GetHappenTime(const string& src, const string& regex)
169020a203aSopenharmony_ci{
170020a203aSopenharmony_ci    int64_t happenTime = HAPPEN_TIME_DEFAULT;
171020a203aSopenharmony_ci    std::regex recordRegex(regex);
172020a203aSopenharmony_ci    struct tm tmHappenTime;
173020a203aSopenharmony_ci    (void)memset_s(&tmHappenTime, sizeof(struct tm), 0, sizeof(struct tm));
174020a203aSopenharmony_ci    std::smatch matches;
175020a203aSopenharmony_ci    if (!std::regex_match(src, matches, recordRegex)) {
176020a203aSopenharmony_ci        HIVIEW_LOGE("unmatch event:%{public}s, skip", src.c_str());
177020a203aSopenharmony_ci        return happenTime;
178020a203aSopenharmony_ci    }
179020a203aSopenharmony_ci
180020a203aSopenharmony_ci    string timeStr;
181020a203aSopenharmony_ci    for (size_t i = 1; i < matches.size(); ++i) {
182020a203aSopenharmony_ci        timeStr += matches[i].str();
183020a203aSopenharmony_ci    }
184020a203aSopenharmony_ci    strptime(timeStr.c_str(), "%Y%m%d%H%M%S", &tmHappenTime);
185020a203aSopenharmony_ci    happenTime = mktime(&tmHappenTime);
186020a203aSopenharmony_ci    //if the HappenTime is 1970, return as original information
187020a203aSopenharmony_ci    if (tmHappenTime.tm_year == 70) { // 70: The number of years since the HappenTime in 1900
188020a203aSopenharmony_ci        return happenTime;
189020a203aSopenharmony_ci    }
190020a203aSopenharmony_ci
191020a203aSopenharmony_ci    time_t now = time(nullptr);
192020a203aSopenharmony_ci    struct tm result;
193020a203aSopenharmony_ci    gmtime_r(&now, &result);
194020a203aSopenharmony_ci    double offset = difftime(now, mktime(&result)); // zone offset with second. Example, 1 zone is 3600 sec
195020a203aSopenharmony_ci    if (difftime(now, happenTime) > offset) {
196020a203aSopenharmony_ci        happenTime = timegm(&tmHappenTime);
197020a203aSopenharmony_ci    }
198020a203aSopenharmony_ci    return happenTime;
199020a203aSopenharmony_ci}
200020a203aSopenharmony_ci}
201020a203aSopenharmony_ci}
202