diff --git a/js_environment/frameworks/js_environment/src/uncaught_exception_callback.cpp b/js_environment/frameworks/js_environment/src/uncaught_exception_callback.cpp index 1c5047df8b72153241455aebc98db9fb36cfa923..ef9916c465d05c55e1f70c44de5639cfcada793c 100644 --- a/js_environment/frameworks/js_environment/src/uncaught_exception_callback.cpp +++ b/js_environment/frameworks/js_environment/src/uncaught_exception_callback.cpp @@ -15,6 +15,7 @@ #include "uncaught_exception_callback.h" #include +#include #include #include @@ -33,6 +34,9 @@ namespace JsEnv { constexpr char BACKTRACE[] = "=====================Backtrace========================"; constexpr size_t FLAG_SPLIT_POS = 16; constexpr size_t FLAG_PC_POS = 4; +static const std::string LIB_AYNC_STACK_SO_NAME = "libasync_stack.z.so"; + +typedef int (*SubmitterStackFunc)(char*, size_t); std::string NapiUncaughtExceptionCallback::GetNativeStrFromJsTaggedObj(napi_value obj, const char* key) { @@ -80,7 +84,6 @@ void NapiUncaughtExceptionCallback::CallbackTask(napi_value& obj) std::string errorMsg = GetNativeStrFromJsTaggedObj(obj, "message"); std::string errorName = GetNativeStrFromJsTaggedObj(obj, "name"); std::string errorStack = GetNativeStrFromJsTaggedObj(obj, "stack"); - std::string topStack = GetNativeStrFromJsTaggedObj(obj, "topstack"); std::string summary = "Error name:" + errorName + "\n"; summary += "Error message:" + errorMsg + "\n"; const JsEnv::ErrorObject errorObj = { @@ -98,21 +101,10 @@ void NapiUncaughtExceptionCallback::CallbackTask(napi_value& obj) TAG_LOGE(AAFwkTag::JSENV, "errorStack is empty"); return; } - auto errorPos = SourceMap::GetErrorPos(topStack); - std::string error; - if (obj != nullptr) { - napi_value fuc = nullptr; - napi_get_named_property(env_, obj, "errorfunc", &fuc); - napi_valuetype valueType = napi_undefined; - napi_typeof(env_, fuc, &valueType); - if (valueType == napi_function) { - error = reinterpret_cast(env_)->GetSourceCodeInfo(fuc, errorPos); - } - } if (errorStack.find(BACKTRACE) != std::string::npos) { - summary += error + "Stacktrace:\n" + GetFuncNameAndBuildId(errorStack); + summary += "Stacktrace:\n" + GetFuncNameAndBuildId(errorStack); } else { - summary += error + "Stacktrace:\n" + errorStack; + summary += "Stacktrace:\n" + errorStack; } #ifdef SUPPORT_GRAPHICS std::string str = Ace::UIContent::GetCurrentUIStackInfo(); @@ -120,6 +112,11 @@ void NapiUncaughtExceptionCallback::CallbackTask(napi_value& obj) summary.append(str); } #endif // SUPPORT_GRAPHICS + std::string submitterStack = GetSubmitterStackLocal(); + if (!submitterStack.empty()) { + summary.append("========SubmitterStacktrace========\n"); + summary.append(submitterStack); + } if (uncaughtTask_) { uncaughtTask_(summary, errorObj); } @@ -175,5 +172,29 @@ std::string NapiUncaughtExceptionCallback::GetFuncNameAndBuildId(std::string nat } return appendInfo; } + +std::string NapiUncaughtExceptionCallback::GetSubmitterStackLocal() +{ + static SubmitterStackFunc sbmitterStack = nullptr; + void *handle = dlopen(LIB_AYNC_STACK_SO_NAME.c_str(), RTLD_NOW); + if (!handle) { + TAG_LOGE(AAFwkTag::JSENV, "Failed to dlopen libasync_stack, %{public}s", dlerror()); + return ""; + } + sbmitterStack = reinterpret_cast(dlsym(handle, "DfxGetSubmitterStackLocal")); + if (sbmitterStack == nullptr) { + TAG_LOGE(AAFwkTag::JSENV, "dlsym libasync_stack failed"); + return ""; + } + const size_t bufferSize = 64 * 1024; + char stackTrace[bufferSize] = {0}; + int result = sbmitterStack(stackTrace, bufferSize); + if (result == 0) { + return stackTrace; + } else { + TAG_LOGE(AAFwkTag::JSENV, "submitterStack interface failed"); + return ""; + } +} } // namespace JsEnv } // namespace OHOS diff --git a/js_environment/interfaces/inner_api/uncaught_exception_callback.h b/js_environment/interfaces/inner_api/uncaught_exception_callback.h index b8723554eafad611757f039d0bd8fac73da1df63..3838a527cc8e6522ab6e046a99eab73dc7ba5eb6 100644 --- a/js_environment/interfaces/inner_api/uncaught_exception_callback.h +++ b/js_environment/interfaces/inner_api/uncaught_exception_callback.h @@ -56,6 +56,8 @@ public: static std::string GetFuncNameAndBuildId(std::string nativeStack); + static std::string GetSubmitterStackLocal(); + private: std::function uncaughtTask_; std::shared_ptr sourceMapOperator_ = nullptr; diff --git a/js_environment/test/unittest/uncaught_exception_callback_test/uncaught_exception_callback_test.cpp b/js_environment/test/unittest/uncaught_exception_callback_test/uncaught_exception_callback_test.cpp index 1dbaf4662fdb9ab107035f0854cdeef31ab360f3..84e16898a653e79aa5b8560c1b46aa1e5f825f38 100644 --- a/js_environment/test/unittest/uncaught_exception_callback_test/uncaught_exception_callback_test.cpp +++ b/js_environment/test/unittest/uncaught_exception_callback_test/uncaught_exception_callback_test.cpp @@ -13,6 +13,8 @@ * limitations under the License. */ +#include "uv.h" + #include #include "uncaught_exception_callback.h" @@ -330,5 +332,42 @@ HWTEST_F(NapiUncaughtExceptionCallbackTest, GetFuncNameAndBuildIdTest_0100, Test ASSERT_EQ(stackinfo.find("GetFuncNameAndBuildIdTest") != std::string::npos, true); GTEST_LOG_(INFO) << "GetFuncNameAndBuildIdTest_0100 end" << stackinfo.c_str(); } + +std::string submitterStack; +int g_result = -1; +static bool g_done = false; + +static void WorkCallback(uv_work_t* req) +{ + submitterStack = NapiUncaughtExceptionCallback::GetSubmitterStackLocal(); +} + +static void AfterWorkCallback(uv_work_t* req, int status) +{ + if (!g_done) { + uv_queue_work(req->loop, req, WorkCallback, AfterWorkCallback); + } +} + +static void TimerCallback(uv_timer_t* handle) +{ + g_done = true; +} + +HWTEST_F(NapiUncaughtExceptionCallbackTest, GetSubmitterStackLocal_0100, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetSubmitterStackLocal_0100 start"; + setenv("HAP_DEBUGGABLE", "true", 1); + uv_timer_t timerHandle; + uv_work_t work; + uv_loop_t* loop = uv_default_loop(); + int timeout = 1000; + uv_timer_init(loop, &timerHandle); + uv_timer_start(&timerHandle, TimerCallback, timeout, 0); + uv_queue_work(loop, &work, WorkCallback, AfterWorkCallback); + uv_run(loop, UV_RUN_DEFAULT); + EXPECT_TRUE(!submitterStack.empty()); + GTEST_LOG_(INFO) << "GetSubmitterStackLocal_0100 end"; +} } // namespace AppExecFwk } // namespace OHOS