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