Fix crashes when the phone signal does not allow the use of malloc related functions

Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IABHLM?from=project-issue
Signed-off-by: harryhrp <herongpeng@huawei.com>
Change-Id: Ibfffc984049a97f5a295915b5cd7935c73f33704

Change-Id: Iee9c74ea23bf2983e3c238e5974d3026ffba5e5b
This commit is contained in:
harryhrp 2024-07-08 22:10:37 +08:00
parent c40f00d60f
commit 5ba737abfa
23 changed files with 928 additions and 415 deletions

View File

@ -1035,12 +1035,14 @@ if (is_mingw) {
"ecmascript/platform/windows/os.cpp",
"ecmascript/platform/windows/time.cpp",
"ecmascript/platform/windows/log.cpp",
"ecmascript/platform/windows/aot_crash_info.cpp",
]
} else {
ecma_platform_source += [
"ecmascript/platform/unix/file.cpp",
"ecmascript/platform/unix/map.cpp",
"ecmascript/platform/unix/time.cpp",
"ecmascript/platform/unix/aot_crash_info.cpp",
]
if (is_mac) {
ecma_platform_source += [

View File

@ -28,9 +28,9 @@
#include "ecmascript/log.h"
#include "ecmascript/log_wrapper.h"
#include "ecmascript/napi/include/jsnapi.h"
#include "ecmascript/ohos/aot_crash_info.h"
#include "ecmascript/ohos/enable_aot_list_helper.h"
#include "ecmascript/ohos/ohos_pkg_args.h"
#include "ecmascript/platform/aot_crash_info.h"
#include "ecmascript/platform/file.h"
#include "ecmascript/platform/filesystem.h"
#include "ecmascript/platform/os.h"
@ -121,7 +121,7 @@ int Main(const int argc, const char **argv)
}
if (IsExistsPkgInfo(cPreprocessor)) {
if (ohos::AotCrashInfo::IsAotEscape(cPreprocessor.GetMainPkgArgs()->GetPgoDir())) {
if (AotCrashInfo::IsAotEscaped(cPreprocessor.GetMainPkgArgs()->GetPgoDir())) {
LOG_COMPILER(ERROR) << "Stop compile AOT because there are multiple crashes";
return ERR_FAIL;
}

View File

@ -24,8 +24,8 @@
#include "ecmascript/jspandafile/program_object.h"
#include "ecmascript/mem/heap-inl.h"
#include "ecmascript/message_string.h"
#include "ecmascript/ohos/aot_crash_info.h"
#include "ecmascript/ohos/aot_runtime_info.h"
#include "ecmascript/platform/aot_crash_info.h"
#include "ecmascript/platform/os.h"
#include "ecmascript/stubs/runtime_stubs-inl.h"
#if defined(PANDA_TARGET_OHOS)
@ -157,7 +157,7 @@ void JsStackInfo::DumpJitCode(JSThread *thread)
}
std::string fileName = "jitCode-" + std::to_string(getpid());
std::string realOutPath;
std::string sanboxPath = panda::os::file::File::GetExtendedFilePath(ohos::AotCrashInfo::GetSandBoxPath());
std::string sanboxPath = panda::os::file::File::GetExtendedFilePath(AotCrashInfo::GetSandBoxPath());
if (!ecmascript::RealPath(sanboxPath, realOutPath, false)) {
return;
}
@ -246,12 +246,10 @@ std::string JsStackInfo::BuildJsStackTraceInfo(JSThread *thread, Method *method,
void JsStackInfo::BuildCrashInfo(bool isJsCrash, FrameType frameType, JSThread *thread)
{
if (JsStackInfo::loader == nullptr || JsStackInfo::options == nullptr) {
LOG_ECMA(ERROR) << "Loader or options initialization error.";
return;
}
if (!JsStackInfo::loader->IsEnableAOT() && !JsStackInfo::options->IsEnableJIT() &&
!JsStackInfo::options->IsEnablePGOProfiler()) {
LOG_ECMA(INFO) << "Neither AOT nor JIT is enabled.";
return;
}
ohos::RuntimeInfoType type;
@ -259,13 +257,13 @@ void JsStackInfo::BuildCrashInfo(bool isJsCrash, FrameType frameType, JSThread *
type = ohos::RuntimeInfoType::JS;
} else if (frameType == FrameType::OPTIMIZED_JS_FUNCTION_FRAME ||
frameType == FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME) {
type = ohos::RuntimeInfoType::AOT;
type = ohos::RuntimeInfoType::AOT_CRASH;
} else if (IsFastJitFunctionFrame(frameType)) {
type = ohos::RuntimeInfoType::JIT;
} else {
type = ohos::RuntimeInfoType::OTHERS;
}
ohos::AotRuntimeInfo::GetInstance().BuildCrashRuntimeInfo(ohos::AotRuntimeInfo::GetRuntimeInfoTypeStr(type));
ohos::AotRuntimeInfo::GetInstance().BuildCrashRuntimeInfo(type);
if (isJsCrash) {
DumpJitCode(thread);
}

View File

@ -44,8 +44,8 @@
#include "ecmascript/module/module_path_helper.h"
#include "ecmascript/module/js_shared_module.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/ohos/aot_crash_info.h"
#include "ecmascript/patch/patch_loader.h"
#include "ecmascript/platform/aot_crash_info.h"
#include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
#include "ecmascript/require/js_cjs_module_cache.h"
#include "ecmascript/require/js_require_manager.h"
@ -1105,7 +1105,7 @@ bool EcmaContext::LoadAOTFilesInternal(const std::string& aotFileName)
{
#ifdef AOT_ESCAPE_ENABLE
std::string bundleName = pgo::PGOProfilerManager::GetInstance()->GetBundleName();
if (ohos::AotCrashInfo::GetInstance().IsAotEscapeOrNotInEnableList(vm_, bundleName)) {
if (AotCrashInfo::GetInstance().IsAotEscapedOrNotInEnableList(vm_, bundleName)) {
return false;
}
#endif

View File

@ -92,10 +92,10 @@
#include "ecmascript/tagged_queue.h"
#include "ecmascript/taskpool/task.h"
#include "ecmascript/taskpool/taskpool.h"
#include "ecmascript/ohos/aot_crash_info.h"
#include "ecmascript/ohos/enable_aot_list_helper.h"
#include "ecmascript/ohos/jit_tools.h"
#include "ecmascript/ohos/aot_tools.h"
#include "ecmascript/platform/aot_crash_info.h"
#if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
#include "parameters.h"
@ -104,54 +104,11 @@
namespace panda::ecmascript {
using RandomGenerator = base::RandomGenerator;
using PGOProfilerManager = pgo::PGOProfilerManager;
using AotCrashInfo = ohos::AotCrashInfo;
using JitTools = ohos::JitTools;
AOTFileManager *JsStackInfo::loader = nullptr;
JSRuntimeOptions *JsStackInfo::options = nullptr;
bool EcmaVM::multiThreadCheck_ = false;
#ifdef JIT_ESCAPE_ENABLE
static struct sigaction s_oldSa[SIGSYS + 1]; // SIGSYS = 31
void GetSignalHandler(int signal, siginfo_t *info, void *context)
{
#if defined(__aarch64__) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS)
ucontext_t *ucontext = static_cast<ucontext_t*>(context);
uintptr_t fp = ucontext->uc_mcontext.regs[29];
FrameIterator frame(reinterpret_cast<JSTaggedType *>(fp));
ecmascript::JsStackInfo::BuildCrashInfo(false, frame.GetFrameType());
#else
ecmascript::JsStackInfo::BuildCrashInfo(false);
#endif
sigaction(signal, &s_oldSa[signal], nullptr);
int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), syscall(SYS_gettid), info->si_signo, info);
if (rc != 0) {
LOG_ECMA(ERROR) << "GetSignalHandler() failed to resend signal during crash";
}
}
void SignalReg(int signo)
{
sigaction(signo, nullptr, &s_oldSa[signo]);
struct sigaction newAction;
newAction.sa_flags = SA_RESTART | SA_SIGINFO;
newAction.sa_sigaction = GetSignalHandler;
sigaction(signo, &newAction, nullptr);
}
void SignalAllReg()
{
SignalReg(SIGABRT);
SignalReg(SIGBUS);
SignalReg(SIGSEGV);
SignalReg(SIGILL);
SignalReg(SIGKILL);
SignalReg(SIGSTKFLT);
SignalReg(SIGFPE);
SignalReg(SIGTRAP);
}
#endif
EcmaVM *EcmaVM::Create(const JSRuntimeOptions &options)
{
Runtime::CreateIfFirstVm(options);
@ -212,21 +169,15 @@ void EcmaVM::PostFork()
Taskpool::GetCurrentTaskpool()->Initialize();
SetPostForked(true);
LOG_ECMA(INFO) << "multi-thread check enabled: " << options_.EnableThreadCheck();
#if defined(JIT_ESCAPE_ENABLE) || defined(AOT_ESCAPE_ENABLE)
SignalAllReg();
#endif
SharedHeap::GetInstance()->EnableParallelGC(GetJSOptions());
DaemonThread::GetInstance()->StartRunning();
heap_->EnableParallelGC();
std::string bundleName = PGOProfilerManager::GetInstance()->GetBundleName();
pgo::PGOTrace::GetInstance()->SetEnable(ohos::AotTools::GetPgoTraceEnable());
#ifdef AOT_ESCAPE_ENABLE
AotCrashInfo::GetInstance().SetOptionPGOProfiler(&options_, bundleName);
#endif
ResetPGOProfiler();
#ifdef JIT_ESCAPE_ENABLE
ohos::JitTools::GetInstance().SetJitEnable(this, bundleName);
#endif
#ifdef ENABLE_POSTFORK_FORCEEXPAND
heap_->NotifyPostFork();
heap_->NotifyFinishColdStartSoon();

View File

@ -24,7 +24,7 @@
#include "ecmascript/dfx/vmstat/jit_warmup_profiler.h"
#include "ecmascript/ohos/jit_tools.h"
#include "ecmascript/dfx/dump_code/jit_dump_elf.h"
#include "ecmascript/ohos/aot_crash_info.h"
#include "ecmascript/platform/aot_crash_info.h"
namespace panda::ecmascript {
@ -222,7 +222,7 @@ void DumpJitCode(JSHandle<MachineCode> &machineCode, JSHandle<Method> &method)
fileName = fileName + "_" + std::to_string(addr) + "+" + std::to_string(len);
jitDumpElf.AppendSymbolToSymTab(0, 0, len, std::string(filename));
std::string realOutPath;
std::string sanboxPath = panda::os::file::File::GetExtendedFilePath(ohos::AotCrashInfo::GetSandBoxPath());
std::string sanboxPath = panda::os::file::File::GetExtendedFilePath(AotCrashInfo::GetSandBoxPath());
if (!ecmascript::RealPath(sanboxPath, realOutPath, false)) {
return;
}

View File

@ -92,10 +92,10 @@
#include "ecmascript/serializer/value_serializer.h"
#include "ecmascript/tagged_array.h"
#include "ecmascript/js_weak_container.h"
#include "ecmascript/ohos/aot_crash_info.h"
#include "ecmascript/ohos/aot_runtime_info.h"
#include "ecmascript/ohos/enable_aot_list_helper.h"
#include "ecmascript/ohos/framework_helper.h"
#include "ecmascript/platform/aot_crash_info.h"
#ifdef ARK_SUPPORT_INTL
#include "ecmascript/js_bigint.h"
#include "ecmascript/js_collator.h"
@ -202,11 +202,9 @@ using ModulePathHelper = ecmascript::ModulePathHelper;
using JsDebuggerManager = ecmascript::tooling::JsDebuggerManager;
using FrameIterator = ecmascript::FrameIterator;
using Concurrent = ecmascript::Concurrent;
using CrashInfo = ecmascript::ohos::AotCrashInfo;
using EnableAotJitListHelper = ecmascript::ohos::EnableAotJitListHelper;
using PGOProfilerManager = ecmascript::pgo::PGOProfilerManager;
using AotRuntimeInfo = ecmascript::ohos::AotRuntimeInfo;
using AotCrashInfo = ecmascript::ohos::AotCrashInfo;
namespace {
// NOLINTNEXTLINE(fuchsia-statically-constructed-objects)

View File

@ -1,130 +0,0 @@
/*
* 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.
*/
#ifndef ECMASCRIPT_COMPILER_OHOS_AOT_CRASH_INFO_H
#define ECMASCRIPT_COMPILER_OHOS_AOT_CRASH_INFO_H
#include "ohos_constants.h"
#include "ecmascript/base/string_helper.h"
#include "ecmascript/ohos/aot_runtime_info.h"
#include "ecmascript/ohos/enable_aot_list_helper.h"
#ifdef AOT_ESCAPE_ENABLE
#include "parameters.h"
#endif
namespace panda::ecmascript::ohos {
class AotCrashInfo {
constexpr static const char *const SPLIT_STR = "|";
constexpr static const char *const AOT_ESCAPE_DISABLE = "ark.aot.escape.disable";
constexpr static int AOT_CRASH_COUNT = 1;
constexpr static int OTHERS_CRASH_COUNT = 3;
constexpr static int CRASH_LOG_SIZE = 3;
constexpr static int JIT_CRASH_COUNT = 1;
constexpr static int JS_CRASH_COUNT = 3;
public:
explicit AotCrashInfo() = default;
virtual ~AotCrashInfo() = default;
static AotCrashInfo &GetInstance()
{
static AotCrashInfo singleAotCrashInfo;
return singleAotCrashInfo;
}
bool IsAotEscapeOrNotInEnableList(EcmaVM *vm, const std::string &bundleName) const
{
if (!vm->GetJSOptions().WasAOTOutputFileSet() &&
!EnableAotJitListHelper::GetInstance()->IsEnableAot(bundleName)) {
LOG_ECMA(INFO) << "Stop load AOT because it's not in enable list";
return true;
}
if (IsAotEscape()) {
LOG_ECMA(INFO) << "Stop load AOT because there are more crashes";
return true;
}
return false;
}
void SetOptionPGOProfiler(JSRuntimeOptions *options, const std::string &bundleName) const
{
if (EnableAotJitListHelper::GetInstance()->IsEnableAot(bundleName)) {
options->SetEnablePGOProfiler(true);
}
if (EnableAotJitListHelper::GetInstance()->IsAotCompileSuccessOnce()) {
options->SetEnablePGOProfiler(false);
LOG_ECMA(INFO) << "Aot has compile success once.";
}
if (IsAotEscape()) {
options->SetEnablePGOProfiler(false);
LOG_ECMA(INFO) << "Aot has escaped.";
}
}
static bool IsAotEscape(const std::string &pgoRealPath = "")
{
if (GetAotEscapeDisable()) {
return false;
}
auto escapeMap = AotRuntimeInfo::GetInstance().CollectCrashSum(pgoRealPath);
return escapeMap[RuntimeInfoType::AOT] >= GetAotCrashCount() ||
escapeMap[RuntimeInfoType::OTHERS] >= GetOthersCrashCount() ||
escapeMap[RuntimeInfoType::JS] >= GetJsCrashCount();
}
static bool IsJitEscape()
{
auto escapeMap = AotRuntimeInfo::GetInstance().CollectCrashSum();
return escapeMap[RuntimeInfoType::JIT] >= GetJitCrashCount() ||
escapeMap[RuntimeInfoType::AOT] >= GetAotCrashCount() ||
escapeMap[RuntimeInfoType::OTHERS] >= GetOthersCrashCount() ||
escapeMap[RuntimeInfoType::JS] >= GetJsCrashCount();
}
static bool GetAotEscapeDisable()
{
#ifdef AOT_ESCAPE_ENABLE
return OHOS::system::GetBoolParameter(AOT_ESCAPE_DISABLE, false);
#endif
return false;
}
static std::string GetSandBoxPath()
{
return OhosConstants::SANDBOX_ARK_PROFILE_PATH;
}
static int GetAotCrashCount()
{
return AOT_CRASH_COUNT;
}
static int GetJitCrashCount()
{
return JIT_CRASH_COUNT;
}
static int GetJsCrashCount()
{
return JS_CRASH_COUNT;
}
static int GetOthersCrashCount()
{
return OTHERS_CRASH_COUNT;
}
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_COMPILER_OHOS_AOT_CRASH_INFO_H

View File

@ -17,6 +17,8 @@
#define ECMASCRIPT_COMPILER_OHOS_RUNTIME_BUILD_INFO_H
#include <sys/time.h>
#include <fcntl.h>
#include <stdio.h>
#include "ecmascript/platform/directory.h"
#include "ecmascript/platform/file.h"
@ -29,7 +31,7 @@
namespace panda::ecmascript::ohos {
#define RUNTIME_INFO_TYPE(V) \
V(AOT) \
V(AOT_CRASH) \
V(OTHERS) \
V(NONE) \
V(JIT) \
@ -37,46 +39,27 @@ namespace panda::ecmascript::ohos {
V(AOT_BUILD) \
enum class RuntimeInfoType {
AOT,
AOT_CRASH,
JIT,
OTHERS,
NONE,
JS,
AOT_BUILD,
};
struct RuntimeInfoPart {
std::string buildId;
std::string timestamp;
std::string type;
RuntimeInfoPart() = default;
RuntimeInfoPart(const std::string &buildId, const std::string &timestamp, const std::string &type)
: buildId(buildId), timestamp(timestamp), type(type)
{
}
};
/*
* The JSON format is as follows
* type: "AOT_BUILD" Used at compile time,
* "AOT", "JIT", "OTHERS", "JS" Used at crash time.
* {"key":
* [
* {"buildId":"xxxxxx", "timestamp":"123456789", "type":"AOT"},
* {"buildId":"xxxxxx", "timestamp":"123456789", "type":"AOT"}
* ]
* }
*/
class AotRuntimeInfo {
public:
constexpr static const int USEC_PER_SEC = 1000 * 1000;
constexpr static const int NSEC_PER_USEC = 1000;
constexpr static const int NT_GNU_BUILD_ID = 3;
constexpr static const int CRASH_INFO_SIZE = 3;
constexpr static const char *const RUNTIME_INFO_ARRAY_KEY = "runtime_info_array";
constexpr static const char *const RUNTIME_KEY_BUILDID = "buildId";
constexpr static const char *const RUNTIME_KEY_TIMESTAMP = "timestamp";
constexpr static const char *const RUNTIME_KEY_TYPE = "type";
constexpr static const int MAX_LENGTH = 255;
constexpr static const int BUFFER_SIZE = 4096;
constexpr static const int TIME_STAMP_SIZE = 21;
constexpr static const int RUNTIME_INDEX_BUILDID = 0;
constexpr static const int RUNTIME_INDEX_TIMESTAMP = 1;
constexpr static const int RUNTIME_INDEX_TYPE = 2;
static AotRuntimeInfo &GetInstance()
{
@ -84,40 +67,70 @@ public:
return singleAotRuntimeInfo;
}
void BuildCompileRuntimeInfo(const std::string &type, const std::string &pgoPath) const
void BuildCompileRuntimeInfo(RuntimeInfoType type, const std::string &pgoPath) const
{
std::string soBuildId = GetRuntimeBuildId();
if (soBuildId == "") {
static char soBuildId[NAME_MAX];
if (!GetRuntimeBuildId(soBuildId)) {
return;
}
if (IsCharEmpty(soBuildId)) {
LOG_ECMA(INFO) << "can't get so buildId.";
return;
}
std::string realOutPath;
std::string runtimePgoRealPath = pgoPath + OhosConstants::PATH_SEPARATOR + OhosConstants::AOT_RUNTIME_INFO_NAME;
if (!ecmascript::RealPath(runtimePgoRealPath, realOutPath, false)) {
if (!ecmascript::RealPath(pgoPath, realOutPath, false)) {
LOG_ECMA(INFO) << "Build compile pgo path fail.";
return;
}
std::vector<RuntimeInfoPart> lines = GetRuntimeInfoByPath(realOutPath, soBuildId);
uint64_t timestamp = GetMicrosecondsTimeStamp();
RuntimeInfoPart buildLine = RuntimeInfoPart(soBuildId, std::to_string(timestamp), type);
lines.emplace_back(buildLine);
SetRuntimeInfo(realOutPath, lines);
}
void BuildCrashRuntimeInfo(const std::string &type) const
{
std::string soBuildId = GetRuntimeBuildId();
if (soBuildId == "") {
LOG_ECMA(INFO) << "can't get so buildId.";
static char lines[MAX_LENGTH][BUFFER_SIZE];
for (int i = 0; i < MAX_LENGTH; i++) {
memset_s(lines[i], BUFFER_SIZE, '\0', BUFFER_SIZE);
}
GetRuntimeInfoByPath(lines, realOutPath.c_str(), soBuildId);
static char timestamp[TIME_STAMP_SIZE] = { '\0' };
if (!GetMicrosecondsTimeStamp(timestamp)) {
return;
}
std::vector<RuntimeInfoPart> lines = GetCrashRuntimeInfoList();
uint64_t timestamp = GetMicrosecondsTimeStamp();
RuntimeInfoPart buildLine = RuntimeInfoPart(soBuildId, std::to_string(timestamp), type);
lines.emplace_back(buildLine);
std::string realOutPath = GetCrashSandBoxRealPath();
if (realOutPath == "") {
LOG_ECMA(INFO) << "Get crash sanbox path fail.";
int lineCount = getLength(lines, MAX_LENGTH);
if (lineCount < MAX_LENGTH) {
if (!BuildRuntimeInfoPart(lines[lineCount], soBuildId, timestamp, type)) {
return;
}
}
SetRuntimeInfo(realOutPath.c_str(), lines);
}
void BuildCrashRuntimeInfo(RuntimeInfoType type) const
{
static char soBuildId[NAME_MAX];
if (!GetRuntimeBuildId(soBuildId)) {
return;
}
if (IsCharEmpty(soBuildId)) {
return;
}
static char lines[MAX_LENGTH][BUFFER_SIZE];
for (int i = 0; i < MAX_LENGTH; i++) {
memset_s(lines[i], BUFFER_SIZE, '\0', BUFFER_SIZE);
}
GetCrashRuntimeInfoList(lines);
static char timestamp[TIME_STAMP_SIZE] = { '\0' };
if (!GetMicrosecondsTimeStamp(timestamp)) {
return;
}
int lineCount = getLength(lines, MAX_LENGTH);
if (lineCount < MAX_LENGTH) {
if (!BuildRuntimeInfoPart(lines[lineCount], soBuildId, timestamp, type)) {
return;
}
}
static char realOutPath[PATH_MAX];
if (!GetCrashSandBoxRealPath(realOutPath)) {
return;
}
if (IsCharEmpty(realOutPath)) {
return;
}
SetRuntimeInfo(realOutPath, lines);
@ -137,34 +150,47 @@ public:
if (IsLoadedMap()) {
return escapeMap_;
}
std::vector<RuntimeInfoPart> runtimeInfoParts;
if (pgoRealPath == "") {
runtimeInfoParts = GetCrashRuntimeInfoList();
char lines[MAX_LENGTH][BUFFER_SIZE];
if (IsCharEmpty(pgoRealPath.c_str())) {
GetCrashRuntimeInfoList(lines);
} else {
runtimeInfoParts = GetRealPathRuntimeInfoList(pgoRealPath);
GetRealPathRuntimeInfoList(lines, pgoRealPath);
}
for (const auto &runtimeInfoPart: runtimeInfoParts) {
RuntimeInfoType runtimeInfoType = GetRuntimeInfoTypeByStr(runtimeInfoPart.type);
escapeMap_[runtimeInfoType]++;
char *typeChar = new char[NAME_MAX];
for (int i = 0; i < MAX_LENGTH; i++) {
if (lines[i][0] != '\0') {
if (strcpy_s(typeChar, NAME_MAX, GetInfoFromBuffer(lines[i], RUNTIME_INDEX_TYPE)) !=0) {
continue;
}
std::string typeStr(typeChar);
escapeMap_[GetRuntimeInfoTypeByStr(typeStr)]++;
}
}
SetLoadedMap(true);
return escapeMap_;
}
static std::string GetRuntimeInfoTypeStr(RuntimeInfoType type)
const char *GetRuntimeInfoTypeStr(const RuntimeInfoType type) const
{
const std::map<RuntimeInfoType, const char *> strMap = {
#define RUNTIME_INFO_TYPE_MAP(name) { RuntimeInfoType::name, #name },
RUNTIME_INFO_TYPE(RUNTIME_INFO_TYPE_MAP)
#undef RUNTIME_INFO_TYPE_MAP
};
if (strMap.count(type) > 0) {
return strMap.at(type);
switch (type) {
case RuntimeInfoType::AOT_CRASH:
return "AOT_CRASH";
case RuntimeInfoType::JIT:
return "JIT";
case RuntimeInfoType::OTHERS:
return "OTHERS";
case RuntimeInfoType::NONE:
return "NONE";
case RuntimeInfoType::JS:
return "JS";
case RuntimeInfoType::AOT_BUILD:
return "AOT_BUILD";
default:
return "NONE";
}
return "";
}
static RuntimeInfoType GetRuntimeInfoTypeByStr(std::string type)
RuntimeInfoType GetRuntimeInfoTypeByStr(std::string &type) const
{
const std::map<std::string, RuntimeInfoType> strMap = {
#define RUNTIME_INFO_TYPE_MAP(name) { #name, RuntimeInfoType::name },
@ -177,149 +203,195 @@ public:
return RuntimeInfoType::NONE;
}
private:
std::vector<RuntimeInfoPart> GetCrashRuntimeInfoList() const
virtual bool GetRuntimeBuildId(char *buildId) const
{
std::string realOutPath = GetCrashSandBoxRealPath();
std::vector<RuntimeInfoPart> list;
if (!FileExist(realOutPath.c_str())) {
LOG_ECMA(INFO) << "Get crash sanbox path fail.";
return list;
}
std::string soBuildId = GetRuntimeBuildId();
if (soBuildId == "") {
LOG_ECMA(INFO) << "can't get so buildId.";
return list;
}
list = GetRuntimeInfoByPath(realOutPath, soBuildId);
return list;
}
std::vector<RuntimeInfoPart> GetRealPathRuntimeInfoList(const std::string &pgoRealPath) const
{
std::vector<RuntimeInfoPart> list;
std::string realOutPath;
std::string runtimePgoRealPath = pgoRealPath + OhosConstants::PATH_SEPARATOR +
OhosConstants::AOT_RUNTIME_INFO_NAME;
if (!ecmascript::RealPath(runtimePgoRealPath, realOutPath, false)) {
return list;
}
if (!FileExist(realOutPath.c_str())) {
LOG_ECMA(INFO) << "Get pgo real path fail.";
return list;
}
std::string soBuildId = GetRuntimeBuildId();
if (soBuildId == "") {
LOG_ECMA(INFO) << "can't get so buildId.";
return list;
}
list = GetRuntimeInfoByPath(realOutPath, soBuildId);
return list;
}
std::string GetRuntimeBuildId() const
{
std::string realPath;
if (!FileExist(OhosConstants::RUNTIME_SO_PATH)) {
return "";
return false;
}
std::string soPath = panda::os::file::File::GetExtendedFilePath(OhosConstants::RUNTIME_SO_PATH);
if (!ecmascript::RealPath(soPath, realPath, false)) {
return "";
static char realPath[PATH_MAX] = { '\0' };
if (!ecmascript::RealPathByChar(OhosConstants::RUNTIME_SO_PATH, realPath, PATH_MAX, false)) {
return false;
}
if (!FileExist(realPath.c_str())) {
return "";
if (!FileExist(realPath)) {
return false;
}
ecmascript::MemMap fileMap = ecmascript::FileMap(realPath.c_str(), FILE_RDONLY, PAGE_PROT_READ);
ecmascript::MemMap fileMap = ecmascript::FileMap(realPath, FILE_RDONLY, PAGE_PROT_READ);
if (fileMap.GetOriginAddr() == nullptr) {
LOG_ECMA(INFO) << "runtime info file mmap failed";
return "";
return false;
}
std::string buildId = ParseELFSectionsForBuildId(fileMap);
ParseELFSectionsForBuildId(fileMap, buildId);
ecmascript::FileUnMap(fileMap);
fileMap.Reset();
return buildId;
return true;
}
uint64_t GetMicrosecondsTimeStamp() const
virtual bool GetMicrosecondsTimeStamp(char *timestamp) const
{
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
return time.tv_sec * USEC_PER_SEC + time.tv_nsec / NSEC_PER_USEC;
}
void SetRuntimeInfo(const std::string &realOutPath, std::vector<RuntimeInfoPart> &runtimeInfoParts) const
{
std::ofstream file(realOutPath.c_str(), std::ofstream::out);
JsonObjectBuilder objBuilder;
auto arrayObject = [runtimeInfoParts](JsonArrayBuilder &arrayBuilder) {
for (const auto &runtimeInfoPart : runtimeInfoParts) {
auto addObj = [runtimeInfoPart](JsonObjectBuilder &obj) {
obj.AddProperty(RUNTIME_KEY_BUILDID, runtimeInfoPart.buildId);
obj.AddProperty(RUNTIME_KEY_TIMESTAMP, runtimeInfoPart.timestamp);
obj.AddProperty(RUNTIME_KEY_TYPE, runtimeInfoPart.type);
};
arrayBuilder.Add(addObj);
}
};
objBuilder.AddProperty(RUNTIME_INFO_ARRAY_KEY, arrayObject);
if (file.is_open()) {
file << std::move(objBuilder).Build();
file.close();
} else {
LOG_ECMA(INFO) << "open file to set runtime info fail :" << realOutPath.c_str();
time_t current_time;
if (time(&current_time) == -1) {
return false;
}
}
std::vector<RuntimeInfoPart> GetRuntimeInfoByPath(const std::string &realOutPath,
const std::string &soBuildId) const
{
std::ifstream ifile(realOutPath.c_str());
std::vector<RuntimeInfoPart> infoParts;
if (ifile.is_open()) {
std::string jsonStr((std::istreambuf_iterator<char>(ifile)), std::istreambuf_iterator<char>());
JsonObject obj(jsonStr);
if (obj.GetValue<JsonObject::ArrayT>(RUNTIME_INFO_ARRAY_KEY) == nullptr) {
ifile.close();
return infoParts;
}
auto &mainArray = *obj.GetValue<JsonObject::ArrayT>(RUNTIME_INFO_ARRAY_KEY);
for (size_t i = 0; i < mainArray.size(); i++) {
if (mainArray[i].Get<JsonObject::JsonObjPointer>() == nullptr) {
continue;
}
auto &innerObj = *(mainArray[i]).Get<JsonObject::JsonObjPointer>()->get();
auto buildId = innerObj.GetValue<JsonObject::StringT>(RUNTIME_KEY_BUILDID);
auto timestamp = innerObj.GetValue<JsonObject::StringT>(RUNTIME_KEY_TIMESTAMP);
auto type = innerObj.GetValue<JsonObject::StringT>(RUNTIME_KEY_TYPE);
if (buildId == nullptr || timestamp == nullptr || type == nullptr) {
LOG_ECMA(INFO) << "runtime info get wrong json object info.";
continue;
}
std::string buildIdStr = *buildId;
if (buildIdStr != soBuildId) {
continue;
}
infoParts.emplace_back(RuntimeInfoPart(*buildId, *timestamp, *type));
}
ifile.close();
struct tm *local_time = localtime(&current_time);
if (local_time == NULL) {
return false;
}
return infoParts;
int result = strftime(timestamp, TIME_STAMP_SIZE, "%Y-%m-%d %H:%M:%S", local_time);
if (result == 0) {
return false;
}
return true;
}
std::string GetCrashSandBoxRealPath() const
virtual bool GetCrashSandBoxRealPath(char *realOutPath) const
{
if (!ecmascript::RealPathByChar(OhosConstants::SANDBOX_ARK_PROFILE_PATH, realOutPath, PATH_MAX, false)) {
return false;
}
if (strcat_s(realOutPath, NAME_MAX, OhosConstants::PATH_SEPARATOR) != 0) {
return false;
}
if (strcat_s(realOutPath, NAME_MAX, OhosConstants::AOT_RUNTIME_INFO_NAME) !=0) {
return false;
}
return true;
}
protected:
bool IsCharEmpty(const char *value) const
{
if (value == NULL || *value == '\0') {
return true;
}
return false;
}
bool BuildRuntimeInfoPart(char *runtimeInfoPart, const char *soBuildId, const char *timestamp,
RuntimeInfoType type) const
{
if (strcat_s(runtimeInfoPart, NAME_MAX, soBuildId) != 0) {
return false;
}
if (strcat_s(runtimeInfoPart, NAME_MAX, OhosConstants::SPLIT_STR) != 0) {
return false;
}
if (strcat_s(runtimeInfoPart, NAME_MAX, timestamp) != 0) {
return false;
}
if (strcat_s(runtimeInfoPart, NAME_MAX, OhosConstants::SPLIT_STR) != 0) {
return false;
}
if (strcat_s(runtimeInfoPart, NAME_MAX, GetRuntimeInfoTypeStr(type)) != 0) {
return false;
}
return true;
}
char *GetInfoFromBuffer(char *line, int index) const
{
char *saveptr;
char buffer[BUFFER_SIZE];
if (strncpy_s(buffer, BUFFER_SIZE - 1, line, sizeof(buffer) - 1) != 0) {
return NULL;
}
char *token = strtok_r(buffer, OhosConstants::SPLIT_STR, &saveptr);
for (int i = 0; i < index; i++) {
token = strtok_r(NULL, OhosConstants::SPLIT_STR, &saveptr);
}
return token;
}
int getLength(char lines[][BUFFER_SIZE], int maxInput) const
{
int count = 0;
for (int i = 0; i < maxInput; i++) {
if (lines[i][0] != '\0') {
count++;
}
}
return count;
}
void GetCrashRuntimeInfoList(char lines[][BUFFER_SIZE]) const
{
static char realOutPath[PATH_MAX];
if (!GetCrashSandBoxRealPath(realOutPath)) {
return;
}
if (!FileExist(realOutPath)) {
return;
}
static char soBuildId[NAME_MAX];
if (!GetRuntimeBuildId(soBuildId)) {
return;
}
if (IsCharEmpty(soBuildId)) {
return;
}
GetRuntimeInfoByPath(lines, realOutPath, soBuildId);
return;
}
void GetRealPathRuntimeInfoList(char lines[][BUFFER_SIZE], const std::string &pgoRealPath) const
{
std::string realOutPath;
std::string arkProfilePath = OhosConstants::SANDBOX_ARK_PROFILE_PATH;
std::string sanboxPath = panda::os::file::File::GetExtendedFilePath(arkProfilePath);
if (!ecmascript::RealPath(sanboxPath, realOutPath, false)) {
return "";
if (!ecmascript::RealPath(pgoRealPath, realOutPath, false)) {
return;
}
realOutPath = realOutPath + OhosConstants::PATH_SEPARATOR + OhosConstants::AOT_RUNTIME_INFO_NAME;
return realOutPath;
if (!FileExist(realOutPath.c_str())) {
return;
}
char soBuildId[NAME_MAX];
if (!GetRuntimeBuildId(soBuildId)) {
return;
}
if (IsCharEmpty(soBuildId)) {
return;
}
GetRuntimeInfoByPath(lines, realOutPath.c_str(), soBuildId);
}
std::string ParseELFSectionsForBuildId(ecmascript::MemMap &fileMap) const
void SetRuntimeInfo(const char *realOutPath, char lines[][BUFFER_SIZE]) const
{
int fd = open(realOutPath, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd == -1) {
return;
}
for (int i = 0; lines[i] != NULL && i < MAX_LENGTH; i++) {
if (lines[i][0] != '\0') {
write(fd, lines[i], strlen(lines[i]));
write(fd, "\n", 1);
}
}
close(fd);
}
void GetRuntimeInfoByPath(char lines[][BUFFER_SIZE], const char *realOutPath, const char *soBuildId) const
{
int fd = open(realOutPath, O_RDONLY);
if (fd == -1) {
return;
}
char buffer[BUFFER_SIZE];
char *saveptr;
char *token;
ssize_t bytesRead;
int lineCount = 0;
while ((bytesRead = read(fd, buffer, BUFFER_SIZE)) > 0) {
token = strtok_r(buffer, "\n", &saveptr);
while (token != NULL) {
if (strcmp(GetInfoFromBuffer(token, RUNTIME_INDEX_BUILDID), soBuildId) == 0 &&
lineCount < MAX_LENGTH &&
strcpy_s(lines[lineCount], BUFFER_SIZE, buffer) == 0) {
lineCount++;
}
token = strtok_r(NULL, "\n", &saveptr);
}
}
close(fd);
}
void ParseELFSectionsForBuildId(ecmascript::MemMap &fileMap, char *buildId) const
{
llvm::ELF::Elf64_Ehdr *ehdr = reinterpret_cast<llvm::ELF::Elf64_Ehdr *>(fileMap.GetOriginAddr());
char *addr = reinterpret_cast<char *>(ehdr);
@ -327,17 +399,17 @@ private:
ASSERT(ehdr->e_shstrndx != static_cast<llvm::ELF::Elf64_Half>(-1));
llvm::ELF::Elf64_Shdr strdr = shdr[ehdr->e_shstrndx];
int secId = -1;
std::string sectionName = ".note.gnu.build-id";
static const char sectionName[] = ".note.gnu.build-id";
for (size_t i = 0; i < ehdr->e_shnum; i++) {
llvm::ELF::Elf64_Word shName = shdr[i].sh_name;
char *curShName = reinterpret_cast<char *>(addr) + shName + strdr.sh_offset;
if (sectionName.compare(curShName) == 0) {
if (strcmp(sectionName, curShName) == 0) {
secId = static_cast<int>(i);
break;
}
}
if (secId == -1) {
return "";
return;
}
llvm::ELF::Elf64_Shdr secShdr = shdr[secId];
uint64_t buildIdOffset = secShdr.sh_offset;
@ -345,43 +417,37 @@ private:
llvm::ELF::Elf64_Nhdr *nhdr = reinterpret_cast<llvm::ELF::Elf64_Nhdr *>(addr + buildIdOffset);
char *curShNameForNhdr = reinterpret_cast<char *>(addr + buildIdOffset + sizeof(*nhdr));
if (buildIdSize - sizeof(*nhdr) < nhdr->n_namesz) {
return "";
}
std::string curShNameStr = curShNameForNhdr;
if (curShNameStr.back() == '\0') {
curShNameStr.resize(curShNameStr.size() - 1);
return;
}
if (curShNameStr != "GNU" || nhdr->n_type != NT_GNU_BUILD_ID) {
return "";
static const char gnu[] = "GNU";
if (strcmp(curShNameForNhdr, gnu) != 0 || nhdr->n_type != NT_GNU_BUILD_ID) {
return;
}
if ((buildIdSize - sizeof(*nhdr) - AlignValues(nhdr->n_namesz, 4) < nhdr->n_descsz) || nhdr->n_descsz == 0) {
return "";
return;
}
char *curShNameValueForNhdr = reinterpret_cast<char *>(addr + buildIdOffset + sizeof(*nhdr) +
AlignValues(nhdr->n_namesz, 4));
std::string curShNameValueForNhdrStr = curShNameValueForNhdr;
return GetReadableBuildId(curShNameValueForNhdrStr);
GetReadableBuildId(curShNameValueForNhdr, buildId);
}
std::string GetReadableBuildId(std::string &buildIdHex) const
void GetReadableBuildId(char *buildIdHex, char *buildId) const
{
if (buildIdHex.empty()) {
return "";
if (IsCharEmpty(buildIdHex)) {
return;
}
static const char HEXTABLE[] = "0123456789abcdef";
static const int HEXLENGTH = 16;
static const int HEX_EXPAND_PARAM = 2;
const size_t len = buildIdHex.length();
std::string buildId(len * HEX_EXPAND_PARAM, '\0');
const int len = strlen(buildIdHex);
for (size_t i = 0; i < len; i++) {
for (int i = 0; i < len; i++) {
unsigned int n = buildIdHex[i];
buildId[i * HEX_EXPAND_PARAM] = HEXTABLE[(n >> 4) % HEXLENGTH]; // 4 : higher 4 bit of uint8
buildId[i * HEX_EXPAND_PARAM + 1] = HEXTABLE[n % HEXLENGTH];
}
return buildId;
}
uint64_t AlignValues(uint64_t val, uint64_t align) const

View File

@ -29,7 +29,7 @@
#include "ecmascript/ohos/aot_runtime_info.h"
#include "macros.h"
#ifdef AOT_ESCAPE_ENABLE
#if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
#include "parameters.h"
#endif
namespace panda::ecmascript::ohos {
@ -74,7 +74,7 @@ public:
static bool GetAotBuildCountDisable()
{
#ifdef AOT_ESCAPE_ENABLE
#if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
return OHOS::system::GetBoolParameter(AOT_BUILD_COUNT_DISABLE, false);
#endif
return false;
@ -85,8 +85,11 @@ public:
if (!isCompileSuccess) {
return;
}
ohos::AotRuntimeInfo::GetInstance().BuildCompileRuntimeInfo(
ohos::AotRuntimeInfo::GetRuntimeInfoTypeStr(ohos::RuntimeInfoType::AOT_BUILD), pgoPath);
std::string runtimePgoRealPath = pgoPath;
runtimePgoRealPath.append(ohos::OhosConstants::PATH_SEPARATOR);
runtimePgoRealPath.append(ohos::OhosConstants::AOT_RUNTIME_INFO_NAME);
ohos::AotRuntimeInfo::GetInstance().BuildCompileRuntimeInfo(ohos::RuntimeInfoType::AOT_BUILD,
runtimePgoRealPath);
}
bool IsAotCompileSuccessOnce(const std::string &pgoRealPath = "") const

View File

@ -15,9 +15,9 @@
#ifndef ECMASCRIPT_JIT_TOOLS_H
#define ECMASCRIPT_JIT_TOOLS_H
#include "ecmascript/ohos/aot_crash_info.h"
#include "ecmascript/ohos/enable_aot_list_helper.h"
#include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
#include "ecmascript/platform/aot_crash_info.h"
#if defined(JIT_ESCAPE_ENABLE) || defined(GET_PARAMETER_FOR_JIT)
#include "base/startup/init/interfaces/innerkits/include/syspara/parameters.h"

View File

@ -43,15 +43,52 @@ host_unittest_action("OhosTest") {
external_deps += [ "zlib:libz" ]
}
host_unittest_action("CrashTest") {
module_out_path = module_output_path
sources = [
# test file
"crash_test.cpp",
"mock/mock_aot_runtime_info.cpp",
]
configs = [
"$js_root:ecma_test_config",
"$ark_root/assembler:arkassembler_public_config",
]
deps = [
"$ark_third_party_root/icu/icu4c:shared_icui18n",
"$ark_third_party_root/icu/icu4c:shared_icuuc",
"$js_root:libark_jsruntime_test",
"$js_root/ecmascript/compiler:libark_jsoptimizer_set",
sdk_libc_secshared_dep,
]
# hiviewdfx libraries
external_deps = hiviewdfx_ext_deps
deps += hiviewdfx_deps
external_deps += [ "zlib:libz" ]
}
group("unittest") {
testonly = true
deps = [ ":OhosTest" ]
deps = [
":CrashTest",
":OhosTest",
]
}
group("host_unittest") {
testonly = true
deps = [ ":OhosTestAction" ]
deps = [
":CrashTestAction",
":OhosTestAction",
]
if (is_mac) {
deps -= [ ":OhosTestAction" ]
deps -= [
":CrashTestAction",
":OhosTestAction",
]
}
}

View File

@ -0,0 +1,117 @@
/*
* 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 <cstdint>
#include <fstream>
#include <memory>
#include <string>
#include <utility>
#include <gtest/gtest.h>
#include "ecmascript/napi/include/jsnapi.h"
#include "ecmascript/ohos/aot_runtime_info.h"
#include "ecmascript/ohos/tests/mock/mock_aot_runtime_info.h"
#include "ecmascript/platform/aot_crash_info.h"
#include "ecmascript/platform/file.h"
#include "ecmascript/tests/test_helper.h"
using namespace panda;
using namespace panda::ecmascript;
using namespace panda::ecmascript::kungfu;
namespace panda::test {
class CrashTest : public testing::Test {
public:
static void SetUpTestCase()
{
GTEST_LOG_(INFO) << "SetUpTestCase";
}
static void TearDownTestCase()
{
GTEST_LOG_(INFO) << "TearDownCase";
}
void SetUp() override {}
void TearDown() override {}
MockAotRuntimeInfo mockAotRuntimeInfo;
protected:
EcmaVM *vm_ {nullptr};
};
HWTEST_F_L0(CrashTest, CrashGetBuildId)
{
char soBuildId[NAME_MAX];
ohos::AotRuntimeInfo *runtimeInfo = new MockAotRuntimeInfo();
runtimeInfo->GetRuntimeBuildId(soBuildId);
ASSERT_TRUE(std::string(soBuildId).size() > 0);
ASSERT_EQ(std::string(soBuildId), "abcd1234567890");
}
HWTEST_F_L0(CrashTest, GetMicrosecondsTimeStamp)
{
char timestamp[ohos::AotRuntimeInfo::TIME_STAMP_SIZE];
ohos::AotRuntimeInfo *runtimeInfo = new MockAotRuntimeInfo();
runtimeInfo->GetMicrosecondsTimeStamp(timestamp);
ASSERT_TRUE(std::string(timestamp).size() > 0);
ASSERT_EQ(std::string(timestamp), "1970-01-01 00:00:00");
}
HWTEST_F_L0(CrashTest, BuildCrashRuntimeInfo)
{
char timestamp[ohos::AotRuntimeInfo::TIME_STAMP_SIZE];
char soBuildId[NAME_MAX];
ohos::AotRuntimeInfo *runtimeInfo = new MockAotRuntimeInfo();
runtimeInfo->GetMicrosecondsTimeStamp(timestamp);
runtimeInfo->GetRuntimeBuildId(soBuildId);
char sanboxRealPath[PATH_MAX];
mkdir(MockAotRuntimeInfo::SANBOX_DIR, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
std::ofstream file(sanboxRealPath);
file.close();
runtimeInfo->GetCrashSandBoxRealPath(sanboxRealPath);
runtimeInfo->BuildCrashRuntimeInfo(ecmascript::ohos::RuntimeInfoType::AOT_CRASH);
std::map<ecmascript::ohos::RuntimeInfoType, int> escapeMap = runtimeInfo->CollectCrashSum();
ASSERT_EQ(escapeMap[ecmascript::ohos::RuntimeInfoType::AOT_CRASH], 1);
ASSERT_EQ(runtimeInfo->GetCompileCountByType(ecmascript::ohos::RuntimeInfoType::AOT_CRASH), 1);
unlink(sanboxRealPath);
rmdir(MockAotRuntimeInfo::SANBOX_DIR);
}
HWTEST_F_L0(CrashTest, BuildCompileRuntimeInfo)
{
char timestamp[ohos::AotRuntimeInfo::TIME_STAMP_SIZE];
char soBuildId[NAME_MAX];
ohos::AotRuntimeInfo *runtimeInfo = new MockAotRuntimeInfo();
runtimeInfo->GetMicrosecondsTimeStamp(timestamp);
runtimeInfo->GetRuntimeBuildId(soBuildId);
char sanboxRealPath[PATH_MAX];
mkdir(MockAotRuntimeInfo::SANBOX_DIR, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
std::ofstream file(sanboxRealPath);
file.close();
runtimeInfo->GetCrashSandBoxRealPath(sanboxRealPath);
runtimeInfo->BuildCompileRuntimeInfo(ecmascript::ohos::RuntimeInfoType::AOT_CRASH, sanboxRealPath);
std::map<ecmascript::ohos::RuntimeInfoType, int> escapeMapRealPath = runtimeInfo->CollectCrashSum(sanboxRealPath);
ASSERT_EQ(escapeMapRealPath[ecmascript::ohos::RuntimeInfoType::AOT_CRASH], 1);
ASSERT_EQ(runtimeInfo->GetCompileCountByType(ecmascript::ohos::RuntimeInfoType::AOT_CRASH, sanboxRealPath), 1);
unlink(sanboxRealPath);
rmdir(MockAotRuntimeInfo::SANBOX_DIR);
}
} // namespace panda::test

View File

@ -0,0 +1,60 @@
/*
* 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 "ecmascript/ohos/tests/mock/mock_aot_runtime_info.h"
namespace panda::test {
MockAotRuntimeInfo::MockAotRuntimeInfo()
{}
MockAotRuntimeInfo::~MockAotRuntimeInfo()
{}
bool MockAotRuntimeInfo::GetRuntimeBuildId(char *buildId) const
{
char tmp[NAME_MAX] = "abcd1234567890";
if (strcpy_s(buildId, NAME_MAX, tmp) != 0) {
return false;
}
return true;
}
bool MockAotRuntimeInfo::GetMicrosecondsTimeStamp(char *timestamp) const
{
char tmp[ecmascript::ohos::AotRuntimeInfo::TIME_STAMP_SIZE] = "1970-01-01 00:00:00";
if (strcpy_s(timestamp, ecmascript::ohos::AotRuntimeInfo::TIME_STAMP_SIZE, tmp) != 0) {
return false;
}
return true;
}
bool MockAotRuntimeInfo::GetCrashSandBoxRealPath(char *realOutPath) const
{
if (strcpy_s(realOutPath, NAME_MAX, SANBOX_DIR) != 0) {
return false;
}
if (strcat_s(realOutPath, NAME_MAX, "/") != 0) {
return false;
}
if (strcat_s(realOutPath, NAME_MAX, AOT_RUNTIME_INFO) != 0) {
return false;
}
return true;
}
bool MockAotRuntimeInfo::BuildRuntimeInfoPart(char *runtimeInfoPart, const char *soBuildId, const char *timestamp,
ecmascript::ohos::RuntimeInfoType type) const
{
return ecmascript::ohos::AotRuntimeInfo::BuildRuntimeInfoPart(runtimeInfoPart, soBuildId, timestamp, type);
}
};

View File

@ -0,0 +1,39 @@
/*
* 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.
*/
#ifndef MOCK_ECMASCRIPT_AOT_RUNTIME_INFO_H
#define MOCK_ECMASCRIPT_AOT_RUNTIME_INFO_H
#include "ecmascript/ohos/aot_runtime_info.h"
namespace panda::test {
class MockAotRuntimeInfo : public ecmascript::ohos::AotRuntimeInfo {
public:
static constexpr const char *SANBOX_DIR = "ohos-crash-test";
static constexpr const char *AOT_RUNTIME_INFO = "aot_runtime_info.log";
MockAotRuntimeInfo();
~MockAotRuntimeInfo();
bool GetRuntimeBuildId(char *buildId) const override;
bool GetMicrosecondsTimeStamp(char *timestamp) const override;
bool GetCrashSandBoxRealPath(char *realOutPath) const override;
bool BuildRuntimeInfoPart(char *runtimeInfoPart, const char *soBuildId, const char *timestamp,
ecmascript::ohos::RuntimeInfoType type) const;
void SetRuntimeInfo(const char *realOutPath, char lines[][BUFFER_SIZE]) const;
};
}; // namespace panda::test
#endif // MOCK_ECMASCRIPT_AOT_RUNTIME_INFO_H

View File

@ -0,0 +1,65 @@
/*
* 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.
*/
#ifndef ECMASCRIPT_PLATFORM_AOT_RUNTIME_INFO_H
#define ECMASCRIPT_PLATFORM_AOT_RUNTIME_INFO_H
#include <signal.h>
#include <string>
#include "ecmascript/compiler/aot_compiler_preprocessor.h"
#include "ecmascript/dfx/stackinfo/js_stackinfo.h"
#include "ecmascript/ohos/ohos_pkg_args.h"
#include "ecmascript/ecma_vm.h"
#include "llvm/BinaryFormat/ELF.h"
namespace panda::ecmascript {
#ifdef JIT_ESCAPE_ENABLE
void GetSignalHandler(int signal, siginfo_t *info, void *context);
void SignalReg(int signo);
#endif
void SignalAllReg();
using AotCompilerPreprocessor = kungfu::AotCompilerPreprocessor;
class AotCrashInfo {
constexpr static const char *const AOT_ESCAPE_DISABLE = "ark.aot.escape.disable";
constexpr static int AOT_CRASH_COUNT = 1;
constexpr static int OTHERS_CRASH_COUNT = 3;
constexpr static int JIT_CRASH_COUNT = 1;
constexpr static int JS_CRASH_COUNT = 3;
public:
explicit AotCrashInfo() = default;
virtual ~AotCrashInfo() = default;
static AotCrashInfo &GetInstance()
{
static AotCrashInfo singleAotCrashInfo;
return singleAotCrashInfo;
}
bool IsAotEscapedOrNotInEnableList(EcmaVM *vm, const std::string &bundleName) const;
void SetOptionPGOProfiler(JSRuntimeOptions *options, const std::string &bundleName) const;
bool PUBLIC_API IsAotEscapedOrCompiledOnce(AotCompilerPreprocessor &cPreprocessor, int32_t &ret) const;
static bool PUBLIC_API IsAotEscaped(const std::string &pgoRealPath = "");
static bool IsJitEscape();
static bool GetAotEscapeDisable();
static std::string GetSandBoxPath();
static int GetAotCrashCount();
static int GetJitCrashCount();
static int GetJsCrashCount();
static int GetOthersCrashCount();
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_PLATFORM_AOT_RUNTIME_INFO_H

View File

@ -66,6 +66,7 @@ using fd_t = int;
std::string PUBLIC_API GetFileDelimiter();
std::string PUBLIC_API GetPathSeparator();
bool PUBLIC_API RealPath(const std::string &path, std::string &realPath, bool readOnly = true);
bool PUBLIC_API RealPathByChar(const char *path, char *realPath, int rowLength, bool readOnly);
void DPrintf(fd_t fd, const std::string &buffer);
void Close(fd_t fd);
void FSync(fd_t fd);

View File

@ -0,0 +1,172 @@
/*
* 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 "ecmascript/platform/aot_crash_info.h"
#include "ecmascript/ohos/enable_aot_list_helper.h"
#include "ecmascript/ohos/aot_runtime_info.h"
#if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
#include "parameters.h"
#endif
namespace panda::ecmascript {
#ifdef JIT_ESCAPE_ENABLE
static struct sigaction s_oldSa[SIGSYS + 1]; // SIGSYS = 31
void GetSignalHandler(int signal, siginfo_t *info, void *context)
{
(void)context;
#if defined(__aarch64__) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS)
ucontext_t *ucontext = static_cast<ucontext_t*>(context);
uintptr_t fp = ucontext->uc_mcontext.regs[29];
FrameIterator frame(reinterpret_cast<JSTaggedType *>(fp));
ecmascript::JsStackInfo::BuildCrashInfo(false, frame.GetFrameType());
#else
ecmascript::JsStackInfo::BuildCrashInfo(false);
#endif
sigaction(signal, &s_oldSa[signal], nullptr);
int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), syscall(SYS_gettid), info->si_signo, info);
if (rc != 0) {
LOG_ECMA(ERROR) << "GetSignalHandler() failed to resend signal during crash";
}
}
void SignalReg(int signo)
{
sigaction(signo, nullptr, &s_oldSa[signo]);
struct sigaction newAction;
newAction.sa_flags = SA_RESTART | SA_SIGINFO;
newAction.sa_sigaction = GetSignalHandler;
sigaction(signo, &newAction, nullptr);
}
#endif
void SignalAllReg()
{
#ifdef JIT_ESCAPE_ENABLE
SignalReg(SIGABRT);
SignalReg(SIGBUS);
SignalReg(SIGSEGV);
SignalReg(SIGILL);
SignalReg(SIGKILL);
SignalReg(SIGSTKFLT);
SignalReg(SIGFPE);
SignalReg(SIGTRAP);
#endif
}
bool AotCrashInfo::IsAotEscapedOrNotInEnableList(EcmaVM *vm, const std::string &bundleName) const
{
if (!vm->GetJSOptions().WasAOTOutputFileSet() &&
!ohos::EnableAotJitListHelper::GetInstance()->IsEnableAot(bundleName)) {
LOG_ECMA(INFO) << "Stop load AOT because it's not in enable list";
return true;
}
if (IsAotEscaped()) {
LOG_ECMA(INFO) << "Stop load AOT because there are more crashes";
return true;
}
return false;
}
bool AotCrashInfo::IsAotEscapedOrCompiledOnce(AotCompilerPreprocessor &cPreprocessor, int32_t &ret) const
{
if (!cPreprocessor.GetMainPkgArgs()) {
return false;
}
std::string pgoRealPath = cPreprocessor.GetMainPkgArgs()->GetPgoDir();
pgoRealPath.append(ohos::OhosConstants::PATH_SEPARATOR);
pgoRealPath.append(ohos::OhosConstants::AOT_RUNTIME_INFO_NAME);
if (ohos::EnableAotJitListHelper::GetInstance()->IsAotCompileSuccessOnce(pgoRealPath)) {
ret = 0;
LOG_ECMA(INFO) << "Aot has compile success once or escaped.";
return true;
}
if (IsAotEscaped(pgoRealPath)) {
ret = -1;
LOG_ECMA(INFO) << "Aot has escaped";
return true;
}
return false;
}
void AotCrashInfo::SetOptionPGOProfiler(JSRuntimeOptions *options, const std::string &bundleName) const
{
#ifdef AOT_ESCAPE_ENABLE
if (ohos::EnableAotJitListHelper::GetInstance()->IsEnableAot(bundleName)) {
options->SetEnablePGOProfiler(true);
}
if (ohos::EnableAotJitListHelper::GetInstance()->IsAotCompileSuccessOnce() || IsAotEscaped()) {
options->SetEnablePGOProfiler(false);
LOG_ECMA(INFO) << "Aot has compile success once or escaped.";
}
#endif
(void)options;
(void)bundleName;
}
bool AotCrashInfo::IsAotEscaped(const std::string &pgoRealPath)
{
if (AotCrashInfo::GetAotEscapeDisable()) {
return false;
}
auto escapeMap = ohos::AotRuntimeInfo::GetInstance().CollectCrashSum(pgoRealPath);
return escapeMap[ohos::RuntimeInfoType::AOT_CRASH] >= AotCrashInfo::GetAotCrashCount() ||
escapeMap[ohos::RuntimeInfoType::OTHERS] >= AotCrashInfo::GetOthersCrashCount() ||
escapeMap[ohos::RuntimeInfoType::JS] >= AotCrashInfo::GetJsCrashCount();
}
bool AotCrashInfo::IsJitEscape()
{
auto escapeMap = ohos::AotRuntimeInfo::GetInstance().CollectCrashSum();
return escapeMap[ohos::RuntimeInfoType::JIT] >= AotCrashInfo::GetJitCrashCount() ||
escapeMap[ohos::RuntimeInfoType::AOT_CRASH] >= AotCrashInfo::GetAotCrashCount() ||
escapeMap[ohos::RuntimeInfoType::OTHERS] >= AotCrashInfo::GetOthersCrashCount() ||
escapeMap[ohos::RuntimeInfoType::JS] >= AotCrashInfo::GetJsCrashCount();
}
bool AotCrashInfo::GetAotEscapeDisable()
{
#if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
return OHOS::system::GetBoolParameter(AOT_ESCAPE_DISABLE, false);
#endif
return false;
}
std::string AotCrashInfo::GetSandBoxPath()
{
return ohos::OhosConstants::SANDBOX_ARK_PROFILE_PATH;
}
int AotCrashInfo::GetAotCrashCount()
{
return AOT_CRASH_COUNT;
}
int AotCrashInfo::GetJitCrashCount()
{
return JIT_CRASH_COUNT;
}
int AotCrashInfo::GetJsCrashCount()
{
return JS_CRASH_COUNT;
}
int AotCrashInfo::GetOthersCrashCount()
{
return OTHERS_CRASH_COUNT;
}
} // namespace panda::ecmascript

View File

@ -58,6 +58,28 @@ bool RealPath(const std::string &path, std::string &realPath, bool readOnly)
return true;
}
bool RealPathByChar(const char *path, char *realPath, int rowLength, bool readOnly)
{
if (strlen(path) == 0 || strlen(path) > PATH_MAX) {
return false;
}
char buffer[PATH_MAX] = { '\0' };
if (!realpath(path, buffer)) {
// Maybe file does not exist.
if (!readOnly && errno == ENOENT) {
if (strcpy_s(realPath, rowLength, path) != 0) {
return false;
}
return true;
}
return false;
}
if (strcpy_s(realPath, rowLength, buffer) != 0) {
return false;
}
return true;
}
void DPrintf(fd_t fd, const std::string &buffer)
{
int ret = dprintf(fd, "%s", buffer.c_str());

View File

@ -0,0 +1,97 @@
/*
* 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 "ecmascript/platform/aot_crash_info.h"
namespace panda::ecmascript {
#ifdef JIT_ESCAPE_ENABLE
void GetSignalHandler(int signal, siginfo_t *info, void *context)
{
(void)signal;
(void)info;
(void)context;
}
void SignalReg(int signo)
{
(void)signo;
}
#endif
void SignalAllReg()
{
}
bool AotCrashInfo::IsAotEscapedOrNotInEnableList(EcmaVM *vm, const std::string &bundleName) const
{
(void)vm;
(void)bundleName;
return false;
}
bool AotCrashInfo::IsAotEscapedOrCompiledOnce(AotCompilerPreprocessor &cPreprocessor, int32_t &ret) const
{
(void)cPreprocessor;
(void)ret;
return false;
}
void AotCrashInfo::SetOptionPGOProfiler(JSRuntimeOptions *options, const std::string &bundleName) const
{
(void)options;
(void)bundleName;
}
bool AotCrashInfo::IsAotEscaped(const std::string &pgoRealPath)
{
(void)pgoRealPath;
return false;
}
bool AotCrashInfo::IsJitEscape()
{
return false;
}
bool AotCrashInfo::GetAotEscapeDisable()
{
return false;
}
std::string AotCrashInfo::GetSandBoxPath()
{
return ohos::OhosConstants::SANDBOX_ARK_PROFILE_PATH;
}
int AotCrashInfo::GetAotCrashCount()
{
return AOT_CRASH_COUNT;
}
int AotCrashInfo::GetJitCrashCount()
{
return JIT_CRASH_COUNT;
}
int AotCrashInfo::GetJsCrashCount()
{
return JS_CRASH_COUNT;
}
int AotCrashInfo::GetOthersCrashCount()
{
return OTHERS_CRASH_COUNT;
}
} // namespace panda::ecmascript

View File

@ -66,6 +66,15 @@ bool RealPath(const std::string &path, std::string &realPath, [[maybe_unused]] b
return true;
}
bool RealPathByChar(const char *path, char *realPath, int rowLength, bool readOnly)
{
(void)path;
(void)realPath;
(void)rowLength;
(void)readOnly;
return false;
}
void DPrintf(fd_t fd, const std::string &buffer)
{
LOG_ECMA(DEBUG) << "Unsupport dprintf fd(" << fd << ") in windows, buffer:" << buffer;

View File

@ -88,6 +88,7 @@
panda::JsiFastNativeScope::*;
panda::JSExecutionScope::*;
panda::ecmascript::AotCrashInfo*;
panda::ecmascript::Log::*;
panda::ecmascript::AndroidLog*;
panda::ecmascript::Method::*;

View File

@ -722,6 +722,11 @@
<option name="push" value="test/test/libark_jsruntime_test.so -> /data/test" src="out"/>
</preparer>
</target>
<target name="CrashTest">
<preparer>
<option name="push" value="test/test/libark_jsruntime_test.so -> /data/test" src="out"/>
</preparer>
</target>
<target name="PGOProfilerTest">
<preparer>
<option name="push" value="test/test/libark_jsruntime_test.so -> /data/test" src="out"/>