• 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     static const int SYS_MATCH_NUM = 1;
31     static const int MILLISECOND = 1000;
32     static const int TIME_STRING_LEN = 16;
33     static const int MIN_KEEP_FILE_NUM = 5;
34     static const int MAX_FOLDER_SIZE = 10 * 1024 * 1024;
35     static constexpr const char* const TRIGGER_HEADER = ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>";
36     static constexpr const char* const HEADER = "*******************************************";
37     static constexpr const char* const HYPHEN = "-";
38     static constexpr const char* const POSTFIX = ".tmp";
39     static constexpr const char* const APPFREEZE = "appfreeze";
40     static constexpr const char* const SYSFREEZE = "sysfreeze";
41     static constexpr const char* const SYSWARNING = "syswarning";
42     static constexpr const char* const FREEZE_DETECTOR_PATH = "/data/log/faultlog/freeze/";
43     static constexpr const char* const FAULT_LOGGER_PATH = "/data/log/faultlog/faultlogger/";
44     static constexpr const char* const COLON = ":";
45     static constexpr const char* const EVENT_DOMAIN = "DOMAIN";
46     static constexpr const char* const EVENT_STRINGID = "STRINGID";
47     static constexpr const char* const EVENT_TIMESTAMP = "TIMESTAMP";
48     static constexpr const char* const DISPLAY_POWER_INFO = "DisplayPowerInfo:";
49     static constexpr const char* const FORE_GROUND = "FOREGROUND";
50     static constexpr const char* const SCB_PROCESS = "SCBPROCESS";
51     static constexpr const char* const SCB_PRO_PREFIX = "ohos.sceneboard:";
52     static constexpr const char* const THREAD_STACK_START = "\nThread stack start:\n";
53     static constexpr const char* const THREAD_STACK_END = "Thread stack end\n";
54     static constexpr const char* const KEY_PROCESS[] = {
55         "foundation", "com.ohos.sceneboard", "render_service"
56     };
57 }
58 
59 DEFINE_LOG_LABEL(0xD002D01, "FreezeDetector");
ReduceRelevanceEvents(std::list<WatchPoint> & list,const FreezeResult & result) const60 bool Vendor::ReduceRelevanceEvents(std::list<WatchPoint>& list, const FreezeResult& result) const
61 {
62     HIVIEW_LOGI("before size=%{public}zu", list.size());
63     if (freezeCommon_ == nullptr) {
64         return false;
65     }
66     if (!freezeCommon_->IsSystemResult(result) && !freezeCommon_->IsApplicationResult(result) &&
67         !freezeCommon_->IsSysWarningResult(result)) {
68         list.clear();
69         return false;
70     }
71 
72     // erase if not system event
73     if (freezeCommon_->IsSystemResult(result)) {
74         std::list<WatchPoint>::iterator watchPoint;
75         for (watchPoint = list.begin(); watchPoint != list.end();) {
76             if (freezeCommon_->IsSystemEvent(watchPoint->GetDomain(), watchPoint->GetStringId())) {
77                 watchPoint++;
78             } else {
79                 watchPoint = list.erase(watchPoint);
80             }
81         }
82     }
83 
84     // erase if not application event
85     if (freezeCommon_->IsApplicationResult(result)) {
86         std::list<WatchPoint>::iterator watchPoint;
87         for (watchPoint = list.begin(); watchPoint != list.end();) {
88             if (freezeCommon_->IsApplicationEvent(watchPoint->GetDomain(), watchPoint->GetStringId())) {
89                 watchPoint++;
90             } else {
91                 watchPoint = list.erase(watchPoint);
92             }
93         }
94     }
95 
96     // erase if not sysWarning event
97     if (freezeCommon_->IsSysWarningResult(result)) {
98         std::list<WatchPoint>::iterator watchPoint;
99         for (watchPoint = list.begin(); watchPoint != list.end();) {
100             if (freezeCommon_->IsSysWarningEvent(watchPoint->GetDomain(), watchPoint->GetStringId())) {
101                 watchPoint++;
102             } else {
103                 watchPoint = list.erase(watchPoint);
104             }
105         }
106     }
107 
108     list.sort();
109     list.unique();
110     HIVIEW_LOGI("after size=%{public}zu", list.size());
111     return list.size() != 0;
112 }
113 
GetTimeString(unsigned long long timestamp) const114 std::string Vendor::GetTimeString(unsigned long long timestamp) const
115 {
116     struct tm tm;
117     time_t ts = static_cast<long long>(timestamp) / MILLISECOND; // ms
118     localtime_r(&ts, &tm);
119     char buf[TIME_STRING_LEN] = {0};
120 
121     strftime(buf, TIME_STRING_LEN - 1, "%Y%m%d%H%M%S", &tm);
122     return std::string(buf, strlen(buf));
123 }
124 
SendFaultLog(const WatchPoint & watchPoint,const std::string & logPath,const std::string & type,const std::string & processName,const std::string & isScbPro) const125 std::string Vendor::SendFaultLog(const WatchPoint &watchPoint, const std::string& logPath,
126     const std::string& type, const std::string& processName, const std::string& isScbPro) const
127 {
128     if (freezeCommon_ == nullptr) {
129         return "";
130     }
131     std::string stringId = watchPoint.GetStringId();
132 
133     FaultLogInfoInner info;
134     info.time = watchPoint.GetTimestamp();
135     info.id = watchPoint.GetUid();
136     info.pid = watchPoint.GetPid();
137     info.faultLogType = (type == APPFREEZE) ? FaultLogType::APP_FREEZE : ((type == SYSFREEZE) ?
138         FaultLogType::SYS_FREEZE : FaultLogType::SYS_WARNING);
139     info.module = processName;
140     info.reason = stringId;
141     std::string disPlayPowerInfo = GetDisPlayPowerInfo();
142     info.summary = type + ": " + processName + " " + stringId +
143         " at " + GetTimeString(watchPoint.GetTimestamp()) + "\n";
144     info.summary += std::string(DISPLAY_POWER_INFO) + disPlayPowerInfo;
145     info.logPath = logPath;
146     info.sectionMaps[FreezeCommon::HIREACE_TIME] = watchPoint.GetHitraceTime();
147     info.sectionMaps[FreezeCommon::SYSRQ_TIME] = watchPoint.GetSysrqTime();
148     info.sectionMaps[FORE_GROUND] = watchPoint.GetForeGround();
149     info.sectionMaps[SCB_PROCESS] = isScbPro;
150     info.sectionMaps[FreezeCommon::TERMINAL_THREAD_STACK] = watchPoint.GetTerminalThreadStack();
151     AddFaultLog(info);
152     return logPath;
153 }
154 
DumpEventInfo(std::ostringstream & oss,const std::string & header,const WatchPoint & watchPoint) const155 void Vendor::DumpEventInfo(std::ostringstream& oss, const std::string& header, const WatchPoint& watchPoint) const
156 {
157     uint64_t timestamp = watchPoint.GetTimestamp() / TimeUtil::SEC_TO_MILLISEC;
158     oss << header << std::endl;
159     oss << std::string(EVENT_DOMAIN) << std::string(COLON) << watchPoint.GetDomain() << std::endl;
160     oss << std::string(EVENT_STRINGID) << std::string(COLON) << watchPoint.GetStringId() << std::endl;
161     oss << std::string(EVENT_TIMESTAMP) << std::string(COLON) <<
162         TimeUtil::TimestampFormatToDate(timestamp, "%Y/%m/%d-%H:%M:%S") <<
163         ":" << watchPoint.GetTimestamp() % TimeUtil::SEC_TO_MILLISEC << std::endl;
164     oss << FreezeCommon::EVENT_PID << std::string(COLON) << watchPoint.GetPid() << std::endl;
165     oss << FreezeCommon::EVENT_UID << std::string(COLON) << watchPoint.GetUid() << std::endl;
166     oss << FreezeCommon::EVENT_PACKAGE_NAME << std::string(COLON) << watchPoint.GetPackageName() << std::endl;
167     oss << FreezeCommon::EVENT_PROCESS_NAME << std::string(COLON) << watchPoint.GetProcessName() << std::endl;
168 }
169 
MergeFreezeJsonFile(const WatchPoint & watchPoint,const std::vector<WatchPoint> & list) const170 void Vendor::MergeFreezeJsonFile(const WatchPoint &watchPoint, const std::vector<WatchPoint>& list) const
171 {
172     std::ostringstream oss;
173     for (auto node : list) {
174         std::string filePath = FreezeJsonUtil::GetFilePath(node.GetPid(), node.GetUid(), node.GetTimestamp());
175         if (!FileUtil::FileExists(filePath)) {
176             continue;
177         }
178         std::string realPath;
179         if (!FileUtil::PathToRealPath(filePath, realPath)) {
180             continue;
181         }
182         std::ifstream ifs(realPath, std::ios::in);
183         if (ifs.is_open()) {
184             oss << ifs.rdbuf();
185             ifs.close();
186         }
187         FreezeJsonUtil::DelFile(realPath);
188     }
189 
190     std::string mergeFilePath = FreezeJsonUtil::GetFilePath(watchPoint.GetPid(),
191         watchPoint.GetUid(), watchPoint.GetTimestamp());
192     int jsonFd = FreezeJsonUtil::GetFd(mergeFilePath);
193     if (jsonFd < 0) {
194         HIVIEW_LOGE("fail to open FreezeJsonFile! jsonFd: %{public}d", jsonFd);
195         return;
196     } else {
197         HIVIEW_LOGI("success to open FreezeJsonFile! jsonFd: %{public}d", jsonFd);
198     }
199     HIVIEW_LOGI("MergeFreezeJsonFile oss size: %{public}zu.", oss.str().size());
200     FileUtil::SaveStringToFd(jsonFd, oss.str());
201     FreezeJsonUtil::WriteKeyValue(jsonFd, "domain", watchPoint.GetDomain());
202     FreezeJsonUtil::WriteKeyValue(jsonFd, "stringId", watchPoint.GetStringId());
203     FreezeJsonUtil::WriteKeyValue(jsonFd, "timestamp", watchPoint.GetTimestamp());
204     FreezeJsonUtil::WriteKeyValue(jsonFd, "pid", watchPoint.GetPid());
205     FreezeJsonUtil::WriteKeyValue(jsonFd, "uid", watchPoint.GetUid());
206     FreezeJsonUtil::WriteKeyValue(jsonFd, "package_name", watchPoint.GetPackageName());
207     FreezeJsonUtil::WriteKeyValue(jsonFd, "process_name", watchPoint.GetProcessName());
208     close(jsonFd);
209     HIVIEW_LOGI("success to merge FreezeJsonFiles!");
210 }
211 
InitLogInfo(const WatchPoint & watchPoint,std::string & type,std::string & pubLogPathName,std::string & processName,std::string & isScbPro) const212 void Vendor::InitLogInfo(const WatchPoint& watchPoint, std::string& type, std::string& pubLogPathName,
213     std::string& processName, std::string& isScbPro) const
214 {
215     std::string stringId = watchPoint.GetStringId();
216     std::string timestamp = GetTimeString(watchPoint.GetTimestamp());
217     long uid = watchPoint.GetUid();
218     std::string packageName = StringUtil::TrimStr(watchPoint.GetPackageName());
219     processName = StringUtil::TrimStr(watchPoint.GetProcessName());
220     processName = processName.empty() ? (packageName.empty() ? stringId : packageName) : processName;
221     if (stringId == "SCREEN_ON") {
222         processName = stringId;
223     } else {
224         isScbPro = IsScbProName(processName);
225         StringUtil::FormatProcessName(processName);
226     }
227     type = freezeCommon_->IsApplicationEvent(watchPoint.GetDomain(), watchPoint.GetStringId()) ? APPFREEZE :
228         (freezeCommon_->IsSystemEvent(watchPoint.GetDomain(), watchPoint.GetStringId()) ? SYSFREEZE : SYSWARNING);
229     pubLogPathName = type + std::string(HYPHEN) + processName + std::string(HYPHEN) + std::to_string(uid) +
230         std::string(HYPHEN) + timestamp;
231 }
232 
InitLogBody(const std::vector<WatchPoint> & list,std::ostringstream & body,bool & isFileExists,WatchPoint & watchPoint) const233 void Vendor::InitLogBody(const std::vector<WatchPoint>& list, std::ostringstream& body,
234     bool& isFileExists, WatchPoint &watchPoint) const
235 {
236     HIVIEW_LOGI("merging list size %{public}zu", list.size());
237     for (auto node : list) {
238         std::string filePath = node.GetLogPath();
239         if (filePath == "nolog" || filePath == "") {
240             HIVIEW_LOGI("only header, no content:[%{public}s, %{public}s]",
241                 node.GetDomain().c_str(), node.GetStringId().c_str());
242             DumpEventInfo(body, HEADER, node);
243             continue;
244         }
245 
246         if (FileUtil::FileExists(filePath) == false) {
247             isFileExists = false;
248             HIVIEW_LOGE("[%{public}s, %{public}s] File:%{public}s does not exist",
249                 node.GetDomain().c_str(), node.GetStringId().c_str(), filePath.c_str());
250             return;
251         }
252 
253         HIVIEW_LOGI("merging file:%{public}s.", filePath.c_str());
254         std::string realPath;
255         if (!FileUtil::PathToRealPath(filePath, realPath)) {
256             HIVIEW_LOGE("PathToRealPath Failed:%{public}s.", filePath.c_str());
257             continue;
258         }
259         std::ifstream ifs(realPath, std::ios::in);
260         if (!ifs.is_open()) {
261             HIVIEW_LOGE("cannot open log file for reading:%{public}s.", realPath.c_str());
262             DumpEventInfo(body, HEADER, node);
263             continue;
264         }
265 
266         body << std::string(HEADER) << std::endl;
267         if (std::find(std::begin(FreezeCommon::PB_EVENTS), std::end(FreezeCommon::PB_EVENTS), node.GetStringId()) !=
268             std::end(FreezeCommon::PB_EVENTS) && watchPoint.GetTerminalThreadStack().empty()) {
269             std::stringstream ss;
270             ss << ifs.rdbuf();
271             std::string logContent = ss.str();
272             size_t startPos = logContent.find(THREAD_STACK_START);
273             size_t endPos = logContent.find(THREAD_STACK_END, startPos);
274             if (startPos != std::string::npos && endPos != std::string::npos && endPos > startPos) {
275                 size_t startSize = strlen(THREAD_STACK_START);
276                 std::string threadStack = logContent.substr(startPos + startSize, endPos - (startPos + startSize));
277                 watchPoint.SetTerminalThreadStack(threadStack);
278                 logContent.erase(startPos, endPos - startPos + strlen(THREAD_STACK_END));
279             }
280             body << logContent << std::endl;
281         } else {
282             body << ifs.rdbuf();
283         }
284         ifs.close();
285     }
286 }
287 
JudgeSysWarningEvent(const std::string & stringId,std::string & type,const std::string & processName,const std::vector<WatchPoint> & list,const std::vector<FreezeResult> & result) const288 bool Vendor::JudgeSysWarningEvent(const std::string& stringId, std::string& type, const std::string& processName,
289     const std::vector<WatchPoint>& list, const std::vector<FreezeResult>& result) const
290 {
291     if  (stringId != "SERVICE_WARNING" && stringId != "THREAD_BLOCK_3S") {
292         return true;
293     }
294 
295     if (std::find(std::begin(KEY_PROCESS), std::end(KEY_PROCESS), processName) == std::end(KEY_PROCESS)) {
296         return false;
297     }
298 
299     if (list.size() != SYS_MATCH_NUM) {
300         HIVIEW_LOGW("Not meeting the requirements for syswarning reporting.");
301         return false;
302     }
303     type = SYSWARNING;
304     return true;
305 }
306 
MergeEventLog(WatchPoint & watchPoint,const std::vector<WatchPoint> & list,const std::vector<FreezeResult> & result) const307 std::string Vendor::MergeEventLog(WatchPoint &watchPoint, const std::vector<WatchPoint>& list,
308     const std::vector<FreezeResult>& result) const
309 {
310     if (freezeCommon_ == nullptr) {
311         return "";
312     }
313 
314     std::string type;
315     std::string pubLogPathName;
316     std::string processName;
317     std::string isScbPro;
318     InitLogInfo(watchPoint, type, pubLogPathName, processName, isScbPro);
319     if (!JudgeSysWarningEvent(watchPoint.GetStringId(), type, processName, list, result)) {
320         return "";
321     }
322     std::string retPath = std::string(FAULT_LOGGER_PATH) + pubLogPathName;
323     std::string tmpLogName = pubLogPathName + std::string(POSTFIX);
324     std::string tmpLogPath = std::string(FREEZE_DETECTOR_PATH) + tmpLogName;
325 
326     if (FileUtil::FileExists(retPath)) {
327         HIVIEW_LOGW("filename: %{public}s is existed, direct use.", retPath.c_str());
328         return retPath;
329     }
330 
331     std::ostringstream header;
332     DumpEventInfo(header, TRIGGER_HEADER, watchPoint);
333 
334     std::ostringstream body;
335     bool isFileExists = true;
336     InitLogBody(list, body, isFileExists, watchPoint);
337     HIVIEW_LOGI("After Init --body size: %{public}zu, pid: %{public}ld, processName: %{public}s ",
338         body.str().size(), watchPoint.GetPid(), processName.c_str());
339 
340     if (!isFileExists) {
341         HIVIEW_LOGE("Failed to open the body file.");
342         return "";
343     }
344 
345     if (type == APPFREEZE || FreezeJsonUtil::IsAppHicollie(watchPoint.GetStringId())) {
346         MergeFreezeJsonFile(watchPoint, list);
347     }
348 
349     int fd = logStore_->CreateLogFile(tmpLogName);
350     if (fd < 0) {
351         HIVIEW_LOGE("failed to create tmp log file %{public}s.", tmpLogPath.c_str());
352         return "";
353     }
354 
355     FileUtil::SaveStringToFd(fd, header.str());
356     FileUtil::SaveStringToFd(fd, body.str());
357     close(fd);
358     return SendFaultLog(watchPoint, tmpLogPath, type, processName, isScbPro);
359 }
360 
Init()361 bool Vendor::Init()
362 {
363     if (freezeCommon_ == nullptr) {
364         return false;
365     }
366     logStore_ = std::make_unique<LogStoreEx>(FREEZE_DETECTOR_PATH, true);
367     logStore_->SetMaxSize(MAX_FOLDER_SIZE);
368     logStore_->SetMinKeepingFileNumber(MIN_KEEP_FILE_NUM);
369     LogStoreEx::LogFileComparator comparator = [this](const LogFile &lhs, const LogFile &rhs) {
370         return rhs < lhs;
371     };
372     logStore_->SetLogFileComparator(comparator);
373     logStore_->Init();
374     return true;
375 }
376 
GetDisPlayPowerInfo()377 std::string Vendor::GetDisPlayPowerInfo()
378 {
379     std::string disPlayPowerInfo;
380     OHOS::PowerMgr::PowerState powerState = OHOS::PowerMgr::PowerMgrClient::GetInstance().GetState();
381     disPlayPowerInfo = "powerState:" + GetPowerStateString(powerState) + "\n";
382     return disPlayPowerInfo;
383 }
384 
GetPowerStateString(OHOS::PowerMgr::PowerState state)385 std::string Vendor::GetPowerStateString(OHOS::PowerMgr::PowerState state)
386 {
387     switch (state) {
388         case OHOS::PowerMgr::PowerState::AWAKE:
389             return std::string("AWAKE");
390         case OHOS::PowerMgr::PowerState::FREEZE:
391             return std::string("FREEZE");
392         case OHOS::PowerMgr::PowerState::INACTIVE:
393             return std::string("INACTIVE");
394         case OHOS::PowerMgr::PowerState::STAND_BY:
395             return std::string("STAND_BY");
396         case OHOS::PowerMgr::PowerState::DOZE:
397             return std::string("DOZE");
398         case OHOS::PowerMgr::PowerState::SLEEP:
399             return std::string("SLEEP");
400         case OHOS::PowerMgr::PowerState::HIBERNATE:
401             return std::string("HIBERNATE");
402         case OHOS::PowerMgr::PowerState::SHUTDOWN:
403             return std::string("SHUTDOWN");
404         case OHOS::PowerMgr::PowerState::UNKNOWN:
405             return std::string("UNKNOWN");
406         default:
407             break;
408     }
409     return std::string("UNKNOWN");
410 }
411 
IsScbProName(std::string & processName)412 std::string Vendor::IsScbProName(std::string& processName)
413 {
414     std::string isScb = "No";
415     size_t scbIndex = processName.find(SCB_PRO_PREFIX);
416     if (scbIndex != std::string::npos) {
417         isScb = "Yes";
418         processName = processName.substr(scbIndex + std::strlen(SCB_PRO_PREFIX));
419         size_t colonIndex = processName.rfind(":");
420         if (colonIndex != std::string::npos) {
421             std::string pNameEndStr = processName.substr(colonIndex + std::strlen(":"));
422             if (std::all_of(pNameEndStr.begin(), pNameEndStr.end(), [] (const char& c) {
423                 return isdigit(c);
424             })) {
425                 processName = processName.substr(0, colonIndex);
426             }
427         }
428     }
429     return isScb;
430 }
431 } // namespace HiviewDFX
432 } // namespace OHOS
433