• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "vendor.h"
17 
18 #include <regex>
19 
20 #include "faultlogger_client.h"
21 #include "file_util.h"
22 #include "freeze_json_util.h"
23 #include "hiview_logger.h"
24 #include "string_util.h"
25 #include "time_util.h"
26 
27 namespace OHOS {
28 namespace HiviewDFX {
29 namespace {
30     const int SYS_MATCH_NUM = 1;
31     const int MILLISECOND = 1000;
32     const int TIME_STRING_LEN = 16;
33     const int MIN_KEEP_FILE_NUM = 5;
34     const int MAX_FOLDER_SIZE = 10 * 1024 * 1024;
35     constexpr const char* TRIGGER_HEADER = ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>";
36     constexpr const char* HEADER = "*******************************************";
37     constexpr const char* HYPHEN = "-";
38     constexpr const char* POSTFIX = ".tmp";
39     constexpr const char* APPFREEZE = "appfreeze";
40     constexpr const char* SYSFREEZE = "sysfreeze";
41     constexpr const char* SYSWARNING = "syswarning";
42     constexpr const char* FREEZE_DETECTOR_PATH = "/data/log/faultlog/freeze/";
43     constexpr const char* FAULT_LOGGER_PATH = "/data/log/faultlog/faultlogger/";
44     constexpr const char* COLON = ":";
45     constexpr const char* EVENT_DOMAIN = "DOMAIN";
46     constexpr const char* EVENT_STRINGID = "STRINGID";
47     constexpr const char* EVENT_TIMESTAMP = "TIMESTAMP";
48     constexpr const char* DISPLAY_POWER_INFO = "DisplayPowerInfo:";
49     constexpr const char* FORE_GROUND = "FOREGROUND";
50     constexpr const char* SCB_PROCESS = "SCBPROCESS";
51     constexpr const char* SCB_PRO_FLAG = "com.ohos.sceneboard";
52     constexpr const char* THREAD_STACK_START = "\nThread stack start:\n";
53     constexpr const char* THREAD_STACK_END = "Thread stack end\n";
54     constexpr const char* KEY_PROCESS[] = {
55         "foundation", "com.ohos.sceneboard", "render_service"
56     };
57     constexpr const char* HITRACE_ID_INFO = "HitraceIdInfo: ";
58     constexpr const char* HOST_RESOURCE_WARNING_INFO =
59         "NOTE: Current fault may be caused by system issue, you may ignore it and analysis other faults.";
60 }
61 
62 DEFINE_LOG_LABEL(0xD002D01, "FreezeDetector");
GetTimeString(unsigned long long timestamp) const63 std::string Vendor::GetTimeString(unsigned long long timestamp) const
64 {
65     struct tm tm;
66     time_t ts = static_cast<long long>(timestamp) / MILLISECOND; // ms
67     localtime_r(&ts, &tm);
68     char buf[TIME_STRING_LEN] = {0};
69 
70     strftime(buf, TIME_STRING_LEN - 1, "%Y%m%d%H%M%S", &tm);
71     return std::string(buf, strlen(buf));
72 }
73 
SendFaultLog(const WatchPoint & watchPoint,const std::string & logPath,const std::string & type,const std::string & processName,const std::string & isScbPro) const74 std::string Vendor::SendFaultLog(const WatchPoint &watchPoint, const std::string& logPath,
75     const std::string& type, const std::string& processName, const std::string& isScbPro) const
76 {
77     if (freezeCommon_ == nullptr) {
78         return "";
79     }
80     std::string stringId = watchPoint.GetStringId();
81 
82     FaultLogInfoInner info;
83     info.time = watchPoint.GetTimestamp();
84     info.id = watchPoint.GetUid();
85     info.pid = watchPoint.GetPid();
86     info.faultLogType = (type == APPFREEZE) ? FaultLogType::APP_FREEZE : ((type == SYSFREEZE) ?
87         FaultLogType::SYS_FREEZE : FaultLogType::SYS_WARNING);
88     info.module = processName;
89     info.reason = stringId;
90     std::string disPlayPowerInfo = GetDisPlayPowerInfo();
91     info.summary = type + ": " + processName + " " + stringId +
92         " at " + GetTimeString(watchPoint.GetTimestamp()) + "\n";
93     info.summary += std::string(DISPLAY_POWER_INFO) + disPlayPowerInfo;
94     std::string hiTraceIdInfo = watchPoint.GetHitraceIdInfo();
95     info.summary += hiTraceIdInfo.empty() ? "" : (std::string(HITRACE_ID_INFO) + hiTraceIdInfo + "\n");
96     info.logPath = logPath;
97     info.sectionMaps[FreezeCommon::HITRACE_TIME] = watchPoint.GetHitraceTime();
98     info.sectionMaps[FreezeCommon::SYSRQ_TIME] = watchPoint.GetSysrqTime();
99     info.sectionMaps[FORE_GROUND] = watchPoint.GetForeGround();
100     info.sectionMaps[SCB_PROCESS] = isScbPro;
101     info.sectionMaps[FreezeCommon::TERMINAL_THREAD_STACK] = watchPoint.GetTerminalThreadStack();
102     info.sectionMaps[FreezeCommon::TELEMETRY_ID] = watchPoint.GetTelemetryId();
103     info.sectionMaps[FreezeCommon::TRACE_NAME] = watchPoint.GetTraceName();
104     info.sectionMaps[FreezeCommon::PROC_STATM] = watchPoint.GetProcStatm();
105     AddFaultLog(info);
106     return logPath;
107 }
108 
DumpEventInfo(std::ostringstream & oss,const std::string & header,const WatchPoint & watchPoint) const109 void Vendor::DumpEventInfo(std::ostringstream& oss, const std::string& header, const WatchPoint& watchPoint) const
110 {
111     uint64_t timestamp = watchPoint.GetTimestamp() / TimeUtil::SEC_TO_MILLISEC;
112     oss << header << std::endl;
113     oss << EVENT_DOMAIN << COLON << watchPoint.GetDomain() << std::endl;
114     oss << EVENT_STRINGID << COLON << watchPoint.GetStringId() << std::endl;
115     oss << EVENT_TIMESTAMP << COLON <<
116         TimeUtil::TimestampFormatToDate(timestamp, "%Y/%m/%d-%H:%M:%S") <<
117         ":" << watchPoint.GetTimestamp() % TimeUtil::SEC_TO_MILLISEC << std::endl;
118     oss << FreezeCommon::EVENT_PID << COLON << watchPoint.GetPid() << std::endl;
119     oss << FreezeCommon::EVENT_UID << COLON << watchPoint.GetUid() << std::endl;
120     oss << FreezeCommon::EVENT_PACKAGE_NAME << COLON << watchPoint.GetPackageName() << std::endl;
121     oss << FreezeCommon::EVENT_PROCESS_NAME << COLON << watchPoint.GetProcessName() << std::endl;
122     if (watchPoint.GetHostResourceWarning() == "Yes") {
123         oss << HOST_RESOURCE_WARNING_INFO << std::endl;
124     }
125 }
126 
MergeFreezeJsonFile(const WatchPoint & watchPoint,const std::vector<WatchPoint> & list) const127 void Vendor::MergeFreezeJsonFile(const WatchPoint &watchPoint, const std::vector<WatchPoint>& list) const
128 {
129     std::ostringstream oss;
130     for (auto node : list) {
131         std::string filePath = FreezeJsonUtil::GetFilePath(node.GetPid(), node.GetUid(), node.GetTimestamp());
132         if (!FileUtil::FileExists(filePath)) {
133             continue;
134         }
135         std::string realPath;
136         if (!FileUtil::PathToRealPath(filePath, realPath)) {
137             continue;
138         }
139         std::ifstream ifs(realPath, std::ios::in);
140         if (ifs.is_open()) {
141             oss << ifs.rdbuf();
142             ifs.close();
143         }
144         FreezeJsonUtil::DelFile(realPath);
145     }
146 
147     std::string mergeFilePath = FreezeJsonUtil::GetFilePath(watchPoint.GetPid(),
148         watchPoint.GetUid(), watchPoint.GetTimestamp());
149     int jsonFd = FreezeJsonUtil::GetFd(mergeFilePath);
150     if (jsonFd < 0) {
151         HIVIEW_LOGE("fail to open FreezeJsonFile! jsonFd: %{public}d", jsonFd);
152         return;
153     } else {
154         HIVIEW_LOGI("success to open FreezeJsonFile! jsonFd: %{public}d", jsonFd);
155     }
156     HIVIEW_LOGI("MergeFreezeJsonFile oss size: %{public}zu.", oss.str().size());
157     FileUtil::SaveStringToFd(jsonFd, oss.str());
158     FreezeJsonUtil::WriteKeyValue(jsonFd, "domain", watchPoint.GetDomain());
159     FreezeJsonUtil::WriteKeyValue(jsonFd, "stringId", watchPoint.GetStringId());
160     FreezeJsonUtil::WriteKeyValue(jsonFd, "timestamp", watchPoint.GetTimestamp());
161     FreezeJsonUtil::WriteKeyValue(jsonFd, "pid", watchPoint.GetPid());
162     FreezeJsonUtil::WriteKeyValue(jsonFd, "uid", watchPoint.GetUid());
163     FreezeJsonUtil::WriteKeyValue(jsonFd, "package_name", watchPoint.GetPackageName());
164     FreezeJsonUtil::WriteKeyValue(jsonFd, "process_name", watchPoint.GetProcessName());
165     close(jsonFd);
166     HIVIEW_LOGI("success to merge FreezeJsonFiles!");
167 }
168 
InitLogInfo(const WatchPoint & watchPoint,std::string & type,std::string & pubLogPathName,std::string & processName,std::string & isScbPro) const169 void Vendor::InitLogInfo(const WatchPoint& watchPoint, std::string& type, std::string& pubLogPathName,
170     std::string& processName, std::string& isScbPro) const
171 {
172     std::string stringId = watchPoint.GetStringId();
173     std::string timestamp = GetTimeString(watchPoint.GetTimestamp());
174     long uid = watchPoint.GetUid();
175     std::string packageName = StringUtil::TrimStr(watchPoint.GetPackageName());
176     processName = StringUtil::TrimStr(watchPoint.GetProcessName());
177     processName = processName.empty() ? (packageName.empty() ? stringId : packageName) : processName;
178     if (stringId == "SCREEN_ON") {
179         processName = stringId;
180     } else {
181         CheckProcessName(processName, isScbPro);
182     }
183     type = freezeCommon_->IsApplicationEvent(watchPoint.GetDomain(), watchPoint.GetStringId()) ? APPFREEZE :
184         (freezeCommon_->IsSystemEvent(watchPoint.GetDomain(), watchPoint.GetStringId()) ? SYSFREEZE : SYSWARNING);
185     pubLogPathName = type + std::string(HYPHEN) + processName + std::string(HYPHEN) + std::to_string(uid) +
186         std::string(HYPHEN) + timestamp + std::string(HYPHEN) + std::to_string(watchPoint.GetTimestamp());
187 }
188 
InitLogBody(const std::vector<WatchPoint> & list,std::ostringstream & body,bool & isFileExists,WatchPoint & watchPoint) const189 void Vendor::InitLogBody(const std::vector<WatchPoint>& list, std::ostringstream& body,
190     bool& isFileExists, WatchPoint &watchPoint) const
191 {
192     HIVIEW_LOGI("merging list size %{public}zu", list.size());
193     for (auto node : list) {
194         std::string filePath = node.GetLogPath();
195         if (filePath == "nolog" || filePath == "") {
196             HIVIEW_LOGI("only header, no content:[%{public}s, %{public}s]",
197                 node.GetDomain().c_str(), node.GetStringId().c_str());
198             DumpEventInfo(body, HEADER, node);
199             continue;
200         }
201 
202         if (FileUtil::FileExists(filePath) == false) {
203             isFileExists = false;
204             HIVIEW_LOGE("[%{public}s, %{public}s] File:%{public}s does not exist",
205                 node.GetDomain().c_str(), node.GetStringId().c_str(), filePath.c_str());
206             return;
207         }
208 
209         HIVIEW_LOGI("merging file:%{public}s.", filePath.c_str());
210         std::string realPath;
211         if (!FileUtil::PathToRealPath(filePath, realPath)) {
212             HIVIEW_LOGE("PathToRealPath Failed:%{public}s.", filePath.c_str());
213             continue;
214         }
215         std::ifstream ifs(realPath, std::ios::in);
216         if (!ifs.is_open()) {
217             HIVIEW_LOGE("cannot open log file for reading:%{public}s.", realPath.c_str());
218             DumpEventInfo(body, HEADER, node);
219             continue;
220         }
221 
222         body << std::string(HEADER) << std::endl;
223         if (std::find(std::begin(FreezeCommon::PB_EVENTS), std::end(FreezeCommon::PB_EVENTS), node.GetStringId()) !=
224             std::end(FreezeCommon::PB_EVENTS) && watchPoint.GetTerminalThreadStack().empty()) {
225             std::stringstream ss;
226             ss << ifs.rdbuf();
227             std::string logContent = ss.str();
228             size_t startPos = logContent.find(THREAD_STACK_START);
229             size_t endPos = logContent.find(THREAD_STACK_END, startPos);
230             if (startPos != std::string::npos && endPos != std::string::npos && endPos > startPos) {
231                 size_t startSize = strlen(THREAD_STACK_START);
232                 std::string threadStack = logContent.substr(startPos + startSize, endPos - (startPos + startSize));
233                 watchPoint.SetTerminalThreadStack(threadStack);
234                 logContent.erase(startPos, endPos - startPos + strlen(THREAD_STACK_END));
235             }
236             body << logContent << std::endl;
237         } else {
238             body << ifs.rdbuf();
239         }
240         ifs.close();
241     }
242 }
243 
JudgeSysWarningEvent(const std::string & stringId,std::string & type,const std::string & processName,const std::vector<WatchPoint> & list,const std::vector<FreezeResult> & result) const244 bool Vendor::JudgeSysWarningEvent(const std::string& stringId, std::string& type, const std::string& processName,
245     const std::vector<WatchPoint>& list, const std::vector<FreezeResult>& result) const
246 {
247     if (stringId != "SERVICE_WARNING" && stringId != "THREAD_BLOCK_3S") {
248         return true;
249     }
250 
251     if (std::find(std::begin(KEY_PROCESS), std::end(KEY_PROCESS), processName) == std::end(KEY_PROCESS)) {
252         return false;
253     }
254 
255     if (list.size() != SYS_MATCH_NUM) {
256         HIVIEW_LOGW("Not meeting the requirements for syswarning reporting.");
257         return false;
258     }
259     type = SYSWARNING;
260     return true;
261 }
262 
MergeEventLog(WatchPoint & watchPoint,const std::vector<WatchPoint> & list,const std::vector<FreezeResult> & result) const263 std::string Vendor::MergeEventLog(WatchPoint &watchPoint, const std::vector<WatchPoint>& list,
264     const std::vector<FreezeResult>& result) const
265 {
266     if (freezeCommon_ == nullptr) {
267         return "";
268     }
269 
270     std::string type;
271     std::string pubLogPathName;
272     std::string processName;
273     std::string isScbPro;
274     InitLogInfo(watchPoint, type, pubLogPathName, processName, isScbPro);
275     if (!JudgeSysWarningEvent(watchPoint.GetStringId(), type, processName, list, result)) {
276         return "";
277     }
278     std::string retPath = std::string(FAULT_LOGGER_PATH) + pubLogPathName;
279     std::string tmpLogName = pubLogPathName + std::string(POSTFIX);
280     std::string tmpLogPath = std::string(FREEZE_DETECTOR_PATH) + tmpLogName;
281 
282     if (FileUtil::FileExists(retPath)) {
283         HIVIEW_LOGW("filename: %{public}s is existed, direct use.", retPath.c_str());
284         return retPath;
285     }
286 
287     std::ostringstream header;
288     DumpEventInfo(header, TRIGGER_HEADER, watchPoint);
289 
290     std::ostringstream body;
291     bool isFileExists = true;
292     InitLogBody(list, body, isFileExists, watchPoint);
293     HIVIEW_LOGI("After Init --body size: %{public}zu, pid: %{public}ld, processName: %{public}s ",
294         body.str().size(), watchPoint.GetPid(), processName.c_str());
295 
296     if (!isFileExists) {
297         HIVIEW_LOGE("Failed to open the body file.");
298         return "";
299     }
300 
301     if (type == APPFREEZE || FreezeJsonUtil::IsAppHicollie(watchPoint.GetStringId())) {
302         MergeFreezeJsonFile(watchPoint, list);
303     }
304 
305     int fd = logStore_->CreateLogFile(tmpLogName);
306     if (fd < 0) {
307         HIVIEW_LOGE("failed to create tmp log file %{public}s.", tmpLogPath.c_str());
308         return "";
309     }
310 
311     FileUtil::SaveStringToFd(fd, header.str());
312     FileUtil::SaveStringToFd(fd, body.str());
313     close(fd);
314     return SendFaultLog(watchPoint, tmpLogPath, type, processName, isScbPro);
315 }
316 
Init()317 bool Vendor::Init()
318 {
319     if (freezeCommon_ == nullptr) {
320         return false;
321     }
322     logStore_ = std::make_unique<LogStoreEx>(FREEZE_DETECTOR_PATH, true);
323     logStore_->SetMaxSize(MAX_FOLDER_SIZE);
324     logStore_->SetMinKeepingFileNumber(MIN_KEEP_FILE_NUM);
325     LogStoreEx::LogFileComparator comparator = [this](const LogFile &lhs, const LogFile &rhs) {
326         return rhs < lhs;
327     };
328     logStore_->SetLogFileComparator(comparator);
329     logStore_->Init();
330     return true;
331 }
332 
GetDisPlayPowerInfo()333 std::string Vendor::GetDisPlayPowerInfo()
334 {
335     std::string disPlayPowerInfo;
336     OHOS::PowerMgr::PowerState powerState = OHOS::PowerMgr::PowerMgrClient::GetInstance().GetState();
337     disPlayPowerInfo = "powerState:" + GetPowerStateString(powerState) + "\n";
338     return disPlayPowerInfo;
339 }
340 
GetPowerStateString(OHOS::PowerMgr::PowerState state)341 std::string Vendor::GetPowerStateString(OHOS::PowerMgr::PowerState state)
342 {
343     switch (state) {
344         case OHOS::PowerMgr::PowerState::AWAKE:
345             return std::string("AWAKE");
346         case OHOS::PowerMgr::PowerState::FREEZE:
347             return std::string("FREEZE");
348         case OHOS::PowerMgr::PowerState::INACTIVE:
349             return std::string("INACTIVE");
350         case OHOS::PowerMgr::PowerState::STAND_BY:
351             return std::string("STAND_BY");
352         case OHOS::PowerMgr::PowerState::DOZE:
353             return std::string("DOZE");
354         case OHOS::PowerMgr::PowerState::SLEEP:
355             return std::string("SLEEP");
356         case OHOS::PowerMgr::PowerState::HIBERNATE:
357             return std::string("HIBERNATE");
358         case OHOS::PowerMgr::PowerState::SHUTDOWN:
359             return std::string("SHUTDOWN");
360         case OHOS::PowerMgr::PowerState::UNKNOWN:
361             return std::string("UNKNOWN");
362         default:
363             break;
364     }
365     return std::string("UNKNOWN");
366 }
367 
CheckProcessName(std::string & processName,std::string & isScbPro)368 void Vendor::CheckProcessName(std::string& processName, std::string& isScbPro)
369 {
370     isScbPro = "No";
371     size_t scbIndex = processName.find(SCB_PRO_FLAG);
372     size_t scbSize = std::strlen(SCB_PRO_FLAG);
373     if (scbIndex != std::string::npos && (scbIndex + scbSize + 1) <= processName.size()) {
374         processName = processName.substr(scbIndex + scbSize);
375         std::replace(processName.begin(), processName.end(), '/', '_');
376         isScbPro = "Yes";
377     }
378     size_t firstAlphaIndex = 0;
379     size_t lastAlphaIndex = processName.size() - 1;
380     while (firstAlphaIndex < processName.size() && !std::isalpha(processName[firstAlphaIndex])) {
381         firstAlphaIndex++;
382     }
383     while (lastAlphaIndex > firstAlphaIndex && !std::isalpha(processName[lastAlphaIndex])) {
384         lastAlphaIndex--;
385     }
386     processName = processName.substr(firstAlphaIndex, lastAlphaIndex - firstAlphaIndex + 1);
387     StringUtil::FormatProcessName(processName);
388 }
389 } // namespace HiviewDFX
390 } // namespace OHOS
391