From 66e9392a5abdb08555b77dde37f1976acd139eff Mon Sep 17 00:00:00 2001 From: xlgitee Date: Fri, 14 Mar 2025 17:57:08 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=85=E6=A0=B8=E8=BD=AC=E5=82=A8=E9=87=8D?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: xlgitee Change-Id: I22f3c67a11ec11bb6025a9343e74b00ef63755e9 --- services/BUILD.gn | 15 +- services/main.cpp | 10 +- services/snapshot/kernel_snapshot_data.h | 85 +++ .../snapshot/kernel_snapshot_kernel_frame.cpp | 47 ++ .../snapshot/kernel_snapshot_kernel_frame.h | 36 ++ services/snapshot/kernel_snapshot_manager.cpp | 108 ++++ services/snapshot/kernel_snapshot_manager.h | 35 + .../kernel_snapshot_parser.cpp} | 442 ++----------- services/snapshot/kernel_snapshot_parser.h | 54 ++ services/snapshot/kernel_snapshot_printer.cpp | 65 ++ services/snapshot/kernel_snapshot_printer.h | 34 + .../kernel_snapshot_processor.h} | 14 +- .../kernel_snapshot_processor_impl.cpp | 27 + .../snapshot/kernel_snapshot_processor_impl.h | 39 ++ .../snapshot/kernel_snapshot_reporter.cpp | 66 ++ services/snapshot/kernel_snapshot_reporter.h | 37 ++ services/snapshot/kernel_snapshot_util.cpp | 71 ++ services/snapshot/kernel_snapshot_util.h | 31 + test/resource/ohos_test.xml | 7 + .../testdata/kernel_snapshot_2_execption.txt | 465 ++++++++++++++ .../testdata/kernel_snapshot_abort.txt | 590 +++++++++++++++++ .../testdata/kernel_snapshot_execption.txt | 241 +++++++ test/unittest/BUILD.gn | 1 + test/unittest/kernel_snapshot/BUILD.gn | 75 +++ .../kernel_snapshot/kernel_snapshot_test.cpp | 607 ++++++++++++++++++ 25 files changed, 2811 insertions(+), 391 deletions(-) create mode 100644 services/snapshot/kernel_snapshot_data.h create mode 100644 services/snapshot/kernel_snapshot_kernel_frame.cpp create mode 100644 services/snapshot/kernel_snapshot_kernel_frame.h create mode 100644 services/snapshot/kernel_snapshot_manager.cpp create mode 100644 services/snapshot/kernel_snapshot_manager.h rename services/{fault_kernel_snapshot.cpp => snapshot/kernel_snapshot_parser.cpp} (34%) create mode 100644 services/snapshot/kernel_snapshot_parser.h create mode 100644 services/snapshot/kernel_snapshot_printer.cpp create mode 100644 services/snapshot/kernel_snapshot_printer.h rename services/{fault_kernel_snapshot.h => snapshot/kernel_snapshot_processor.h} (70%) create mode 100644 services/snapshot/kernel_snapshot_processor_impl.cpp create mode 100644 services/snapshot/kernel_snapshot_processor_impl.h create mode 100644 services/snapshot/kernel_snapshot_reporter.cpp create mode 100644 services/snapshot/kernel_snapshot_reporter.h create mode 100644 services/snapshot/kernel_snapshot_util.cpp create mode 100644 services/snapshot/kernel_snapshot_util.h create mode 100644 test/resource/testdata/kernel_snapshot_2_execption.txt create mode 100644 test/resource/testdata/kernel_snapshot_abort.txt create mode 100644 test/resource/testdata/kernel_snapshot_execption.txt create mode 100644 test/unittest/kernel_snapshot/BUILD.gn create mode 100644 test/unittest/kernel_snapshot/kernel_snapshot_test.cpp diff --git a/services/BUILD.gn b/services/BUILD.gn index b4cfac56c..2b747fa61 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -15,7 +15,6 @@ import("//base/hiviewdfx/faultloggerd/faultloggerd.gni") faultloggerd_sources = [ "epoll_manager.cpp", - "fault_kernel_snapshot.cpp", "fault_logger_config.cpp", "fault_logger_daemon.cpp", "fault_logger_server.cpp", @@ -43,7 +42,6 @@ if (defined(ohos_lite)) { "$faultloggerd_interfaces_path/common", "$faultloggerd_path/common/dfxlog", "$faultloggerd_path/common/dfxutil", - "$faultloggerd_path/tools/process_dump", "$hilog_lite_include_path", "$faultloggerd_path/interfaces/innerkits/faultloggerd_client/include", "$faultloggerd_path/interfaces/innerkits/faultloggerd_client", @@ -75,17 +73,26 @@ if (defined(ohos_lite)) { } } } else { - faultloggerd_sources += [ "fault_logger_pipe.cpp" ] + faultloggerd_sources += [ + "./snapshot/kernel_snapshot_kernel_frame.cpp", + "./snapshot/kernel_snapshot_manager.cpp", + "./snapshot/kernel_snapshot_parser.cpp", + "./snapshot/kernel_snapshot_printer.cpp", + "./snapshot/kernel_snapshot_processor_impl.cpp", + "./snapshot/kernel_snapshot_reporter.cpp", + "./snapshot/kernel_snapshot_util.cpp", + "fault_logger_pipe.cpp", + ] config("faultloggerd_config") { visibility = [ ":*" ] include_dirs = [ ".", + "./snapshot", "$faultloggerd_interfaces_path/common", "$faultloggerd_path/common/dfxlog", "$faultloggerd_path/common/dfxutil", - "$faultloggerd_path/tools/process_dump", "$faultloggerd_path/interfaces/innerkits/faultloggerd_client", "$faultloggerd_path/interfaces/innerkits/signal_handler", ] diff --git a/services/main.cpp b/services/main.cpp index e86f836bb..7cb2fa9f0 100644 --- a/services/main.cpp +++ b/services/main.cpp @@ -13,7 +13,9 @@ * limitations under the License. */ -#include "fault_kernel_snapshot.h" +#ifndef is_ohos_lite +#include "kernel_snapshot_manager.h" +#endif #include "fault_logger_daemon.h" #if defined(DEBUG_CRASH_LOCAL_HANDLER) @@ -38,8 +40,10 @@ int main(int argc, char *argv[]) DFX_GetCrashFdFunc(DoGetCrashFd); DFX_InstallLocalSignalHandler(); #endif - OHOS::HiviewDFX::FaultKernelSnapshot snapshot; - snapshot.StartMonitor(); +#ifndef is_ohos_lite + OHOS::HiviewDFX::KernelSnapshotManager snapshotManager; + snapshotManager.StartMonitor(); +#endif auto& faultLoggerDaemon = OHOS::HiviewDFX::FaultLoggerDaemon::GetInstance(); faultLoggerDaemon.StartServer(); return 0; diff --git a/services/snapshot/kernel_snapshot_data.h b/services/snapshot/kernel_snapshot_data.h new file mode 100644 index 000000000..cfbd56d50 --- /dev/null +++ b/services/snapshot/kernel_snapshot_data.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KERNEL_SNAPSHOT_DATA_H +#define KERNEL_SNAPSHOT_DATA_H + +#include +#include + +namespace OHOS { +namespace HiviewDFX { +constexpr int DECIMAL_BASE = 10; +constexpr const char * const KERNEL_SNAPSHOT_REASON = "CppCrashKernelSnapshot"; + +enum class CrashSection { + BUILD_INFO, + TIME_STAMP, + PID, + UID, + PROCESS_NAME, + REASON, + FAULT_THREAD_INFO, + CREGISTERS, + MEMORY_NEAR_REGISTERS, + FAULT_STACK, + MAPS, + EXCEPTION_REGISTERS, + INVALID_SECTION +}; + +enum class SnapshotSection { + TRANSACTION_START, + EXCEPTION_REGISTERS, + ABORT_ADDRESS_PTE, + THREAD_INFO, + DUMP_REGISTERS, + DUMP_FPU_OR_SIMD_REGISTERS, + STACK_BACKTRACE, + ELF_LOAD_INFO, + DATA_ON_TARGET_OF_LAST_BL, + DATA_AROUND_REGS, + CONTENT_OF_USER_STACK, + BASE_ACTV_DUMPED, + PROCESS_STATISTICS, + TRANSACTION_END +}; + +struct SnapshotSectionInfo { + SnapshotSection type; + const char* key; +}; + +const SnapshotSectionInfo SNAPSHOT_SECTION_KEYWORDS[] = { + {SnapshotSection::TRANSACTION_START, "[transaction start] now mono_time"}, + {SnapshotSection::EXCEPTION_REGISTERS, "Exception registers:"}, + {SnapshotSection::ABORT_ADDRESS_PTE, "Abort address pte"}, + {SnapshotSection::THREAD_INFO, "Thread info:"}, + {SnapshotSection::DUMP_REGISTERS, "Dump registers:"}, + {SnapshotSection::DUMP_FPU_OR_SIMD_REGISTERS, "Dump fpu or simd registers:"}, + {SnapshotSection::STACK_BACKTRACE, "Stack backtrace"}, + {SnapshotSection::ELF_LOAD_INFO, "Elf load info"}, + {SnapshotSection::DATA_ON_TARGET_OF_LAST_BL, "Data on target of last"}, + {SnapshotSection::DATA_AROUND_REGS, "Data around regs"}, + {SnapshotSection::CONTENT_OF_USER_STACK, "Contents of user stack"}, + {SnapshotSection::BASE_ACTV_DUMPED, "[base actv dumped]"}, + {SnapshotSection::PROCESS_STATISTICS, "Process statistics:"}, + {SnapshotSection::TRANSACTION_END, "[transaction end] now mono_time"} +}; + +using CrashMap = std::unordered_map; +} // namespace HiviewDFX +} // namespace OHOS +#endif diff --git a/services/snapshot/kernel_snapshot_kernel_frame.cpp b/services/snapshot/kernel_snapshot_kernel_frame.cpp new file mode 100644 index 000000000..b67ee901f --- /dev/null +++ b/services/snapshot/kernel_snapshot_kernel_frame.cpp @@ -0,0 +1,47 @@ +/* +* Copyright (c) 2025 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "kernel_snapshot_kernel_frame.h" + +namespace OHOS { +namespace HiviewDFX { +void KernelFrame::Parse(const std::string& line) +{ + size_t pos = 0; + pc = ExtractContent(line, pos, '[', ']'); + fp = ExtractContent(line, ++pos, '[', ']'); + funcNameOffset = ExtractContent(line, ++pos, '<', '>'); + elf = ExtractContent(line, ++pos, '(', ')'); +} + +std::string KernelFrame::ToString(int count) const +{ + return std::string("#") + (count < 10 ? "0" : "") + std::to_string(count) + " pc " + pc + " " + elf; // 10 : add leading 0 if less than 10 +} + +std::string KernelFrame::ExtractContent(const std::string& line, size_t& pos, char startChar, char endChar) +{ + size_t start = line.find(startChar, pos); + if (start == std::string::npos) { + return ""; + } + size_t end = line.find(endChar, start + 1); + if (end == std::string::npos) { + return ""; + } + return line.substr(start + 1, end - start - 1); +} +} // namespace HiviewDFX +} // namespace OHOS diff --git a/services/snapshot/kernel_snapshot_kernel_frame.h b/services/snapshot/kernel_snapshot_kernel_frame.h new file mode 100644 index 000000000..87ab06b14 --- /dev/null +++ b/services/snapshot/kernel_snapshot_kernel_frame.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KERNEL_SNAPSHOT_KERNEL_FRAME_H +#define KERNEL_SNAPSHOT_KERNEL_FRAME_H + +#include + +namespace OHOS { +namespace HiviewDFX { +class KernelFrame { +public: + void Parse(const std::string& line); + std::string ToString(int count) const; +private: + static std::string ExtractContent(const std::string& line, size_t& pos, char startChar, char endChar); + std::string pc; + std::string fp; + std::string funcNameOffset; + std::string elf; +}; +} // namespace HiviewDFX +} // namespace OHOS +#endif diff --git a/services/snapshot/kernel_snapshot_manager.cpp b/services/snapshot/kernel_snapshot_manager.cpp new file mode 100644 index 000000000..d93587012 --- /dev/null +++ b/services/snapshot/kernel_snapshot_manager.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "kernel_snapshot_manager.h" + +#include +#include +#include +#include +#include + +#include "parameters.h" + +#include "dfx_log.h" +#include "dfx_util.h" + +#include "kernel_snapshot_processor_impl.h" +#include "kernel_snapshot_util.h" + +namespace OHOS { +namespace HiviewDFX { +namespace { +constexpr const char * const KERNEL_KBOX_SNAPSHOT = "/sys/kbox/snapshot_clear"; +constexpr const char * const KERNEL_SNAPSHOT_INTERVAL = "kernel_snapshot_check_interval"; +constexpr int BUFFER_LEN = 1024; +constexpr int DEFAULT_INTERVAL = 60; +constexpr int MIN_INTERVAL = 3; +} + +int KernelSnapshotManager::GetSnapshotCheckInterval() +{ + static int value = OHOS::system::GetIntParameter(KERNEL_SNAPSHOT_INTERVAL, DEFAULT_INTERVAL); + value = std::max(value, MIN_INTERVAL); + DFXLOGI("monitor crash kernel snapshot interval %{public}d", value); + return value; +} + +std::string KernelSnapshotManager::ReadKernelSnpashot() +{ + int snapshotFd = open(KERNEL_KBOX_SNAPSHOT, O_RDONLY); + if (snapshotFd < 0) { + DFXLOGE("open snapshot filed %{public}d", errno); + return ""; + } + + char buffer[BUFFER_LEN] = {0}; + std::string snapshotCont; + ssize_t ret = 0; + do { + ret = read(snapshotFd, buffer, BUFFER_LEN - 1); + if (ret > 0) { + snapshotCont += buffer; + } + if (ret < 0) { + DFXLOGE("read snapshot filed %{public}d", errno); + } + } while (ret > 0); + + close(snapshotFd); + return snapshotCont; +} + +void KernelSnapshotManager::MonitorCrashKernelSnapshot() +{ + DFXLOGI("enter %{public}s ", __func__); + pthread_setname_np(pthread_self(), "KernelSnapshot"); + int interval = GetSnapshotCheckInterval(); + std::unique_ptr proessor(new KernelSnapshotProcessorImpl()); + + while (true) { + std::this_thread::sleep_for(std::chrono::seconds(interval)); + if (access(KERNEL_KBOX_SNAPSHOT, F_OK) < 0) { + DFXLOGE("can't find %{public}s, just exit", KERNEL_KBOX_SNAPSHOT); + break; + } + std::string snapshotCont = ReadKernelSnpashot(); + proessor->Process(snapshotCont); + } +} +1 +2 + +void KernelSnapshotManager::StartMonitor() +{ + DFXLOGI("monitor kernel crash snapshot start!"); + if (!IsBetaVersion()) { + DFXLOGW("monitor kernel crash snapshot func not support"); + return; + } + std::thread catchThread = std::thread([this] { + MonitorCrashKernelSnapshot(); + }); + catchThread.detach(); +} +} // namespace HiviewDFX +} // namespace OHOS diff --git a/services/snapshot/kernel_snapshot_manager.h b/services/snapshot/kernel_snapshot_manager.h new file mode 100644 index 000000000..6a4e929e9 --- /dev/null +++ b/services/snapshot/kernel_snapshot_manager.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KERNEL_SNAPSHOT_MANAGER_H +#define KERNEL_SNAPSHOT_MANAGER_H + +#include +namespace OHOS { +namespace HiviewDFX { +class KernelSnapshotManager { +public: + KernelSnapshotManager() = default; + KernelSnapshotManager(const KernelSnapshotManager&) = delete; + KernelSnapshotManager& operator=(const KernelSnapshotManager&) = delete; + void StartMonitor(); +private: + void MonitorCrashKernelSnapshot(); + int GetSnapshotCheckInterval(); + std::string ReadKernelSnpashot(); +}; +} // namespace HiviewDFX +} // namespace OHOS +#endif diff --git a/services/fault_kernel_snapshot.cpp b/services/snapshot/kernel_snapshot_parser.cpp similarity index 34% rename from services/fault_kernel_snapshot.cpp rename to services/snapshot/kernel_snapshot_parser.cpp index 2ee20f1bf..487f50065 100644 --- a/services/fault_kernel_snapshot.cpp +++ b/services/snapshot/kernel_snapshot_parser.cpp @@ -1,197 +1,34 @@ /* - * Copyright (c) 2024 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "fault_kernel_snapshot.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef HISYSEVENT_DISABLE -#include "hisysevent.h" -#endif -#ifndef is_ohos_lite -#include "parameters.h" -#endif // !is_ohos_lite - -#include "faultlogger_client_msg.h" +* Copyright (c) 2025 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "kernel_snapshot_parser.h" #include "dfx_log.h" -#include "dfx_util.h" #include "string_util.h" +#include "kernel_snapshot_kernel_frame.h" + namespace OHOS { namespace HiviewDFX { namespace { -constexpr const char * const KERNEL_KBOX_SNAPSHOT = "/sys/kbox/snapshot_clear"; -constexpr const char * const KBOX_SNAPSHOT_DUMP_PATH = "/data/log/faultlog/temp/"; -constexpr const char * const KERNEL_SNAPSHOT_CHECK_INTERVAL = "kernel_snapshot_check_interval"; -constexpr const char * const DEFAULT_CHECK_INTERVAL = "60"; -constexpr const char * const KERNEL_SNAPSHOT_REASON = "CppCrashKernelSnapshot"; -constexpr int MIN_CHECK_INTERVAL = 3; -constexpr int BUFFER_LEN = 1024; -constexpr int SEQUENCE_LEN = 7; -constexpr int DECIMAL_BASE = 10; - -enum class CrashSection { - TIME_STAMP, - PID, - UID, - PROCESS_NAME, - REASON, - FAULT_THREAD_INFO, - REGISTERS, - MEMORY_NEAR_REGISTERS, - FAULT_STACK, - MAPS, - EXCEPTION_REGISTERS, - INVALID_SECTION -}; - -enum class SnapshotSection { - TRANSACTION_START, - EXCEPTION_REGISTERS, - ABORT_ADDRESS_PTE, - THREAD_INFO, - DUMP_REGISTERS, - DUMP_FPU_OR_SIMD_REGISTERS, - STACK_BACKTRACE, - ELF_LOAD_INFO, - DATA_ON_TARGET_OF_LAST_BL, - DATA_AROUND_REGS, - CONTENT_OF_USER_STACK, - BASE_ACTV_DUMPED, - PROCESS_STATISTICS, - TRANSACTION_END -}; - -struct SnapshotSectionInfo { - SnapshotSection type; - const char* key; -}; - -const SnapshotSectionInfo SNAPSHOT_SECTION_KEYWORDS[] = { - {SnapshotSection::TRANSACTION_START, "[transaction start] now mono_time"}, - {SnapshotSection::EXCEPTION_REGISTERS, "Exception registers:"}, - {SnapshotSection::ABORT_ADDRESS_PTE, "Abort address pte"}, - {SnapshotSection::THREAD_INFO, "Thread info:"}, - {SnapshotSection::DUMP_REGISTERS, "Dump registers:"}, - {SnapshotSection::DUMP_FPU_OR_SIMD_REGISTERS, "Dump fpu or simd registers:"}, - {SnapshotSection::STACK_BACKTRACE, "Stack backtrace"}, - {SnapshotSection::ELF_LOAD_INFO, "Elf load info"}, - {SnapshotSection::DATA_ON_TARGET_OF_LAST_BL, "Data on target of last"}, - {SnapshotSection::DATA_AROUND_REGS, "Data around regs"}, - {SnapshotSection::CONTENT_OF_USER_STACK, "Contents of user stack"}, - {SnapshotSection::BASE_ACTV_DUMPED, "[base actv dumped]"}, - {SnapshotSection::PROCESS_STATISTICS, "Process statistics:"}, - {SnapshotSection::TRANSACTION_END, "[transaction end] now mono_time"} -}; - -using CrashMap = std::unordered_map; - -void ReportCrashNoLogEvent(CrashMap& output); -void SaveSnapshot(CrashMap& output); - -class CrashKernelFrame { -public: - void Parse(const std::string& line) - { - size_t pos = 0; - pc = ExtractContent(line, pos, '[', ']'); - fp = ExtractContent(line, ++pos, '[', ']'); - funcNameOffset = ExtractContent(line, ++pos, '<', '>'); - elf = ExtractContent(line, ++pos, '(', ')'); - } - - std::string ToString(int count) const - { - std::string data = std::string("#") + (count < 10 ? "0" : "") + std::to_string(count); - data += " pc " + pc + " " + elf; - return data; - } - -private: - std::string pc; - std::string fp; - std::string funcNameOffset; - std::string elf; - - static std::string ExtractContent(const std::string& line, size_t& pos, char startChar, char endChar) - { - size_t start = line.find(startChar, pos); - size_t end = line.find(endChar, start); - pos = end + 1; - if (start != std::string::npos && end != std::string::npos) { - return line.substr(start + 1, end - start - 1); - } - return ""; - } -}; - -void ReportCrashEvent(CrashMap& output) -{ - if (output[CrashSection::UID].empty()) { - DFXLOGE("uid is empty, not report"); - return; - } - - void* handle = dlopen("libfaultlogger.z.so", RTLD_LAZY | RTLD_NODELETE); - if (handle == nullptr) { - DFXLOGW("Failed to dlopen libfaultlogger, %{public}s\n", dlerror()); - return; - } - - auto addFaultLog = reinterpret_cast(dlsym(handle, "AddFaultLog")); - if (addFaultLog == nullptr) { - DFXLOGW("Failed to dlsym AddFaultLog, %{public}s\n", dlerror()); - dlclose(handle); - return; - } - - FaultDFXLOGIInner info; - info.time = strtoul(output[CrashSection::TIME_STAMP].c_str(), nullptr, DECIMAL_BASE); - info.id = static_cast(strtoul(output[CrashSection::UID].c_str(), nullptr, DECIMAL_BASE)); - info.pid = static_cast(strtol(output[CrashSection::PID].c_str(), nullptr, DECIMAL_BASE)); - info.faultLogType = 2; // 2 : CPP_CRASH_TYPE - info.module = output[CrashSection::PROCESS_NAME]; - info.reason = KERNEL_SNAPSHOT_REASON; - info.summary = output[CrashSection::FAULT_THREAD_INFO]; - addFaultLog(&info); - DFXLOGI("Finish report fault to FaultLogger (%{public}u,%{public}d)", info.id, info.pid); - dlclose(handle); -} - -std::string GetBuildInfo() -{ -#ifndef is_ohos_lite - static std::string buildInfo = OHOS::system::GetParameter("const.product.software.version", "Unknown"); - return buildInfo; -#else - return "Unknown"; -#endif +constexpr int SEQUENCE_LENGTH = 7; } -bool PreProcessLine(std::string& line) +bool KernelSnapshotParser::PreProcessLine(std::string& line) const { - if (line.size() <= SEQUENCE_LEN || line[0] == '\t') { + if (line.size() <= SEQUENCE_LENGTH || line[0] == '\t') { return false; } // move timestamp to end @@ -205,29 +42,27 @@ bool PreProcessLine(std::string& line) return true; } -std::unordered_map ConvertThreadInfoToPairs(const std::string& line) +std::unordered_map KernelSnapshotParser::ConvertThreadInfoToPairs(const std::string& line) { std::unordered_map pairs; size_t pos = 0; while (pos < line.size()) { - while (pos < line.size() && line[pos] == ' ') { - pos++; + pos = line.find_first_not_of(' ', pos); + if (pos == std::string::npos) { + break; } size_t keyStart = pos; - while (pos < line.size() && line[pos] != '=') { - pos++; - } - if (pos >= line.size()) { + pos = line.find('=', pos); + if (pos == std::string::npos) { break; } std::string key = line.substr(keyStart, pos - keyStart); size_t valueStart = ++pos; - while (pos < line.size() && line[pos] != ',') { - pos++; - } - if (pos >= line.size()) { + pos = line.find(',', pos); + if (pos == std::string::npos) { + pairs[key] = line.substr(valueStart); break; } pairs[key] = line.substr(valueStart, pos - valueStart); @@ -236,7 +71,7 @@ std::unordered_map ConvertThreadInfoToPairs(const std: return pairs; } -void ParseTransStart(const std::string& cont, CrashMap& output) +void KernelSnapshotParser::ParseTransStart(const std::string& cont, CrashMap& output) { /** * kernel crash snapshot transaction start format: @@ -258,7 +93,7 @@ void ParseTransStart(const std::string& cont, CrashMap& output) } } -void ParseThreadInfo(const std::vector& lines, int start, int end, CrashMap& output) +void KernelSnapshotParser::ParseThreadInfo(const std::vector& lines, int start, int end, CrashMap& output) { if (start + 1 > end) { return; @@ -270,7 +105,7 @@ void ParseThreadInfo(const std::vector& lines, int start, int end, * ppid=656, pgid=1, uid=20020048, cpu=7, cur_rq=7 */ std::string info = lines[start + 1]; - DFXLOGI("kenel snapshot thread info : %{public}s", info.c_str()); + DFXLOGI("kernel snapshot thread info : %{public}s", info.c_str()); auto pairs = ConvertThreadInfoToPairs(info); output[CrashSection::PROCESS_NAME] = pairs["name"]; // native process use this output[CrashSection::FAULT_THREAD_INFO] = "Tid:" + pairs["tid"] + ", Name: " + pairs["name"] + "\n"; @@ -278,16 +113,19 @@ void ParseThreadInfo(const std::vector& lines, int start, int end, output[CrashSection::UID] = pairs["uid"]; } -void ParseStackBacktrace(const std::vector& lines, int start, int end, CrashMap& output) +void KernelSnapshotParser::ParseStackBacktrace(const std::vector& lines, int start, int end, + CrashMap& output) { - CrashKernelFrame frame; + KernelFrame frame; for (int i = start + 1; i <= end; i++) { frame.Parse(lines[i]); - output[CrashSection::FAULT_THREAD_INFO] += frame.ToString(i - start - 1) + "\n"; + int pos = i - start - 1; + output[CrashSection::FAULT_THREAD_INFO] += frame.ToString(pos) + "\n"; } } -void ParseProcessRealName(const std::vector& lines, int start, int end, CrashMap& output) +void KernelSnapshotParser::ParseProcessRealName(const std::vector& lines, int start, int end, + CrashMap& output) { /** * kernel crash snapshot process statistics format: @@ -324,11 +162,11 @@ void ParseProcessRealName(const std::vector& lines, int start, int } } -CrashSection GetSnapshotMapCrashItem(const SnapshotSection& item) +CrashSection GetSnapshotMapCrashItem(SnapshotSection& item) { switch (item) { case SnapshotSection::DUMP_REGISTERS: - return CrashSection::REGISTERS; + return CrashSection::CREGISTERS; case SnapshotSection::DATA_AROUND_REGS: return CrashSection::MEMORY_NEAR_REGISTERS; case SnapshotSection::CONTENT_OF_USER_STACK: @@ -342,7 +180,7 @@ CrashSection GetSnapshotMapCrashItem(const SnapshotSection& item) } } -void ParseDefaultAction(const std::vector& lines, int start, int end, +void KernelSnapshotParser::ParseDefaultAction(const std::vector& lines, int start, int end, SnapshotSection key, CrashMap& output) { auto it = GetSnapshotMapCrashItem(key); @@ -354,7 +192,7 @@ void ParseDefaultAction(const std::vector& lines, int start, int en } } -void ProcessSnapshotSection(SnapshotSection sectionKey, const std::vector& lines, +void KernelSnapshotParser::ProcessSnapshotSection(SnapshotSection sectionKey, const std::vector& lines, size_t start, size_t end, CrashMap& output) { switch (sectionKey) { @@ -376,7 +214,7 @@ void ProcessSnapshotSection(SnapshotSection sectionKey, const std::vector& lines, size_t& index, +bool KernelSnapshotParser::ProcessTransStart(const std::vector& lines, size_t& index, std::list>& keywordList, CrashMap& output) { const auto& keyword = keywordList.front().second; @@ -396,7 +234,7 @@ bool ProcessTransStart(const std::vector& lines, size_t& index, return true; } -void ParseSnapshotUnit(const std::vector& lines, size_t& index) +CrashMap KernelSnapshotParser::ParseSnapshotUnit(const std::vector& lines, size_t& index) { CrashMap output; std::list> keywordList; @@ -405,7 +243,7 @@ void ParseSnapshotUnit(const std::vector& lines, size_t& index) } if (!ProcessTransStart(lines, index, keywordList, output)) { - return; + return output; } // process other snapshot sections @@ -433,21 +271,22 @@ void ParseSnapshotUnit(const std::vector& lines, size_t& index) break; } } - - SaveSnapshot(output); - ReportCrashEvent(output); - ReportCrashNoLogEvent(output); + return output; } -void ParseSameSeqSnapshot(const std::vector& lines) +void KernelSnapshotParser::ParseSameSeqSnapshot(const std::vector& lines, std::vector& crashMaps) { size_t curLineNum = 0; + while (curLineNum < lines.size()) { - ParseSnapshotUnit(lines, curLineNum); + auto cm = ParseSnapshotUnit(lines, curLineNum); + if (!cm.empty()) { + crashMaps.emplace_back(cm); + } } } -void ParseSnapshot(std::vector& snapshotLines) +std::vector KernelSnapshotParser::ParseSnapshot(std::vector& snapshotLines) { std::unordered_map> kernelSnapshotMap; // devide snapshot info by sequence number @@ -456,93 +295,18 @@ void ParseSnapshot(std::vector& snapshotLines) continue; } - std::string seqNum = line.substr(0, SEQUENCE_LEN); - kernelSnapshotMap[seqNum].emplace_back(line.substr(SEQUENCE_LEN)); + std::string seqNum = line.substr(0, SEQUENCE_LENGTH); + kernelSnapshotMap[seqNum].emplace_back(line.substr(SEQUENCE_LENGTH)); } + std::vector crashMaps; for (auto &item : kernelSnapshotMap) { - ParseSameSeqSnapshot(item.second); - } -} - -std::string FilterEmptySection(const std::string& secHead, const std::string& secCont, const std::string& end) -{ - if (secCont.empty()) { - return ""; + ParseSameSeqSnapshot(item.second, crashMaps); } - return secHead + secCont + end; + return crashMaps; } -std::string FormatTimestamp(const std::string& timestamp) -{ - uint64_t time = strtoul(timestamp.c_str(), nullptr, DECIMAL_BASE); - if (errno == ERANGE) { - DFXLOGE("Failed to convert timestamp to uint64_t"); - time = 0; - } - return GetCurrentTimeStr(time); -} - -void OutputToFile(const std::string& filePath, CrashMap& output) -{ - FILE* file = fopen(filePath.c_str(), "w"); - if (file == nullptr) { - DFXLOGE("open file failed %{public}s errno %{public}d", filePath.c_str(), errno); - return; - } - std::string outputCont; - outputCont += FilterEmptySection("Build info: ", GetBuildInfo(), "\n"); - outputCont += FilterEmptySection("Timestamp: ", FormatTimestamp(output[CrashSection::TIME_STAMP]), ""); - outputCont += FilterEmptySection("Pid: ", output[CrashSection::PID], "\n"); - outputCont += FilterEmptySection("Uid: ", output[CrashSection::UID], "\n"); - outputCont += FilterEmptySection("Process name: ", output[CrashSection::PROCESS_NAME], "\n"); - outputCont += FilterEmptySection("Reason: ", KERNEL_SNAPSHOT_REASON, "\n"); - outputCont += FilterEmptySection("Exception registers:\n", output[CrashSection::EXCEPTION_REGISTERS], ""); - outputCont += FilterEmptySection("Fault thread info:\n", output[CrashSection::FAULT_THREAD_INFO], ""); - outputCont += FilterEmptySection("Registers:\n", output[CrashSection::REGISTERS], ""); - outputCont += FilterEmptySection("Memory near registers:\n", output[CrashSection::MEMORY_NEAR_REGISTERS], ""); - outputCont += FilterEmptySection("FaultStack:\n", output[CrashSection::FAULT_STACK], ""); - outputCont += FilterEmptySection("Elfs:\n", output[CrashSection::MAPS], ""); - if (fwrite(outputCont.c_str(), sizeof(char), outputCont.length(), file) != outputCont.length()) { - DFXLOGE("write file failed %{public}s errno %{public}d", filePath.c_str(), errno); - } - if (fclose(file) != 0) { - DFXLOGE("close file failed %{public}s errno %{public}d", filePath.c_str(), errno); - } -} - -void SaveSnapshot(CrashMap& output) -{ - if (output[CrashSection::PID].empty()) { - DFXLOGE("pid is empty, not save snapshot"); - return; - } - - std::string filePath = std::string(KBOX_SNAPSHOT_DUMP_PATH) + "cppcrash-" + - output[CrashSection::PID] + "-" + - output[CrashSection::TIME_STAMP]; - OutputToFile(filePath, output); -} - -int GetSnapshotCheckInterval() -{ -#ifndef is_ohos_lite - std::string interval = OHOS::system::GetParameter(KERNEL_SNAPSHOT_CHECK_INTERVAL, DEFAULT_CHECK_INTERVAL); -#else - std::string interval = DEFAULT_CHECK_INTERVAL; -#endif - int value = static_cast(strtol(interval.c_str(), nullptr, DECIMAL_BASE)); - if (errno == ERANGE) { - DFXLOGE("get snapshot check interval failed, use default interval"); - value = 60; // 60 : default interval - } - value = value < MIN_CHECK_INTERVAL ? MIN_CHECK_INTERVAL : value; - - DFXLOGI("monitor crash kernel snapshot interval %{public}d", value); - return value; -} - -void SplitByNewLine(const std::string& str, std::vector& lines) +void KernelSnapshotParser::SplitByNewLine(const std::string& str, std::vector& lines) { size_t start = 0; while (start < str.size()) { @@ -555,89 +319,11 @@ void SplitByNewLine(const std::string& str, std::vector& lines) } } -void MonitorCrashKernelSnapshot() +std::vector KernelSnapshotParser::ParseAll(const std::string& cont) { - DFXLOGI("enter %{public}s ", __func__); - pthread_setname_np(pthread_self(), "KernelSnapshot"); - int interval = GetSnapshotCheckInterval(); - while (true) { - std::this_thread::sleep_for(std::chrono::seconds(interval)); - if (access(KERNEL_KBOX_SNAPSHOT, F_OK) < 0) { - DFXLOGE("can't find %{public}s, just exit", KERNEL_KBOX_SNAPSHOT); - return; - } - int snapshotFd = open(KERNEL_KBOX_SNAPSHOT, O_RDONLY); - if (snapshotFd < 0) { - DFXLOGE("open snapshot filed %{public}d", errno); - continue; - } - - char buffer[BUFFER_LEN] = {0}; - std::vector snapshotLines; - std::string snapshotCont; - - int ret = read(snapshotFd, buffer, BUFFER_LEN - 1); - while (ret > 0) { - snapshotCont += buffer; - ret = read(snapshotFd, buffer, BUFFER_LEN - 1); - } - close(snapshotFd); - - SplitByNewLine(snapshotCont, snapshotLines); - ParseSnapshot(snapshotLines); - } -} - -void ReportCrashNoLogEvent(CrashMap& output) -{ - if (output[CrashSection::UID].empty()) { - DFXLOGE("uid is empty, not report"); - return; - } -#ifndef HISYSEVENT_DISABLE - int32_t uid = static_cast(strtol(output[CrashSection::UID].c_str(), nullptr, DECIMAL_BASE)); - int32_t pid = static_cast(strtol(output[CrashSection::PID].c_str(), nullptr, DECIMAL_BASE)); - int64_t timeStamp = strtoll(output[CrashSection::TIME_STAMP].c_str(), nullptr, DECIMAL_BASE); - if (errno == ERANGE) { - DFXLOGE("Failed to convert string to number, error: %{public}s", strerror(errno)); - return; - } - - std::string summary; - summary += FilterEmptySection("Build info: ", GetBuildInfo(), "\n"); - summary += FilterEmptySection("Timestamp: ", FormatTimestamp(output[CrashSection::TIME_STAMP]), ""); - summary += FilterEmptySection("Pid: ", output[CrashSection::PID], "\n"); - summary += FilterEmptySection("Uid: ", output[CrashSection::UID], "\n"); - summary += FilterEmptySection("Process name: ", output[CrashSection::PROCESS_NAME], "\n"); - summary += FilterEmptySection("Reason: ", KERNEL_SNAPSHOT_REASON, "\n"); - summary += FilterEmptySection("Exception registers:\n", output[CrashSection::EXCEPTION_REGISTERS], ""); - summary += FilterEmptySection("Fault thread info:\n", output[CrashSection::FAULT_THREAD_INFO], ""); - summary += FilterEmptySection("Registers:\n", output[CrashSection::REGISTERS], ""); - summary += FilterEmptySection("Elfs:\n", output[CrashSection::MAPS], ""); - - HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::RELIABILITY, "CPP_CRASH_NO_LOG", - OHOS::HiviewDFX::HiSysEvent::EventType::FAULT, - "UID", uid, - "PID", pid, - "PROCESS_NAME", output[CrashSection::PROCESS_NAME].c_str(), - "HAPPEN_TIME", timeStamp, - "SUMMARY", summary); - DFXLOGI("Report kernel snapshot event done."); -#else - DFXLOGI("Not supported for kernel snapshot report."); -#endif -} -} // namespace - -void FaultKernelSnapshot::StartMonitor() -{ - DFXLOGI("monitor kernel crash snapshot start!"); - if (!IsBetaVersion()) { - DFXLOGW("monitor kernel crash snapshot func not support"); - return; - } - std::thread catchThread = std::thread([] { MonitorCrashKernelSnapshot(); }); - catchThread.detach(); + lines_.clear(); + SplitByNewLine(cont, lines_); + return ParseSnapshot(lines_); } } // namespace HiviewDFX } // namespace OHOS diff --git a/services/snapshot/kernel_snapshot_parser.h b/services/snapshot/kernel_snapshot_parser.h new file mode 100644 index 000000000..8a3b3a904 --- /dev/null +++ b/services/snapshot/kernel_snapshot_parser.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KERNEL_SNAPSHOT_PARSER_H +#define KERNEL_SNAPSHOT_PARSER_H + +#include + +#include "kernel_snapshot_data.h" + +namespace OHOS { +namespace HiviewDFX { +class KernelSnapshotParser { +public: + std::vector ParseAll(const std::string &cont); +private: + void SplitByNewLine(const std::string &str, std::vector &lines); + std::vector ParseSnapshot(std::vector &snapshotLines); + void ParseSameSeqSnapshot(const std::vector &lines, std::vector& crashMaps); + CrashMap ParseSnapshotUnit(const std::vector &lines, size_t &index); + + bool PreProcessLine(std::string &line) const; + std::unordered_map ConvertThreadInfoToPairs(const std::string &line); + + bool ProcessTransStart(const std::vector& lines, size_t& index, + std::list>& keywordList, CrashMap& output); + + void ParseTransStart(const std::string &cont, CrashMap &output); + void ParseThreadInfo(const std::vector &lines, int start, int end, CrashMap &output); + void ParseStackBacktrace(const std::vector &lines, int start, int end, CrashMap &output); + void ParseProcessRealName(const std::vector& lines, int start, int end, CrashMap& output); + void ParseDefaultAction(const std::vector &lines, int start, int end, + SnapshotSection key, CrashMap &output); + + void ProcessSnapshotSection(SnapshotSection sectionKey, const std::vector &lines, + size_t start, size_t end, CrashMap &output); + + std::vector lines_; +}; +} // namespace HiviewDFX +} // namespace OHOS +#endif diff --git a/services/snapshot/kernel_snapshot_printer.cpp b/services/snapshot/kernel_snapshot_printer.cpp new file mode 100644 index 000000000..42ab7b644 --- /dev/null +++ b/services/snapshot/kernel_snapshot_printer.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "kernel_snapshot_printer.h" + +#include "dfx_log.h" +#include "string_util.h" + +#include "kernel_snapshot_util.h" +namespace OHOS { +namespace HiviewDFX { +namespace { +constexpr const char * const KBOX_SNAPSHOT_DUMP_PATH = "/data/log/faultlog/temp/"; +} + +void KernelSnapshotPrinter::OutputToFile(const std::string& filePath, CrashMap& output) +{ + FILE* file = fopen(filePath.c_str(), "w"); + if (file == nullptr) { + DFXLOGE("open file failed %{public}s errno %{public}d", filePath.c_str(), errno); + return; + } + + std::string outputCont = KernelSnapshotUtil::FillSummary(output, true); + if (fwrite(outputCont.c_str(), sizeof(char), outputCont.length(), file) != outputCont.length()) { + DFXLOGE("write file failed %{public}s errno %{public}d", filePath.c_str(), errno); + } + if (fclose(file) != 0) { + DFXLOGE("close file failed %{public}s errno %{public}d", filePath.c_str(), errno); + } +} + +void KernelSnapshotPrinter::SaveSnapshot(CrashMap& output) +{ + if (output[CrashSection::PID].empty()) { + DFXLOGE("pid is empty, not save snapshot"); + return; + } + + std::string filePath = std::string(KBOX_SNAPSHOT_DUMP_PATH) + "cppcrash-" + + output[CrashSection::PID] + "-" + + output[CrashSection::TIME_STAMP]; + OutputToFile(filePath, output); +} + +void KernelSnapshotPrinter::SaveSnapshots(std::vector& outputs) +{ + for (auto& output : outputs) { + SaveSnapshot(output); + } +} +} // namespace HiviewDFX +} // namespace OHOS diff --git a/services/snapshot/kernel_snapshot_printer.h b/services/snapshot/kernel_snapshot_printer.h new file mode 100644 index 000000000..ae179ec61 --- /dev/null +++ b/services/snapshot/kernel_snapshot_printer.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KERNEL_SNAPSHOT_PRINTER_H +#define KERNEL_SNAPSHOT_PRINTER_H + +#include + +#include "kernel_snapshot_data.h" + +namespace OHOS { +namespace HiviewDFX { +class KernelSnapshotPrinter { +public: + void SaveSnapshots(std::vector& outputs); +private: + void SaveSnapshot(CrashMap& output); + void OutputToFile(const std::string& filePath, CrashMap& output); +}; +} // namespace HiviewDFX +} // namespace OHOS +#endif diff --git a/services/fault_kernel_snapshot.h b/services/snapshot/kernel_snapshot_processor.h similarity index 70% rename from services/fault_kernel_snapshot.h rename to services/snapshot/kernel_snapshot_processor.h index 2b0ebd01b..12682764e 100644 --- a/services/fault_kernel_snapshot.h +++ b/services/snapshot/kernel_snapshot_processor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Huawei Device Co., Ltd. + * Copyright (c) 2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,16 +13,18 @@ * limitations under the License. */ -#ifndef FAULT_KERNEL_SNAPSHOT_H -#define FAULT_KERNEL_SNAPSHOT_H +#ifndef KERNEL_SNAPSHOT_OBSERVER_H +#define KERNEL_SNAPSHOT_OBSERVER_H + +#include namespace OHOS { namespace HiviewDFX { -class FaultKernelSnapshot { +class KernelSnapshotProcessor { public: - void StartMonitor(); + virtual void Process(const std::string& snapshot) = 0; + virtual ~KernelSnapshotProcessor() = default; }; } // namespace HiviewDFX } // namespace OHOS - #endif diff --git a/services/snapshot/kernel_snapshot_processor_impl.cpp b/services/snapshot/kernel_snapshot_processor_impl.cpp new file mode 100644 index 000000000..9a29c5eff --- /dev/null +++ b/services/snapshot/kernel_snapshot_processor_impl.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "kernel_snapshot_processor_impl.h" + +namespace OHOS { +namespace HiviewDFX { +void KernelSnapshotProcessorImpl::Process(const std::string& snapshot) +{ + auto crashMaps = parser_.ParseAll(snapshot); + printer_.SaveSnapshots(crashMaps); + reporter_.ReportEvents(crashMaps); +} +} // namespace HiviewDFX +} // namespace OHOS diff --git a/services/snapshot/kernel_snapshot_processor_impl.h b/services/snapshot/kernel_snapshot_processor_impl.h new file mode 100644 index 000000000..1c82634ab --- /dev/null +++ b/services/snapshot/kernel_snapshot_processor_impl.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KERNEL_SNAPSHOT_OBSERVER_IMPL_H +#define KERNEL_SNAPSHOT_OBSERVER_IMPL_H + +#include "kernel_snapshot_parser.h" +#include "kernel_snapshot_printer.h" +#include "kernel_snapshot_processor.h" +#include "kernel_snapshot_reporter.h" + +namespace OHOS { +namespace HiviewDFX { +class KernelSnapshotProcessorImpl : public KernelSnapshotProcessor { +public: + KernelSnapshotProcessorImpl() = default; + void Process(const std::string& snapshot) override; + KernelSnapshotProcessorImpl(KernelSnapshotProcessorImpl&) = delete; + KernelSnapshotProcessorImpl& operator=(KernelSnapshotProcessorImpl&) = delete; +private: + KernelSnapshotParser parser_; + KernelSnapshotPrinter printer_; + KernelSnapshotReporter reporter_; +}; +} // namespace HiviewDFX +} // namespace OHOS +#endif diff --git a/services/snapshot/kernel_snapshot_reporter.cpp b/services/snapshot/kernel_snapshot_reporter.cpp new file mode 100644 index 000000000..238bd2aff --- /dev/null +++ b/services/snapshot/kernel_snapshot_reporter.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "kernel_snapshot_reporter.h" + +#include + +#include "dfx_log.h" +#ifndef HISYSEVENT_DISABLE +#include "hisysevent.h" +#endif + +#include "kernel_snapshot_util.h" + +namespace OHOS { +namespace HiviewDFX { +void KernelSnapshotReporter::ReportEvents(std::vector& outputs) +{ + for (auto& output : outputs) { + ReportCrashNoLogEvent(output); + } +} + +bool KernelSnapshotReporter::ReportCrashNoLogEvent(CrashMap& output) +{ + if (output[CrashSection::UID].empty()) { + DFXLOGE("uid is empty, not report"); + return false; + } +#ifndef HISYSEVENT_DISABLE + int32_t uid = static_cast(strtol(output[CrashSection::UID].c_str(), nullptr, DECIMAL_BASE)); + int32_t pid = static_cast(strtol(output[CrashSection::PID].c_str(), nullptr, DECIMAL_BASE)); + int64_t timeStamp = strtoll(output[CrashSection::TIME_STAMP].c_str(), nullptr, DECIMAL_BASE); + if (errno == ERANGE) { + DFXLOGE("Failed to convert string to number, error: %{public}s", strerror(errno)); + return false; + } + + auto ret = HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::RELIABILITY, "CPP_CRASH_NO_LOG", + OHOS::HiviewDFX::HiSysEvent::EventType::FAULT, + "UID", uid, + "PID", pid, + "PROCESS_NAME", output[CrashSection::PROCESS_NAME], + "HAPPEN_TIME", timeStamp, + "SUMMARY", KernelSnapshotUtil::FillSummary(output)); + DFXLOGI("Report kernel snapshot event done."); + return ret == 0; +#else + DFXLOGI("Not supported for kernel snapshot report."); + return true; +#endif +} +} // namespace HiviewDFX +} // namespace OHOS diff --git a/services/snapshot/kernel_snapshot_reporter.h b/services/snapshot/kernel_snapshot_reporter.h new file mode 100644 index 000000000..0df7c90a7 --- /dev/null +++ b/services/snapshot/kernel_snapshot_reporter.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KERNEL_SNAPSHOT_REPORTER_H +#define KERNEL_SNAPSHOT_REPORTER_H + +#include "kernel_snapshot_data.h" + +namespace OHOS { +namespace HiviewDFX { +class IKernelSnapshotReporter { +public: + virtual ~IKernelSnapshotReporter() = default; + virtual void ReportEvents(std::vector& outputs) = 0; +}; + +class KernelSnapshotReporter : public IKernelSnapshotReporter { +public: + void ReportEvents(std::vector& outputs) override; +private: + bool ReportCrashNoLogEvent(CrashMap& output); +}; +} // namespace HiviewDFX +} // namespace OHOS +#endif diff --git a/services/snapshot/kernel_snapshot_util.cpp b/services/snapshot/kernel_snapshot_util.cpp new file mode 100644 index 000000000..ea2259447 --- /dev/null +++ b/services/snapshot/kernel_snapshot_util.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "kernel_snapshot_util.h" + +#include "parameters.h" + +#include "dfx_log.h" +#include "dfx_util.h" + +namespace OHOS { +namespace HiviewDFX { +namespace KernelSnapshotUtil { +std::string FilterEmptySection(const std::string& secHead, const std::string& secCont, const std::string& end) +{ + if (secCont.empty()) { + return ""; + } + return secHead + secCont + end; +} + +std::string FormatTimestamp(const std::string& timestamp) +{ + uint64_t time = strtoul(timestamp.c_str(), nullptr, DECIMAL_BASE); + if (errno == ERANGE) { + DFXLOGE("Failed to convert timestamp to uint64_t"); + time = 0; + } + return GetCurrentTimeStr(time); +} + +std::string GetBuildInfo() +{ + static std::string buildInfo = OHOS::system::GetParameter("const.product.software.version", "Unknown"); + return buildInfo; +} + +std::string FillSummary(CrashMap& output, bool isLocal) +{ + std::string summary; + summary += FilterEmptySection("Build info: ", GetBuildInfo(), "\n"); + summary += FilterEmptySection("Timestamp: ", FormatTimestamp(output[CrashSection::TIME_STAMP]), ""); + summary += FilterEmptySection("Pid: ", output[CrashSection::PID], "\n"); + summary += FilterEmptySection("Uid: ", output[CrashSection::UID], "\n"); + summary += FilterEmptySection("Process name: ", output[CrashSection::PROCESS_NAME], "\n"); + summary += FilterEmptySection("Reason: ", KERNEL_SNAPSHOT_REASON, "\n"); + summary += FilterEmptySection("Exception registers:\n", output[CrashSection::EXCEPTION_REGISTERS], ""); + summary += FilterEmptySection("Fault thread info:\n", output[CrashSection::FAULT_THREAD_INFO], ""); + summary += FilterEmptySection("Registers:\n", output[CrashSection::CREGISTERS], ""); + if (!isLocal) { + summary += FilterEmptySection("Memory near registers:\n", output[CrashSection::MEMORY_NEAR_REGISTERS], ""); + summary += FilterEmptySection("FaultStack:\n", output[CrashSection::FAULT_STACK], ""); + } + summary += FilterEmptySection("Elfs:\n", output[CrashSection::MAPS], ""); + return summary; +} +} +} // namespace HiviewDFX +} // namespace OHOS diff --git a/services/snapshot/kernel_snapshot_util.h b/services/snapshot/kernel_snapshot_util.h new file mode 100644 index 000000000..defaa3b17 --- /dev/null +++ b/services/snapshot/kernel_snapshot_util.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KERNEL_SNAPSHOT_UTIL_H +#define KERNEL_SNAPSHOT_UTIL_H +#include +#include "kernel_snapshot_data.h" + +namespace OHOS { +namespace HiviewDFX { +namespace KernelSnapshotUtil { +std::string FilterEmptySection(const std::string& secHead, const std::string& secCont, const std::string& end); +std::string FormatTimestamp(const std::string& timestamp); +std::string GetBuildInfo(); +std::string FillSummary(CrashMap& output, bool isLocal = false); +} +} // namespace HiviewDFX +} // namespace OHOS +#endif diff --git a/test/resource/ohos_test.xml b/test/resource/ohos_test.xml index f49008d9f..dd424b35a 100644 --- a/test/resource/ohos_test.xml +++ b/test/resource/ohos_test.xml @@ -57,4 +57,11 @@