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