133eb0b6dSopenharmony_ci/* 233eb0b6dSopenharmony_ci * Copyright (c) 2021-2022 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#include "native_async_work.h" 1733eb0b6dSopenharmony_ci 1833eb0b6dSopenharmony_ci#ifdef ENABLE_HITRACE 1933eb0b6dSopenharmony_ci#include "hitrace/trace.h" 2033eb0b6dSopenharmony_ci#include "hitrace_meter.h" 2133eb0b6dSopenharmony_ci#include "parameter.h" 2233eb0b6dSopenharmony_ci#include <securec.h> 2333eb0b6dSopenharmony_ci#endif 2433eb0b6dSopenharmony_ci#ifdef ENABLE_CONTAINER_SCOPE 2533eb0b6dSopenharmony_ci#include "core/common/container_scope.h" 2633eb0b6dSopenharmony_ci#endif 2733eb0b6dSopenharmony_ci 2833eb0b6dSopenharmony_ci#include <cinttypes> 2933eb0b6dSopenharmony_ci#include "ecmascript/napi/include/jsnapi.h" 3033eb0b6dSopenharmony_ci#include "native_api_internal.h" 3133eb0b6dSopenharmony_ci#include "napi/native_api.h" 3233eb0b6dSopenharmony_ci#include "native_engine.h" 3333eb0b6dSopenharmony_ci#include "utils/log.h" 3433eb0b6dSopenharmony_ci 3533eb0b6dSopenharmony_ci#ifdef ENABLE_CONTAINER_SCOPE 3633eb0b6dSopenharmony_ciusing OHOS::Ace::ContainerScope; 3733eb0b6dSopenharmony_ci#endif 3833eb0b6dSopenharmony_ci 3933eb0b6dSopenharmony_ci#ifdef ENABLE_HITRACE 4033eb0b6dSopenharmony_cibool g_napiTraceIdEnabled = false; 4133eb0b6dSopenharmony_cibool g_ParamUpdated = false; 4233eb0b6dSopenharmony_ciconstexpr size_t TRACE_BUFFER_SIZE = 120; 4333eb0b6dSopenharmony_ciconstexpr size_t TRACEID_PARAM_SIZE = 10; 4433eb0b6dSopenharmony_ciconst std::string TRACE_POINT_QUEUE = "napi::NativeAsyncWork::Queue"; 4533eb0b6dSopenharmony_ciconst std::string TRACE_POINT_QUEUE_WITH_QOS = "napi::NativeAsyncWork::QueueWithQos"; 4633eb0b6dSopenharmony_ciconst std::string TRACE_POINT_ASYNCWORKCALLBACK = "napi::NativeAsyncWork::AsyncWorkCallback"; 4733eb0b6dSopenharmony_ciusing namespace OHOS::HiviewDFX; 4833eb0b6dSopenharmony_ci#endif 4933eb0b6dSopenharmony_ci 5033eb0b6dSopenharmony_ciNativeAsyncWork::NativeAsyncWork(NativeEngine* engine, 5133eb0b6dSopenharmony_ci NativeAsyncExecuteCallback execute, 5233eb0b6dSopenharmony_ci NativeAsyncCompleteCallback complete, 5333eb0b6dSopenharmony_ci const std::string &asyncResourceName, 5433eb0b6dSopenharmony_ci void* data) 5533eb0b6dSopenharmony_ci : work_({ 0 }), engine_(engine), engineId_(engine->GetId()), execute_(execute), complete_(complete), data_(data) 5633eb0b6dSopenharmony_ci{ 5733eb0b6dSopenharmony_ci work_.data = this; 5833eb0b6dSopenharmony_ci (void)asyncResourceName; 5933eb0b6dSopenharmony_ci#ifdef ENABLE_HITRACE 6033eb0b6dSopenharmony_ci if (!g_ParamUpdated) { 6133eb0b6dSopenharmony_ci char napiTraceIdEnabled[TRACEID_PARAM_SIZE] = {0}; 6233eb0b6dSopenharmony_ci int ret = GetParameter("persist.hiviewdfx.napitraceid.enabled", "false", 6333eb0b6dSopenharmony_ci napiTraceIdEnabled, sizeof(napiTraceIdEnabled)); 6433eb0b6dSopenharmony_ci if (ret > 0 && strcmp(napiTraceIdEnabled, "true") == 0) { 6533eb0b6dSopenharmony_ci g_napiTraceIdEnabled = true; 6633eb0b6dSopenharmony_ci } 6733eb0b6dSopenharmony_ci g_ParamUpdated = true; 6833eb0b6dSopenharmony_ci } 6933eb0b6dSopenharmony_ci bool createdTraceId = false; 7033eb0b6dSopenharmony_ci 7133eb0b6dSopenharmony_ci HiTraceId thisId = HiTraceChain::GetId(); 7233eb0b6dSopenharmony_ci if (g_napiTraceIdEnabled && (!thisId.IsValid())) { 7333eb0b6dSopenharmony_ci thisId = HiTraceChain::Begin("New NativeAsyncWork", 0); 7433eb0b6dSopenharmony_ci createdTraceId = true; 7533eb0b6dSopenharmony_ci } 7633eb0b6dSopenharmony_ci if (thisId.IsValid()) { 7733eb0b6dSopenharmony_ci taskTraceId_ = HiTraceChain::CreateSpan(); 7833eb0b6dSopenharmony_ci } 7933eb0b6dSopenharmony_ci char traceStr[TRACE_BUFFER_SIZE] = {0}; 8033eb0b6dSopenharmony_ci if (sprintf_s(traceStr, sizeof(traceStr), 8133eb0b6dSopenharmony_ci "name:%s, traceid:0x%x", asyncResourceName.c_str(), taskTraceId_.GetChainId()) < 0) { 8233eb0b6dSopenharmony_ci HILOG_ERROR("Get traceStr fail"); 8333eb0b6dSopenharmony_ci } 8433eb0b6dSopenharmony_ci traceDescription_ = traceStr; 8533eb0b6dSopenharmony_ci if (createdTraceId) { 8633eb0b6dSopenharmony_ci OHOS::HiviewDFX::HiTraceChain::ClearId(); 8733eb0b6dSopenharmony_ci } 8833eb0b6dSopenharmony_ci#endif 8933eb0b6dSopenharmony_ci#ifdef ENABLE_CONTAINER_SCOPE 9033eb0b6dSopenharmony_ci containerScopeId_ = ContainerScope::CurrentId(); 9133eb0b6dSopenharmony_ci#endif 9233eb0b6dSopenharmony_ci} 9333eb0b6dSopenharmony_ci 9433eb0b6dSopenharmony_ciNativeAsyncWork::~NativeAsyncWork() = default; 9533eb0b6dSopenharmony_ci 9633eb0b6dSopenharmony_cibool NativeAsyncWork::Queue() 9733eb0b6dSopenharmony_ci{ 9833eb0b6dSopenharmony_ci if (engineId_ != engine_->GetId()) { 9933eb0b6dSopenharmony_ci LOG_IF_SPECIAL(UNLIKELY(engine_->IsCrossThreadCheckEnabled()), 10033eb0b6dSopenharmony_ci "owner env has been destroyed, " 10133eb0b6dSopenharmony_ci "current env id: %{public}" PRIu64 ", owner id: %{public}" PRIu64, 10233eb0b6dSopenharmony_ci engineId_, engine_->GetId()); 10333eb0b6dSopenharmony_ci } 10433eb0b6dSopenharmony_ci 10533eb0b6dSopenharmony_ci uv_loop_t* loop = engine_->GetUVLoop(); 10633eb0b6dSopenharmony_ci if (loop == nullptr) { 10733eb0b6dSopenharmony_ci HILOG_ERROR("Get loop failed"); 10833eb0b6dSopenharmony_ci return false; 10933eb0b6dSopenharmony_ci } 11033eb0b6dSopenharmony_ci engine_->IncreaseWaitingRequestCounter(); 11133eb0b6dSopenharmony_ci#ifdef ENABLE_HITRACE 11233eb0b6dSopenharmony_ci StartTrace(HITRACE_TAG_ACE, "Napi queue, " + this->GetTraceDescription()); 11333eb0b6dSopenharmony_ci HiTraceId taskId = taskTraceId_; 11433eb0b6dSopenharmony_ci HiTraceChain::Tracepoint(HITRACE_TP_CS, taskId, "%s", TRACE_POINT_QUEUE.c_str()); 11533eb0b6dSopenharmony_ci#endif 11633eb0b6dSopenharmony_ci int status = uv_queue_work(loop, &work_, AsyncWorkCallback, AsyncAfterWorkCallback); 11733eb0b6dSopenharmony_ci#ifdef ENABLE_HITRACE 11833eb0b6dSopenharmony_ci HiTraceChain::Tracepoint(HITRACE_TP_CR, taskId, "%s", TRACE_POINT_QUEUE.c_str()); 11933eb0b6dSopenharmony_ci FinishTrace(HITRACE_TAG_ACE); 12033eb0b6dSopenharmony_ci#endif 12133eb0b6dSopenharmony_ci if (status != 0) { 12233eb0b6dSopenharmony_ci HILOG_ERROR("uv_queue_work failed"); 12333eb0b6dSopenharmony_ci engine_->DecreaseWaitingRequestCounter(); 12433eb0b6dSopenharmony_ci return false; 12533eb0b6dSopenharmony_ci } 12633eb0b6dSopenharmony_ci HILOG_DEBUG("uv_queue_work succeed"); 12733eb0b6dSopenharmony_ci return true; 12833eb0b6dSopenharmony_ci} 12933eb0b6dSopenharmony_ci 13033eb0b6dSopenharmony_cibool NativeAsyncWork::QueueWithQos(napi_qos_t qos) 13133eb0b6dSopenharmony_ci{ 13233eb0b6dSopenharmony_ci if (engineId_ != engine_->GetId()) { 13333eb0b6dSopenharmony_ci LOG_IF_SPECIAL(UNLIKELY(engine_->IsCrossThreadCheckEnabled()), 13433eb0b6dSopenharmony_ci "param env is not equal to its owner, " 13533eb0b6dSopenharmony_ci "current env id: %{public}" PRIu64 ", owner id: %{public}" PRIu64, 13633eb0b6dSopenharmony_ci engineId_, engine_->GetId()); 13733eb0b6dSopenharmony_ci } 13833eb0b6dSopenharmony_ci 13933eb0b6dSopenharmony_ci uv_loop_t* loop = engine_->GetUVLoop(); 14033eb0b6dSopenharmony_ci if (loop == nullptr) { 14133eb0b6dSopenharmony_ci HILOG_ERROR("Get loop failed"); 14233eb0b6dSopenharmony_ci return false; 14333eb0b6dSopenharmony_ci } 14433eb0b6dSopenharmony_ci engine_->IncreaseWaitingRequestCounter(); 14533eb0b6dSopenharmony_ci#ifdef ENABLE_HITRACE 14633eb0b6dSopenharmony_ci StartTrace(HITRACE_TAG_ACE, "Napi queueWithQos, " + this->GetTraceDescription()); 14733eb0b6dSopenharmony_ci HiTraceId taskId = taskTraceId_; 14833eb0b6dSopenharmony_ci HiTraceChain::Tracepoint(HITRACE_TP_CS, taskId, "%s", TRACE_POINT_QUEUE_WITH_QOS.c_str()); 14933eb0b6dSopenharmony_ci#endif 15033eb0b6dSopenharmony_ci int status = uv_queue_work_with_qos(loop, &work_, AsyncWorkCallback, AsyncAfterWorkCallback, uv_qos_t(qos)); 15133eb0b6dSopenharmony_ci#ifdef ENABLE_HITRACE 15233eb0b6dSopenharmony_ci HiTraceChain::Tracepoint(HITRACE_TP_CR, taskId, "%s", TRACE_POINT_QUEUE_WITH_QOS.c_str()); 15333eb0b6dSopenharmony_ci FinishTrace(HITRACE_TAG_ACE); 15433eb0b6dSopenharmony_ci#endif 15533eb0b6dSopenharmony_ci if (status != 0) { 15633eb0b6dSopenharmony_ci HILOG_ERROR("uv_queue_work_with_qos failed"); 15733eb0b6dSopenharmony_ci engine_->DecreaseWaitingRequestCounter(); 15833eb0b6dSopenharmony_ci return false; 15933eb0b6dSopenharmony_ci } 16033eb0b6dSopenharmony_ci HILOG_DEBUG("uv_queue_work_with_qos succeed"); 16133eb0b6dSopenharmony_ci return true; 16233eb0b6dSopenharmony_ci} 16333eb0b6dSopenharmony_ci 16433eb0b6dSopenharmony_cibool NativeAsyncWork::Cancel() 16533eb0b6dSopenharmony_ci{ 16633eb0b6dSopenharmony_ci if (engineId_ != engine_->GetId()) { 16733eb0b6dSopenharmony_ci LOG_IF_SPECIAL(UNLIKELY(engine_->IsCrossThreadCheckEnabled()), 16833eb0b6dSopenharmony_ci "param env is not equal to its owner, " 16933eb0b6dSopenharmony_ci "current env id: %{public}" PRIu64 ", owner id: %{public}" PRIu64, 17033eb0b6dSopenharmony_ci engineId_, engine_->GetId()); 17133eb0b6dSopenharmony_ci } 17233eb0b6dSopenharmony_ci 17333eb0b6dSopenharmony_ci int status = uv_cancel((uv_req_t*)&work_); 17433eb0b6dSopenharmony_ci if (status != 0) { 17533eb0b6dSopenharmony_ci HILOG_ERROR("uv_cancel failed"); 17633eb0b6dSopenharmony_ci return false; 17733eb0b6dSopenharmony_ci } 17833eb0b6dSopenharmony_ci return true; 17933eb0b6dSopenharmony_ci} 18033eb0b6dSopenharmony_ci 18133eb0b6dSopenharmony_civoid NativeAsyncWork::AsyncWorkCallback(uv_work_t* req) 18233eb0b6dSopenharmony_ci{ 18333eb0b6dSopenharmony_ci if (req == nullptr) { 18433eb0b6dSopenharmony_ci HILOG_ERROR("req is nullptr"); 18533eb0b6dSopenharmony_ci return; 18633eb0b6dSopenharmony_ci } 18733eb0b6dSopenharmony_ci 18833eb0b6dSopenharmony_ci auto that = reinterpret_cast<NativeAsyncWork*>(req->data); 18933eb0b6dSopenharmony_ci HILOG_DEBUG("NativeAsyncWork::AsyncWorkCallback start to execute."); 19033eb0b6dSopenharmony_ci 19133eb0b6dSopenharmony_ci#ifdef ENABLE_HITRACE 19233eb0b6dSopenharmony_ci StartTrace(HITRACE_TAG_ACE, "Napi execute, " + that->GetTraceDescription()); 19333eb0b6dSopenharmony_ci if (that->taskTraceId_.IsValid()) { 19433eb0b6dSopenharmony_ci HiTraceId currentId = HiTraceChain::SaveAndSet(that->taskTraceId_); 19533eb0b6dSopenharmony_ci HiTraceChain::Tracepoint(HITRACE_TP_SR, that->taskTraceId_, "%s", TRACE_POINT_ASYNCWORKCALLBACK.c_str()); 19633eb0b6dSopenharmony_ci that->execute_(that->engine_, that->data_); 19733eb0b6dSopenharmony_ci FinishTrace(HITRACE_TAG_ACE); 19833eb0b6dSopenharmony_ci HiTraceChain::Tracepoint(HITRACE_TP_SS, that->taskTraceId_, "%s", TRACE_POINT_ASYNCWORKCALLBACK.c_str()); 19933eb0b6dSopenharmony_ci HiTraceChain::Restore(currentId); 20033eb0b6dSopenharmony_ci return; 20133eb0b6dSopenharmony_ci } 20233eb0b6dSopenharmony_ci#endif 20333eb0b6dSopenharmony_ci that->execute_(that->engine_, that->data_); 20433eb0b6dSopenharmony_ci#ifdef ENABLE_HITRACE 20533eb0b6dSopenharmony_ci FinishTrace(HITRACE_TAG_ACE); 20633eb0b6dSopenharmony_ci#endif 20733eb0b6dSopenharmony_ci} 20833eb0b6dSopenharmony_ci 20933eb0b6dSopenharmony_civoid NativeAsyncWork::AsyncAfterWorkCallback(uv_work_t* req, int status) 21033eb0b6dSopenharmony_ci{ 21133eb0b6dSopenharmony_ci if (req == nullptr) { 21233eb0b6dSopenharmony_ci HILOG_ERROR("req is nullptr"); 21333eb0b6dSopenharmony_ci return; 21433eb0b6dSopenharmony_ci } 21533eb0b6dSopenharmony_ci 21633eb0b6dSopenharmony_ci auto that = reinterpret_cast<NativeAsyncWork*>(req->data); 21733eb0b6dSopenharmony_ci auto engine = that->engine_; 21833eb0b6dSopenharmony_ci engine->DecreaseWaitingRequestCounter(); 21933eb0b6dSopenharmony_ci auto vm = engine->GetEcmaVm(); 22033eb0b6dSopenharmony_ci panda::LocalScope scope(vm); 22133eb0b6dSopenharmony_ci napi_status nstatus = napi_generic_failure; 22233eb0b6dSopenharmony_ci switch (status) { 22333eb0b6dSopenharmony_ci case 0: 22433eb0b6dSopenharmony_ci nstatus = napi_ok; 22533eb0b6dSopenharmony_ci break; 22633eb0b6dSopenharmony_ci case (int)UV_EINVAL: 22733eb0b6dSopenharmony_ci nstatus = napi_invalid_arg; 22833eb0b6dSopenharmony_ci break; 22933eb0b6dSopenharmony_ci case (int)UV_ECANCELED: 23033eb0b6dSopenharmony_ci nstatus = napi_cancelled; 23133eb0b6dSopenharmony_ci break; 23233eb0b6dSopenharmony_ci default: 23333eb0b6dSopenharmony_ci nstatus = napi_generic_failure; 23433eb0b6dSopenharmony_ci } 23533eb0b6dSopenharmony_ci#ifdef ENABLE_CONTAINER_SCOPE 23633eb0b6dSopenharmony_ci ContainerScope containerScope(that->containerScopeId_); 23733eb0b6dSopenharmony_ci#endif 23833eb0b6dSopenharmony_ci 23933eb0b6dSopenharmony_ci TryCatch tryCatch(reinterpret_cast<napi_env>(engine)); 24033eb0b6dSopenharmony_ci HILOG_DEBUG("NativeAsyncWork::AsyncAfterWorkCallback start to execute."); 24133eb0b6dSopenharmony_ci#ifdef ENABLE_HITRACE 24233eb0b6dSopenharmony_ci StartTrace(HITRACE_TAG_ACE, "Napi complete, " + that->GetTraceDescription()); 24333eb0b6dSopenharmony_ci bool isValidTraceId = that->taskTraceId_.IsValid(); 24433eb0b6dSopenharmony_ci if (isValidTraceId) { 24533eb0b6dSopenharmony_ci OHOS::HiviewDFX::HiTraceChain::SaveAndSet(that->taskTraceId_); 24633eb0b6dSopenharmony_ci } 24733eb0b6dSopenharmony_ci#endif 24833eb0b6dSopenharmony_ci 24933eb0b6dSopenharmony_ci // Don't use that after complete 25033eb0b6dSopenharmony_ci that->complete_(engine, nstatus, that->data_); 25133eb0b6dSopenharmony_ci if (tryCatch.HasCaught()) { 25233eb0b6dSopenharmony_ci engine->HandleUncaughtException(); 25333eb0b6dSopenharmony_ci } 25433eb0b6dSopenharmony_ci 25533eb0b6dSopenharmony_ci#ifdef ENABLE_HITRACE 25633eb0b6dSopenharmony_ci FinishTrace(HITRACE_TAG_ACE); 25733eb0b6dSopenharmony_ci if (isValidTraceId) { 25833eb0b6dSopenharmony_ci OHOS::HiviewDFX::HiTraceChain::ClearId(); 25933eb0b6dSopenharmony_ci } 26033eb0b6dSopenharmony_ci#endif 26133eb0b6dSopenharmony_ci} 26233eb0b6dSopenharmony_ci 26333eb0b6dSopenharmony_cistd::string NativeAsyncWork::GetTraceDescription() 26433eb0b6dSopenharmony_ci{ 26533eb0b6dSopenharmony_ci return traceDescription_; 26633eb0b6dSopenharmony_ci} 267