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