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