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