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 #include "js_plugin_callback.h"
16
17
18 #include "js_plugin_callback_mgr.h"
19 #include "js_plugin_util.h"
20 #include "js_plugin_want.h"
21
22 #include "core/common/ace_engine.h"
23 #include "core/components/plugin/plugin_component_manager.h"
24
25 namespace OHOS::Ace::Napi {
26 std::atomic_size_t JSPluginCallback::uuid_ = 0;
27 constexpr int ACE_ARGS_TWO = 2;
28 constexpr int ACE_ARGS_THREE = 3;
29 constexpr int ACE_ARGS_FOUR = 4;
30 constexpr int ACE_PARAM0 = 0;
31 constexpr int ACE_PARAM1 = 1;
32 constexpr int ACE_PARAM2 = 2;
33 constexpr int ACE_PARAM3 = 3;
34
operator ==(const AceJSPluginRequestParam & param) const35 bool AceJSPluginRequestParam::operator==(const AceJSPluginRequestParam& param) const
36 {
37 AppExecFwk::ElementName leftElement = want_.GetElement();
38 AppExecFwk::ElementName rightElement = param.want_.GetElement();
39 if (leftElement == rightElement) {
40 if (name_ == param.name_ && data_ == param.data_ && jsonPath_ == param.jsonPath_) {
41 return true;
42 }
43 }
44 return false;
45 }
46
operator !=(const AceJSPluginRequestParam & param) const47 bool AceJSPluginRequestParam::operator!=(const AceJSPluginRequestParam& param) const
48 {
49 return !operator==(param);
50 }
51
JSPluginCallback(CallBackType eventType,ACECallbackInfo & cbInfo,ACEAsyncJSCallbackInfo * jsCallbackInfo)52 JSPluginCallback::JSPluginCallback(
53 CallBackType eventType, ACECallbackInfo& cbInfo, ACEAsyncJSCallbackInfo* jsCallbackInfo)
54 : eventType_(eventType), asyncJSCallbackInfo_(jsCallbackInfo)
55 {
56 uuid_++;
57 cbInfo_.env = cbInfo.env;
58 cbInfo_.callback = cbInfo.callback;
59 cbInfo_.containerId = cbInfo.containerId;
60 }
61
~JSPluginCallback()62 JSPluginCallback::~JSPluginCallback()
63 {
64 if (uuid_ > 0) {
65 uuid_--;
66 }
67 DestroyAllResource();
68 }
69
DestroyAllResource(void)70 void JSPluginCallback::DestroyAllResource(void)
71 {
72 if (cbInfo_.env != nullptr && cbInfo_.callback != nullptr) {
73 napi_delete_reference(cbInfo_.env, cbInfo_.callback);
74 }
75 cbInfo_.env = nullptr;
76 cbInfo_.callback = nullptr;
77 cbInfo_.containerId = -1;
78 asyncJSCallbackInfo_ = nullptr;
79 }
80
SetWant(const AAFwk::Want & want)81 void JSPluginCallback::SetWant(const AAFwk::Want& want)
82 {
83 want_ = want;
84 }
85
GetWant()86 AAFwk::Want& JSPluginCallback::GetWant()
87 {
88 return want_;
89 }
90
SetRequestParam(const std::shared_ptr<AceJSPluginRequestParam> & param)91 void JSPluginCallback::SetRequestParam(const std::shared_ptr<AceJSPluginRequestParam>& param)
92 {
93 requestParam_ = param;
94 }
95
GetID(void)96 size_t JSPluginCallback::GetID(void)
97 {
98 return uuid_;
99 }
100
GetContainerId()101 int32_t JSPluginCallback::GetContainerId()
102 {
103 return cbInfo_.containerId;
104 }
105
SendRequestEventResult(napi_value jsObject)106 void JSPluginCallback::SendRequestEventResult(napi_value jsObject)
107 {
108 napi_value jsTemplate = AceGetPropertyValueByPropertyName(cbInfo_.env, jsObject, "template", napi_string);
109 napi_value jsData = AceGetPropertyValueByPropertyName(cbInfo_.env, jsObject, "data", napi_object);
110 napi_value jsExtraData = AceGetPropertyValueByPropertyName(cbInfo_.env, jsObject, "extraData", napi_object);
111
112 struct MyData {
113 AAFwk::Want want;
114 std::string strTemplate;
115 std::string strDate;
116 std::string strExtraData;
117 };
118
119 std::shared_ptr<MyData> data = std::make_shared<MyData>();
120 data->want = want_;
121
122 if (jsTemplate != nullptr) {
123 data->strTemplate = AceUnwrapStringFromJS(cbInfo_.env, jsTemplate);
124 }
125
126 if (jsData != nullptr) {
127 AceKVObjectToString(cbInfo_.env, jsData, data->strDate);
128 }
129
130 if (jsExtraData != nullptr) {
131 AceKVObjectToString(cbInfo_.env, jsExtraData, data->strExtraData);
132 }
133
134 auto container = AceEngine::Get().GetContainer(cbInfo_.containerId);
135 if (!container) {
136 return;
137 }
138
139 auto taskExecutor = container->GetTaskExecutor();
140 if (!taskExecutor) {
141 return;
142 }
143 taskExecutor->PostTask(
144 [data]() {
145 PluginComponentManager::GetInstance()->ReturnRequest(
146 data->want, data->strTemplate, data->strDate, data->strExtraData);
147 },
148 TaskExecutor::TaskType::BACKGROUND, "ArkUIPluginReturnRequest");
149 }
150
MakeCallbackParamForRequest(const PluginComponentTemplate & pluginTemplate,const std::string & data,const std::string & extraData)151 napi_value JSPluginCallback::MakeCallbackParamForRequest(
152 const PluginComponentTemplate& pluginTemplate, const std::string& data, const std::string& extraData)
153 {
154 napi_value jsObject = AceCreateJSObject(cbInfo_.env);
155 if (jsObject == nullptr) {
156 return nullptr;
157 }
158
159 std::string dataTmp("{}");
160 std::string extraDataTmp("{}");
161 if (!data.empty()) {
162 dataTmp = data;
163 }
164 if (!extraData.empty()) {
165 extraDataTmp = extraData;
166 }
167
168 napi_value jsPluginTemplate = MakePluginTemplateObject(pluginTemplate);
169 napi_value jsData = AceStringToKVObject(cbInfo_.env, dataTmp);
170 napi_value jsExtraData = AceStringToKVObject(cbInfo_.env, extraDataTmp);
171
172 if (jsData != nullptr) {
173 AceSetPropertyValueByPropertyName(cbInfo_.env, jsObject, "componentTemplate", jsPluginTemplate);
174 }
175 if (jsData != nullptr) {
176 AceSetPropertyValueByPropertyName(cbInfo_.env, jsObject, "data", jsData);
177 }
178 if (jsExtraData != nullptr) {
179 AceSetPropertyValueByPropertyName(cbInfo_.env, jsObject, "extraData", jsExtraData);
180 }
181 return jsObject;
182 }
183
MakePluginTemplateObject(const PluginComponentTemplate & pluginTemplate)184 napi_value JSPluginCallback::MakePluginTemplateObject(const PluginComponentTemplate& pluginTemplate)
185 {
186 napi_value jsPluginTemplate = AceCreateJSObject(cbInfo_.env);
187 if (jsPluginTemplate != nullptr) {
188 napi_value jsSource = AceWrapStringToJS(cbInfo_.env, pluginTemplate.GetSource());
189 napi_value jsAbility = AceWrapStringToJS(cbInfo_.env, pluginTemplate.GetAbility());
190
191 AceSetPropertyValueByPropertyName(cbInfo_.env, jsPluginTemplate, "source", jsSource);
192 AceSetPropertyValueByPropertyName(cbInfo_.env, jsPluginTemplate, "ability", jsAbility);
193 }
194 return jsPluginTemplate;
195 }
196
OnPushEventInner(const OnPluginUvWorkData * workData)197 void JSPluginCallback::OnPushEventInner(const OnPluginUvWorkData* workData)
198 {
199 napi_value jsCallback = nullptr;
200 napi_value undefined = nullptr;
201 napi_value jsResult = nullptr;
202 napi_value callbackParam[ACE_ARGS_FOUR] = { nullptr };
203 napi_handle_scope scope = nullptr;
204 std::string dataTmp("{}");
205 std::string extraDataTmp("{}");
206 if (!workData->data.empty()) {
207 dataTmp = workData->data;
208 }
209 if (!workData->extraData.empty()) {
210 extraDataTmp = workData->extraData;
211 }
212
213 napi_open_handle_scope(cbInfo_.env, &scope);
214 if (scope == nullptr) {
215 napi_close_handle_scope(cbInfo_.env, scope);
216 return;
217 }
218
219 PluginComponentTemplate componentTemplate;
220 componentTemplate.SetSource(workData->sourceName);
221 componentTemplate.SetAbility(workData->abilityName);
222
223 callbackParam[ACE_PARAM0] = AceWrapWant(cbInfo_.env, workData->want);
224 callbackParam[ACE_PARAM1] = MakePluginTemplateObject(componentTemplate);
225 callbackParam[ACE_PARAM2] = AceStringToKVObject(cbInfo_.env, dataTmp);
226 callbackParam[ACE_PARAM3] = AceStringToKVObject(cbInfo_.env, extraDataTmp);
227
228 napi_get_undefined(cbInfo_.env, &undefined);
229 napi_get_reference_value(cbInfo_.env, cbInfo_.callback, &jsCallback);
230 napi_call_function(cbInfo_.env, undefined, jsCallback, ACE_ARGS_FOUR, callbackParam, &jsResult);
231 napi_close_handle_scope(cbInfo_.env, scope);
232 }
233
OnPushEvent(const AAFwk::Want & want,const PluginComponentTemplate & pluginTemplate,const std::string & data,const std::string & extraData)234 void JSPluginCallback::OnPushEvent(const AAFwk::Want& want, const PluginComponentTemplate& pluginTemplate,
235 const std::string& data, const std::string& extraData)
236 {
237 if (cbInfo_.env == nullptr || cbInfo_.callback == nullptr) {
238 return;
239 }
240
241 auto container = AceEngine::Get().GetContainer(cbInfo_.containerId);
242 if (!container) {
243 return;
244 }
245
246 auto taskExecutor = container->GetTaskExecutor();
247 if (!taskExecutor) {
248 return;
249 }
250 std::weak_ptr<PluginComponentCallBack> weak = weak_from_this();
251 taskExecutor->PostTask(
252 [weak, want, sourceName = pluginTemplate.GetSource(), abilityName = pluginTemplate.GetAbility(), data,
253 extraData]() {
254 OnPluginUvWorkData uvWorkData;
255 uvWorkData.want = want;
256 uvWorkData.sourceName = sourceName;
257 uvWorkData.abilityName = abilityName;
258 uvWorkData.data = data;
259 uvWorkData.extraData = extraData;
260 auto callBack = weak.lock();
261 if (callBack) {
262 auto jsCallback = std::static_pointer_cast<JSPluginCallback>(callBack);
263 jsCallback->OnPushEventInner(&uvWorkData);
264 }
265 },
266 TaskExecutor::TaskType::UI, "ArkUIPluginPushEventInner");
267 }
268
OnRequestEventInner(const OnPluginUvWorkData * workData)269 void JSPluginCallback::OnRequestEventInner(const OnPluginUvWorkData* workData)
270 {
271 napi_value jsCallback = nullptr;
272 napi_value undefined = nullptr;
273 napi_value jsResult = nullptr;
274 napi_handle_scope scope = nullptr;
275 std::string dataTmp("{}");
276 if (!workData->data.empty()) {
277 dataTmp = workData->data;
278 }
279
280 napi_open_handle_scope(cbInfo_.env, &scope);
281 if (scope == nullptr) {
282 napi_close_handle_scope(cbInfo_.env, scope);
283 return;
284 }
285 napi_value callbackParam[ACE_ARGS_THREE] = { nullptr };
286 callbackParam[ACE_PARAM0] = AceWrapWant(cbInfo_.env, workData->want);
287 callbackParam[ACE_PARAM1] = AceWrapStringToJS(cbInfo_.env, workData->name);
288 callbackParam[ACE_PARAM2] = AceStringToKVObject(cbInfo_.env, dataTmp);
289
290 napi_get_undefined(cbInfo_.env, &undefined);
291 napi_get_reference_value(cbInfo_.env, cbInfo_.callback, &jsCallback);
292 napi_call_function(cbInfo_.env, undefined, jsCallback, ACE_ARGS_THREE, callbackParam, &jsResult);
293
294 if (AceIsTypeForNapiValue(cbInfo_.env, jsResult, napi_object)) {
295 SendRequestEventResult(jsResult);
296 }
297 napi_close_handle_scope(cbInfo_.env, scope);
298 }
299
OnRequestEvent(const AAFwk::Want & want,const std::string & name,const std::string & data)300 void JSPluginCallback::OnRequestEvent(const AAFwk::Want& want, const std::string& name, const std::string& data)
301 {
302 if (cbInfo_.env == nullptr || cbInfo_.callback == nullptr) {
303 return;
304 }
305
306 auto container = AceEngine::Get().GetContainer(cbInfo_.containerId);
307 if (!container) {
308 return;
309 }
310
311 auto taskExecutor = container->GetTaskExecutor();
312 if (!taskExecutor) {
313 return;
314 }
315
316 std::weak_ptr<PluginComponentCallBack> weak = weak_from_this();
317 taskExecutor->PostTask(
318 [weak, want, name, data]() {
319 auto callBack = weak.lock();
320 if (callBack) {
321 OnPluginUvWorkData uvWorkData;
322 uvWorkData.that = callBack.get();
323 uvWorkData.want = want;
324 uvWorkData.data = data;
325 uvWorkData.name = name;
326
327 auto jsCallback = std::static_pointer_cast<JSPluginCallback>(callBack);
328 jsCallback->OnRequestEventInner(&uvWorkData);
329 }
330 },
331 TaskExecutor::TaskType::JS, "ArkUIPluginRequestEventInner");
332 }
333
OnRequestCallBackInner(const OnPluginUvWorkData * workData)334 void JSPluginCallback::OnRequestCallBackInner(const OnPluginUvWorkData* workData)
335 {
336 napi_value jsCallback = nullptr;
337 napi_value undefined = nullptr;
338 napi_value jsResult = nullptr;
339 napi_handle_scope scope = nullptr;
340 napi_open_handle_scope(cbInfo_.env, &scope);
341 if (scope == nullptr) {
342 napi_close_handle_scope(cbInfo_.env, scope);
343 return;
344 }
345 PluginComponentTemplate componentTemplate;
346 componentTemplate.SetSource(workData->sourceName);
347 componentTemplate.SetAbility(workData->abilityName);
348
349 if (cbInfo_.callback != nullptr) {
350 napi_value callbackParam[ACE_ARGS_TWO] = { nullptr };
351 callbackParam[ACE_PARAM0] = AceGetCallbackErrorValue(cbInfo_.env, 0);
352 callbackParam[ACE_PARAM1] = MakeCallbackParamForRequest(componentTemplate, workData->data, workData->extraData);
353 napi_get_undefined(cbInfo_.env, &undefined);
354 napi_get_reference_value(cbInfo_.env, cbInfo_.callback, &jsCallback);
355 napi_call_function(cbInfo_.env, undefined, jsCallback, ACE_ARGS_TWO, callbackParam, &jsResult);
356 }
357 napi_close_handle_scope(cbInfo_.env, scope);
358 }
359
OnRequestCallBack(const PluginComponentTemplate & pluginTemplate,const std::string & data,const std::string & extraData)360 void JSPluginCallback::OnRequestCallBack(
361 const PluginComponentTemplate& pluginTemplate, const std::string& data, const std::string& extraData)
362 {
363 JSPluginCallbackMgr::Instance().UnRegisterEvent(GetID());
364 if (cbInfo_.env == nullptr) {
365 return;
366 }
367
368 if (cbInfo_.callback != nullptr) {
369 uvWorkData_.that = (void*)this;
370 uvWorkData_.sourceName = pluginTemplate.GetSource();
371 uvWorkData_.abilityName = pluginTemplate.GetAbility();
372 uvWorkData_.data = data;
373 uvWorkData_.extraData = extraData;
374
375 if (getpid() != gettid()) {
376 struct ResultData {
377 JSPluginCallback* context = nullptr;
378 std::mutex mtx;
379 bool ready = false;
380 std::condition_variable cv;
381 };
382
383 std::shared_ptr<ResultData> resultData = std::make_shared<ResultData>();
384 resultData->context = this;
385
386 auto container = AceEngine::Get().GetContainer(cbInfo_.containerId);
387 if (!container) {
388 return;
389 }
390
391 auto taskExecutor = container->GetTaskExecutor();
392 if (!taskExecutor) {
393 return;
394 }
395 taskExecutor->PostTask(
396 [resultData]() {
397 resultData->context->OnRequestCallBackInner(&resultData->context->uvWorkData_);
398
399 {
400 std::unique_lock<std::mutex> lock(resultData->mtx);
401 resultData->ready = true;
402 resultData->cv.notify_all();
403 }
404 },
405 TaskExecutor::TaskType::JS, "ArkUIPluginRequestCallbackInner");
406
407 {
408 std::unique_lock<std::mutex> lock(resultData->mtx);
409 if (!resultData->ready) {
410 resultData->cv.wait(lock, [&] { return resultData->ready; });
411 }
412 }
413 } else {
414 OnRequestCallBackInner(&uvWorkData_);
415 }
416 } else {
417 if (asyncJSCallbackInfo_) {
418 asyncJSCallbackInfo_->requestCallbackData.sourceName = pluginTemplate.GetSource();
419 asyncJSCallbackInfo_->requestCallbackData.abilityName = pluginTemplate.GetAbility();
420 asyncJSCallbackInfo_->requestCallbackData.data = data;
421 asyncJSCallbackInfo_->requestCallbackData.extraData = extraData;
422 asyncJSCallbackInfo_->onRequestCallbackOK = true;
423 }
424 }
425 }
426
OnEventStrictEquals(CallBackType eventType,const AAFwk::Want & want,ACECallbackInfo & cbInfo)427 bool JSPluginCallback::OnEventStrictEquals(CallBackType eventType, const AAFwk::Want& want, ACECallbackInfo& cbInfo)
428 {
429 if (eventType != eventType_) {
430 return false;
431 }
432 AppExecFwk::ElementName leftElement = want.GetElement();
433 AppExecFwk::ElementName rightElement = want_.GetElement();
434 if (leftElement == rightElement) {
435 return AceIsSameFuncFromJS(cbInfo, cbInfo_);
436 } else {
437 return false;
438 }
439 }
440
RequestStrictEquals(CallBackType eventType,const AAFwk::Want & want,ACECallbackInfo & cbInfo,const std::shared_ptr<AceJSPluginRequestParam> & param)441 bool JSPluginCallback::RequestStrictEquals(CallBackType eventType, const AAFwk::Want& want, ACECallbackInfo& cbInfo,
442 const std::shared_ptr<AceJSPluginRequestParam>& param)
443 {
444 if (eventType != eventType_) {
445 return false;
446 }
447 AppExecFwk::ElementName leftElement = want.GetElement();
448 AppExecFwk::ElementName rightElement = want_.GetElement();
449 if (!(leftElement == rightElement)) {
450 return false;
451 }
452 if (param == nullptr || requestParam_ == nullptr) {
453 return false;
454 }
455 if (*param != *requestParam_) {
456 return false;
457 }
458 return AceIsSameFuncFromJS(cbInfo, cbInfo_);
459 }
460 } // namespace OHOS::Ace::Napi
461