1 /*
2 * Copyright (c) 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 <memory>
17
18 #include "avsession_trace.h"
19 #include "napi_utils.h"
20 #include "napi_async_callback.h"
21
22 namespace OHOS::AVSession {
NapiAsyncCallback(napi_env env)23 NapiAsyncCallback::NapiAsyncCallback(napi_env env) : env_(env)
24 {
25 if (env != nullptr) {
26 napi_get_uv_event_loop(env, &loop_);
27 napi_get_uv_event_loop(env, &loopOrder_);
28 int res = sem_init(&semaphore_, 0, 1);
29 SLOGD("loop to set sem with res %{public}d", res);
30 }
31 }
32
~NapiAsyncCallback()33 NapiAsyncCallback::~NapiAsyncCallback()
34 {
35 SLOGI("no memory leak for queue-callback");
36 env_ = nullptr;
37 sem_destroy(&semaphore_);
38 }
39
GetEnv() const40 napi_env NapiAsyncCallback::GetEnv() const
41 {
42 return env_;
43 }
44
AfterWorkCallback(uv_work_t * work,int aStatus)45 void NapiAsyncCallback::AfterWorkCallback(uv_work_t* work, int aStatus)
46 {
47 AVSESSION_TRACE_SYNC_START("NapiAsyncCallback::AfterWorkCallback");
48 std::shared_ptr<DataContext> context(static_cast<DataContext*>(work->data), [work](DataContext* ptr) {
49 delete ptr;
50 delete work;
51 });
52
53 napi_handle_scope scope = nullptr;
54 napi_open_handle_scope(context->env, &scope);
55
56 int argc = 0;
57 napi_value argv[ARGC_MAX] = { nullptr };
58 if (context->getter) {
59 argc = ARGC_MAX;
60 context->getter(context->env, argc, argv);
61 }
62
63 SLOGD("queue uv_after_work_cb");
64 napi_value global {};
65 napi_get_global(context->env, &global);
66 napi_value function {};
67 napi_get_reference_value(context->env, context->method, &function);
68 napi_value result;
69 napi_status status = napi_call_function(context->env, global, function, argc, argv, &result);
70 if (status != napi_ok) {
71 SLOGE("call function failed status=%{public}d.", status);
72 }
73 napi_close_handle_scope(context->env, scope);
74 }
75
AfterWorkCallbackWithFlag(uv_work_t * work,int aStatus)76 void NapiAsyncCallback::AfterWorkCallbackWithFlag(uv_work_t* work, int aStatus)
77 {
78 AVSESSION_TRACE_SYNC_START("NapiAsyncCallback::AfterWorkCallbackWithFlag");
79 std::shared_ptr<DataContextWithFlag> context(static_cast<DataContextWithFlag*>(work->data),
80 [work](DataContextWithFlag* ptr) {
81 delete ptr;
82 delete work;
83 });
84
85 napi_handle_scope scope = nullptr;
86 napi_open_handle_scope(context->env, &scope);
87
88 int argc = 0;
89 napi_value argv[ARGC_MAX] = { nullptr };
90 if (context->getter) {
91 argc = ARGC_MAX;
92 context->getter(context->env, argc, argv);
93 }
94
95 SLOGD("queue uv_after_work_cb");
96 napi_value global {};
97 napi_get_global(context->env, &global);
98 napi_value function {};
99 SLOGD("callback with flag");
100 if (!*context->isValid) {
101 SLOGE("AfterWorkCallbackWithFlag callback when callback is invalid");
102 napi_close_handle_scope(context->env, scope);
103 return;
104 }
105 SLOGI("callback with flag ref %{public}p, %{public}p", &(context->method), *(&(context->method)));
106 napi_get_reference_value(context->env, context->method, &function);
107 napi_value result;
108 napi_status status = napi_call_function(context->env, global, function, argc, argv, &result);
109 if (status != napi_ok) {
110 SLOGE("call function failed status=%{public}d.", status);
111 }
112 napi_close_handle_scope(context->env, scope);
113 }
114
AfterWorkCallbackWithFunc(uv_work_t * work,int aStatus)115 void NapiAsyncCallback::AfterWorkCallbackWithFunc(uv_work_t* work, int aStatus)
116 {
117 AVSESSION_TRACE_SYNC_START("NapiAsyncCallback::AfterWorkCallbackWithFunc");
118 std::shared_ptr<DataContextWithFunc> context(static_cast<DataContextWithFunc*>(work->data),
119 [work](DataContextWithFunc* ptr) {
120 delete ptr;
121 delete work;
122 });
123
124 napi_handle_scope scope = nullptr;
125 napi_open_handle_scope(context->env, &scope);
126
127 int argc = 0;
128 napi_value argv[ARGC_MAX] = { nullptr };
129 if (context->getter) {
130 argc = ARGC_MAX;
131 context->getter(context->env, argc, argv);
132 }
133
134 SLOGD("queue uv_after_work_cb");
135 if (!*context->isValid) {
136 SLOGE("AfterWorkCallbackWithFunc failed for context is invalid.");
137 napi_close_handle_scope(context->env, scope);
138 return;
139 }
140 napi_value global {};
141 napi_get_global(context->env, &global);
142 napi_value function {};
143 if (!context->checkCallbackValid()) {
144 SLOGE("Get func reference failed for func has been deleted.");
145 napi_close_handle_scope(context->env, scope);
146 return;
147 }
148 napi_get_reference_value(context->env, context->method, &function);
149 napi_value result;
150 if (!context->checkCallbackValid()) {
151 SLOGE("Call func failed for func has been deleted.");
152 napi_close_handle_scope(context->env, scope);
153 return;
154 }
155 napi_status status = napi_call_function(context->env, global, function, argc, argv, &result);
156 if (status != napi_ok) {
157 SLOGE("call function failed status=%{public}d.", status);
158 }
159 napi_close_handle_scope(context->env, scope);
160 }
161
Call(napi_ref & method,NapiArgsGetter getter)162 void NapiAsyncCallback::Call(napi_ref& method, NapiArgsGetter getter)
163 {
164 CHECK_RETURN_VOID(loop_ != nullptr, "loop_ is nullptr");
165 CHECK_RETURN_VOID(method != nullptr, "method is nullptr");
166
167 auto* work = new (std::nothrow) uv_work_t;
168 CHECK_RETURN_VOID(work != nullptr, "no memory for uv_work_t");
169
170 work->data = new DataContext{env_, method, std::move(getter)};
171 int res = uv_queue_work_with_qos(loop_, work, [](uv_work_t* work) {}, AfterWorkCallback, uv_qos_user_initiated);
172 CHECK_RETURN_VOID(res == 0, "uv queue work failed");
173 }
174
CallWithFlag(napi_ref & method,std::shared_ptr<bool> isValid,NapiArgsGetter getter)175 void NapiAsyncCallback::CallWithFlag(napi_ref& method, std::shared_ptr<bool> isValid, NapiArgsGetter getter)
176 {
177 CHECK_RETURN_VOID(loop_ != nullptr, "loop_ is nullptr");
178 CHECK_RETURN_VOID(method != nullptr, "method is nullptr");
179
180 auto* work = new (std::nothrow) uv_work_t;
181 CHECK_RETURN_VOID(work != nullptr, "no memory for uv_work_t");
182
183 work->data = new DataContextWithFlag { env_, method, isValid, std::move(getter) };
184 int res = uv_queue_work_with_qos(loop_, work, [](uv_work_t* work) {}, AfterWorkCallbackWithFlag,
185 uv_qos_user_initiated);
186 CHECK_RETURN_VOID(res == 0, "uv queue work failed");
187 }
188
CallWithFunc(napi_ref & method,std::shared_ptr<bool> isValid,const std::function<bool ()> & checkCallbackValid,NapiArgsGetter getter)189 void NapiAsyncCallback::CallWithFunc(napi_ref& method, std::shared_ptr<bool> isValid,
190 const std::function<bool()>& checkCallbackValid, NapiArgsGetter getter)
191 {
192 CHECK_RETURN_VOID(loop_ != nullptr, "loop_ is nullptr");
193 CHECK_RETURN_VOID(method != nullptr, "method is nullptr");
194
195 auto* work = new (std::nothrow) uv_work_t;
196 CHECK_RETURN_VOID(work != nullptr, "no memory for uv_work_t");
197
198 work->data = new DataContextWithFunc { env_, method, isValid, std::move(getter), checkCallbackValid };
199 int res = uv_queue_work_with_qos(loop_, work, [](uv_work_t* work) {}, AfterWorkCallbackWithFunc,
200 uv_qos_user_initiated);
201 CHECK_RETURN_VOID(res == 0, "uv queue work failed");
202 }
203 }