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