1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "native_async_work.h"
17
18 #ifdef ENABLE_HITRACE
19 #include "hitrace/trace.h"
20 #include "hitrace_meter.h"
21 #include "parameter.h"
22 #include <securec.h>
23 #endif
24
25 #include "ecmascript/napi/include/jsnapi.h"
26 #include "napi/native_api.h"
27 #include "native_engine.h"
28 #include "utils/log.h"
29
30 #ifdef ENABLE_HITRACE
31 bool g_napiTraceIdEnabled = false;
32 bool g_ParamUpdated = false;
33 constexpr size_t TRACE_BUFFER_SIZE = 120;
34 constexpr size_t TRACEID_PARAM_SIZE = 10;
35 #endif
36
NativeAsyncWork(NativeEngine * engine,NativeAsyncExecuteCallback execute,NativeAsyncCompleteCallback complete,const std::string & asyncResourceName,void * data)37 NativeAsyncWork::NativeAsyncWork(NativeEngine* engine,
38 NativeAsyncExecuteCallback execute,
39 NativeAsyncCompleteCallback complete,
40 const std::string &asyncResourceName,
41 void* data)
42 : work_({ 0 }), engine_(engine), execute_(execute), complete_(complete), data_(data)
43 {
44 work_.data = this;
45 (void)asyncResourceName;
46 #ifdef ENABLE_HITRACE
47 if (!g_ParamUpdated) {
48 char napiTraceIdEnabled[TRACEID_PARAM_SIZE] = {0};
49 int ret = GetParameter("persist.hiviewdfx.napitraceid.enabled", "false",
50 napiTraceIdEnabled, sizeof(napiTraceIdEnabled));
51 if (ret > 0 && strcmp(napiTraceIdEnabled, "true") == 0) {
52 g_napiTraceIdEnabled = true;
53 }
54 g_ParamUpdated = true;
55 }
56 bool createdTraceId = false;
57 traceId_ = std::make_unique<OHOS::HiviewDFX::HiTraceId>(OHOS::HiviewDFX::HiTraceChain::GetId());
58 if (g_napiTraceIdEnabled && (!traceId_ || !traceId_->IsValid())) {
59 traceId_ = std::make_unique<OHOS::HiviewDFX::HiTraceId>(
60 OHOS::HiviewDFX::HiTraceChain::Begin("New NativeAsyncWork", 0));
61 createdTraceId = true;
62 }
63 char traceStr[TRACE_BUFFER_SIZE] = {0};
64 if (sprintf_s(traceStr, sizeof(traceStr),
65 "name:%s, traceid:0x%x", asyncResourceName.c_str(), traceId_->GetChainId()) < 0) {
66 HILOG_ERROR("Get traceStr fail");
67 }
68 traceDescription_ = traceStr;
69 if (createdTraceId) {
70 OHOS::HiviewDFX::HiTraceChain::ClearId();
71 }
72 #endif
73 }
74
75 NativeAsyncWork::~NativeAsyncWork() = default;
76
Queue()77 bool NativeAsyncWork::Queue()
78 {
79 uv_loop_t* loop = engine_->GetUVLoop();
80 if (loop == nullptr) {
81 HILOG_ERROR("Get loop failed");
82 return false;
83 }
84 engine_->IncreaseWaitingRequestCounter();
85 #ifdef ENABLE_HITRACE
86 StartTrace(HITRACE_TAG_ACE, "Napi queue, " + this->GetTraceDescription());
87 #endif
88 int status = uv_queue_work(loop, &work_, AsyncWorkCallback, AsyncAfterWorkCallback);
89 #ifdef ENABLE_HITRACE
90 FinishTrace(HITRACE_TAG_ACE);
91 #endif
92 if (status != 0) {
93 HILOG_ERROR("uv_queue_work failed");
94 return false;
95 }
96 return true;
97 }
98
QueueWithQos(napi_qos_t qos)99 bool NativeAsyncWork::QueueWithQos(napi_qos_t qos)
100 {
101 uv_loop_t* loop = engine_->GetUVLoop();
102 if (loop == nullptr) {
103 HILOG_ERROR("Get loop failed");
104 return false;
105 }
106 engine_->IncreaseWaitingRequestCounter();
107 #ifdef ENABLE_HITRACE
108 StartTrace(HITRACE_TAG_ACE, "Napi queueWithQos, " + this->GetTraceDescription());
109 #endif
110 int status = uv_queue_work_with_qos(loop, &work_, AsyncWorkCallback, AsyncAfterWorkCallback, uv_qos_t(qos));
111 #ifdef ENABLE_HITRACE
112 FinishTrace(HITRACE_TAG_ACE);
113 #endif
114 if (status != 0) {
115 HILOG_ERROR("uv_queue_work_with_qos failed");
116 return false;
117 }
118 return true;
119 }
120
Cancel()121 bool NativeAsyncWork::Cancel()
122 {
123 int status = uv_cancel((uv_req_t*)&work_);
124 if (status != 0) {
125 HILOG_ERROR("uv_cancel failed");
126 return false;
127 }
128 return true;
129 }
130
AsyncWorkCallback(uv_work_t * req)131 void NativeAsyncWork::AsyncWorkCallback(uv_work_t* req)
132 {
133 if (req == nullptr) {
134 HILOG_ERROR("req is nullptr");
135 return;
136 }
137
138 auto that = reinterpret_cast<NativeAsyncWork*>(req->data);
139
140 #ifdef ENABLE_HITRACE
141 StartTrace(HITRACE_TAG_ACE, "Napi execute, " + that->GetTraceDescription());
142 if (that->traceId_ && that->traceId_->IsValid()) {
143 OHOS::HiviewDFX::HiTraceChain::SetId(*(that->traceId_.get()));
144 that->execute_(that->engine_, that->data_);
145 FinishTrace(HITRACE_TAG_ACE);
146 OHOS::HiviewDFX::HiTraceChain::ClearId();
147 return;
148 }
149 #endif
150 that->execute_(that->engine_, that->data_);
151 #ifdef ENABLE_HITRACE
152 FinishTrace(HITRACE_TAG_ACE);
153 #endif
154 }
155
AsyncAfterWorkCallback(uv_work_t * req,int status)156 void NativeAsyncWork::AsyncAfterWorkCallback(uv_work_t* req, int status)
157 {
158 if (req == nullptr) {
159 HILOG_ERROR("req is nullptr");
160 return;
161 }
162
163 auto that = reinterpret_cast<NativeAsyncWork*>(req->data);
164 auto engine = that->engine_;
165 engine->DecreaseWaitingRequestCounter();
166 auto vm = engine->GetEcmaVm();
167 panda::LocalScope scope(vm);
168 napi_status nstatus = napi_generic_failure;
169 switch (status) {
170 case 0:
171 nstatus = napi_ok;
172 break;
173 case (int)UV_EINVAL:
174 nstatus = napi_invalid_arg;
175 break;
176 case (int)UV_ECANCELED:
177 nstatus = napi_cancelled;
178 break;
179 default:
180 nstatus = napi_generic_failure;
181 }
182
183 TryCatch tryCatch(reinterpret_cast<napi_env>(engine));
184 #ifdef ENABLE_HITRACE
185 StartTrace(HITRACE_TAG_ACE, "Napi complete, " + that->GetTraceDescription());
186 bool isValidTraceId = that->traceId_ && that->traceId_->IsValid();
187 if (isValidTraceId) {
188 OHOS::HiviewDFX::HiTraceChain::SetId(*(that->traceId_.get()));
189 }
190 #endif
191
192 // Don't use that after complete
193 that->complete_(engine, nstatus, that->data_);
194 if (tryCatch.HasCaught()) {
195 engine->HandleUncaughtException();
196 }
197
198 #ifdef ENABLE_HITRACE
199 FinishTrace(HITRACE_TAG_ACE);
200 if (isValidTraceId) {
201 OHOS::HiviewDFX::HiTraceChain::ClearId();
202 }
203 #endif
204 }
205
GetTraceDescription()206 std::string NativeAsyncWork::GetTraceDescription()
207 {
208 return traceDescription_;
209 }
210