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 #ifdef ENABLE_CONTAINER_SCOPE
25 #include "core/common/container_scope.h"
26 #endif
27
28 #include "napi/native_api.h"
29 #include "native_engine.h"
30 #include "utils/log.h"
31
32 #ifdef ENABLE_CONTAINER_SCOPE
33 using OHOS::Ace::ContainerScope;
34 #endif
35
36 #ifdef ENABLE_HITRACE
37 bool g_napiTraceIdEnabled = false;
38 bool g_ParamUpdated = false;
39 constexpr size_t TRACE_BUFFER_SIZE = 120;
40 constexpr size_t TRACEID_PARAM_SIZE = 10;
41 #endif
42
NativeAsyncWork(NativeEngine * engine,NativeAsyncExecuteCallback execute,NativeAsyncCompleteCallback complete,const std::string & asyncResourceName,void * data)43 NativeAsyncWork::NativeAsyncWork(NativeEngine* engine,
44 NativeAsyncExecuteCallback execute,
45 NativeAsyncCompleteCallback complete,
46 const std::string &asyncResourceName,
47 void* data)
48 : work_({ 0 }), engine_(engine), execute_(execute), complete_(complete), data_(data)
49 {
50 work_.data = this;
51 (void)asyncResourceName;
52 #ifdef ENABLE_HITRACE
53 if (!g_ParamUpdated) {
54 char napiTraceIdEnabled[TRACEID_PARAM_SIZE] = {0};
55 int ret = GetParameter("persist.hiviewdfx.napitraceid.enabled", "false",
56 napiTraceIdEnabled, sizeof(napiTraceIdEnabled));
57 if (ret > 0 && strcmp(napiTraceIdEnabled, "true") == 0) {
58 g_napiTraceIdEnabled = true;
59 }
60 g_ParamUpdated = true;
61 }
62 bool createdTraceId = false;
63 traceId_ = std::make_unique<OHOS::HiviewDFX::HiTraceId>(OHOS::HiviewDFX::HiTraceChain::GetId());
64 if (g_napiTraceIdEnabled && (!traceId_ || !traceId_->IsValid())) {
65 traceId_ = std::make_unique<OHOS::HiviewDFX::HiTraceId>(
66 OHOS::HiviewDFX::HiTraceChain::Begin("New NativeAsyncWork", 0));
67 createdTraceId = true;
68 }
69 char traceStr[TRACE_BUFFER_SIZE] = {0};
70 if (sprintf_s(traceStr, sizeof(traceStr),
71 "name:%s, traceid:0x%x", asyncResourceName.c_str(), traceId_->GetChainId()) < 0) {
72 HILOG_ERROR("Get traceStr fail");
73 }
74 traceDescription_ = traceStr;
75 if (createdTraceId) {
76 OHOS::HiviewDFX::HiTraceChain::ClearId();
77 }
78 #endif
79 #ifdef ENABLE_CONTAINER_SCOPE
80 containerScopeId_ = ContainerScope::CurrentId();
81 #endif
82 }
83
84 NativeAsyncWork::~NativeAsyncWork() = default;
85
Queue()86 bool NativeAsyncWork::Queue()
87 {
88 uv_loop_t* loop = engine_->GetUVLoop();
89 if (loop == nullptr) {
90 HILOG_ERROR("Get loop failed");
91 return false;
92 }
93 engine_->IncreaseWaitingRequestCounter();
94 #ifdef ENABLE_HITRACE
95 StartTrace(HITRACE_TAG_ACE, "Napi queue, " + this->GetTraceDescription());
96 #endif
97 int status = uv_queue_work(loop, &work_, AsyncWorkCallback, AsyncAfterWorkCallback);
98 #ifdef ENABLE_HITRACE
99 FinishTrace(HITRACE_TAG_ACE);
100 #endif
101 if (status != 0) {
102 HILOG_ERROR("uv_queue_work failed");
103 return false;
104 }
105 return true;
106 }
107
Cancel()108 bool NativeAsyncWork::Cancel()
109 {
110 int status = uv_cancel((uv_req_t*)&work_);
111 if (status != 0) {
112 HILOG_ERROR("uv_cancel failed");
113 return false;
114 }
115 return true;
116 }
117
AsyncWorkCallback(uv_work_t * req)118 void NativeAsyncWork::AsyncWorkCallback(uv_work_t* req)
119 {
120 if (req == nullptr) {
121 HILOG_ERROR("req is nullptr");
122 return;
123 }
124
125 auto that = reinterpret_cast<NativeAsyncWork*>(req->data);
126
127 #ifdef ENABLE_CONTAINER_SCOPE
128 ContainerScope containerScope(that->containerScopeId_);
129 #endif
130 #ifdef ENABLE_HITRACE
131 StartTrace(HITRACE_TAG_ACE, "Napi execute, " + that->GetTraceDescription());
132 if (that->traceId_ && that->traceId_->IsValid()) {
133 OHOS::HiviewDFX::HiTraceChain::SetId(*(that->traceId_.get()));
134 that->execute_(that->engine_, that->data_);
135 FinishTrace(HITRACE_TAG_ACE);
136 OHOS::HiviewDFX::HiTraceChain::ClearId();
137 return;
138 }
139 FinishTrace(HITRACE_TAG_ACE);
140 #endif
141 that->execute_(that->engine_, that->data_);
142 }
143
AsyncAfterWorkCallback(uv_work_t * req,int status)144 void NativeAsyncWork::AsyncAfterWorkCallback(uv_work_t* req, int status)
145 {
146 if (req == nullptr) {
147 HILOG_ERROR("req is nullptr");
148 return;
149 }
150
151 auto that = reinterpret_cast<NativeAsyncWork*>(req->data);
152
153 NativeScopeManager* scopeManager = that->engine_->GetScopeManager();
154 that->engine_->DecreaseWaitingRequestCounter();
155 if (scopeManager == nullptr) {
156 HILOG_ERROR("Get scope manager failed");
157 return;
158 }
159
160 NativeScope* scope = scopeManager->Open();
161 if (scope == nullptr) {
162 HILOG_ERROR("Open scope failed");
163 return;
164 }
165
166 napi_status nstatus = napi_generic_failure;
167 switch (status) {
168 case 0:
169 nstatus = napi_ok;
170 break;
171 case (int)UV_EINVAL:
172 nstatus = napi_invalid_arg;
173 break;
174 case (int)UV_ECANCELED:
175 nstatus = napi_cancelled;
176 break;
177 default:
178 nstatus = napi_generic_failure;
179 }
180 #ifdef ENABLE_CONTAINER_SCOPE
181 ContainerScope containerScope(that->containerScopeId_);
182 #endif
183 #ifdef ENABLE_HITRACE
184 StartTrace(HITRACE_TAG_ACE, "Napi complete, " + that->GetTraceDescription());
185 if (that->traceId_ && that->traceId_->IsValid()) {
186 OHOS::HiviewDFX::HiTraceChain::SetId(*(that->traceId_.get()));
187 that->complete_(that->engine_, nstatus, that->data_);
188 FinishTrace(HITRACE_TAG_ACE);
189 OHOS::HiviewDFX::HiTraceChain::ClearId();
190 scopeManager->Close(scope);
191 return;
192 }
193 FinishTrace(HITRACE_TAG_ACE);
194 #endif
195 that->complete_(that->engine_, nstatus, that->data_);
196 scopeManager->Close(scope);
197 }
198
GetTraceDescription()199 std::string NativeAsyncWork::GetTraceDescription()
200 {
201 return traceDescription_;
202 }
203