• 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 #include "js_plugin_callback.h"
16 #include <mutex>
17 
18 #include "hilog_wrapper.h"
19 #include "js_plugin_callback_mgr.h"
20 #include "js_plugin_util.h"
21 #include "js_plugin_want.h"
22 
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(CallBackType eventType,
53     ACECallbackInfo& cbInfo, ACEAsyncJSCallbackInfo* jsCallbackInfo) : eventType_(eventType),
54     asyncJSCallbackInfo_(jsCallbackInfo)
55 {
56     uuid_++;
57     cbInfo_.env = cbInfo.env;
58     cbInfo_.callback = cbInfo.callback;
59 }
60 
~JSPluginCallback()61 JSPluginCallback::~JSPluginCallback()
62 {
63     if (uuid_ > 0) {
64         uuid_--;
65     }
66     DestroyAllResource();
67 }
68 
DestroyAllResource(void)69 void JSPluginCallback::DestroyAllResource(void)
70 {
71     if (cbInfo_.env != nullptr && cbInfo_.callback != nullptr) {
72         napi_delete_reference(cbInfo_.env, cbInfo_.callback);
73     }
74     cbInfo_.env = nullptr;
75     cbInfo_.callback = nullptr;
76     asyncJSCallbackInfo_ = nullptr;
77 }
78 
SetWant(const AAFwk::Want & want)79 void JSPluginCallback::SetWant(const AAFwk::Want& want)
80 {
81     want_ = want;
82 }
83 
GetWant()84 AAFwk::Want& JSPluginCallback::GetWant()
85 {
86     return want_;
87 }
88 
SetRequestParam(const std::shared_ptr<AceJSPluginRequestParam> & param)89 void JSPluginCallback::SetRequestParam(const std::shared_ptr<AceJSPluginRequestParam>& param)
90 {
91     requestParam_ = param;
92 }
93 
GetID(void)94 size_t JSPluginCallback::GetID(void)
95 {
96     return uuid_;
97 }
98 
SendRequestEventResult(napi_value jsObject)99 void JSPluginCallback::SendRequestEventResult(napi_value jsObject)
100 {
101     napi_value jsTemplate = AceGetPropertyValueByPropertyName(cbInfo_.env, jsObject, "template", napi_string);
102     napi_value jsData = AceGetPropertyValueByPropertyName(cbInfo_.env, jsObject, "data", napi_object);
103     napi_value jsExtraData = AceGetPropertyValueByPropertyName(cbInfo_.env, jsObject, "extraData", napi_object);
104 
105     struct MyData {
106         AAFwk::Want want;
107         std::string strTemplate;
108         std::string strDate;
109         std::string strExtraData;
110     };
111 
112     MyData* data = new MyData;
113     data->want = want_;
114 
115     if (jsTemplate != nullptr) {
116         data->strTemplate = AceUnwrapStringFromJS(cbInfo_.env, jsTemplate);
117     }
118 
119     if (jsData != nullptr) {
120         AceKVObjectToString(cbInfo_.env, jsData, data->strDate);
121     }
122 
123     if (jsExtraData != nullptr) {
124         AceKVObjectToString(cbInfo_.env, jsExtraData, data->strExtraData);
125     }
126 
127     uv_loop_s* loop = nullptr;
128     napi_get_uv_event_loop(cbInfo_.env, &loop);
129     uv_work_t* work = new uv_work_t;
130     work->data = (void*)data;
131     int rev = uv_queue_work(
132         loop, work, [](uv_work_t* work) {
133             MyData* data = (MyData*)work->data;
134             PluginComponentManager::GetInstance()->ReturnRequest(
135                 data->want, data->strTemplate, data->strDate, data->strExtraData);
136         },
137         [](uv_work_t* work, int status) {
138             delete (MyData*)work->data;
139             delete work;
140         });
141     if (rev != 0) {
142         delete work;
143         delete data;
144     }
145 }
146 
MakeCallbackParamForRequest(const PluginComponentTemplate & pluginTemplate,const std::string & data,const std::string & extraData)147 napi_value JSPluginCallback::MakeCallbackParamForRequest(
148     const PluginComponentTemplate& pluginTemplate, const std::string& data, const std::string& extraData)
149 {
150     napi_value jsObject = AceCreateJSObject(cbInfo_.env);
151     if (jsObject == nullptr) {
152         return nullptr;
153     }
154 
155     std::string dataTmp("{}");
156     std::string extraDataTmp("{}");
157     if (!data.empty()) {
158         dataTmp = data;
159     }
160     if (!extraData.empty()) {
161         extraDataTmp = extraData;
162     }
163 
164     napi_value jsPluginTemplate = MakePluginTemplateObject(pluginTemplate);
165     napi_value jsData = AceStringToKVObject(cbInfo_.env, dataTmp);
166     napi_value jsExtraData = AceStringToKVObject(cbInfo_.env, extraDataTmp);
167 
168     if (jsData != nullptr) {
169         AceSetPropertyValueByPropertyName(cbInfo_.env, jsObject, "componentTemplate", jsPluginTemplate);
170     }
171     if (jsData != nullptr) {
172         AceSetPropertyValueByPropertyName(cbInfo_.env, jsObject, "data", jsData);
173     }
174     if (jsExtraData != nullptr) {
175         AceSetPropertyValueByPropertyName(cbInfo_.env, jsObject, "extraData", jsExtraData);
176     }
177     return jsObject;
178 }
179 
MakePluginTemplateObject(const PluginComponentTemplate & pluginTemplate)180 napi_value JSPluginCallback::MakePluginTemplateObject(const PluginComponentTemplate& pluginTemplate)
181 {
182     HILOG_INFO("%{public}s called.", __func__);
183     napi_value jsPluginTemplate = AceCreateJSObject(cbInfo_.env);
184     if (jsPluginTemplate != nullptr) {
185         napi_value jsSource = AceWrapStringToJS(cbInfo_.env, pluginTemplate.GetSource());
186         napi_value jsAbility = AceWrapStringToJS(cbInfo_.env, pluginTemplate.GetAbility());
187 
188         AceSetPropertyValueByPropertyName(cbInfo_.env, jsPluginTemplate, "source", jsSource);
189         AceSetPropertyValueByPropertyName(cbInfo_.env, jsPluginTemplate, "ability", jsAbility);
190     }
191     return jsPluginTemplate;
192 }
193 
OnPushEventInner(const OnPluginUvWorkData * workData)194 void JSPluginCallback::OnPushEventInner(const OnPluginUvWorkData* workData)
195 {
196     napi_value jsCallback = nullptr;
197     napi_value undefined = nullptr;
198     napi_value jsResult = nullptr;
199     napi_value callbackParam[ACE_ARGS_FOUR] = {nullptr};
200     napi_handle_scope scope = nullptr;
201     std::string dataTmp("{}");
202     std::string extraDataTmp("{}");
203     if (!workData->data.empty()) {
204         dataTmp = workData->data;
205     }
206     if (!workData->extraData.empty()) {
207         extraDataTmp = workData->extraData;
208     }
209 
210     napi_open_handle_scope(cbInfo_.env, &scope);
211     if (scope == nullptr) {
212         napi_close_handle_scope(cbInfo_.env, scope);
213         return;
214     }
215 
216     PluginComponentTemplate componentTemplate;
217     componentTemplate.SetSource(workData->sourceName);
218     componentTemplate.SetAbility(workData->abilityName);
219 
220     callbackParam[ACE_PARAM0] = AceWrapWant(cbInfo_.env, workData->want);
221     callbackParam[ACE_PARAM1] = MakePluginTemplateObject(componentTemplate);
222     callbackParam[ACE_PARAM2] = AceStringToKVObject(cbInfo_.env, dataTmp);
223     callbackParam[ACE_PARAM3] = AceStringToKVObject(cbInfo_.env, extraDataTmp);
224 
225     napi_get_undefined(cbInfo_.env, &undefined);
226     napi_get_reference_value(cbInfo_.env, cbInfo_.callback, &jsCallback);
227     napi_call_function(cbInfo_.env, undefined, jsCallback, ACE_ARGS_FOUR, callbackParam, &jsResult);
228     napi_close_handle_scope(cbInfo_.env, scope);
229 }
230 
OnPushEvent(const AAFwk::Want & want,const PluginComponentTemplate & pluginTemplate,const std::string & data,const std::string & extraData)231 void JSPluginCallback::OnPushEvent(const AAFwk::Want& want,
232     const PluginComponentTemplate& pluginTemplate, const std::string& data, const std::string& extraData)
233 {
234     HILOG_INFO("%{public}s called.", __func__);
235     if (cbInfo_.env == nullptr || cbInfo_.callback == nullptr) {
236         HILOG_INFO("%{public}s called, env or callback is null.", __func__);
237         return;
238     }
239 
240     uvWorkData_.that = (void *)this;
241     uvWorkData_.want = want;
242     uvWorkData_.sourceName = pluginTemplate.GetSource();
243     uvWorkData_.abilityName = pluginTemplate.GetAbility();
244     uvWorkData_.data = data;
245     uvWorkData_.extraData = extraData;
246 
247     uv_loop_s* loop = nullptr;
248     napi_get_uv_event_loop(cbInfo_.env, &loop);
249     uv_work_t* work = new uv_work_t;
250     work->data = (void*)this;
251     int rev = uv_queue_work(
252         loop, work, [](uv_work_t* work) {},
253         [](uv_work_t* work, int status) {
254             if (work == nullptr) {
255                 return;
256             }
257             JSPluginCallback* context = (JSPluginCallback*)work->data;
258             if (context) {
259                 context->OnPushEventInner(&context->uvWorkData_);
260             }
261             delete work;
262             work = nullptr;
263         });
264     if (rev != 0) {
265         if (work != nullptr) {
266             delete work;
267             work = nullptr;
268         }
269     }
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,
304     const std::string& data)
305 {
306     if (cbInfo_.env == nullptr || cbInfo_.callback == nullptr) {
307         HILOG_INFO("%{public}s called, env or callback is null.", __func__);
308         return;
309     }
310 
311     uvWorkData_.that = (void *)this;
312     uvWorkData_.want = want;
313     uvWorkData_.data = data;
314     uvWorkData_.name = name;
315 
316     uv_loop_s* loop = nullptr;
317     napi_get_uv_event_loop(cbInfo_.env, &loop);
318     uv_work_t* work = new uv_work_t;
319     work->data = (void*)this;
320     int rev = uv_queue_work(
321         loop, work, [](uv_work_t* work) {},
322         [](uv_work_t* work, int status) {
323             if (work == nullptr) {
324                 return;
325             }
326             JSPluginCallback* context = (JSPluginCallback*)work->data;
327             if (context) {
328                 context->OnRequestEventInner(&context->uvWorkData_);
329             }
330             delete work;
331             work = nullptr;
332         });
333     if (rev != 0) {
334         if (work != nullptr) {
335             delete work;
336             work = nullptr;
337         }
338     }
339 }
340 
OnRequestCallBackInner(const OnPluginUvWorkData * workData)341 void JSPluginCallback::OnRequestCallBackInner(const OnPluginUvWorkData* workData)
342 {
343     HILOG_INFO("%{public}s called.", __func__);
344     napi_value jsCallback = nullptr;
345     napi_value undefined = nullptr;
346     napi_value jsResult = nullptr;
347     napi_handle_scope scope = nullptr;
348     napi_open_handle_scope(cbInfo_.env, &scope);
349     if (scope == nullptr) {
350         napi_close_handle_scope(cbInfo_.env, scope);
351         return;
352     }
353     PluginComponentTemplate componentTemplate;
354     componentTemplate.SetSource(workData->sourceName);
355     componentTemplate.SetAbility(workData->abilityName);
356 
357     if (cbInfo_.callback != nullptr) {
358         napi_value callbackParam[ACE_ARGS_TWO] = {nullptr};
359         callbackParam[ACE_PARAM0] = AceGetCallbackErrorValue(cbInfo_.env, 0);
360         callbackParam[ACE_PARAM1] = MakeCallbackParamForRequest(componentTemplate, workData->data,
361             workData->extraData);
362         napi_get_undefined(cbInfo_.env, &undefined);
363         napi_get_reference_value(cbInfo_.env, cbInfo_.callback, &jsCallback);
364         napi_call_function(cbInfo_.env, undefined, jsCallback, ACE_ARGS_TWO, callbackParam, &jsResult);
365     }
366     napi_close_handle_scope(cbInfo_.env, scope);
367 }
368 
OnRequestCallBack(const PluginComponentTemplate & pluginTemplate,const std::string & data,const std::string & extraData)369 void JSPluginCallback::OnRequestCallBack(const PluginComponentTemplate& pluginTemplate,
370     const std::string& data, const std::string& extraData)
371 {
372     HILOG_INFO("%{public}s called.", __func__);
373     JSPluginCallbackMgr::Instance().UnRegisterEvent(GetID());
374     if (cbInfo_.env == nullptr) {
375         HILOG_INFO("%{public}s called, env or callback is null.", __func__);
376         return;
377     }
378 
379     if (cbInfo_.callback != nullptr) {
380         uvWorkData_.that = (void*)this;
381         uvWorkData_.sourceName = pluginTemplate.GetSource();
382         uvWorkData_.abilityName = pluginTemplate.GetAbility();
383         uvWorkData_.data = data;
384         uvWorkData_.extraData = extraData;
385 
386         if (getpid() != gettid()) {
387             uv_loop_s* loop = nullptr;
388             napi_get_uv_event_loop(cbInfo_.env, &loop);
389 
390             struct ResultData {
391                 JSPluginCallback* context = nullptr;
392                 std::mutex mtx;
393                 bool ready = false;
394                 std::condition_variable cv;
395             };
396 
397             ResultData* resultData = new ResultData;
398             resultData->context = this;
399 
400             uv_work_t* work = new uv_work_t;
401             work->data = (void*)resultData;
402             int rev = uv_queue_work(
403                 loop, work, [](uv_work_t* work) {},
404                 [](uv_work_t* work, int status) {
405                     if (work == nullptr) {
406                         return;
407                     }
408                     ResultData* data = (ResultData*)work->data;
409                     if (data->context) {
410                         data->context->OnRequestCallBackInner(&data->context->uvWorkData_);
411                     }
412 
413                     {
414                         std::unique_lock<std::mutex> lock(data->mtx);
415                         data->ready=true;
416                         data->cv.notify_all();
417                     }
418                     delete work;
419                 });
420             if (rev != 0) {
421                 delete resultData;
422                 delete work;
423             } else {
424                 {
425                     std::unique_lock<std::mutex> lock(resultData->mtx);
426                     resultData->cv.wait(lock, [&] { return resultData->ready; });
427                 }
428                 delete resultData;
429             }
430         } else {
431             OnRequestCallBackInner(&uvWorkData_);
432         }
433     } else {
434         if (asyncJSCallbackInfo_) {
435             asyncJSCallbackInfo_->requestCallbackData.sourceName = pluginTemplate.GetSource();
436             asyncJSCallbackInfo_->requestCallbackData.abilityName = pluginTemplate.GetAbility();
437             asyncJSCallbackInfo_->requestCallbackData.data = data;
438             asyncJSCallbackInfo_->requestCallbackData.extraData = extraData;
439             asyncJSCallbackInfo_->onRequestCallbackOK = true;
440         }
441     }
442 }
443 
OnEventStrictEquals(CallBackType eventType,const AAFwk::Want & want,ACECallbackInfo & cbInfo)444 bool JSPluginCallback::OnEventStrictEquals(CallBackType eventType, const AAFwk::Want& want,
445     ACECallbackInfo& cbInfo)
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 AceIsSameFuncFromJS(cbInfo, cbInfo_);
454     } else {
455         return false;
456     }
457 }
458 
RequestStrictEquals(CallBackType eventType,const AAFwk::Want & want,ACECallbackInfo & cbInfo,const std::shared_ptr<AceJSPluginRequestParam> & param)459 bool JSPluginCallback::RequestStrictEquals(CallBackType eventType, const AAFwk::Want& want,
460     ACECallbackInfo& cbInfo, const std::shared_ptr<AceJSPluginRequestParam>& param)
461 {
462     if (eventType != eventType_) {
463         return false;
464     }
465     AppExecFwk::ElementName leftElement = want.GetElement();
466     AppExecFwk::ElementName rightElement = want_.GetElement();
467     if (!(leftElement == rightElement)) {
468         return false;
469     }
470     if (param == nullptr || requestParam_ == nullptr) {
471         return false;
472     }
473     if (*param != *requestParam_) {
474         return false;
475     }
476     return AceIsSameFuncFromJS(cbInfo, cbInfo_);
477 }
478 }  // namespace OHOS::Ace::Napi
479