!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:
openharmony_ci
2025-12-26 03:41:05 +08:00
11 changed files with 304 additions and 94 deletions
@@ -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 &params,
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
+55 -37
View File
@@ -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 &params, 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;
};
@@ -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;