diff --git a/frameworks/js/napi/app/error_manager/BUILD.gn b/frameworks/js/napi/app/error_manager/BUILD.gn index c004b8e51ad85670b00730ad4bcc1b2fbd69c9e3..8949155520ccdba594cc4be3d1df1e79c600f230 100644 --- a/frameworks/js/napi/app/error_manager/BUILD.gn +++ b/frameworks/js/napi/app/error_manager/BUILD.gn @@ -41,6 +41,7 @@ template("errormanager") { external_deps = [ "c_utils:utils", + "eventhandler:libeventhandler", "hilog:libhilog", "napi:ace_napi", ] diff --git a/frameworks/js/napi/app/error_manager/js_error_manager.cpp b/frameworks/js/napi/app/error_manager/js_error_manager.cpp index c4973594bff9f73e8b2f99b62984b94a56374b70..3e09fd5a70558dfb50af8bcb0aeed8e05847cd69 100644 --- a/frameworks/js/napi/app/error_manager/js_error_manager.cpp +++ b/frameworks/js/napi/app/error_manager/js_error_manager.cpp @@ -16,9 +16,11 @@ #include "js_error_manager.h" #include +#include #include "ability_business_error.h" #include "application_data_manager.h" +#include "event_runner.h" #include "hilog_wrapper.h" #include "js_error_observer.h" #include "js_error_utils.h" @@ -29,13 +31,21 @@ namespace OHOS { namespace AbilityRuntime { namespace { +struct JsLoopObserver { + std::shared_ptr mainRunner; + std::shared_ptr observerObject; + napi_env env; +}; +static std::shared_ptr loopObserver_; constexpr int32_t INDEX_ZERO = 0; constexpr int32_t INDEX_ONE = 1; constexpr int32_t INDEX_TWO = 2; +constexpr size_t ARGC_ONE = 1; constexpr size_t ARGC_TWO = 2; constexpr size_t ARGC_THREE = 3; constexpr const char* ON_OFF_TYPE = "error"; constexpr const char* ON_OFF_TYPE_SYNC = "errorEvent"; +constexpr const char* ON_OFF_TYPE_SYNC_LOOP = "loopObserver"; class JsErrorManager final { public: @@ -66,6 +76,14 @@ private: if (type == ON_OFF_TYPE_SYNC) { return OnOnNew(env, argc, argv); } + if (type == ON_OFF_TYPE_SYNC_LOOP) { + if (!AppExecFwk::EventRunner::IsAppMainThread()) { + HILOG_ERROR("LoopObserver can only be set from main thread."); + ThrowInvaildCallerError(env); + return CreateJsUndefined(env); + } + return OnSetLoopWatch(env, argc, argv); + } return OnOnOld(env, argc, argv); } @@ -139,6 +157,14 @@ private: if (type == ON_OFF_TYPE_SYNC) { return OnOffNew(env, argc, argv); } + if (type == ON_OFF_TYPE_SYNC_LOOP) { + if (!AppExecFwk::EventRunner::IsAppMainThread()) { + HILOG_ERROR("LoopObserver can only be set from main thread."); + ThrowInvaildCallerError(env); + return CreateJsUndefined(env); + } + return OnRemoveLoopWatch(env, argc, argv); + } return OnOffOld(env, argc, argv); } @@ -219,6 +245,99 @@ private: return CreateJsUndefined(env); } + static void CallJsFunction(napi_env env, napi_value obj, const char* methodName, + napi_value const* argv, size_t argc) + { + HILOG_INFO("CallJsFunction begin methodName: %{public}s", methodName); + if (obj == nullptr) { + HILOG_ERROR("Failed to get object"); + return; + } + + napi_value method = nullptr; + napi_get_named_property(env, obj, methodName, &method); + if (method == nullptr) { + HILOG_ERROR("Failed to get method"); + return; + } + napi_value callResult = nullptr; + napi_call_function(env, obj, method, argc, argv, &callResult); + } + + static void CallbackTimeout(int64_t number) + { + std::unique_ptr complete = std::make_unique + ([number](napi_env env, NapiAsyncTask &task, int32_t status) { + if (loopObserver_ == nullptr) { + HILOG_ERROR("CallbackTimeout: loopObserver_ is null."); + return; + } + if (loopObserver_->env == nullptr) { + HILOG_ERROR("CallbackTimeout: env is null."); + return; + } + if (loopObserver_->observerObject == nullptr) { + HILOG_ERROR("CallbackTimeout: observerObject is null."); + return; + } + napi_value jsValue[] = { CreateJsValue(loopObserver_->env, number) }; + CallJsFunction(loopObserver_->env, loopObserver_->observerObject->GetNapiValue(), "onLoopTimeOut", + jsValue, ARGC_ONE); + }); + napi_ref callback = nullptr; + std::unique_ptr execute = nullptr; + if (loopObserver_ && loopObserver_->env) { + NapiAsyncTask::Schedule("JsErrorObserver::CallbackTimeout", + loopObserver_->env, std::make_unique(callback, std::move(execute), std::move(complete))); + } + } + + napi_value OnSetLoopWatch(napi_env env, size_t argc, napi_value* argv) + { + if (argc != ARGC_THREE) { + HILOG_ERROR("OnSetLoopWatch: Not enough params."); + ThrowTooFewParametersError(env); + return CreateJsUndefined(env); + } + if (!CheckTypeForNapiValue(env, argv[INDEX_ONE], napi_number)) { + HILOG_ERROR("OnSetLoopWatch: Invalid param"); + ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM); + return CreateJsUndefined(env); + } + if (!CheckTypeForNapiValue(env, argv[INDEX_TWO], napi_object)) { + HILOG_ERROR("OnSetLoopWatch: Invalid param"); + ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM); + return CreateJsUndefined(env); + } + int64_t number; + if (!ConvertFromJsNumber(env, argv[INDEX_ONE], number)) { + HILOG_ERROR("OnSetLoopWatch: Parse timeout failed"); + ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM); + return CreateJsUndefined(env); + } + + if (loopObserver_ == nullptr) { + loopObserver_ = std::make_shared(); + } + loopObserver_->mainRunner = AppExecFwk::EventRunner::GetMainEventRunner(); + napi_ref ref = nullptr; + napi_create_reference(env, argv[INDEX_TWO], 1, &ref); + loopObserver_->observerObject = std::shared_ptr(reinterpret_cast(ref)); + loopObserver_->env = env; + loopObserver_->mainRunner->SetTimeout(number); + loopObserver_->mainRunner->SetTimeoutCallback(CallbackTimeout); + return nullptr; + } + + napi_value OnRemoveLoopWatch(napi_env env, size_t argc, napi_value* argv) + { + if (loopObserver_) { + loopObserver_.reset(); + loopObserver_ = nullptr; + } + return nullptr; + } + std::string ParseParamType(napi_env env, const size_t argc, napi_value* argv) { std::string type; diff --git a/frameworks/native/runtime/js_error_utils.cpp b/frameworks/native/runtime/js_error_utils.cpp index 08e6f66b554be00e3808f638720d86e7e0b0432c..b4fdabf08d553ab799f27d83d870ee7ae4551fa4 100755 --- a/frameworks/native/runtime/js_error_utils.cpp +++ b/frameworks/native/runtime/js_error_utils.cpp @@ -22,6 +22,7 @@ namespace OHOS { namespace AbilityRuntime { namespace { constexpr const char* ERR_MSG_TOO_FEW_PARAM = "Parameter error. Too few parameters."; +constexpr const char* ERR_MSG_NOT_MAINTHREAD = "Caller error. Caller from non-main thread."; } // namespace void ThrowError(napi_env env, int32_t errCode, const std::string& errorMsg) @@ -34,6 +35,13 @@ void ThrowError(napi_env env, const AbilityErrorCode& err) napi_throw(env, CreateJsError(env, static_cast(err), GetErrorMsg(err))); } +void ThrowInvaildCallerError(napi_env env) +{ + napi_throw(env, CreateJsError(env, + static_cast(AbilityErrorCode::ERROR_CODE_INVALID_CALLER), + ERR_MSG_NOT_MAINTHREAD)); +} + void ThrowTooFewParametersError(napi_env env) { napi_throw(env, CreateJsError(env, diff --git a/interfaces/inner_api/runtime/include/js_error_utils.h b/interfaces/inner_api/runtime/include/js_error_utils.h index ac867bb07f1171a6a711a21b0d45e67c3f915b80..dd69891b1055222096174adf6977eca24c833753 100755 --- a/interfaces/inner_api/runtime/include/js_error_utils.h +++ b/interfaces/inner_api/runtime/include/js_error_utils.h @@ -24,6 +24,7 @@ namespace AbilityRuntime { void ThrowError(napi_env env, int32_t errCode, const std::string& errorMsg = ""); void ThrowError(napi_env env, const AbilityErrorCode& err); +void ThrowInvaildCallerError(napi_env env); void ThrowTooFewParametersError(napi_env env); void ThrowNoPermissionError(napi_env env, const std::string& permission); void ThrowErrorByNativeErr(napi_env env, int32_t err);