1 /*
2 * Copyright (c) 2021-2023 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 #include "faultlogger.h"
16
17 #include <climits>
18 #include <cstdint>
19 #include <ctime>
20 #include <memory>
21 #include <regex>
22 #include <string>
23 #include <vector>
24
25 #include <fcntl.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28
29 #include <cerrno>
30 #include <thread>
31 #include <unistd.h>
32
33 #include "common_utils.h"
34 #include "constants.h"
35 #include "event.h"
36 #include "file_util.h"
37 #include "hisysevent.h"
38 #include "hiview_global.h"
39 #include "logger.h"
40 #include "parameter_ex.h"
41 #include "plugin_factory.h"
42 #include "string_util.h"
43 #include "sys_event_dao.h"
44 #include "sys_event.h"
45 #include "time_util.h"
46
47 #include "faultlog_formatter.h"
48 #include "faultlog_info.h"
49 #include "faultlog_query_result_inner.h"
50 #include "faultlog_util.h"
51 #include "faultlogger_adapter.h"
52 #include "log_analyzer.h"
53
54 #include "bundle_mgr_client.h"
55
56 #include "securec.h"
57 #include "asan_collector.h"
58 #include "sanitizerd_collector.h"
59 #include "sanitizerd_monitor.h"
60 #include "reporter.h"
61 #include "zip_helper.h"
62
63 namespace OHOS {
64 namespace HiviewDFX {
65 REGISTER(Faultlogger);
66 DEFINE_LOG_TAG("Faultlogger");
67 using namespace FaultLogger;
68 using namespace OHOS::AppExecFwk;
69 #ifndef UNIT_TEST
70 static std::unordered_map<std::string, std::string> g_stacks;
71 static AsanCollector g_collector(g_stacks);
72 #endif
73 namespace {
74 constexpr char FILE_SEPERATOR[] = "******";
75 constexpr uint32_t DUMP_MAX_NUM = 100;
76 constexpr int32_t MAX_QUERY_NUM = 100;
77 constexpr int MIN_APP_UID = 10000;
78 constexpr int DUMP_PARSE_CMD = 0;
79 constexpr int DUMP_PARSE_FILE_NAME = 1;
80 constexpr int DUMP_PARSE_TIME = 2;
81 constexpr int DUMP_START_PARSE_MODULE_NAME = 3;
82 constexpr uint32_t MAX_NAME_LENGTH = 4096;
83 constexpr char TEMP_LOG_PATH[] = "/data/log/faultlog/temp";
84 constexpr time_t FORTYEIGHT_HOURS = 48 * 60 * 60;
85 #ifndef UNIT_TEST
86 constexpr int RETRY_COUNT = 10;
87 constexpr int RETRY_DELAY = 10;
88 #endif
InitDumpRequest()89 DumpRequest InitDumpRequest()
90 {
91 DumpRequest request;
92 request.requestDetail = false;
93 request.requestList = false;
94 request.fileName = "";
95 request.moduleName = "";
96 request.time = -1;
97 return request;
98 }
99
IsLogNameValid(const std::string & name)100 bool IsLogNameValid(const std::string& name)
101 {
102 if (name.empty() || name.size() > MAX_NAME_LENGTH) {
103 HIVIEW_LOGI("invalid log name.");
104 return false;
105 }
106
107 std::vector<std::string> out;
108 StringUtil::SplitStr(name, "-", out, true, false);
109 if (out.size() != 4) { // FileName LogType-ModuleName-uid-YYYYMMDDHHMMSS, thus contains 4 sections
110 return false;
111 }
112
113 std::regex reType("^[a-z]+$");
114 if (!std::regex_match(out[0], reType)) { // 0 : type section
115 HIVIEW_LOGI("invalid type.");
116 return false;
117 }
118
119 if (!IsModuleNameValid(out[1])) { // 1 : module section
120 HIVIEW_LOGI("invalid module name.");
121 return false;
122 }
123
124 std::regex reDigits("^[0-9]*$");
125 if (!std::regex_match(out[2], reDigits)) { // 2 : uid section
126 HIVIEW_LOGI("invalid uid.");
127 return false;
128 }
129
130 if (!std::regex_match(out[3], reDigits)) { // 3 : time section
131 HIVIEW_LOGI("invalid digits.");
132 return false;
133 }
134 return true;
135 }
136
FillDumpRequest(DumpRequest & request,int status,const std::string & item)137 bool FillDumpRequest(DumpRequest &request, int status, const std::string &item)
138 {
139 switch (status) {
140 case DUMP_PARSE_FILE_NAME:
141 if (!IsLogNameValid(item)) {
142 return false;
143 }
144 request.fileName = item;
145 break;
146 case DUMP_PARSE_TIME:
147 if (item.size() == 14) { // 14 : BCD time size
148 request.time = TimeUtil::StrToTimeStamp(item, "%Y%m%d%H%M%S");
149 } else {
150 StringUtil::ConvertStringTo<time_t>(item, request.time);
151 }
152 break;
153 case DUMP_START_PARSE_MODULE_NAME:
154 if (!IsModuleNameValid(item)) {
155 return false;
156 }
157 request.moduleName = item;
158 break;
159 default:
160 HIVIEW_LOGI("Unknown status.");
161 break;
162 }
163 return true;
164 }
165
GetSummaryFromSectionMap(int32_t type,const std::map<std::string,std::string> & maps)166 std::string GetSummaryFromSectionMap(int32_t type, const std::map<std::string, std::string>& maps)
167 {
168 std::string key = "";
169 switch (type) {
170 case CPP_CRASH:
171 key = "KEY_THREAD_INFO";
172 break;
173 default:
174 break;
175 }
176
177 if (key.empty()) {
178 return "";
179 }
180
181 auto value = maps.find(key);
182 if (value == maps.end()) {
183 return "";
184 }
185 return value->second;
186 }
187 } // namespace
188
AddPublicInfo(FaultLogInfo & info)189 void Faultlogger::AddPublicInfo(FaultLogInfo &info)
190 {
191 info.sectionMap["DEVICE_INFO"] = Parameter::GetString("const.product.name", "Unknown");
192 info.sectionMap["BUILD_INFO"] = Parameter::GetString("const.product.software.version", "Unknown");
193 info.sectionMap["UID"] = std::to_string(info.id);
194 info.sectionMap["PID"] = std::to_string(info.pid);
195 info.module = RegulateModuleNameIfNeed(info.module);
196 info.sectionMap["MODULE"] = info.module;
197 std::string version = GetApplicationVersion(info.id, info.module);
198 if (!version.empty()) {
199 info.sectionMap["VERSION"] = version;
200 }
201
202 if (info.reason.empty()) {
203 info.reason = info.sectionMap["REASON"];
204 } else {
205 info.sectionMap["REASON"] = info.reason;
206 }
207
208 if (info.summary.empty()) {
209 info.summary = GetSummaryFromSectionMap(info.faultLogType, info.sectionMap);
210 } else {
211 info.sectionMap["SUMMARY"] = info.summary;
212 }
213 }
214
Dump(int fd,const std::vector<std::string> & cmds)215 void Faultlogger::Dump(int fd, const std::vector<std::string> &cmds)
216 {
217 auto request = InitDumpRequest();
218 int32_t status = DUMP_PARSE_CMD;
219 for (auto it = cmds.begin(); it != cmds.end(); it++) {
220 if ((*it) == "-f") {
221 status = DUMP_PARSE_FILE_NAME;
222 continue;
223 } else if ((*it) == "-l") {
224 request.requestList = true;
225 continue;
226 } else if ((*it) == "-t") {
227 status = DUMP_PARSE_TIME;
228 continue;
229 } else if ((*it) == "-m") {
230 status = DUMP_START_PARSE_MODULE_NAME;
231 continue;
232 } else if ((*it) == "-d") {
233 request.requestDetail = true;
234 continue;
235 } else if ((*it) == "Faultlogger") {
236 // skip first params
237 continue;
238 } else if ((!(*it).empty()) && ((*it).at(0) == '-')) {
239 dprintf(fd, "Unknown command.\n");
240 return;
241 }
242
243 if (!FillDumpRequest(request, status, *it)) {
244 dprintf(fd, "invalid parameters.\n");
245 return;
246 }
247 status = DUMP_PARSE_CMD;
248 }
249
250 if (status != DUMP_PARSE_CMD) {
251 dprintf(fd, "empty parameters.\n");
252 return;
253 }
254
255 HIVIEW_LOGI("DumpRequest: detail:%d, list:%d, file:%s, name:%s, time:%ld",
256 request.requestDetail, request.requestList, request.fileName.c_str(), request.moduleName.c_str(),
257 request.time);
258 Dump(fd, request);
259 }
260
Dump(int fd,const DumpRequest & request) const261 void Faultlogger::Dump(int fd, const DumpRequest &request) const
262 {
263 if (!request.fileName.empty()) {
264 std::string content;
265 if (mgr_->GetFaultLogContent(request.fileName, content)) {
266 dprintf(fd, "%s\n", content.c_str());
267 } else {
268 dprintf(fd, "Fail to dump the log.\n");
269 }
270 return;
271 }
272
273 auto fileList = mgr_->GetFaultLogFileList(request.moduleName, request.time, -1, 0, DUMP_MAX_NUM);
274 if (fileList.empty()) {
275 dprintf(fd, "No fault log exist.\n");
276 return;
277 }
278
279 dprintf(fd, "Fault log list:\n");
280 dprintf(fd, "%s\n", FILE_SEPERATOR);
281 for (auto &file : fileList) {
282 std::string fileName = FileUtil::ExtractFileName(file);
283 dprintf(fd, "%s\n", fileName.c_str());
284 if (request.requestDetail) {
285 std::string content;
286 if (FileUtil::LoadStringFromFile(file, content)) {
287 dprintf(fd, "%s\n", content.c_str());
288 } else {
289 dprintf(fd, "Fail to dump detail log.\n");
290 }
291 dprintf(fd, "%s\n", FILE_SEPERATOR);
292 }
293 }
294 dprintf(fd, "%s\n", FILE_SEPERATOR);
295 }
296
JudgmentRateLimiting(std::shared_ptr<Event> event)297 bool Faultlogger::JudgmentRateLimiting(std::shared_ptr<Event> event)
298 {
299 int interval = 60; // 60s time interval
300 auto sysEvent = std::static_pointer_cast<SysEvent>(event);
301 long pid = sysEvent->GetPid();
302 std::string eventPid = std::to_string(pid);
303
304 std::time_t now = std::time(0);
305 for (auto it = eventTagTime_.begin(); it != eventTagTime_.end();) {
306 if ((now - it->second) >= interval) {
307 it = eventTagTime_.erase(it);
308 continue;
309 }
310 ++it;
311 }
312
313 auto it = eventTagTime_.find(eventPid);
314 if (it != eventTagTime_.end()) {
315 if ((now - it->second) < interval) {
316 HIVIEW_LOGW("event: id:0x%{public}d, eventName:%{public}s pid:%{public}s. \
317 interval:%{public}ld There's not enough interval",
318 sysEvent->eventId_, sysEvent->eventName_.c_str(), eventPid.c_str(), interval);
319 return false;
320 }
321 }
322 eventTagTime_[eventPid] = now;
323 HIVIEW_LOGI("event: id:0x%{public}d, eventName:%{public}s pid:%{public}s. \
324 interval:%{public}ld normal interval",
325 sysEvent->eventId_, sysEvent->eventName_.c_str(), eventPid.c_str(), interval);
326 return true;
327 }
328
IsInterestedPipelineEvent(std::shared_ptr<Event> event)329 bool Faultlogger::IsInterestedPipelineEvent(std::shared_ptr<Event> event)
330 {
331 if (!hasInit_ || event == nullptr) {
332 return false;
333 }
334
335 if (event->eventName_ != "PROCESS_EXIT" &&
336 event->eventName_ != "JS_ERROR" &&
337 event->eventName_ != "RUST_PANIC") {
338 return false;
339 }
340
341 return true;
342 }
343
OnEvent(std::shared_ptr<Event> & event)344 bool Faultlogger::OnEvent(std::shared_ptr<Event> &event)
345 {
346 if (!hasInit_ || event == nullptr) {
347 return false;
348 }
349 if (event->eventName_ != "JS_ERROR" && event->eventName_ != "RUST_PANIC") {
350 return true;
351 }
352 if (event->rawData_ == nullptr) {
353 return false;
354 }
355 bool isJsError = event->eventName_ == "JS_ERROR";
356 auto sysEvent = std::static_pointer_cast<SysEvent>(event);
357 HIVIEW_LOGI("Receive %{public}s Event:%{public}s.", event->eventName_.c_str(),
358 sysEvent->AsJsonStr().c_str());
359 FaultLogInfo info;
360 info.time = sysEvent->happenTime_;
361 info.id = sysEvent->GetUid();
362 info.pid = sysEvent->GetPid();
363 info.faultLogType = isJsError ? FaultLogType::JS_CRASH : FaultLogType::RUST_PANIC;
364 info.module = isJsError ? sysEvent->GetEventValue("PACKAGE_NAME") : sysEvent->GetEventValue("MODULE");
365 info.reason = sysEvent->GetEventValue("REASON");
366 auto summary = sysEvent->GetEventValue("SUMMARY");
367 info.summary = StringUtil::UnescapeJsonStringValue(summary);
368 info.sectionMap = sysEvent->GetKeyValuePairs();
369 AddFaultLog(info);
370 sysEvent->SetEventValue("FAULT_TYPE", std::to_string(info.faultLogType));
371 sysEvent->SetEventValue("MODULE", info.module);
372 sysEvent->SetEventValue("LOG_PATH", info.logPath);
373 sysEvent->SetEventValue("HAPPEN_TIME", sysEvent->happenTime_);
374 sysEvent->SetEventValue("tz_", TimeUtil::GetTimeZone());
375 sysEvent->SetEventValue("VERSION", info.sectionMap["VERSION"]);
376 std::map<std::string, std::string> eventInfos;
377 if (AnalysisFaultlog(info, eventInfos)) {
378 sysEvent->SetEventValue("PNAME", eventInfos["PNAME"].empty() ? "/" : eventInfos["PNAME"]);
379 sysEvent->SetEventValue("FIRST_FRAME", eventInfos["FIRST_FRAME"].empty() ? "/" :
380 StringUtil::EscapeJsonStringValue(eventInfos["FIRST_FRAME"]));
381 sysEvent->SetEventValue("SECOND_FRAME", eventInfos["SECOND_FRAME"].empty() ? "/" :
382 StringUtil::EscapeJsonStringValue(eventInfos["SECOND_FRAME"]));
383 sysEvent->SetEventValue("LAST_FRAME", eventInfos["LAST_FRAME"].empty() ? "/" :
384 StringUtil::EscapeJsonStringValue(eventInfos["LAST_FRAME"]));
385 }
386 sysEvent->SetEventValue("FINGERPRINT", eventInfos["fingerPrint"]);
387 return true;
388 }
389
CanProcessEvent(std::shared_ptr<Event> event)390 bool Faultlogger::CanProcessEvent(std::shared_ptr<Event> event)
391 {
392 return true;
393 }
394
ReadyToLoad()395 bool Faultlogger::ReadyToLoad()
396 {
397 return true;
398 }
399
OnLoad()400 void Faultlogger::OnLoad()
401 {
402 mgr_ = std::make_unique<FaultLogManager>(GetHiviewContext()->GetSharedWorkLoop());
403 mgr_->Init();
404 hasInit_ = true;
405 #ifndef UNITTEST
406 FaultloggerAdapter::StartService(this);
407 #endif
408
409 // some crash happened before hiview start, ensure every crash event is added into eventdb
410 auto eventloop = GetHiviewContext()->GetSharedWorkLoop();
411 if (eventloop != nullptr) {
412 auto task = std::bind(&Faultlogger::StartBootScan, this);
413 eventloop->AddTimerEvent(nullptr, nullptr, task, 10, false); // delay 10 seconds
414 workLoop_ = eventloop;
415 }
416 #ifndef UNIT_TEST
417 std::thread sanitizerdThread(&Faultlogger::RunSanitizerd);
418 sanitizerdThread.detach();
419 #endif
420 }
421
422 #ifndef UNIT_TEST
HandleNotify(int32_t type,const std::string & fname)423 void Faultlogger::HandleNotify(int32_t type, const std::string& fname)
424 {
425 HIVIEW_LOGE("HandleNotify file:[%{public}s]\n", fname.c_str());
426 // start sanitizerd work thread if log ready
427 std::thread collector(&AsanCollector::Collect, &g_collector, fname);
428 collector.detach();
429 // Work done.
430 }
431
RunSanitizerd()432 int Faultlogger::RunSanitizerd()
433 {
434 SanitizerdMonitor sanMonitor;
435
436 // Init the monitor first.
437 bool ready = false;
438 int rcount = RETRY_COUNT;
439 for (; rcount > 0; rcount--) {
440 if (sanMonitor.Init(&Faultlogger::HandleNotify) != 0) {
441 sleep(RETRY_DELAY); // 10s
442 continue;
443 } else {
444 ready = true;
445 break;
446 }
447 }
448
449 if (!ready) {
450 HIVIEW_LOGE("sanitizerd: failed to initialize monitor");
451 return -1;
452 }
453
454 // Waits on notify callback and resume the collector.
455 HIVIEW_LOGE("sanitizerd: starting\n");
456
457 // Waiting for notify event.
458 while (true) {
459 std::string rfile;
460 // Let the monitor check if log ready.
461 if (sanMonitor.RunMonitor(&rfile, -1) == 0) {
462 HIVIEW_LOGE("sanitizerd ready file:[%s]\n", rfile.c_str());
463 } else {
464 break;
465 }
466 }
467
468 sanMonitor.Uninit();
469 return 0;
470 }
471 #endif
472
AddFaultLog(FaultLogInfo & info)473 void Faultlogger::AddFaultLog(FaultLogInfo& info)
474 {
475 if (!hasInit_) {
476 return;
477 }
478
479 AddFaultLogIfNeed(info, nullptr);
480 }
481
GetFaultLogInfo(const std::string & logPath)482 std::unique_ptr<FaultLogInfo> Faultlogger::GetFaultLogInfo(const std::string &logPath)
483 {
484 if (!hasInit_) {
485 return nullptr;
486 }
487
488 auto info = std::make_unique<FaultLogInfo>(FaultLogger::ParseFaultLogInfoFromFile(logPath));
489 info->logPath = logPath;
490 return info;
491 }
492
QuerySelfFaultLog(int32_t id,int32_t pid,int32_t faultType,int32_t maxNum)493 std::unique_ptr<FaultLogQueryResultInner> Faultlogger::QuerySelfFaultLog(int32_t id,
494 int32_t pid, int32_t faultType, int32_t maxNum)
495 {
496 if (!hasInit_) {
497 return nullptr;
498 }
499
500 if ((faultType < FaultLogType::ALL) || (faultType > FaultLogType::RUST_PANIC)) {
501 HIVIEW_LOGW("Unsupported fault type");
502 return nullptr;
503 }
504
505 if (maxNum < 0 || maxNum > MAX_QUERY_NUM) {
506 maxNum = MAX_QUERY_NUM;
507 }
508
509 std::string name = "";
510 if (id >= MIN_APP_UID) {
511 name = GetApplicationNameById(id);
512 }
513
514 if (name.empty()) {
515 name = CommonUtils::GetProcNameByPid(pid);
516 }
517 return std::make_unique<FaultLogQueryResultInner>(mgr_->GetFaultInfoList(name, id, faultType, maxNum));
518 }
519
AddFaultLogIfNeed(FaultLogInfo & info,std::shared_ptr<Event> event)520 void Faultlogger::AddFaultLogIfNeed(FaultLogInfo& info, std::shared_ptr<Event> event)
521 {
522 if ((info.faultLogType <= FaultLogType::ALL) || (info.faultLogType > FaultLogType::RUST_PANIC)) {
523 HIVIEW_LOGW("Unsupported fault type");
524 return;
525 }
526 HIVIEW_LOGI("Start saving Faultlog of Process:%{public}d, Name:%{public}s, Reason:%{public}s.",
527 info.pid, info.module.c_str(), info.reason.c_str());
528
529 std::string appName = GetApplicationNameById(info.id);
530 if (!appName.empty()) {
531 info.module = appName;
532 }
533
534 HIVIEW_LOGD("nameProc %{public}s", info.module.c_str());
535 if ((info.module.empty()) || (!IsModuleNameValid(info.module))) {
536 HIVIEW_LOGW("Invalid module name %{public}s", info.module.c_str());
537 return;
538 }
539
540 AddPublicInfo(info);
541 mgr_->SaveFaultLogToFile(info);
542 if (info.faultLogType != FaultLogType::JS_CRASH && info.faultLogType != FaultLogType::RUST_PANIC) {
543 mgr_->SaveFaultInfoToRawDb(info);
544 }
545 HIVIEW_LOGI("\nSave Faultlog of Process:%{public}d\n"
546 "ModuleName:%{public}s\n"
547 "Reason:%{public}s\n"
548 "Summary:%{public}s\n",
549 info.pid,
550 info.module.c_str(),
551 info.reason.c_str(),
552 info.summary.c_str());
553 }
554
OnUnorderedEvent(const Event & msg)555 void Faultlogger::OnUnorderedEvent(const Event &msg)
556 {
557 }
558
GetListenerName()559 std::string Faultlogger::GetListenerName()
560 {
561 return "FaultLogger";
562 }
563
StartBootScan()564 void Faultlogger::StartBootScan()
565 {
566 std::vector<std::string> files;
567 time_t now = time(nullptr);
568 FileUtil::GetDirFiles(TEMP_LOG_PATH, files);
569 for (const auto& file : files) {
570 time_t lastAccessTime = GetFileLastAccessTimeStamp(file);
571 if (now > lastAccessTime && now - lastAccessTime > FORTYEIGHT_HOURS) {
572 HIVIEW_LOGI("Skip this file(%{public}s) that were created 48 hours ago.", file.c_str());
573 continue;
574 }
575 auto info = ParseFaultLogInfoFromFile(file, true);
576 if (info.summary.find("#00") == std::string::npos) {
577 HIVIEW_LOGI("Skip this file(%{public}s) which stack is empty.", file.c_str());
578 HiSysEventWrite(HiSysEvent::Domain::RELIABILITY, "CPP_CRASH_NO_LOG", HiSysEvent::EventType::FAULT,
579 "PID", info.pid,
580 "UID", info.id,
581 "PROCESS_NAME", info.module,
582 "HAPPEN_TIME", std::to_string(info.time)
583 );
584 if (remove(file.c_str()) != 0) {
585 HIVIEW_LOGE("Failed to remove file(%{public}s) which stack is empty", file.c_str());
586 }
587 continue;
588 }
589 if (mgr_->IsProcessedFault(info.pid, info.id, info.faultLogType)) {
590 HIVIEW_LOGI("Skip processed fault.(%{public}d:%{public}d) ", info.pid, info.id);
591 continue;
592 }
593 AddFaultLogIfNeed(info, nullptr);
594 }
595 }
596 } // namespace HiviewDFX
597 } // namespace OHOS
598
599