• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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