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