mirror of
https://github.com/openharmony/ability_ability_runtime.git
synced 2026-08-24 22:21:36 -04:00
!17744 merge master into master
Message: uncatchable Exception change to sync, others which are async limt in Created-by: zhengdongdong12 Commit-by: 郑冬冬冬 Merged-by: openharmony_ci Description: **IssueNo**: https://gitcode.com/openharmony/arkcompiler_ets_runtime/issues/12033 **Description**: JsErrorManager中不可捕获异常改为同步处理回调函数,可捕获异常的异步处理限制在2s内;在主线程及worker线程归一 **稳定性自检:** | 自检项 | 自检结果 | | ------------------------------------------------------------ | -------- | | 涉及跨进程调用的相关操作需要抛至主线程或加锁防止并发 | OK | | 成员变量进行赋值或创建需要排查并发 | OK | | 谨慎在lambda表达式中使用引用捕获 | OK | | 谨慎在未经拷贝的情况下使用外部传入的string、C字符串 | OK | | map\vector\list\set等stl模板类使用时需要排查并发 | OK | | 谨慎考虑加锁范围 | OK | | 在IPC通信中谨慎使用同步通信方式 | OK | | 禁止传递this指针至其他模块或线程(特别是eventhandler任务) | OK | | 禁止将外部传入的裸指针在内部直接构造智能指针 | OK | | 禁止多个独立创建的智能指针管理同一地址 | OK | | 禁止在析构函数中抛异步任务 | OK | | 禁止js对象在非js线程(例如在IPC线程)创建、使用或销毁 | OK | | 禁止在对外接口中未经判空直接使用外部传入的指针 | OK | | 禁止接口返回局部变量引用 | OK | | 禁止在信号函数中加锁 | OK | | 禁止在关键流程(SA启动、应用启动等主流程)执行耗时的操作 | OK | | 禁止将同一个cpp编译在不同的so中 | OK | **安全编码自检:** | 自检项 | 自检结果 | | -------------------------------------------------------------- | -------- | | 裸指针避免通过隐式转换构造为sptr | OK | | json对象在取值之前必须先判断类型,避免类型不匹配 | OK | | 序列化时必须对传入的数组大小进行校验,避免出现超大数组 | OK | | 避免使用未明确位宽的整型,选择使用int8_t、uint8_t等类型 | OK | | 外部传入的路径要做规范化校验,对路径中的.、..、../等特殊字符严格校验 | OK | | 指针变量、表示资源描述符的变量、bool变量必须赋初值 | OK | | readParcelable获取的对象使用前需要判空 | OK | | 分配和释放内存的函数需要成对出现 | OK | | 申请内存后异常退出前需要及时进行内存释放 | OK | | 内存申请前必须对内存大小进行合法性校验 | OK | | 内存分配后必须判断是否成功 | OK | | 禁止使用realloc、alloca函数 | OK | | 禁止打印文件路径、口令等敏感信息,如有需要,使用private修饰 | OK | | 禁止打印内存地址 | OK | | 整数之间运算时必须严格检查,确保不会出现溢出、反转、除0 | OK | | 禁止对有符号整数进行位操作符运算 | OK | | 禁止对指针进行逻辑或位运算 | OK | | 循环次数如果收外部数据控制,需要检验其合法性 | OK | | 禁止使用内存操作类危险函数,需要使用安全函数 | OK | | 谨慎使用不可重入函数 | OK | | 必须检查安全函数的返回值,并进行正确处理 | OK | | 禁止仅通过TokenType类型判断绕过权限校验 | OK | **TDD Result**: OK **XTS Result**: OK ### 是否已执行L0用例 - [x] 已验证 - [ ] 不涉及。如不涉及,请写明理由 See merge request: openharmony/ability_ability_runtime!17744
This commit is contained in:
@@ -46,6 +46,7 @@ struct WorkItem {
|
||||
std::string name;
|
||||
std::string message;
|
||||
std::string stack;
|
||||
std::shared_ptr<std::atomic<int>> remainingCount;
|
||||
};
|
||||
struct GlobalObserverItem {
|
||||
napi_ref ref;
|
||||
@@ -75,6 +76,9 @@ static std::once_flag registerCallbackFlag;
|
||||
static std::shared_ptr<JsLoopObserver> loopObserver_;
|
||||
static bool freezeCallbackRegistered = false;
|
||||
static bool isSetHandler = false;
|
||||
static std::mutex onErrorMtx;
|
||||
static std::condition_variable onErrorCv;
|
||||
constexpr int ON_ERROR_ASYNC_TIMEOUT = 2;
|
||||
constexpr int32_t INDEX_ZERO = 0;
|
||||
constexpr int32_t INDEX_ONE = 1;
|
||||
constexpr int32_t INDEX_TWO = 2;
|
||||
@@ -332,17 +336,15 @@ static void CallJsFunction(napi_env env, napi_value obj, const char *methodName,
|
||||
napi_call_function(env, obj, method, argc, argv, &callResult);
|
||||
}
|
||||
|
||||
static void DoFunctionCallback(uv_work_t *reqwork, int status)
|
||||
static bool NapiDoFunctionCallBack(WorkItem *newItem)
|
||||
{
|
||||
WorkItem *newItem = static_cast<WorkItem *>(reqwork->data);
|
||||
if (newItem == nullptr) {
|
||||
TAG_LOGI(AAFwkTag::JSNAPI, "Get WorkItem Failed");
|
||||
return;
|
||||
}
|
||||
napi_handle_scope scope_ = nullptr;
|
||||
napi_status scopeStatus = napi_open_handle_scope(newItem->env, &scope_);
|
||||
if (scopeStatus != napi_ok || scope_ == nullptr) {
|
||||
TAG_LOGE(AAFwkTag::JSNAPI, "napi_open_handle_scope failed");
|
||||
delete newItem;
|
||||
newItem = nullptr;
|
||||
return false;
|
||||
}
|
||||
napi_value global = nullptr;
|
||||
if (napi_get_global(newItem->env, &global) != napi_ok) {
|
||||
@@ -350,7 +352,7 @@ static void DoFunctionCallback(uv_work_t *reqwork, int status)
|
||||
napi_close_handle_scope(newItem->env, scope_);
|
||||
delete newItem;
|
||||
newItem = nullptr;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
size_t argc = ARGC_ONE;
|
||||
napi_value args[] = {CreateGlobalObject(newItem->env, newItem)};
|
||||
@@ -360,7 +362,7 @@ static void DoFunctionCallback(uv_work_t *reqwork, int status)
|
||||
napi_close_handle_scope(newItem->env, scope_);
|
||||
delete newItem;
|
||||
newItem = nullptr;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
napi_value result = nullptr;
|
||||
if (napi_call_function(newItem->env, global, function, argc, args, &result) != napi_ok) {
|
||||
@@ -368,44 +370,98 @@ static void DoFunctionCallback(uv_work_t *reqwork, int status)
|
||||
napi_close_handle_scope(newItem->env, scope_);
|
||||
delete newItem;
|
||||
newItem = nullptr;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
napi_close_handle_scope(newItem->env, scope_);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void DoFunctionCallback(uv_work_t *reqwork, int status)
|
||||
{
|
||||
WorkItem *newItem = static_cast<WorkItem *>(reqwork->data);
|
||||
if (newItem == nullptr) {
|
||||
TAG_LOGI(AAFwkTag::JSNAPI, "Get WorkItem Failed");
|
||||
return;
|
||||
}
|
||||
if (!NapiDoFunctionCallBack(newItem)) {
|
||||
return;
|
||||
}
|
||||
if (newItem->remainingCount) {
|
||||
int oldValue = newItem->remainingCount->fetch_sub(1, std::memory_order_acq_rel);
|
||||
if (oldValue == 1) {
|
||||
std::lock_guard<std::mutex> lock(onErrorMtx);
|
||||
onErrorCv.notify_all();
|
||||
TAG_LOGI(AAFwkTag::JSNAPI, "onError cv notify");
|
||||
}
|
||||
}
|
||||
delete newItem;
|
||||
newItem = nullptr;
|
||||
}
|
||||
|
||||
static void OnErrorWorkerWait(std::shared_ptr<std::atomic<int>>& remainingCount)
|
||||
{
|
||||
if (remainingCount && remainingCount->load() > 0) {
|
||||
std::unique_lock<std::mutex> onErrorLock(onErrorMtx);
|
||||
if (onErrorCv.wait_for(onErrorLock, std::chrono::seconds(ON_ERROR_ASYNC_TIMEOUT)) == std::cv_status::timeout) {
|
||||
TAG_LOGI(AAFwkTag::JSNAPI, "async onError callback has been extecting more than 2s");
|
||||
} else {
|
||||
TAG_LOGI(AAFwkTag::JSNAPI, "async onError callback has finished less than 2s");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DoCallbackInRegesterThread(napi_env env, WorkItem &info)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(globalErrorMtx);
|
||||
for (auto iter : globalObserverList) {
|
||||
uv_loop_t *loop = nullptr;
|
||||
if (napi_get_uv_event_loop(iter.env, &loop) != napi_ok) {
|
||||
TAG_LOGI(AAFwkTag::JSNAPI, "Get Loop Failed");
|
||||
continue;
|
||||
std::shared_ptr<std::atomic<int>> remainingCount = nullptr;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(globalErrorMtx);
|
||||
if (AppExecFwk::ApplicationDataManager::GetInstance().GetIsUncatchable() && !globalObserverList.empty()) {
|
||||
remainingCount = std::make_shared<std::atomic<int>>(globalObserverList.size());
|
||||
}
|
||||
WorkItem *item = new (std::nothrow) WorkItem();
|
||||
if (item == nullptr) {
|
||||
TAG_LOGI(AAFwkTag::JSNAPI, "new WorkItem Failed");
|
||||
continue;
|
||||
}
|
||||
item->env = iter.env;
|
||||
item->ref = iter.ref;
|
||||
item->instanceName = info.instanceName;
|
||||
item->instanceType = info.instanceType;
|
||||
item->work.data = item;
|
||||
item->name = info.name;
|
||||
item->stack = info.stack;
|
||||
item->message = info.message;
|
||||
int ret = uv_queue_work(
|
||||
loop, &item->work, [](uv_work_t *reqwork) {}, DoFunctionCallback);
|
||||
if (ret != 0) {
|
||||
if (item != nullptr) {
|
||||
|
||||
for (auto iter : globalObserverList) {
|
||||
WorkItem *item = new (std::nothrow) WorkItem();
|
||||
if (item == nullptr) {
|
||||
TAG_LOGI(AAFwkTag::JSNAPI, "new WorkItem Failed");
|
||||
continue;
|
||||
}
|
||||
item->env = iter.env;
|
||||
item->ref = iter.ref;
|
||||
item->instanceName = info.instanceName;
|
||||
item->instanceType = info.instanceType;
|
||||
item->work.data = item;
|
||||
item->name = info.name;
|
||||
item->stack = info.stack;
|
||||
item->message = info.message;
|
||||
item->remainingCount = remainingCount;
|
||||
|
||||
if (remainingCount && env == item->env) {
|
||||
remainingCount->fetch_sub(1, std::memory_order_acq_rel);
|
||||
if (NapiDoFunctionCallBack(item)) {
|
||||
delete item;
|
||||
item = nullptr;
|
||||
TAG_LOGI(AAFwkTag::JSNAPI, "Do uncatchable callback successfully with the same env");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
uv_loop_t *loop = nullptr;
|
||||
if (napi_get_uv_event_loop(iter.env, &loop) != napi_ok) {
|
||||
delete item;
|
||||
item = nullptr;
|
||||
TAG_LOGI(AAFwkTag::JSNAPI, "Get Loop Failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
int ret = uv_queue_work(loop, &item->work, [](uv_work_t *reqwork) {}, DoFunctionCallback);
|
||||
if (ret != 0 && item != nullptr) {
|
||||
delete item;
|
||||
item = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
OnErrorWorkerWait(remainingCount);
|
||||
}
|
||||
|
||||
static void DoGlobalCallback(napi_env env, napi_value exception, std::string instanceName, uint32_t type)
|
||||
{
|
||||
{
|
||||
@@ -508,14 +564,11 @@ static void DoWorkThreadCallback(napi_env env, napi_value exception)
|
||||
CallJsFunction(env, functionTemp.second->GetNapiValue(), "onException", args, argc);
|
||||
}
|
||||
}
|
||||
|
||||
static bool ErrorManagerWorkerCallback(napi_env env, napi_value exception, std::string instanceName, uint32_t type)
|
||||
{
|
||||
if (!AppExecFwk::ApplicationDataManager::GetInstance().GetIsUncatchable()) {
|
||||
DoGlobalCallback(env, exception, instanceName, type);
|
||||
} else {
|
||||
TAG_LOGI(AAFwkTag::JSNAPI, "Uncatchable exception, skip this step.");
|
||||
}
|
||||
DoWorkThreadCallback(env, exception);
|
||||
DoGlobalCallback(env, exception, instanceName, type);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -589,11 +642,7 @@ static bool ErrorManagerMainWorkerCallback(
|
||||
item.stack = stack;
|
||||
item.instanceName = "";
|
||||
item.instanceType = 0;
|
||||
if (!AppExecFwk::ApplicationDataManager::GetInstance().GetIsUncatchable()) {
|
||||
DoCallbackInRegesterThread(env, item);
|
||||
} else {
|
||||
TAG_LOGI(AAFwkTag::JSNAPI, "Uncatchable exception, skip this step.");
|
||||
}
|
||||
DoCallbackInRegesterThread(env, item);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,23 @@
|
||||
|
||||
#include "app_recovery.h"
|
||||
#include "hilog_tag_wrapper.h"
|
||||
#include "native_engine.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace AppExecFwk {
|
||||
namespace {
|
||||
constexpr size_t STACK_MAX_SZIE = 1024;
|
||||
constexpr size_t AT_SKIP_SZIE = 3;
|
||||
constexpr const char* TASK_POOL_THREAD = "Taskpool Thread";
|
||||
enum class InstanceType {
|
||||
DEFAULT_TYPE = -1,
|
||||
WORKER_THREAD_TYPE = 1,
|
||||
TASK_POOL_THREAD_TYPE = 2,
|
||||
};
|
||||
thread_local bool g_hasNotified = false;
|
||||
}
|
||||
|
||||
std::atomic<bool> ApplicationDataManager::jsErrorHasReport_{false};
|
||||
ApplicationDataManager::ApplicationDataManager() {}
|
||||
|
||||
ApplicationDataManager::~ApplicationDataManager() {}
|
||||
@@ -94,7 +108,7 @@ bool ApplicationDataManager::NotifyCJExceptionObject(const AppExecFwk::ErrorObje
|
||||
}
|
||||
|
||||
// if apprecovery is enabled, we could callback to save current state
|
||||
// and restart as developer wants
|
||||
// and restart developer wants
|
||||
return AppRecovery::GetInstance().TryRecoverApp(StateReason::CJ_ERROR);
|
||||
}
|
||||
|
||||
@@ -118,5 +132,97 @@ bool ApplicationDataManager::GetIsUncatchable()
|
||||
bool isUncatchable = isUncatchable_.load();
|
||||
return isUncatchable;
|
||||
}
|
||||
|
||||
std::string ApplicationDataManager::GetFuncNameFromError(napi_env env, napi_value error)
|
||||
{
|
||||
if (error == nullptr) {
|
||||
return TASK_POOL_THREAD;
|
||||
}
|
||||
|
||||
napi_value stack;
|
||||
if (napi_get_named_property(env, error, "stack", &stack) != napi_ok ||stack == nullptr) {
|
||||
return TASK_POOL_THREAD;
|
||||
}
|
||||
|
||||
std::string rawStack;
|
||||
size_t rawStackSize = 0;
|
||||
napi_get_value_string_utf8(env, stack, nullptr, 0, &rawStackSize);
|
||||
rawStackSize = std::min(rawStackSize, STACK_MAX_SZIE);
|
||||
rawStack.reserve(rawStackSize + 1);
|
||||
rawStack.resize(rawStackSize);
|
||||
napi_get_value_string_utf8(env, stack, rawStack.data(), rawStack.size() + 1, &rawStackSize);
|
||||
|
||||
size_t pos = rawStack.find("at");
|
||||
if (pos == std::string::npos) {
|
||||
return TASK_POOL_THREAD;
|
||||
}
|
||||
size_t endPos = rawStack.find("(", pos);
|
||||
if (endPos == std::string::npos) {
|
||||
return TASK_POOL_THREAD;
|
||||
}
|
||||
size_t startPos = pos + AT_SKIP_SZIE;
|
||||
if (endPos <= startPos + 1) {
|
||||
return TASK_POOL_THREAD;
|
||||
}
|
||||
|
||||
std::string funcName = std::string(TASK_POOL_THREAD);
|
||||
funcName.append(rawStack.substr(startPos, endPos - startPos - 1));
|
||||
return funcName;
|
||||
}
|
||||
|
||||
bool ApplicationDataManager::NotifyUncaughtException(const ExceptionParams ¶ms,
|
||||
const AppExecFwk::ErrorObject &errorObj)
|
||||
{
|
||||
if (params.isUncatchable && g_hasNotified) {
|
||||
return false;
|
||||
}
|
||||
g_hasNotified = params.isUncatchable;
|
||||
|
||||
bool isMainEnv = (params.env == params.mainEnv);
|
||||
auto napiEnv = params.env ? params.env : params.mainEnv;
|
||||
if (isMainEnv) {
|
||||
TAG_LOGI(AAFwkTag::APPKIT, "main thread");
|
||||
if (NapiErrorManager::GetInstance()->NotifyUncaughtException(napiEnv, params.summary,
|
||||
errorObj.name, errorObj.message, errorObj.stack)) {
|
||||
TAG_LOGI(AAFwkTag::APPKIT, "Complete all callbacks");
|
||||
}
|
||||
} else if (params.isUncatchable) {
|
||||
NativeEngine* engine = reinterpret_cast<NativeEngine*>(napiEnv);
|
||||
if (engine == nullptr) {
|
||||
return false;
|
||||
}
|
||||
std::string instanceName;
|
||||
InstanceType instanceType = InstanceType::DEFAULT_TYPE;
|
||||
if (engine->IsWorkerThread()) {
|
||||
instanceType = InstanceType::WORKER_THREAD_TYPE;
|
||||
napi_value workerGlobalObject = nullptr;
|
||||
napi_get_global(napiEnv, &workerGlobalObject);
|
||||
napi_value valueStr = nullptr;
|
||||
if (napi_get_named_property(napiEnv, workerGlobalObject, "name", &valueStr) != napi_ok) {
|
||||
return false;
|
||||
}
|
||||
napi_valuetype valueType = napi_undefined;
|
||||
napi_typeof(napiEnv, valueStr, &valueType);
|
||||
|
||||
if (valueType == napi_string) {
|
||||
size_t instanceNameSize = 0;
|
||||
napi_get_value_string_utf8(napiEnv, valueStr, nullptr, 0, &instanceNameSize);
|
||||
instanceName.reserve(instanceNameSize + 1);
|
||||
instanceName.resize(instanceNameSize);
|
||||
napi_get_value_string_utf8(napiEnv, valueStr, instanceName.data(), instanceName.size() + 1,
|
||||
&instanceNameSize);
|
||||
}
|
||||
TAG_LOGE(AAFwkTag::APPKIT, "worker thread, instanceType=1, instanceName=%{public}s", instanceName.c_str());
|
||||
} else if (engine->IsTaskPoolThread()) {
|
||||
instanceType = InstanceType::TASK_POOL_THREAD_TYPE;
|
||||
instanceName = GetFuncNameFromError(napiEnv, params.exception);
|
||||
TAG_LOGE(AAFwkTag::APPKIT, "task pool thread, instanceType=2, instanceName=%{public}s",
|
||||
instanceName.c_str());
|
||||
}
|
||||
NapiErrorManager::GetInstance()->NotifyUncaughtException(napiEnv, params.exception, instanceName,
|
||||
static_cast<uint32_t>(instanceType));
|
||||
}
|
||||
return (isMainEnv && !g_hasNotified);
|
||||
}
|
||||
} // namespace AppExecFwk
|
||||
} // namespace OHOS
|
||||
|
||||
@@ -172,7 +172,7 @@ constexpr char EVENT_KEY_CANGJIE[] = "CANGJIE";
|
||||
constexpr char EVENT_KEY_SUMMARY[] = "SUMMARY";
|
||||
constexpr char EVENT_KEY_PNAME[] = "PNAME";
|
||||
constexpr char EVENT_KEY_THREAD_NAME[] = "THREAD_NAME";
|
||||
constexpr char EVENT_KEY_APP_RUNING_UNIQUE_ID[] = "APP_RUNNING_UNIQUE_ID";
|
||||
constexpr char EVENT_KEY_APP_RUNNING_UNIQUE_ID[] = "APP_RUNNING_UNIQUE_ID";
|
||||
constexpr char EVENT_KEY_PROCESS_RSS_MEMINFO[] = "PROCESS_RSS_MEMINFO";
|
||||
constexpr char EVENT_KEY_PROCESS_LIFETIME[] = "PROCESS_LIFETIME";
|
||||
constexpr char DEVELOPER_MODE_STATE[] = "const.security.developermode.state";
|
||||
@@ -1470,7 +1470,7 @@ EtsEnv::ETSUncaughtExceptionInfo MainThread::CreateEtsExceptionInfo(const std::s
|
||||
OHOS::HiviewDFX::HiSysEvent::EventType::FAULT, EVENT_KEY_PACKAGE_NAME, bundleName,
|
||||
EVENT_KEY_VERSION, std::to_string(versionCode), EVENT_KEY_TYPE, JSCRASH_TYPE, EVENT_KEY_HAPPEN_TIME, timet,
|
||||
EVENT_KEY_REASON, errorObj.name, EVENT_KEY_JSVM, JSVM_TYPE, EVENT_KEY_SUMMARY, summary,
|
||||
EVENT_KEY_PNAME, processName, EVENT_KEY_APP_RUNING_UNIQUE_ID, appRunningId,
|
||||
EVENT_KEY_PNAME, processName, EVENT_KEY_APP_RUNNING_UNIQUE_ID, appRunningId,
|
||||
EVENT_KEY_PROCESS_RSS_MEMINFO, std::to_string(DumpProcessHelper::GetProcRssMemInfo()),
|
||||
EVENT_KEY_THREAD_NAME, DumpProcessHelper::GetThreadName());
|
||||
ErrorObject appExecErrorObj = { .name = errorObj.name, .message = errorObj.message, .stack = errorObj.stack };
|
||||
@@ -1491,7 +1491,7 @@ EtsEnv::ETSUncaughtExceptionInfo MainThread::CreateEtsExceptionInfo(const std::s
|
||||
}
|
||||
int result = HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::FRAMEWORK, "PROCESS_KILL",
|
||||
HiviewDFX::HiSysEvent::EventType::FAULT, "PID", pid, "PROCESS_NAME", processName, "MSG", KILL_REASON,
|
||||
EVENT_KEY_APP_RUNING_UNIQUE_ID, appRunningId, EVENT_KEY_REASON, "JsError",
|
||||
EVENT_KEY_APP_RUNNING_UNIQUE_ID, appRunningId, EVENT_KEY_REASON, "JsError",
|
||||
"FOREGROUND", foreground);
|
||||
TAG_LOGW(AAFwkTag::APPKIT, "hisysevent write result=%{public}d, send event "
|
||||
"[FRAMEWORK,PROCESS_KILL],"
|
||||
@@ -2052,59 +2052,77 @@ void MainThread::InitUncatchableTask(JsEnv::UncatchableTask &uncatchableTask, co
|
||||
uncatchableTask = [weak, bundleName = uncatchableTaskInfo.bundleName,
|
||||
versionCode = uncatchableTaskInfo.versionCode, appRunningId = uncatchableTaskInfo.appRunningId,
|
||||
pid = uncatchableTaskInfo.pid, processName = uncatchableTaskInfo.processName, isUncatchable]
|
||||
(std::string summary, const JsEnv::ErrorObject errorObject) {
|
||||
(std::string summary, const JsEnv::ErrorObject errorObject, napi_env env, napi_value exception) {
|
||||
auto appThread = weak.promote();
|
||||
if (appThread == nullptr) {
|
||||
TAG_LOGE(AAFwkTag::APPKIT, "null appThread");
|
||||
return;
|
||||
}
|
||||
|
||||
time_t timet;
|
||||
time(&timet);
|
||||
std::string lifeTime = GetProcessLifeCycleByPid(pid);
|
||||
HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::AAFWK, "JS_ERROR",
|
||||
OHOS::HiviewDFX::HiSysEvent::EventType::FAULT, EVENT_KEY_PACKAGE_NAME, bundleName,
|
||||
EVENT_KEY_VERSION, std::to_string(versionCode), EVENT_KEY_TYPE, JSCRASH_TYPE, EVENT_KEY_HAPPEN_TIME, timet,
|
||||
EVENT_KEY_REASON, errorObject.name, EVENT_KEY_JSVM, JSVM_TYPE, EVENT_KEY_SUMMARY, summary,
|
||||
EVENT_KEY_PNAME, processName, EVENT_KEY_APP_RUNING_UNIQUE_ID, appRunningId,
|
||||
EVENT_KEY_PROCESS_RSS_MEMINFO, std::to_string(DumpProcessHelper::GetProcRssMemInfo()),
|
||||
EVENT_KEY_THREAD_NAME, DumpProcessHelper::GetThreadName(), EVENT_KEY_PROCESS_LIFETIME, lifeTime);
|
||||
if (!ApplicationDataManager::jsErrorHasReport_.exchange(true)) {
|
||||
int result = HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::AAFWK, "JS_ERROR",
|
||||
OHOS::HiviewDFX::HiSysEvent::EventType::FAULT, EVENT_KEY_PACKAGE_NAME, bundleName, EVENT_KEY_VERSION,
|
||||
std::to_string(versionCode), EVENT_KEY_TYPE, JSCRASH_TYPE, EVENT_KEY_HAPPEN_TIME, timet,
|
||||
EVENT_KEY_REASON, errorObject.name, EVENT_KEY_JSVM, JSVM_TYPE, EVENT_KEY_SUMMARY, summary,
|
||||
EVENT_KEY_PNAME, processName, EVENT_KEY_APP_RUNNING_UNIQUE_ID, appRunningId,
|
||||
EVENT_KEY_PROCESS_RSS_MEMINFO, std::to_string(DumpProcessHelper::GetProcRssMemInfo()),
|
||||
EVENT_KEY_THREAD_NAME, DumpProcessHelper::GetThreadName(), EVENT_KEY_PROCESS_LIFETIME, lifeTime);
|
||||
TAG_LOGW(AAFwkTag::APPKIT, "hisysevent write result=%{public}d, send event [FRAMEWORK,JS_ERROR],"
|
||||
" packageName=%{public}s, pid=%{public}d, appRunningId=%{public}s, threadName=%{public}s,"
|
||||
" isUncatchable=%{public}d", result, bundleName.c_str(), pid, appRunningId.c_str(),
|
||||
DumpProcessHelper::GetThreadName().c_str(), isUncatchable);
|
||||
}
|
||||
|
||||
ApplicationDataManager::GetInstance().SetIsUncatchable(isUncatchable);
|
||||
|
||||
ErrorObject appExecErrorObj = { errorObject.name, errorObject.message, errorObject.stack};
|
||||
auto napiEnv = (static_cast<AbilityRuntime::JsRuntime&>(*appThread->application_->GetRuntime())).GetNapiEnv();
|
||||
AAFwk::ExitReason exitReason = { REASON_JS_ERROR, errorObject.name };
|
||||
AbilityManagerClient::GetInstance()->RecordAppExitReason(exitReason);
|
||||
AppExecFwk::ApplicationDataManager::GetInstance().SetIsUncatchable(isUncatchable);
|
||||
if (NapiErrorManager::GetInstance()->NotifyUncaughtException(napiEnv, summary,
|
||||
appExecErrorObj.name, appExecErrorObj.message, appExecErrorObj.stack)) {
|
||||
TAG_LOGI(AAFwkTag::APPKIT, "Complete all callbacks");
|
||||
if (!isUncatchable) {
|
||||
return;
|
||||
}
|
||||
auto mainEnv = (static_cast<AbilityRuntime::JsRuntime&>(*appThread->application_->GetRuntime())).GetNapiEnv();
|
||||
ApplicationDataManager::ExceptionParams params = {env, mainEnv, exception, summary, isUncatchable};
|
||||
if (ApplicationDataManager::NotifyUncaughtException(params, appExecErrorObj)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isUncatchable && ApplicationDataManager::GetInstance().NotifyUnhandledException(summary) &&
|
||||
ApplicationDataManager::GetInstance().NotifyExceptionObject(appExecErrorObj)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if app's callback has been registered, let app decide whether exit or not.
|
||||
TAG_LOGE(AAFwkTag::APPKIT, "\n%{public}s is about to exit due to RuntimeError\nError type:%{public}s\n"
|
||||
"%{public}s", bundleName.c_str(), errorObject.name.c_str(), summary.c_str());
|
||||
bool foreground = false;
|
||||
if (appThread->applicationImpl_ && appThread->applicationImpl_->GetState() ==
|
||||
ApplicationImpl::APP_STATE_FOREGROUND) {
|
||||
foreground = true;
|
||||
}
|
||||
int result = HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::FRAMEWORK, "PROCESS_KILL",
|
||||
HiviewDFX::HiSysEvent::EventType::FAULT, "PID", pid, "PROCESS_NAME", processName,
|
||||
EVENT_KEY_APP_RUNING_UNIQUE_ID, appRunningId, EVENT_KEY_REASON, "JsError",
|
||||
"MSG", KILL_REASON, "FOREGROUND", foreground, "IS_UNCATCHABLE", isUncatchable);
|
||||
TAG_LOGW(AAFwkTag::APPKIT, "hisysevent write result=%{public}d, send event [FRAMEWORK,PROCESS_KILL],"
|
||||
" pid=%{public}d, processName=%{public}s, msg=%{public}s, foreground=%{public}d, isUncatchable=%{public}d",
|
||||
result, pid, processName.c_str(), KILL_REASON, foreground, isUncatchable);
|
||||
_exit(JS_ERROR_EXIT);
|
||||
bool foreground = (appThread->applicationImpl_ && appThread->applicationImpl_->GetState() ==
|
||||
ApplicationImpl::APP_STATE_FOREGROUND) ? true : false;
|
||||
ProcessExitInfo info = {bundleName, errorObject.name, summary, appRunningId, processName, pid, foreground,
|
||||
isUncatchable};
|
||||
ProcessExit(info);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Handle process exit.
|
||||
*
|
||||
* @param processExitInfo The info of the process exit info.
|
||||
*
|
||||
*/
|
||||
void MainThread::ProcessExit(const ProcessExitInfo& info)
|
||||
{
|
||||
AAFwk::ExitReason exitReason = { REASON_JS_ERROR, info.errorObjectName };
|
||||
AbilityManagerClient::GetInstance()->RecordAppExitReason(exitReason);
|
||||
|
||||
// if app's callback has been registered, let app decide whether exit or not.
|
||||
TAG_LOGE(AAFwkTag::APPKIT, "\n%{public}s is about to exit due to RuntimeError\nError type:%{public}s\n"
|
||||
"%{public}s", info.bundleName.c_str(), info.errorObjectName.c_str(), info.summary.c_str());
|
||||
int result = HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::FRAMEWORK, "PROCESS_KILL",
|
||||
HiviewDFX::HiSysEvent::EventType::FAULT, "PID", info.pid, "PROCESS_NAME", info.processName,
|
||||
EVENT_KEY_APP_RUNNING_UNIQUE_ID, info.appRunningId, EVENT_KEY_REASON, "JsError",
|
||||
"MSG", KILL_REASON, "FOREGROUND", info.foreground, "IS_UNCATCHABLE", info.isUncatchable);
|
||||
TAG_LOGW(AAFwkTag::APPKIT, "hisysevent write result=%{public}d, send event [FRAMEWORK,PROCESS_KILL],"
|
||||
" pid=%{public}d, processName=%{public}s, msg=%{public}s, foreground=%{public}d, isUncatchable=%{public}d",
|
||||
result, info.pid, info.processName.c_str(), KILL_REASON, info.foreground, info.isUncatchable);
|
||||
_exit(JS_ERROR_EXIT);
|
||||
}
|
||||
|
||||
#if defined(NWEB) && defined(NWEB_GRAPHIC)
|
||||
void MainThread::HandleNWebPreload()
|
||||
{
|
||||
|
||||
@@ -47,7 +47,8 @@ class JsEnvironment;
|
||||
class SourceMapOperator;
|
||||
struct ErrorObject;
|
||||
struct UncaughtExceptionInfo;
|
||||
using UncatchableTask = std::function<void(std::string summary, const JsEnv::ErrorObject errorObject)>;
|
||||
using UncatchableTask = std::function<void(std::string summary, const JsEnv::ErrorObject errorObject, napi_env env,
|
||||
napi_value exception)>;
|
||||
} // namespace JsEnv
|
||||
|
||||
using AppLibPathMap = std::map<std::string, std::vector<std::string>>;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#define OHOS_ABILITY_RUNTIME_APPLICATION_DATA_MANAGER_H
|
||||
|
||||
#include <string>
|
||||
#include "napi/native_api.h"
|
||||
|
||||
#include "ierror_observer.h"
|
||||
#include "nocopyable.h"
|
||||
@@ -25,6 +26,15 @@ namespace OHOS {
|
||||
namespace AppExecFwk {
|
||||
class ApplicationDataManager {
|
||||
public:
|
||||
struct ExceptionParams {
|
||||
napi_env env;
|
||||
napi_env mainEnv;
|
||||
napi_value exception;
|
||||
std::string summary;
|
||||
bool isUncatchable;
|
||||
};
|
||||
|
||||
static std::atomic<bool> jsErrorHasReport_;
|
||||
static ApplicationDataManager &GetInstance();
|
||||
void AddErrorObserver(const std::shared_ptr<IErrorObserver> &observer);
|
||||
bool NotifyUnhandledException(const std::string &errMsg);
|
||||
@@ -36,10 +46,11 @@ public:
|
||||
bool NotifyETSExceptionObject(const AppExecFwk::ErrorObject &errorObj);
|
||||
void SetIsUncatchable(bool isUncatchable);
|
||||
bool GetIsUncatchable();
|
||||
|
||||
static bool NotifyUncaughtException(const ExceptionParams ¶ms, const AppExecFwk::ErrorObject &errorObj);
|
||||
private:
|
||||
ApplicationDataManager();
|
||||
~ApplicationDataManager();
|
||||
static std::string GetFuncNameFromError(napi_env env, napi_value error);
|
||||
DISALLOW_COPY_AND_MOVE(ApplicationDataManager);
|
||||
std::shared_ptr<IErrorObserver> errorObserver_;
|
||||
std::atomic_bool isUncatchable_;
|
||||
|
||||
@@ -55,7 +55,8 @@ class Runtime;
|
||||
namespace OHOS {
|
||||
namespace JsEnv {
|
||||
struct ErrorObject;
|
||||
using UncatchableTask = std::function<void(std::string summary, const JsEnv::ErrorObject errorObject)>;
|
||||
using UncatchableTask = std::function<void(std::string summary, const JsEnv::ErrorObject errorObject, napi_env env,
|
||||
napi_value exception)>;
|
||||
} // namespace JsEnv
|
||||
namespace EtsEnv {
|
||||
struct ETSUncaughtExceptionInfo;
|
||||
@@ -80,6 +81,16 @@ struct RuntimeUpdateParam {
|
||||
UncatchableTaskInfo uncatchableTaskInfo;
|
||||
std::string hapPath;
|
||||
};
|
||||
struct ProcessExitInfo {
|
||||
std::string bundleName;
|
||||
std::string errorObjectName;
|
||||
std::string summary;
|
||||
std::string appRunningId;
|
||||
std::string processName;
|
||||
int32_t pid;
|
||||
bool foreground;
|
||||
bool isUncatchable;
|
||||
};
|
||||
class ContextDeal;
|
||||
struct ModuleTestRunner;
|
||||
// class Global::Resource::ResourceManager;
|
||||
@@ -460,6 +471,15 @@ private:
|
||||
void InitUncatchableTask(JsEnv::UncatchableTask &uncatchableTask, const UncatchableTaskInfo &uncatchableTaskInfo,
|
||||
bool isUncatchable = false);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Handle process exit.
|
||||
*
|
||||
* @param processExitInfo The info of the process exit info.
|
||||
*
|
||||
*/
|
||||
static void ProcessExit(const ProcessExitInfo& info);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief update the application info after new module installed.
|
||||
|
||||
@@ -177,8 +177,9 @@ void JsEnvironment::RegisterUncatchableExceptionHandler(const JsEnv::Uncatchable
|
||||
[weakThis, uncatchableTask] (auto& trycatch) {
|
||||
auto sharedThis = weakThis.lock();
|
||||
if (sharedThis) {
|
||||
void* env = trycatch.GetEnv();
|
||||
NapiUncaughtExceptionCallback napiUncaughtExceptionCallback(uncatchableTask,
|
||||
sharedThis->sourceMapOperator_, reinterpret_cast<napi_env>(sharedThis->engine_));
|
||||
sharedThis->sourceMapOperator_, reinterpret_cast<napi_env>(env));
|
||||
napiUncaughtExceptionCallback(trycatch);
|
||||
} else {
|
||||
TAG_LOGE(AAFwkTag::JSENV, "JsEnvironment has been destructed.");
|
||||
|
||||
@@ -129,7 +129,7 @@ void NapiUncaughtExceptionCallback::CallbackTask(napi_value& obj)
|
||||
}
|
||||
}
|
||||
if (uncaughtTask_) {
|
||||
uncaughtTask_(summary, errorObj);
|
||||
uncaughtTask_(summary, errorObj, env_, obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@ class JsEnvironmentImpl;
|
||||
using DebuggerPostTask = std::function<void(std::function<void()>&&)>;
|
||||
using RequestAotCallback =
|
||||
std::function<int32_t(const std::string& bundleName, const std::string& moduleName, int32_t triggerMode)>;
|
||||
using UncatchableTask = std::function<void(std::string summary, const JsEnv::ErrorObject errorObject)>;
|
||||
using UncatchableTask = std::function<void(std::string summary, const JsEnv::ErrorObject errorObject, napi_env env,
|
||||
napi_value exception)>;
|
||||
class JsEnvironment final : public std::enable_shared_from_this<JsEnvironment> {
|
||||
public:
|
||||
JsEnvironment() {}
|
||||
|
||||
@@ -33,13 +33,15 @@ struct ErrorObject {
|
||||
|
||||
struct UncaughtExceptionInfo {
|
||||
std::string hapPath;
|
||||
std::function<void(std::string summary, const JsEnv::ErrorObject errorObj)> uncaughtTask;
|
||||
std::function<void(std::string summary, const JsEnv::ErrorObject errorObj, napi_env env,
|
||||
napi_value exception)> uncaughtTask;
|
||||
};
|
||||
|
||||
class NapiUncaughtExceptionCallback final {
|
||||
public:
|
||||
NapiUncaughtExceptionCallback(
|
||||
std::function<void(const std::string summary, const JsEnv::ErrorObject errorObj)> uncaughtTask,
|
||||
std::function<void(const std::string summary, const JsEnv::ErrorObject errorObj, napi_env env,
|
||||
napi_value exception)> uncaughtTask,
|
||||
std::shared_ptr<SourceMapOperator> sourceMapOperator, napi_env env)
|
||||
: uncaughtTask_(uncaughtTask), sourceMapOperator_(sourceMapOperator), env_(env)
|
||||
{}
|
||||
@@ -65,7 +67,8 @@ public:
|
||||
#endif // SUPPORT_GRAPHICS
|
||||
|
||||
private:
|
||||
std::function<void(std::string summary, const JsEnv::ErrorObject errorObj)> uncaughtTask_;
|
||||
std::function<void(std::string summary, const JsEnv::ErrorObject errorObj, napi_env napi,
|
||||
napi_value exception)> uncaughtTask_;
|
||||
std::shared_ptr<SourceMapOperator> sourceMapOperator_ = nullptr;
|
||||
napi_env env_ = nullptr;
|
||||
};
|
||||
|
||||
+5
-5
@@ -72,7 +72,7 @@ HWTEST_F(NapiUncaughtExceptionCallbackTest, NapiUncaughtExceptionCallbackTest_01
|
||||
EXPECT_NE(env, nullptr);
|
||||
|
||||
// Test with null object
|
||||
auto task = [](std::string summary, const JsEnv::ErrorObject errorObj) {
|
||||
auto task = [](std::string summary, const JsEnv::ErrorObject errorObj, napi_env env, napi_value exception) {
|
||||
summary += "test";
|
||||
};
|
||||
NapiUncaughtExceptionCallback callback(task, nullptr, env);
|
||||
@@ -120,7 +120,7 @@ HWTEST_F(NapiUncaughtExceptionCallbackTest, NapiUncaughtExceptionCallbackTest_01
|
||||
EXPECT_NE(env, nullptr);
|
||||
|
||||
// Test with null object
|
||||
auto task = [](std::string summary, const JsEnv::ErrorObject errorObj) {
|
||||
auto task = [](std::string summary, const JsEnv::ErrorObject errorObj, napi_env env, napi_value exception) {
|
||||
summary += "test";
|
||||
};
|
||||
|
||||
@@ -149,7 +149,7 @@ HWTEST_F(NapiUncaughtExceptionCallbackTest, NapiUncaughtExceptionCallbackTest_02
|
||||
auto env = jsRuntime->GetNapiEnv();
|
||||
EXPECT_NE(env, nullptr);
|
||||
// Test with null object
|
||||
auto task = [](std::string summary, const JsEnv::ErrorObject errorObj) {
|
||||
auto task = [](std::string summary, const JsEnv::ErrorObject errorObj, napi_env env, napi_value exception) {
|
||||
summary += "test";
|
||||
};
|
||||
napi_value nullValue = nullptr;
|
||||
@@ -197,7 +197,7 @@ HWTEST_F(NapiUncaughtExceptionCallbackTest, NapiUncaughtExceptionCallbackTest_03
|
||||
napi_create_string_utf8(env, errorStack.c_str(), errorStack.length(), &nativeErrorStack);
|
||||
napi_set_named_property(env, object, "code", nativeErrorCode);
|
||||
napi_set_named_property(env, object, "stack", nativeErrorStack);
|
||||
auto task = [](std::string summary, const JsEnv::ErrorObject errorObj) {
|
||||
auto task = [](std::string summary, const JsEnv::ErrorObject errorObj, napi_env env, napi_value exception) {
|
||||
summary += "test";
|
||||
};
|
||||
NapiUncaughtExceptionCallback callback(task, nullptr, env);
|
||||
@@ -232,7 +232,7 @@ HWTEST_F(NapiUncaughtExceptionCallbackTest, NapiUncaughtExceptionCallbackTest_04
|
||||
return thisVar;
|
||||
};
|
||||
|
||||
auto task = [](std::string summary, const JsEnv::ErrorObject errorObj) {
|
||||
auto task = [](std::string summary, const JsEnv::ErrorObject errorObj, napi_env env, napi_value exception) {
|
||||
summary += "test";
|
||||
};
|
||||
napi_value nativeErrorCode = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user