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 MILLISECOND = 1000;
30     static const int MAX_LINE_NUM = 100;
31     static const int TIME_STRING_LEN = 16;
32     static const int MAX_FILE_NUM = 500;
33     static const int MAX_FOLDER_SIZE = 50 * 1024 * 1024;
34     static constexpr const char* const TRIGGER_HEADER = ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>";
35     static constexpr const char* const HEADER = "*******************************************";
36     static constexpr const char* const HYPHEN = "-";
37     static constexpr const char* const POSTFIX = ".tmp";
38     static constexpr const char* const APPFREEZE = "appfreeze";
39     static constexpr const char* const SYSFREEZE = "sysfreeze";
40     static constexpr const char* const SYSWARNING = "syswarning";
41     static constexpr const char* const FREEZE_DETECTOR_PATH = "/data/log/faultlog/";
42     static constexpr const char* const FAULT_LOGGER_PATH = "/data/log/faultlog/faultlogger/";
43     static constexpr const char* const COLON = ":";
44     static constexpr const char* const EVENT_DOMAIN = "DOMAIN";
45     static constexpr const char* const EVENT_STRINGID = "STRINGID";
46     static constexpr const char* const EVENT_TIMESTAMP = "TIMESTAMP";
47     static constexpr const char* const DISPLAY_POWER_INFO = "DisplayPowerInfo:";
48     static constexpr const char* const FORE_GROUND = "FOREGROUND";
49 }
50 
51 DEFINE_LOG_LABEL(0xD002D01, "FreezeDetector");
ReduceRelevanceEvents(std::list<WatchPoint>& list, const FreezeResult& result) const52 bool Vendor::ReduceRelevanceEvents(std::list<WatchPoint>& list, const FreezeResult& result) const
53 {
54     HIVIEW_LOGI("before size=%{public}zu", list.size());
55     if (freezeCommon_ == nullptr) {
56         return false;
57     }
58     if (!freezeCommon_->IsSystemResult(result) && !freezeCommon_->IsApplicationResult(result) &&
59         !freezeCommon_->IsSysWarningResult(result)) {
60         list.clear();
61         return false;
62     }
63 
64     // erase if not system event
65     if (freezeCommon_->IsSystemResult(result)) {
66         std::list<WatchPoint>::iterator watchPoint;
67         for (watchPoint = list.begin(); watchPoint != list.end();) {
68             if (freezeCommon_->IsSystemEvent(watchPoint->GetDomain(), watchPoint->GetStringId())) {
69                 watchPoint++;
70             } else {
71                 watchPoint = list.erase(watchPoint);
72             }
73         }
74     }
75 
76     // erase if not application event
77     if (freezeCommon_->IsApplicationResult(result)) {
78         std::list<WatchPoint>::iterator watchPoint;
79         for (watchPoint = list.begin(); watchPoint != list.end();) {
80             if (freezeCommon_->IsApplicationEvent(watchPoint->GetDomain(), watchPoint->GetStringId())) {
81                 watchPoint++;
82             } else {
83                 watchPoint = list.erase(watchPoint);
84             }
85         }
86     }
87 
88     // erase if not sysWarning event
89     if (freezeCommon_->IsSysWarningResult(result)) {
90         std::list<WatchPoint>::iterator watchPoint;
91         for (watchPoint = list.begin(); watchPoint != list.end();) {
92             if (freezeCommon_->IsSysWarningEvent(watchPoint->GetDomain(), watchPoint->GetStringId())) {
93                 watchPoint++;
94             } else {
95                 watchPoint = list.erase(watchPoint);
96             }
97         }
98     }
99 
100     list.sort();
101     list.unique();
102     HIVIEW_LOGI("after size=%{public}zu", list.size());
103     return list.size() != 0;
104 }
105 
GetTimeString(unsigned long long timestamp) const106 std::string Vendor::GetTimeString(unsigned long long timestamp) const
107 {
108     struct tm tm;
109     time_t ts = static_cast<long long>(timestamp) / MILLISECOND; // ms
110     localtime_r(&ts, &tm);
111     char buf[TIME_STRING_LEN] = {0};
112 
113     strftime(buf, TIME_STRING_LEN - 1, "%Y%m%d%H%M%S", &tm);
114     return std::string(buf, strlen(buf));
115 }
116 
SendFaultLog(const WatchPoint &watchPoint, const std::string& logPath, const std::string& type) const117 std::string Vendor::SendFaultLog(const WatchPoint &watchPoint, const std::string& logPath,
118     const std::string& type) const
119 {
120     if (freezeCommon_ == nullptr) {
121         return "";
122     }
123     std::string packageName = StringUtil::TrimStr(watchPoint.GetPackageName());
124     std::string processName = StringUtil::TrimStr(watchPoint.GetProcessName());
125     std::string stringId = watchPoint.GetStringId();
126     processName = processName.empty() ? (packageName.empty() ? stringId : packageName) : processName;
127     if (stringId == "SCREEN_ON") {
128         processName = stringId;
129     } else {
130         FormatProcessName(processName);
131     }
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     AddFaultLog(info);
150     return logPath;
151 }
152 
DumpEventInfo(std::ostringstream& oss, const std::string& header, const WatchPoint& watchPoint) const153 void Vendor::DumpEventInfo(std::ostringstream& oss, const std::string& header, const WatchPoint& watchPoint) const
154 {
155     uint64_t timestamp = watchPoint.GetTimestamp() / TimeUtil::SEC_TO_MILLISEC;
156     oss << header << std::endl;
157     oss << std::string(EVENT_DOMAIN) << std::string(COLON) << watchPoint.GetDomain() << std::endl;
158     oss << std::string(EVENT_STRINGID) << std::string(COLON) << watchPoint.GetStringId() << std::endl;
159     oss << std::string(EVENT_TIMESTAMP) << std::string(COLON) <<
160         TimeUtil::TimestampFormatToDate(timestamp, "%Y/%m/%d-%H:%M:%S") <<
161         ":" << watchPoint.GetTimestamp() % TimeUtil::SEC_TO_MILLISEC << std::endl;
162     oss << FreezeCommon::EVENT_PID << std::string(COLON) << watchPoint.GetPid() << std::endl;
163     oss << FreezeCommon::EVENT_UID << std::string(COLON) << watchPoint.GetUid() << std::endl;
164     oss << FreezeCommon::EVENT_PACKAGE_NAME << std::string(COLON) << watchPoint.GetPackageName() << std::endl;
165     oss << FreezeCommon::EVENT_PROCESS_NAME << std::string(COLON) << watchPoint.GetProcessName() << std::endl;
166 }
167 
MergeFreezeJsonFile(const WatchPoint &watchPoint, const std::vector<WatchPoint>& list) const168 void Vendor::MergeFreezeJsonFile(const WatchPoint &watchPoint, const std::vector<WatchPoint>& list) const
169 {
170     std::ostringstream oss;
171     for (auto node : list) {
172         std::string filePath = FreezeJsonUtil::GetFilePath(node.GetPid(), node.GetUid(), node.GetTimestamp());
173         if (!FileUtil::FileExists(filePath)) {
174             continue;
175         }
176         std::string realPath;
177         if (!FileUtil::PathToRealPath(filePath, realPath)) {
178             continue;
179         }
180         std::ifstream ifs(realPath, std::ios::in);
181         if (ifs.is_open()) {
182             oss << ifs.rdbuf();
183             ifs.close();
184         }
185         FreezeJsonUtil::DelFile(realPath);
186     }
187 
188     std::string mergeFilePath = FreezeJsonUtil::GetFilePath(watchPoint.GetPid(),
189         watchPoint.GetUid(), watchPoint.GetTimestamp());
190     int jsonFd = FreezeJsonUtil::GetFd(mergeFilePath);
191     if (jsonFd < 0) {
192         HIVIEW_LOGE("fail to open FreezeJsonFile! jsonFd: %{public}d", jsonFd);
193         return;
194     } else {
195         HIVIEW_LOGI("success to open FreezeJsonFile! jsonFd: %{public}d", jsonFd);
196     }
197     HIVIEW_LOGI("MergeFreezeJsonFile oss size: %{public}zu.", oss.str().size());
198     FileUtil::SaveStringToFd(jsonFd, oss.str());
199     FreezeJsonUtil::WriteKeyValue(jsonFd, "domain", watchPoint.GetDomain());
200     FreezeJsonUtil::WriteKeyValue(jsonFd, "stringId", watchPoint.GetStringId());
201     FreezeJsonUtil::WriteKeyValue(jsonFd, "timestamp", watchPoint.GetTimestamp());
202     FreezeJsonUtil::WriteKeyValue(jsonFd, "pid", watchPoint.GetPid());
203     FreezeJsonUtil::WriteKeyValue(jsonFd, "uid", watchPoint.GetUid());
204     FreezeJsonUtil::WriteKeyValue(jsonFd, "package_name", watchPoint.GetPackageName());
205     FreezeJsonUtil::WriteKeyValue(jsonFd, "process_name", watchPoint.GetProcessName());
206     close(jsonFd);
207     HIVIEW_LOGI("success to merge FreezeJsonFiles!");
208 }
209 
FormatProcessName(std::string& processName)210 void Vendor::FormatProcessName(std::string& processName)
211 {
212     std::regex regExpress("[\\/:*?\"<>|]");
213     bool isLegal = !std::regex_search(processName, regExpress);
214     if (isLegal) {
215         return;
216     }
217     processName = std::regex_replace(processName, regExpress, "_");
218     HIVIEW_LOGD("FormatProcessName processName=%{public}s", processName.c_str());
219 }
220 
InitLogInfo(const WatchPoint& watchPoint, std::string& type, std::string& retPath, std::string& tmpLogPath, std::string& tmpLogName) const221 void Vendor::InitLogInfo(const WatchPoint& watchPoint, std::string& type, std::string& retPath,
222     std::string& tmpLogPath, std::string& tmpLogName) const
223 {
224     std::string stringId = watchPoint.GetStringId();
225     std::string timestamp = GetTimeString(watchPoint.GetTimestamp());
226     long uid = watchPoint.GetUid();
227     std::string packageName = StringUtil::TrimStr(watchPoint.GetPackageName());
228     std::string processName = StringUtil::TrimStr(watchPoint.GetProcessName());
229     processName = processName.empty() ? (packageName.empty() ? stringId : packageName) : processName;
230     if (stringId == "SCREEN_ON") {
231         processName = stringId;
232     } else {
233         FormatProcessName(processName);
234     }
235     type = freezeCommon_->IsApplicationEvent(watchPoint.GetDomain(), watchPoint.GetStringId()) ? APPFREEZE :
236         (freezeCommon_->IsSystemEvent(watchPoint.GetDomain(), watchPoint.GetStringId()) ? SYSFREEZE : SYSWARNING);
237     std::string pubLogPathName = type + std::string(HYPHEN) + processName + std::string(HYPHEN) + std::to_string(uid) +
238         std::string(HYPHEN) + timestamp;
239     retPath = std::string(FAULT_LOGGER_PATH) + pubLogPathName;
240     tmpLogName = pubLogPathName + std::string(POSTFIX);
241     tmpLogPath = std::string(FREEZE_DETECTOR_PATH) + tmpLogName;
242 }
243 
InitLogBody(const std::vector<WatchPoint>& list, std::ostringstream& body, bool& isFileExists) const244 void Vendor::InitLogBody(const std::vector<WatchPoint>& list, std::ostringstream& body,
245     bool& isFileExists) const
246 {
247     HIVIEW_LOGI("merging list size %{public}zu", list.size());
248     for (auto node : list) {
249         std::string filePath = node.GetLogPath();
250         if (filePath == "nolog" || filePath == "") {
251             HIVIEW_LOGI("only header, no content:[%{public}s, %{public}s]",
252                 node.GetDomain().c_str(), node.GetStringId().c_str());
253             DumpEventInfo(body, HEADER, node);
254             continue;
255         }
256 
257         if (FileUtil::FileExists(filePath) == false) {
258             isFileExists = false;
259             HIVIEW_LOGE("[%{public}s, %{public}s] File:%{public}s does not exist",
260                 node.GetDomain().c_str(), node.GetStringId().c_str(), filePath.c_str());
261             return;
262         }
263 
264         HIVIEW_LOGI("merging file:%{public}s.", filePath.c_str());
265         std::string realPath;
266         if (!FileUtil::PathToRealPath(filePath, realPath)) {
267             HIVIEW_LOGE("PathToRealPath Failed:%{public}s.", filePath.c_str());
268             continue;
269         }
270         std::ifstream ifs(realPath, std::ios::in);
271         if (!ifs.is_open()) {
272             HIVIEW_LOGE("cannot open log file for reading:%{public}s.", realPath.c_str());
273             DumpEventInfo(body, HEADER, node);
274             continue;
275         }
276 
277         body << std::string(HEADER) << std::endl;
278         body << ifs.rdbuf();
279         ifs.close();
280     }
281 }
282 
MergeEventLog( const WatchPoint &watchPoint, const std::vector<WatchPoint>& list, const std::vector<FreezeResult>& result) const283 std::string Vendor::MergeEventLog(
284     const WatchPoint &watchPoint, const std::vector<WatchPoint>& list,
285     const std::vector<FreezeResult>& result) const
286 {
287     if (freezeCommon_ == nullptr) {
288         return "";
289     }
290 
291     std::string type;
292     std::string retPath;
293     std::string tmpLogPath;
294     std::string tmpLogName;
295     InitLogInfo(watchPoint, type, retPath, tmpLogPath, tmpLogName);
296 
297     if (FileUtil::FileExists(retPath)) {
298         HIVIEW_LOGW("filename: %{public}s is existed, direct use.", retPath.c_str());
299         return retPath;
300     }
301 
302     std::ostringstream header;
303     DumpEventInfo(header, TRIGGER_HEADER, watchPoint);
304 
305     std::ostringstream body;
306     bool isFileExists = true;
307     InitLogBody(list, body, isFileExists);
308     HIVIEW_LOGI("After Init --body size: %{public}zu.", body.str().size());
309 
310     if (!isFileExists) {
311         HIVIEW_LOGE("Failed to open the body file.");
312         return "";
313     }
314 
315     if (type == APPFREEZE) {
316         MergeFreezeJsonFile(watchPoint, list);
317     }
318 
319     int fd = logStore_->CreateLogFile(tmpLogName);
320     if (fd < 0) {
321         HIVIEW_LOGE("failed to create tmp log file %{public}s.", tmpLogPath.c_str());
322         return "";
323     }
324 
325     FileUtil::SaveStringToFd(fd, header.str());
326     FileUtil::SaveStringToFd(fd, body.str());
327     close(fd);
328     return SendFaultLog(watchPoint, tmpLogPath, type);
329 }
330 
Init()331 bool Vendor::Init()
332 {
333     if (freezeCommon_ == nullptr) {
334         return false;
335     }
336     logStore_ = std::make_unique<LogStoreEx>(FREEZE_DETECTOR_PATH, true);
337     logStore_->SetMaxSize(MAX_FOLDER_SIZE);
338     logStore_->SetMinKeepingFileNumber(MAX_FILE_NUM);
339     logStore_->Init();
340     return true;
341 }
342 
GetDisPlayPowerInfo()343 std::string Vendor::GetDisPlayPowerInfo()
344 {
345     std::string disPlayPowerInfo;
346     OHOS::PowerMgr::PowerState powerState = OHOS::PowerMgr::PowerMgrClient::GetInstance().GetState();
347     disPlayPowerInfo = "powerState:" + GetPowerStateString(powerState) + "\n";
348     return disPlayPowerInfo;
349 }
350 
GetPowerStateString(OHOS::PowerMgr::PowerState state)351 std::string Vendor::GetPowerStateString(OHOS::PowerMgr::PowerState state)
352 {
353     switch (state) {
354         case OHOS::PowerMgr::PowerState::AWAKE:
355             return std::string("AWAKE");
356         case OHOS::PowerMgr::PowerState::FREEZE:
357             return std::string("FREEZE");
358         case OHOS::PowerMgr::PowerState::INACTIVE:
359             return std::string("INACTIVE");
360         case OHOS::PowerMgr::PowerState::STAND_BY:
361             return std::string("STAND_BY");
362         case OHOS::PowerMgr::PowerState::DOZE:
363             return std::string("DOZE");
364         case OHOS::PowerMgr::PowerState::SLEEP:
365             return std::string("SLEEP");
366         case OHOS::PowerMgr::PowerState::HIBERNATE:
367             return std::string("HIBERNATE");
368         case OHOS::PowerMgr::PowerState::SHUTDOWN:
369             return std::string("SHUTDOWN");
370         case OHOS::PowerMgr::PowerState::UNKNOWN:
371             return std::string("UNKNOWN");
372         default:
373             break;
374     }
375     return std::string("UNKNOWN");
376 }
377 } // namespace HiviewDFX
378 } // namespace OHOS
379