• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "fault_kernel_snapshot.h"
17 
18 #include <cstdio>
19 #include <cstdlib>
20 #include <dlfcn.h>
21 #include <fcntl.h>
22 #include <list>
23 #include <pthread.h>
24 #include <thread>
25 #include <unistd.h>
26 #include <unordered_map>
27 
28 #ifndef HISYSEVENT_DISABLE
29 #include "hisysevent.h"
30 #endif
31 #ifndef is_ohos_lite
32 #include "parameters.h"
33 #endif // !is_ohos_lite
34 
35 #include "faultlogger_client_msg.h"
36 
37 #include "dfx_log.h"
38 #include "dfx_util.h"
39 #include "string_util.h"
40 
41 namespace OHOS {
42 namespace HiviewDFX {
43 namespace {
44 constexpr const char * const KERNEL_KBOX_SNAPSHOT = "/sys/kbox/snapshot_clear";
45 constexpr const char * const KBOX_SNAPSHOT_DUMP_PATH = "/data/log/faultlog/temp/";
46 constexpr const char * const KERNEL_SNAPSHOT_CHECK_INTERVAL = "kernel_snapshot_check_interval";
47 constexpr const char * const DEFAULT_CHECK_INTERVAL = "60";
48 constexpr const char * const KERNEL_SNAPSHOT_REASON = "CppCrashKernelSnapshot";
49 constexpr int MIN_CHECK_INTERVAL = 3;
50 constexpr int BUFFER_LEN = 1024;
51 constexpr int SEQUENCE_LEN = 7;
52 constexpr int DECIMAL_BASE = 10;
53 
54 enum class CrashSection {
55     TIME_STAMP,
56     PID,
57     UID,
58     PROCESS_NAME,
59     REASON,
60     FAULT_THREAD_INFO,
61     REGISTERS,
62     MEMORY_NEAR_REGISTERS,
63     FAULT_STACK,
64     MAPS,
65     EXCEPTION_REGISTERS,
66     INVALID_SECTION
67 };
68 
69 enum class SnapshotSection {
70     TRANSACTION_START,
71     EXCEPTION_REGISTERS,
72     ABORT_ADDRESS_PTE,
73     THREAD_INFO,
74     DUMP_REGISTERS,
75     DUMP_FPU_OR_SIMD_REGISTERS,
76     STACK_BACKTRACE,
77     ELF_LOAD_INFO,
78     DATA_ON_TARGET_OF_LAST_BL,
79     DATA_AROUND_REGS,
80     CONTENT_OF_USER_STACK,
81     BASE_ACTV_DUMPED,
82     PROCESS_STATISTICS,
83     TRANSACTION_END
84 };
85 
86 struct SnapshotSectionInfo {
87     SnapshotSection type;
88     const char* key;
89 };
90 
91 const SnapshotSectionInfo SNAPSHOT_SECTION_KEYWORDS[] = {
92     {SnapshotSection::TRANSACTION_START,              "[transaction start] now mono_time"},
93     {SnapshotSection::EXCEPTION_REGISTERS,            "Exception registers:"},
94     {SnapshotSection::ABORT_ADDRESS_PTE,              "Abort address pte"},
95     {SnapshotSection::THREAD_INFO,                    "Thread info:"},
96     {SnapshotSection::DUMP_REGISTERS,                 "Dump registers:"},
97     {SnapshotSection::DUMP_FPU_OR_SIMD_REGISTERS,     "Dump fpu or simd registers:"},
98     {SnapshotSection::STACK_BACKTRACE,                "Stack backtrace"},
99     {SnapshotSection::ELF_LOAD_INFO,                  "Elf load info"},
100     {SnapshotSection::DATA_ON_TARGET_OF_LAST_BL,      "Data on target of last"},
101     {SnapshotSection::DATA_AROUND_REGS,               "Data around regs"},
102     {SnapshotSection::CONTENT_OF_USER_STACK,          "Contents of user stack"},
103     {SnapshotSection::BASE_ACTV_DUMPED,               "[base actv dumped]"},
104     {SnapshotSection::PROCESS_STATISTICS,             "Process statistics:"},
105     {SnapshotSection::TRANSACTION_END,                "[transaction end] now mono_time"}
106 };
107 
108 using CrashMap = std::unordered_map<CrashSection, std::string>;
109 
110 void ReportCrashNoLogEvent(CrashMap& output);
111 void SaveSnapshot(CrashMap& output);
112 
113 class CrashKernelFrame {
114 public:
Parse(const std::string & line)115     void Parse(const std::string& line)
116     {
117         size_t pos = 0;
118         pc = ExtractContent(line, pos, '[', ']');
119         fp = ExtractContent(line, ++pos, '[', ']');
120         funcNameOffset = ExtractContent(line, ++pos, '<', '>');
121         elf = ExtractContent(line, ++pos, '(', ')');
122     }
123 
ToString(int count) const124     std::string ToString(int count) const
125     {
126         std::string data = std::string("#") + (count < 10 ? "0" : "") + std::to_string(count);
127         data += " pc " + pc + " " + elf;
128         return data;
129     }
130 
131 private:
132     std::string pc;
133     std::string fp;
134     std::string funcNameOffset;
135     std::string elf;
136 
ExtractContent(const std::string & line,size_t & pos,char startChar,char endChar)137     static std::string ExtractContent(const std::string& line, size_t& pos, char startChar, char endChar)
138     {
139         size_t start = line.find(startChar, pos);
140         size_t end = line.find(endChar, start);
141         pos = end + 1;
142         if (start != std::string::npos && end != std::string::npos) {
143             return line.substr(start + 1, end - start - 1);
144         }
145         return "";
146     }
147 };
148 
ReportCrashEvent(CrashMap & output)149 void ReportCrashEvent(CrashMap& output)
150 {
151     if (output[CrashSection::UID].empty()) {
152         DFXLOGE("uid is empty, not report");
153         return;
154     }
155 
156     void* handle = dlopen("libfaultlogger.z.so", RTLD_LAZY | RTLD_NODELETE);
157     if (handle == nullptr) {
158         DFXLOGW("Failed to dlopen libfaultlogger, %{public}s\n", dlerror());
159         return;
160     }
161 
162     auto addFaultLog = reinterpret_cast<void (*)(FaultDFXLOGIInner*)>(dlsym(handle, "AddFaultLog"));
163     if (addFaultLog == nullptr) {
164         DFXLOGW("Failed to dlsym AddFaultLog, %{public}s\n", dlerror());
165         dlclose(handle);
166         return;
167     }
168 
169     FaultDFXLOGIInner info;
170     info.time = strtoul(output[CrashSection::TIME_STAMP].c_str(), nullptr, DECIMAL_BASE);
171     info.id = static_cast<uint32_t>(strtoul(output[CrashSection::UID].c_str(), nullptr, DECIMAL_BASE));
172     info.pid = static_cast<int32_t>(strtol(output[CrashSection::PID].c_str(), nullptr, DECIMAL_BASE));
173     info.faultLogType = 2; // 2 : CPP_CRASH_TYPE
174     info.module = output[CrashSection::PROCESS_NAME];
175     info.reason = KERNEL_SNAPSHOT_REASON;
176     info.summary = output[CrashSection::FAULT_THREAD_INFO];
177     addFaultLog(&info);
178     DFXLOGI("Finish report fault to FaultLogger (%{public}u,%{public}d)", info.id, info.pid);
179     dlclose(handle);
180 }
181 
GetBuildInfo()182 std::string GetBuildInfo()
183 {
184 #ifndef is_ohos_lite
185     static std::string buildInfo = OHOS::system::GetParameter("const.product.software.version", "Unknown");
186     return buildInfo;
187 #else
188     return "Unknown";
189 #endif
190 }
191 
PreProcessLine(std::string & line)192 bool PreProcessLine(std::string& line)
193 {
194     if (line.size() <= SEQUENCE_LEN || line[0] == '\t') {
195         return false;
196     }
197     // move timestamp to end
198     if (isdigit(line[1])) {
199         auto pos = line.find('[', 1);
200         if (pos != std::string::npos) {
201             std::string tmp = line.substr(0, pos);
202             line = line.substr(pos) + tmp;
203         }
204     }
205     return true;
206 }
207 
ConvertThreadInfoToPairs(const std::string & line)208 std::unordered_map<std::string, std::string> ConvertThreadInfoToPairs(const std::string& line)
209 {
210     std::unordered_map<std::string, std::string> pairs;
211     size_t pos = 0;
212     while (pos < line.size()) {
213         while (pos < line.size() && line[pos] == ' ') {
214             pos++;
215         }
216         size_t keyStart = pos;
217 
218         while (pos < line.size() && line[pos] != '=') {
219             pos++;
220         }
221         if (pos >= line.size()) {
222             break;
223         }
224         std::string key = line.substr(keyStart, pos - keyStart);
225 
226         size_t valueStart = ++pos;
227         while (pos < line.size() && line[pos] != ',') {
228             pos++;
229         }
230         if (pos >= line.size()) {
231             break;
232         }
233         pairs[key] = line.substr(valueStart, pos - valueStart);
234         pos++;
235     }
236     return pairs;
237 }
238 
ParseTransStart(const std::string & cont,CrashMap & output)239 void ParseTransStart(const std::string& cont, CrashMap& output)
240 {
241     /**
242      * kernel crash snapshot transaction start format:
243      * [AB_00][transaction start] now mono_time is [45.006871][1733329272.590140]
244      */
245     if (cont.find("mono_time") == std::string::npos) {
246         return;
247     }
248     auto msPos = cont.rfind(".");
249     std::string millsecond;
250     const int millsecondLen = 3;
251     if (msPos != std::string::npos && msPos + 1 < cont.length()) {
252         millsecond = cont.substr(msPos + 1, millsecondLen);
253     }
254     millsecond = millsecond.length() != millsecondLen ? "000" : millsecond;
255     auto secondPos = cont.rfind("[");
256     if (secondPos != std::string::npos && secondPos + 1 < cont.length()) {
257         output[CrashSection::TIME_STAMP] = cont.substr(secondPos + 1, 10) + millsecond; // 10: second timestamp length
258     }
259 }
260 
ParseThreadInfo(const std::vector<std::string> & lines,int start,int end,CrashMap & output)261 void ParseThreadInfo(const std::vector<std::string>& lines, int start, int end, CrashMap& output)
262 {
263     if (start + 1 > end) {
264         return;
265     }
266     /**
267      * kernel crash snapshot thread info format:
268      * Thread info:
269      *   name=ei.hmsapp.music, tid=5601, state=RUNNING, sctime=40.362389062, tcb_cref=502520008108a, pid=5601,
270      *   ppid=656, pgid=1, uid=20020048, cpu=7, cur_rq=7
271      */
272     std::string info = lines[start + 1];
273     DFXLOGI("kenel snapshot thread info : %{public}s", info.c_str());
274     auto pairs = ConvertThreadInfoToPairs(info);
275     output[CrashSection::PROCESS_NAME] = pairs["name"]; // native process use this
276     output[CrashSection::FAULT_THREAD_INFO] = "Tid:" + pairs["tid"] + ", Name: "  + pairs["name"] + "\n";
277     output[CrashSection::PID] = pairs["pid"];
278     output[CrashSection::UID] = pairs["uid"];
279 }
280 
ParseStackBacktrace(const std::vector<std::string> & lines,int start,int end,CrashMap & output)281 void ParseStackBacktrace(const std::vector<std::string>& lines, int start, int end, CrashMap& output)
282 {
283     CrashKernelFrame frame;
284     for (int i = start + 1; i <= end; i++) {
285         frame.Parse(lines[i]);
286         output[CrashSection::FAULT_THREAD_INFO] += frame.ToString(i - start - 1) + "\n";
287     }
288 }
289 
ParseProcessRealName(const std::vector<std::string> & lines,int start,int end,CrashMap & output)290 void ParseProcessRealName(const std::vector<std::string>& lines, int start, int end, CrashMap& output)
291 {
292     /**
293      * kernel crash snapshot process statistics format:
294      * [ED_00]Process statistics:
295      * [ED_00] name         tid  state   tcb_cref      sched_cnt cpu_cur rq_cur cls rtprio ni pri pid ppid pgid
296      * [ED_00] SaInit1      1012 RUNNING 5022a0008106b 7         7       6       TS  -     0   20 799 1    1
297      * [ED_00] audio_server 799  BLOCKED 5022a0008108a 325       4       6       TS  -     0   20 799 1    1
298      */
299     for (int i = start + 2; i <= end; i++) { // 2 : skip header
300         const auto& item = lines[i];
301         size_t nameStart = item.find_first_not_of(' ');
302         if (nameStart == std::string::npos) {
303             continue;
304         }
305         size_t nameEnd = item.find_first_of(' ', nameStart);
306         if (nameEnd == std::string::npos) {
307             continue;
308         }
309         std::string name = item.substr(nameStart, nameEnd - nameStart);
310 
311         size_t tidStart = item.find_first_not_of(' ', nameEnd);
312         if (tidStart == std::string::npos) {
313             continue;
314         }
315         size_t tidEnd = item.find_first_of(' ', tidStart);
316         if (tidEnd == std::string::npos) {
317             continue;
318         }
319         std::string tid = item.substr(tidStart, tidEnd - tidStart);
320         if (tid == output[CrashSection::PID]) {
321             output[CrashSection::PROCESS_NAME] = name;
322             break;
323         }
324     }
325 }
326 
GetSnapshotMapCrashItem(const SnapshotSection & item)327 CrashSection GetSnapshotMapCrashItem(const SnapshotSection& item)
328 {
329     switch (item) {
330         case SnapshotSection::DUMP_REGISTERS:
331             return CrashSection::REGISTERS;
332         case SnapshotSection::DATA_AROUND_REGS:
333             return CrashSection::MEMORY_NEAR_REGISTERS;
334         case SnapshotSection::CONTENT_OF_USER_STACK:
335             return CrashSection::FAULT_STACK;
336         case SnapshotSection::ELF_LOAD_INFO:
337             return CrashSection::MAPS;
338         case SnapshotSection::EXCEPTION_REGISTERS:
339             return CrashSection::EXCEPTION_REGISTERS;
340         default:
341             return CrashSection::INVALID_SECTION;
342     }
343 }
344 
ParseDefaultAction(const std::vector<std::string> & lines,int start,int end,SnapshotSection key,CrashMap & output)345 void ParseDefaultAction(const std::vector<std::string>& lines, int start, int end,
346     SnapshotSection key, CrashMap& output)
347 {
348     auto it = GetSnapshotMapCrashItem(key);
349     if (it == CrashSection::INVALID_SECTION) {
350         return;
351     }
352     for (int i = start + 1; i <= end; i++) {
353         output[it] += lines[i] + "\n";
354     }
355 }
356 
ProcessSnapshotSection(SnapshotSection sectionKey,const std::vector<std::string> & lines,size_t start,size_t end,CrashMap & output)357 void ProcessSnapshotSection(SnapshotSection sectionKey, const std::vector<std::string>& lines,
358     size_t start, size_t end, CrashMap& output)
359 {
360     switch (sectionKey) {
361         case SnapshotSection::TRANSACTION_START:
362             ParseTransStart(lines[start], output);
363             break;
364         case SnapshotSection::THREAD_INFO:
365             ParseThreadInfo(lines, start, end, output);
366             break;
367         case SnapshotSection::STACK_BACKTRACE:
368             ParseStackBacktrace(lines, start, end, output);
369             break;
370         case SnapshotSection::PROCESS_STATISTICS:
371             ParseProcessRealName(lines, start, end, output);
372             break;
373         default:
374             ParseDefaultAction(lines, start, end, sectionKey, output);
375             break;
376     }
377 }
378 
ProcessTransStart(const std::vector<std::string> & lines,size_t & index,std::list<std::pair<SnapshotSection,std::string>> & keywordList,CrashMap & output)379 bool ProcessTransStart(const std::vector<std::string>& lines, size_t& index,
380     std::list<std::pair<SnapshotSection, std::string>>& keywordList, CrashMap& output)
381 {
382     const auto& keyword = keywordList.front().second;
383     for (; index < lines.size(); index++) {
384         if (StartsWith(lines[index], keyword)) {
385             break;
386         }
387     }
388 
389     if (index == lines.size()) {
390         return false;
391     }
392 
393     ProcessSnapshotSection(SnapshotSection::TRANSACTION_START, lines, index, index, output);
394     index++;
395     keywordList.pop_front();
396     return true;
397 }
398 
ParseSnapshotUnit(const std::vector<std::string> & lines,size_t & index)399 void ParseSnapshotUnit(const std::vector<std::string>& lines, size_t& index)
400 {
401     CrashMap output;
402     std::list<std::pair<SnapshotSection, std::string>> keywordList;
403     for (const auto& item : SNAPSHOT_SECTION_KEYWORDS) {
404         keywordList.emplace_back(item.type, item.key);
405     }
406 
407     if (!ProcessTransStart(lines, index, keywordList, output)) {
408         return;
409     }
410 
411     // process other snapshot sections
412     size_t snapshotSecIndex = 0;
413     SnapshotSection snapshotSecKey;
414     bool isTransEnd = false;
415 
416     for (; index < lines.size() && !isTransEnd; index++) {
417         for (auto it = keywordList.begin(); it != keywordList.end(); it++) {
418             if (!StartsWith(lines[index], it->second)) {
419                 continue;
420             }
421             if (snapshotSecIndex == 0) {
422                 snapshotSecIndex = index;
423                 snapshotSecKey = it->first;
424                 break;
425             }
426             ProcessSnapshotSection(snapshotSecKey, lines, snapshotSecIndex, index - 1, output);
427             snapshotSecIndex = index;
428             snapshotSecKey = it->first;
429             if (it->first == SnapshotSection::TRANSACTION_END) {
430                 isTransEnd = true;
431             }
432             keywordList.erase(it);
433             break;
434         }
435     }
436 
437     SaveSnapshot(output);
438     ReportCrashEvent(output);
439     ReportCrashNoLogEvent(output);
440 }
441 
ParseSameSeqSnapshot(const std::vector<std::string> & lines)442 void ParseSameSeqSnapshot(const std::vector<std::string>& lines)
443 {
444     size_t curLineNum = 0;
445     while (curLineNum < lines.size()) {
446         ParseSnapshotUnit(lines, curLineNum);
447     }
448 }
449 
ParseSnapshot(std::vector<std::string> & snapshotLines)450 void ParseSnapshot(std::vector<std::string>& snapshotLines)
451 {
452     std::unordered_map<std::string, std::vector<std::string>> kernelSnapshotMap;
453     // devide snapshot info by sequence number
454     for (auto &line : snapshotLines) {
455         if (!PreProcessLine(line)) {
456             continue;
457         }
458 
459         std::string seqNum = line.substr(0, SEQUENCE_LEN);
460         kernelSnapshotMap[seqNum].emplace_back(line.substr(SEQUENCE_LEN));
461     }
462 
463     for (auto &item : kernelSnapshotMap) {
464         ParseSameSeqSnapshot(item.second);
465     }
466 }
467 
FilterEmptySection(const std::string & secHead,const std::string & secCont,const std::string & end)468 std::string FilterEmptySection(const std::string& secHead, const std::string& secCont, const std::string& end)
469 {
470     if (secCont.empty()) {
471         return "";
472     }
473     return secHead + secCont + end;
474 }
475 
FormatTimestamp(const std::string & timestamp)476 std::string FormatTimestamp(const std::string& timestamp)
477 {
478     uint64_t time = strtoul(timestamp.c_str(), nullptr, DECIMAL_BASE);
479     if (errno == ERANGE) {
480         DFXLOGE("Failed to convert timestamp to uint64_t");
481         time = 0;
482     }
483     return GetCurrentTimeStr(time);
484 }
485 
OutputToFile(const std::string & filePath,CrashMap & output)486 void OutputToFile(const std::string& filePath, CrashMap& output)
487 {
488     FILE* file = fopen(filePath.c_str(), "w");
489     if (file == nullptr) {
490         DFXLOGE("open file failed %{public}s errno %{public}d", filePath.c_str(), errno);
491         return;
492     }
493     std::string outputCont;
494     outputCont += FilterEmptySection("Build info: ", GetBuildInfo(), "\n");
495     outputCont += FilterEmptySection("Timestamp: ", FormatTimestamp(output[CrashSection::TIME_STAMP]), "");
496     outputCont += FilterEmptySection("Pid: ", output[CrashSection::PID], "\n");
497     outputCont += FilterEmptySection("Uid: ", output[CrashSection::UID], "\n");
498     outputCont += FilterEmptySection("Process name: ", output[CrashSection::PROCESS_NAME], "\n");
499     outputCont += FilterEmptySection("Reason: ", KERNEL_SNAPSHOT_REASON, "\n");
500     outputCont += FilterEmptySection("Exception registers:\n", output[CrashSection::EXCEPTION_REGISTERS], "");
501     outputCont += FilterEmptySection("Fault thread info:\n", output[CrashSection::FAULT_THREAD_INFO], "");
502     outputCont += FilterEmptySection("Registers:\n", output[CrashSection::REGISTERS], "");
503     outputCont += FilterEmptySection("Memory near registers:\n", output[CrashSection::MEMORY_NEAR_REGISTERS], "");
504     outputCont += FilterEmptySection("FaultStack:\n", output[CrashSection::FAULT_STACK], "");
505     outputCont += FilterEmptySection("Elfs:\n", output[CrashSection::MAPS], "");
506     if (fwrite(outputCont.c_str(), sizeof(char), outputCont.length(), file) != outputCont.length()) {
507         DFXLOGE("write file failed %{public}s errno %{public}d", filePath.c_str(), errno);
508     }
509     if (fclose(file) != 0) {
510         DFXLOGE("close file failed %{public}s errno %{public}d", filePath.c_str(), errno);
511     }
512 }
513 
SaveSnapshot(CrashMap & output)514 void SaveSnapshot(CrashMap& output)
515 {
516     if (output[CrashSection::PID].empty()) {
517         DFXLOGE("pid is empty, not save snapshot");
518         return;
519     }
520 
521     std::string filePath = std::string(KBOX_SNAPSHOT_DUMP_PATH) + "cppcrash-" +
522                            output[CrashSection::PID] + "-" +
523                            output[CrashSection::TIME_STAMP];
524     OutputToFile(filePath, output);
525 }
526 
GetSnapshotCheckInterval()527 int GetSnapshotCheckInterval()
528 {
529 #ifndef is_ohos_lite
530     std::string interval = OHOS::system::GetParameter(KERNEL_SNAPSHOT_CHECK_INTERVAL, DEFAULT_CHECK_INTERVAL);
531 #else
532     std::string interval = DEFAULT_CHECK_INTERVAL;
533 #endif
534     int value = static_cast<int>(strtol(interval.c_str(), nullptr, DECIMAL_BASE));
535     if (errno == ERANGE) {
536         DFXLOGE("get snapshot check interval failed, use default interval");
537         value = 60; // 60 : default interval
538     }
539     value = value < MIN_CHECK_INTERVAL ? MIN_CHECK_INTERVAL : value;
540 
541     DFXLOGI("monitor crash kernel snapshot interval %{public}d", value);
542     return value;
543 }
544 
SplitByNewLine(const std::string & str,std::vector<std::string> & lines)545 void SplitByNewLine(const std::string& str, std::vector<std::string>& lines)
546 {
547     size_t start = 0;
548     while (start < str.size()) {
549         size_t end = str.find('\n', start);
550         if (end == std::string::npos) {
551             end = str.size();
552         }
553         lines.emplace_back(str.substr(start, end - start));
554         start = end + 1;
555     }
556 }
557 
MonitorCrashKernelSnapshot()558 void MonitorCrashKernelSnapshot()
559 {
560     DFXLOGI("enter %{public}s ", __func__);
561     pthread_setname_np(pthread_self(), "KernelSnapshot");
562     int interval = GetSnapshotCheckInterval();
563     while (true) {
564         std::this_thread::sleep_for(std::chrono::seconds(interval));
565         if (access(KERNEL_KBOX_SNAPSHOT, F_OK) < 0) {
566             DFXLOGE("can't find %{public}s, just exit", KERNEL_KBOX_SNAPSHOT);
567             return;
568         }
569         int snapshotFd = open(KERNEL_KBOX_SNAPSHOT, O_RDONLY);
570         if (snapshotFd < 0) {
571             DFXLOGE("open snapshot filed %{public}d", errno);
572             continue;
573         }
574 
575         char buffer[BUFFER_LEN] = {0};
576         std::vector<std::string> snapshotLines;
577         std::string snapshotCont;
578 
579         int ret = read(snapshotFd, buffer, BUFFER_LEN - 1);
580         while (ret > 0) {
581             snapshotCont += buffer;
582             ret = read(snapshotFd, buffer, BUFFER_LEN - 1);
583         }
584         close(snapshotFd);
585 
586         SplitByNewLine(snapshotCont, snapshotLines);
587         ParseSnapshot(snapshotLines);
588     }
589 }
590 
ReportCrashNoLogEvent(CrashMap & output)591 void ReportCrashNoLogEvent(CrashMap& output)
592 {
593     if (output[CrashSection::UID].empty()) {
594         DFXLOGE("uid is empty, not report");
595         return;
596     }
597 #ifndef HISYSEVENT_DISABLE
598     int32_t uid = static_cast<int32_t>(strtol(output[CrashSection::UID].c_str(), nullptr, DECIMAL_BASE));
599     int32_t pid = static_cast<int32_t>(strtol(output[CrashSection::PID].c_str(), nullptr, DECIMAL_BASE));
600     int64_t timeStamp = strtoll(output[CrashSection::TIME_STAMP].c_str(), nullptr, DECIMAL_BASE);
601     if (errno == ERANGE) {
602         DFXLOGE("Failed to convert string to number, error: %{public}s", strerror(errno));
603         return;
604     }
605 
606     std::string summary;
607     summary += FilterEmptySection("Build info: ", GetBuildInfo(), "\n");
608     summary += FilterEmptySection("Timestamp: ", FormatTimestamp(output[CrashSection::TIME_STAMP]), "");
609     summary += FilterEmptySection("Pid: ", output[CrashSection::PID], "\n");
610     summary += FilterEmptySection("Uid: ", output[CrashSection::UID], "\n");
611     summary += FilterEmptySection("Process name: ", output[CrashSection::PROCESS_NAME], "\n");
612     summary += FilterEmptySection("Reason: ", KERNEL_SNAPSHOT_REASON, "\n");
613     summary += FilterEmptySection("Exception registers:\n", output[CrashSection::EXCEPTION_REGISTERS], "");
614     summary += FilterEmptySection("Fault thread info:\n", output[CrashSection::FAULT_THREAD_INFO], "");
615     summary += FilterEmptySection("Registers:\n", output[CrashSection::REGISTERS], "");
616     summary += FilterEmptySection("Elfs:\n", output[CrashSection::MAPS], "");
617 
618     HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::RELIABILITY, "CPP_CRASH_NO_LOG",
619                     OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
620                     "UID", uid,
621                     "PID", pid,
622                     "PROCESS_NAME", output[CrashSection::PROCESS_NAME].c_str(),
623                     "HAPPEN_TIME", timeStamp,
624                     "SUMMARY", summary);
625     DFXLOGI("Report kernel snapshot event done.");
626 #else
627     DFXLOGI("Not supported for kernel snapshot report.");
628 #endif
629 }
630 } // namespace
631 
StartMonitor()632 void FaultKernelSnapshot::StartMonitor()
633 {
634     DFXLOGI("monitor kernel crash snapshot start!");
635     if (!IsBetaVersion()) {
636         DFXLOGW("monitor kernel crash snapshot func not support");
637         return;
638     }
639     std::thread catchThread = std::thread([] { MonitorCrashKernelSnapshot(); });
640     catchThread.detach();
641 }
642 } // namespace HiviewDFX
643 } // namespace OHOS
644