• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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