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