133eb0b6dSopenharmony_ci/* 233eb0b6dSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 333eb0b6dSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 433eb0b6dSopenharmony_ci * you may not use this file except in compliance with the License. 533eb0b6dSopenharmony_ci * You may obtain a copy of the License at 633eb0b6dSopenharmony_ci * 733eb0b6dSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 833eb0b6dSopenharmony_ci * 933eb0b6dSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1033eb0b6dSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1133eb0b6dSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1233eb0b6dSopenharmony_ci * See the License for the specific language governing permissions and 1333eb0b6dSopenharmony_ci * limitations under the License. 1433eb0b6dSopenharmony_ci */ 1533eb0b6dSopenharmony_ci 1633eb0b6dSopenharmony_ci#ifndef FOUNDATION_ACE_NAPI_NATIVE_ENGINE_NATIVE_ASYNC_HOOK_CONTEXT_H 1733eb0b6dSopenharmony_ci#define FOUNDATION_ACE_NAPI_NATIVE_ENGINE_NATIVE_ASYNC_HOOK_CONTEXT_H 1833eb0b6dSopenharmony_ci 1933eb0b6dSopenharmony_ci#include "callback_scope_manager/native_callback_scope_manager.h" 2033eb0b6dSopenharmony_ci#include "ecmascript/napi/include/jsnapi.h" 2133eb0b6dSopenharmony_ci#include "native_value.h" 2233eb0b6dSopenharmony_ci#include "native_engine.h" 2333eb0b6dSopenharmony_ci#include "utils/log.h" 2433eb0b6dSopenharmony_ci 2533eb0b6dSopenharmony_ciclass NativeAsyncHookContext; 2633eb0b6dSopenharmony_cistatic panda::JSValueRef* InternalMakeCallback(NativeEngine* engine, panda::FunctionRef* funRef, 2733eb0b6dSopenharmony_ci panda::JSValueRef* obj, panda::JSValueRef *const argv[], 2833eb0b6dSopenharmony_ci size_t argc, NativeAsyncHookContext* asyncContext); 2933eb0b6dSopenharmony_ci 3033eb0b6dSopenharmony_cienum CallbackScopeCode { 3133eb0b6dSopenharmony_ci CALLBACK_SCOPE_OK = 0, 3233eb0b6dSopenharmony_ci CALLBACK_SCOPE_INVALID_ARG, 3333eb0b6dSopenharmony_ci CALLBACK_SCOPE_MISMATCH, 3433eb0b6dSopenharmony_ci}; 3533eb0b6dSopenharmony_ci 3633eb0b6dSopenharmony_ciclass NativeAsyncHookContext { 3733eb0b6dSopenharmony_cipublic: 3833eb0b6dSopenharmony_ci NativeAsyncHookContext(NativeEngine* env, 3933eb0b6dSopenharmony_ci panda::Local<panda::ObjectRef> resourceObject, 4033eb0b6dSopenharmony_ci const panda::Local<panda::StringRef> resourceName, 4133eb0b6dSopenharmony_ci bool isExternalResource) : env_(env), resource_(env->GetEcmaVm(), resourceObject) 4233eb0b6dSopenharmony_ci { 4333eb0b6dSopenharmony_ci asyncId_ = env->NewAsyncId(); 4433eb0b6dSopenharmony_ci triggerAsyncId_ = env->GetDefaultTriggerAsyncId(); 4533eb0b6dSopenharmony_ci lostReference_ = false; 4633eb0b6dSopenharmony_ci if (isExternalResource) { 4733eb0b6dSopenharmony_ci resource_.SetWeak(); 4833eb0b6dSopenharmony_ci resource_.SetWeakCallback(reinterpret_cast<void*>(this), FreeGlobalCallBack, NativeFinalizeCallBack); 4933eb0b6dSopenharmony_ci } 5033eb0b6dSopenharmony_ci 5133eb0b6dSopenharmony_ci NativeAsyncWrap::EmitAsyncInit(env, 5233eb0b6dSopenharmony_ci resourceObject, 5333eb0b6dSopenharmony_ci resourceName, 5433eb0b6dSopenharmony_ci asyncId_, 5533eb0b6dSopenharmony_ci triggerAsyncId_); 5633eb0b6dSopenharmony_ci } 5733eb0b6dSopenharmony_ci 5833eb0b6dSopenharmony_ci ~NativeAsyncHookContext() 5933eb0b6dSopenharmony_ci { 6033eb0b6dSopenharmony_ci resource_.FreeGlobalHandleAddr(); 6133eb0b6dSopenharmony_ci lostReference_ = true; 6233eb0b6dSopenharmony_ci NativeAsyncWrap::EmitDestroy(env_, asyncId_); 6333eb0b6dSopenharmony_ci } 6433eb0b6dSopenharmony_ci 6533eb0b6dSopenharmony_ci static void FreeGlobalCallBack(void* ref) 6633eb0b6dSopenharmony_ci { 6733eb0b6dSopenharmony_ci auto that = reinterpret_cast<NativeAsyncHookContext*>(ref); 6833eb0b6dSopenharmony_ci that->resource_.FreeGlobalHandleAddr(); 6933eb0b6dSopenharmony_ci that->lostReference_ = true; 7033eb0b6dSopenharmony_ci } 7133eb0b6dSopenharmony_ci 7233eb0b6dSopenharmony_ci static void NativeFinalizeCallBack(void* ref) {} 7333eb0b6dSopenharmony_ci 7433eb0b6dSopenharmony_ci inline AsyncIdInfo GetAsyncIdInfo() 7533eb0b6dSopenharmony_ci { 7633eb0b6dSopenharmony_ci return {asyncId_, triggerAsyncId_}; 7733eb0b6dSopenharmony_ci } 7833eb0b6dSopenharmony_ci 7933eb0b6dSopenharmony_ci inline NativeCallbackScope* OpenCallbackScope() 8033eb0b6dSopenharmony_ci { 8133eb0b6dSopenharmony_ci EnsureReference(); 8233eb0b6dSopenharmony_ci auto callbackScopeManager = env_->GetCallbackScopeManager(); 8333eb0b6dSopenharmony_ci if (callbackScopeManager == nullptr) { 8433eb0b6dSopenharmony_ci return nullptr; 8533eb0b6dSopenharmony_ci } 8633eb0b6dSopenharmony_ci 8733eb0b6dSopenharmony_ci auto callbackScope = callbackScopeManager->Open(env_, resource_.ToLocal(), GetAsyncIdInfo()); 8833eb0b6dSopenharmony_ci callbackScopeManager->IncrementOpenCallbackScopes(); 8933eb0b6dSopenharmony_ci 9033eb0b6dSopenharmony_ci return callbackScope; 9133eb0b6dSopenharmony_ci } 9233eb0b6dSopenharmony_ci 9333eb0b6dSopenharmony_ci inline void EnsureReference() 9433eb0b6dSopenharmony_ci { 9533eb0b6dSopenharmony_ci if (lostReference_) { 9633eb0b6dSopenharmony_ci auto ecmaVm = env_->GetEcmaVm(); 9733eb0b6dSopenharmony_ci panda::Global<panda::ObjectRef> resource(ecmaVm, panda::ObjectRef::New(ecmaVm)); 9833eb0b6dSopenharmony_ci resource_ = resource; 9933eb0b6dSopenharmony_ci lostReference_ = false; 10033eb0b6dSopenharmony_ci } 10133eb0b6dSopenharmony_ci } 10233eb0b6dSopenharmony_ci 10333eb0b6dSopenharmony_ci static CallbackScopeCode CloseCallbackScope(NativeEngine* env, NativeCallbackScope* scope) 10433eb0b6dSopenharmony_ci { 10533eb0b6dSopenharmony_ci auto callbackScopeManager = env->GetCallbackScopeManager(); 10633eb0b6dSopenharmony_ci if (callbackScopeManager == nullptr) { 10733eb0b6dSopenharmony_ci return CALLBACK_SCOPE_INVALID_ARG; 10833eb0b6dSopenharmony_ci } 10933eb0b6dSopenharmony_ci if (callbackScopeManager->GetOpenCallbackScopes() > 0) { 11033eb0b6dSopenharmony_ci callbackScopeManager->DecrementOpenCallbackScopes(); 11133eb0b6dSopenharmony_ci callbackScopeManager->Close(scope); 11233eb0b6dSopenharmony_ci return CALLBACK_SCOPE_OK; 11333eb0b6dSopenharmony_ci } else { 11433eb0b6dSopenharmony_ci return CALLBACK_SCOPE_MISMATCH; 11533eb0b6dSopenharmony_ci } 11633eb0b6dSopenharmony_ci } 11733eb0b6dSopenharmony_ci 11833eb0b6dSopenharmony_ci panda::JSValueRef* MakeCallback(panda::FunctionRef* funRef, panda::JSValueRef* obj, 11933eb0b6dSopenharmony_ci panda::JSValueRef *const argv[], size_t argc) 12033eb0b6dSopenharmony_ci { 12133eb0b6dSopenharmony_ci EnsureReference(); 12233eb0b6dSopenharmony_ci panda::JSValueRef* rst = InternalMakeCallback(env_, funRef, obj, argv, argc, this); 12333eb0b6dSopenharmony_ci return rst; 12433eb0b6dSopenharmony_ci } 12533eb0b6dSopenharmony_ciprivate: 12633eb0b6dSopenharmony_ci NativeEngine* env_ {nullptr}; 12733eb0b6dSopenharmony_ci double asyncId_ = 0; 12833eb0b6dSopenharmony_ci double triggerAsyncId_ = 0; 12933eb0b6dSopenharmony_ci panda::Global<panda::ObjectRef> resource_; 13033eb0b6dSopenharmony_ci bool lostReference_ = false; 13133eb0b6dSopenharmony_ci}; 13233eb0b6dSopenharmony_ci 13333eb0b6dSopenharmony_cistatic panda::FunctionRef* AsyncHooksCallbackTrampoline() 13433eb0b6dSopenharmony_ci{ 13533eb0b6dSopenharmony_ci return nullptr; // not support async_hook yet, and the actions need to be improved in the future 13633eb0b6dSopenharmony_ci} 13733eb0b6dSopenharmony_ci 13833eb0b6dSopenharmony_cistatic void CloseScope(NativeAsyncHookContext* nativeAsyncContext, 13933eb0b6dSopenharmony_ci NativeCallbackScopeManager* callbackScopeMgr, 14033eb0b6dSopenharmony_ci NativeCallbackScope* callbackScope, 14133eb0b6dSopenharmony_ci NativeEngine* engine) 14233eb0b6dSopenharmony_ci{ 14333eb0b6dSopenharmony_ci if (nativeAsyncContext != nullptr) { 14433eb0b6dSopenharmony_ci nativeAsyncContext->CloseCallbackScope(engine, callbackScope); 14533eb0b6dSopenharmony_ci } else { 14633eb0b6dSopenharmony_ci if (callbackScopeMgr != nullptr) { 14733eb0b6dSopenharmony_ci callbackScopeMgr->Close(callbackScope); 14833eb0b6dSopenharmony_ci } 14933eb0b6dSopenharmony_ci } 15033eb0b6dSopenharmony_ci} 15133eb0b6dSopenharmony_ci 15233eb0b6dSopenharmony_cistatic panda::JSValueRef* InternalMakeCallback(NativeEngine* engine, panda::FunctionRef* funRef, 15333eb0b6dSopenharmony_ci panda::JSValueRef* obj, panda::JSValueRef* const argv[], 15433eb0b6dSopenharmony_ci size_t argc, NativeAsyncHookContext* asyncContext) 15533eb0b6dSopenharmony_ci{ 15633eb0b6dSopenharmony_ci auto vm = engine->GetEcmaVm(); 15733eb0b6dSopenharmony_ci if (funRef == nullptr) { 15833eb0b6dSopenharmony_ci HILOG_ERROR("funRef is nullptr!"); 15933eb0b6dSopenharmony_ci return *panda::JSValueRef::Undefined(vm); 16033eb0b6dSopenharmony_ci } 16133eb0b6dSopenharmony_ci 16233eb0b6dSopenharmony_ci bool useAsyncHooksTrampoline = false; 16333eb0b6dSopenharmony_ci panda::FunctionRef* rstFunRef = AsyncHooksCallbackTrampoline(); 16433eb0b6dSopenharmony_ci if (rstFunRef != nullptr) { 16533eb0b6dSopenharmony_ci useAsyncHooksTrampoline = true; 16633eb0b6dSopenharmony_ci } 16733eb0b6dSopenharmony_ci NativeCallbackScopeManager* callbackScopeMgr = nullptr; 16833eb0b6dSopenharmony_ci NativeCallbackScope* callbackScope; 16933eb0b6dSopenharmony_ci if (asyncContext == nullptr) { 17033eb0b6dSopenharmony_ci callbackScopeMgr = engine->GetCallbackScopeManager(); 17133eb0b6dSopenharmony_ci callbackScope = callbackScopeMgr->Open(engine, 17233eb0b6dSopenharmony_ci panda::Local<panda::ObjectRef>(reinterpret_cast<uintptr_t>(obj)), {0, 0}); 17333eb0b6dSopenharmony_ci } else { 17433eb0b6dSopenharmony_ci callbackScope = asyncContext->OpenCallbackScope(); 17533eb0b6dSopenharmony_ci } 17633eb0b6dSopenharmony_ci 17733eb0b6dSopenharmony_ci panda::JSValueRef* callBackRst; 17833eb0b6dSopenharmony_ci if (useAsyncHooksTrampoline) { 17933eb0b6dSopenharmony_ci callBackRst = nullptr; // not support async_hook yet, and the actions need to be improved in the future 18033eb0b6dSopenharmony_ci } else { 18133eb0b6dSopenharmony_ci callBackRst = funRef->CallForNapi(vm, obj, argv, argc); 18233eb0b6dSopenharmony_ci } 18333eb0b6dSopenharmony_ci 18433eb0b6dSopenharmony_ci if (callbackScope != nullptr) { 18533eb0b6dSopenharmony_ci if (callBackRst == nullptr) { 18633eb0b6dSopenharmony_ci callbackScope->MarkAsFailed(); 18733eb0b6dSopenharmony_ci } 18833eb0b6dSopenharmony_ci callbackScope->Close(); 18933eb0b6dSopenharmony_ci } 19033eb0b6dSopenharmony_ci 19133eb0b6dSopenharmony_ci CloseScope(asyncContext, callbackScopeMgr, callbackScope, engine); 19233eb0b6dSopenharmony_ci return callBackRst; 19333eb0b6dSopenharmony_ci} 19433eb0b6dSopenharmony_ci 19533eb0b6dSopenharmony_cipanda::JSValueRef* MakeCallback(NativeEngine* engine, panda::FunctionRef* funRef, 19633eb0b6dSopenharmony_ci panda::JSValueRef* obj, size_t argc, 19733eb0b6dSopenharmony_ci panda::JSValueRef* const argv[], NativeAsyncHookContext* asyncContext) 19833eb0b6dSopenharmony_ci{ 19933eb0b6dSopenharmony_ci auto vm = engine->GetEcmaVm(); 20033eb0b6dSopenharmony_ci panda::JSValueRef* rst = InternalMakeCallback(engine, funRef, obj, argv, argc, asyncContext); 20133eb0b6dSopenharmony_ci NativeCallbackScopeManager* callbackScopeMgr = engine->GetCallbackScopeManager(); 20233eb0b6dSopenharmony_ci size_t depth = callbackScopeMgr->GetAsyncCallbackScopeDepth(); 20333eb0b6dSopenharmony_ci if (rst == nullptr && depth == 0) { 20433eb0b6dSopenharmony_ci return *panda::JSValueRef::Undefined(vm); 20533eb0b6dSopenharmony_ci } 20633eb0b6dSopenharmony_ci return rst; 20733eb0b6dSopenharmony_ci} 20833eb0b6dSopenharmony_ci 20933eb0b6dSopenharmony_ci#endif /* FOUNDATION_ACE_NAPI_NATIVE_ENGINE_NATIVE_ASYNC_HOOK_CONTEXT_H */ 210