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