• 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 
17 #include <memory>
18 #include <mutex>
19 
20 #include "hilog_wrapper.h"
21 #include "js_plugin_callback_mgr.h"
22 #include "js_plugin_util.h"
23 #include "js_plugin_want.h"
24 
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 
SendRequestEventResult(napi_value jsObject)104 void JSPluginCallback::SendRequestEventResult(napi_value jsObject)
105 {
106     napi_value jsTemplate = AceGetPropertyValueByPropertyName(cbInfo_.env, jsObject, "template", napi_string);
107     napi_value jsData = AceGetPropertyValueByPropertyName(cbInfo_.env, jsObject, "data", napi_object);
108     napi_value jsExtraData = AceGetPropertyValueByPropertyName(cbInfo_.env, jsObject, "extraData", napi_object);
109 
110     struct MyData {
111         AAFwk::Want want;
112         std::string strTemplate;
113         std::string strDate;
114         std::string strExtraData;
115     };
116 
117     std::shared_ptr<MyData> data = std::make_shared<MyData>();
118     data->want = want_;
119 
120     if (jsTemplate != nullptr) {
121         data->strTemplate = AceUnwrapStringFromJS(cbInfo_.env, jsTemplate);
122     }
123 
124     if (jsData != nullptr) {
125         AceKVObjectToString(cbInfo_.env, jsData, data->strDate);
126     }
127 
128     if (jsExtraData != nullptr) {
129         AceKVObjectToString(cbInfo_.env, jsExtraData, data->strExtraData);
130     }
131 
132     auto container = AceEngine::Get().GetContainer(cbInfo_.containerId);
133     if (!container) {
134         HILOG_INFO("%{public}s called, container is null. %{public}d", __func__, cbInfo_.containerId);
135         return;
136     }
137 
138     auto taskExecutor = container->GetTaskExecutor();
139     if (!taskExecutor) {
140         HILOG_INFO("%{public}s called, taskExecutor is null.", __func__);
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);
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     HILOG_INFO("%{public}s called.", __func__);
187     napi_value jsPluginTemplate = AceCreateJSObject(cbInfo_.env);
188     if (jsPluginTemplate != nullptr) {
189         napi_value jsSource = AceWrapStringToJS(cbInfo_.env, pluginTemplate.GetSource());
190         napi_value jsAbility = AceWrapStringToJS(cbInfo_.env, pluginTemplate.GetAbility());
191 
192         AceSetPropertyValueByPropertyName(cbInfo_.env, jsPluginTemplate, "source", jsSource);
193         AceSetPropertyValueByPropertyName(cbInfo_.env, jsPluginTemplate, "ability", jsAbility);
194     }
195     return jsPluginTemplate;
196 }
197 
OnPushEventInner(const OnPluginUvWorkData * workData)198 void JSPluginCallback::OnPushEventInner(const OnPluginUvWorkData* workData)
199 {
200     napi_value jsCallback = nullptr;
201     napi_value undefined = nullptr;
202     napi_value jsResult = nullptr;
203     napi_value callbackParam[ACE_ARGS_FOUR] = {nullptr};
204     napi_handle_scope scope = nullptr;
205     std::string dataTmp("{}");
206     std::string extraDataTmp("{}");
207     if (!workData->data.empty()) {
208         dataTmp = workData->data;
209     }
210     if (!workData->extraData.empty()) {
211         extraDataTmp = workData->extraData;
212     }
213 
214     napi_open_handle_scope(cbInfo_.env, &scope);
215     if (scope == nullptr) {
216         napi_close_handle_scope(cbInfo_.env, scope);
217         return;
218     }
219 
220     PluginComponentTemplate componentTemplate;
221     componentTemplate.SetSource(workData->sourceName);
222     componentTemplate.SetAbility(workData->abilityName);
223 
224     callbackParam[ACE_PARAM0] = AceWrapWant(cbInfo_.env, workData->want);
225     callbackParam[ACE_PARAM1] = MakePluginTemplateObject(componentTemplate);
226     callbackParam[ACE_PARAM2] = AceStringToKVObject(cbInfo_.env, dataTmp);
227     callbackParam[ACE_PARAM3] = AceStringToKVObject(cbInfo_.env, extraDataTmp);
228 
229     napi_get_undefined(cbInfo_.env, &undefined);
230     napi_get_reference_value(cbInfo_.env, cbInfo_.callback, &jsCallback);
231     napi_call_function(cbInfo_.env, undefined, jsCallback, ACE_ARGS_FOUR, callbackParam, &jsResult);
232     napi_close_handle_scope(cbInfo_.env, scope);
233 }
234 
OnPushEvent(const AAFwk::Want & want,const PluginComponentTemplate & pluginTemplate,const std::string & data,const std::string & extraData)235 void JSPluginCallback::OnPushEvent(const AAFwk::Want& want, const PluginComponentTemplate& pluginTemplate,
236     const std::string& data, const std::string& extraData)
237 {
238     HILOG_INFO("%{public}s called.", __func__);
239     if (cbInfo_.env == nullptr || cbInfo_.callback == nullptr) {
240         HILOG_INFO("%{public}s called, env or callback is null.", __func__);
241         return;
242     }
243 
244     auto container = AceEngine::Get().GetContainer(cbInfo_.containerId);
245     if (!container) {
246         HILOG_INFO("%{public}s called, container is null. %{public}d", __func__, cbInfo_.containerId);
247         return;
248     }
249 
250     auto taskExecutor = container->GetTaskExecutor();
251     if (!taskExecutor) {
252         HILOG_INFO("%{public}s called, taskExecutor is null.", __func__);
253         return;
254     }
255     std::weak_ptr<PluginComponentCallBack> weak = weak_from_this();
256     taskExecutor->PostTask(
257         [weak, want, sourceName = pluginTemplate.GetSource(), abilityName = pluginTemplate.GetAbility(), data,
258             extraData]() {
259             OnPluginUvWorkData uvWorkData;
260             uvWorkData.want = want;
261             uvWorkData.sourceName = sourceName;
262             uvWorkData.abilityName = abilityName;
263             uvWorkData.data = data;
264             uvWorkData.extraData = extraData;
265             auto callBack = weak.lock();
266             if (callBack) {
267                 auto jsCallback = std::static_pointer_cast<JSPluginCallback>(callBack);
268                 jsCallback->OnPushEventInner(&uvWorkData);
269             }
270         },
271         TaskExecutor::TaskType::UI);
272 }
273 
OnRequestEventInner(const OnPluginUvWorkData * workData)274 void JSPluginCallback::OnRequestEventInner(const OnPluginUvWorkData* workData)
275 {
276     napi_value jsCallback = nullptr;
277     napi_value undefined = nullptr;
278     napi_value jsResult = nullptr;
279     napi_handle_scope scope = nullptr;
280     std::string dataTmp("{}");
281     if (!workData->data.empty()) {
282         dataTmp = workData->data;
283     }
284 
285     napi_open_handle_scope(cbInfo_.env, &scope);
286     if (scope == nullptr) {
287         napi_close_handle_scope(cbInfo_.env, scope);
288         return;
289     }
290     napi_value callbackParam[ACE_ARGS_THREE] = {nullptr};
291     callbackParam[ACE_PARAM0] = AceWrapWant(cbInfo_.env, workData->want);
292     callbackParam[ACE_PARAM1] = AceWrapStringToJS(cbInfo_.env, workData->name);
293     callbackParam[ACE_PARAM2] = AceStringToKVObject(cbInfo_.env, dataTmp);
294 
295     napi_get_undefined(cbInfo_.env, &undefined);
296     napi_get_reference_value(cbInfo_.env, cbInfo_.callback, &jsCallback);
297     napi_call_function(cbInfo_.env, undefined, jsCallback, ACE_ARGS_THREE, callbackParam, &jsResult);
298 
299     if (AceIsTypeForNapiValue(cbInfo_.env, jsResult, napi_object)) {
300         SendRequestEventResult(jsResult);
301     }
302     napi_close_handle_scope(cbInfo_.env, scope);
303 }
304 
OnRequestEvent(const AAFwk::Want & want,const std::string & name,const std::string & data)305 void JSPluginCallback::OnRequestEvent(const AAFwk::Want& want, const std::string& name,
306     const std::string& data)
307 {
308     if (cbInfo_.env == nullptr || cbInfo_.callback == nullptr) {
309         HILOG_INFO("%{public}s called, env or callback is null.", __func__);
310         return;
311     }
312 
313     uvWorkData_.that = (void *)this;
314     uvWorkData_.want = want;
315     uvWorkData_.data = data;
316     uvWorkData_.name = name;
317 
318     auto container = AceEngine::Get().GetContainer(cbInfo_.containerId);
319     if (!container) {
320         HILOG_INFO("%{public}s called, container is null. %{public}d", __func__, cbInfo_.containerId);
321         return;
322     }
323 
324     auto taskExecutor = container->GetTaskExecutor();
325     if (!taskExecutor) {
326         HILOG_INFO("%{public}s called, taskExecutor is null.", __func__);
327         return;
328     }
329     taskExecutor->PostTask(
330         [uvWorkData = &uvWorkData_]() {
331             JSPluginCallback* context = (JSPluginCallback*)uvWorkData->that;
332             if (context) {
333                 context->OnRequestEventInner(&context->uvWorkData_);
334             }
335         },
336         TaskExecutor::TaskType::JS);
337 }
338 
OnRequestCallBackInner(const OnPluginUvWorkData * workData)339 void JSPluginCallback::OnRequestCallBackInner(const OnPluginUvWorkData* workData)
340 {
341     HILOG_INFO("%{public}s called.", __func__);
342     napi_value jsCallback = nullptr;
343     napi_value undefined = nullptr;
344     napi_value jsResult = nullptr;
345     napi_handle_scope scope = nullptr;
346     napi_open_handle_scope(cbInfo_.env, &scope);
347     if (scope == nullptr) {
348         napi_close_handle_scope(cbInfo_.env, scope);
349         return;
350     }
351     PluginComponentTemplate componentTemplate;
352     componentTemplate.SetSource(workData->sourceName);
353     componentTemplate.SetAbility(workData->abilityName);
354 
355     if (cbInfo_.callback != nullptr) {
356         napi_value callbackParam[ACE_ARGS_TWO] = {nullptr};
357         callbackParam[ACE_PARAM0] = AceGetCallbackErrorValue(cbInfo_.env, 0);
358         callbackParam[ACE_PARAM1] = MakeCallbackParamForRequest(componentTemplate, workData->data,
359             workData->extraData);
360         napi_get_undefined(cbInfo_.env, &undefined);
361         napi_get_reference_value(cbInfo_.env, cbInfo_.callback, &jsCallback);
362         napi_call_function(cbInfo_.env, undefined, jsCallback, ACE_ARGS_TWO, callbackParam, &jsResult);
363     }
364     napi_close_handle_scope(cbInfo_.env, scope);
365 }
366 
OnRequestCallBack(const PluginComponentTemplate & pluginTemplate,const std::string & data,const std::string & extraData)367 void JSPluginCallback::OnRequestCallBack(const PluginComponentTemplate& pluginTemplate,
368     const std::string& data, const std::string& extraData)
369 {
370     HILOG_INFO("%{public}s called.", __func__);
371     JSPluginCallbackMgr::Instance().UnRegisterEvent(GetID());
372     if (cbInfo_.env == nullptr) {
373         HILOG_INFO("%{public}s called, env or callback is null.", __func__);
374         return;
375     }
376 
377     if (cbInfo_.callback != nullptr) {
378         uvWorkData_.that = (void*)this;
379         uvWorkData_.sourceName = pluginTemplate.GetSource();
380         uvWorkData_.abilityName = pluginTemplate.GetAbility();
381         uvWorkData_.data = data;
382         uvWorkData_.extraData = extraData;
383 
384         if (getpid() != gettid()) {
385             uv_loop_s* loop = nullptr;
386             napi_get_uv_event_loop(cbInfo_.env, &loop);
387 
388             struct ResultData {
389                 JSPluginCallback* context = nullptr;
390                 std::mutex mtx;
391                 bool ready = false;
392                 std::condition_variable cv;
393             };
394 
395             std::shared_ptr<ResultData> resultData = std::make_shared<ResultData>();
396             resultData->context = this;
397 
398             auto container = AceEngine::Get().GetContainer(cbInfo_.containerId);
399             if (!container) {
400                 HILOG_INFO("%{public}s called, container is null. %{public}d", __func__, cbInfo_.containerId);
401                 return;
402             }
403 
404             auto taskExecutor = container->GetTaskExecutor();
405             if (!taskExecutor) {
406                 HILOG_INFO("%{public}s called, taskExecutor is null.", __func__);
407                 return;
408             }
409             taskExecutor->PostTask(
410                 [resultData]() {
411                     resultData->context->OnRequestCallBackInner(&resultData->context->uvWorkData_);
412 
413                     {
414                         std::unique_lock<std::mutex> lock(resultData->mtx);
415                         resultData->ready = true;
416                         resultData->cv.notify_all();
417                     }
418                 },
419                 TaskExecutor::TaskType::JS);
420 
421             {
422                 std::unique_lock<std::mutex> lock(resultData->mtx);
423                 resultData->cv.wait(lock, [&] { return resultData->ready; });
424             }
425         } else {
426             OnRequestCallBackInner(&uvWorkData_);
427         }
428     } else {
429         if (asyncJSCallbackInfo_) {
430             asyncJSCallbackInfo_->requestCallbackData.sourceName = pluginTemplate.GetSource();
431             asyncJSCallbackInfo_->requestCallbackData.abilityName = pluginTemplate.GetAbility();
432             asyncJSCallbackInfo_->requestCallbackData.data = data;
433             asyncJSCallbackInfo_->requestCallbackData.extraData = extraData;
434             asyncJSCallbackInfo_->onRequestCallbackOK = true;
435         }
436     }
437 }
438 
OnEventStrictEquals(CallBackType eventType,const AAFwk::Want & want,ACECallbackInfo & cbInfo)439 bool JSPluginCallback::OnEventStrictEquals(CallBackType eventType, const AAFwk::Want& want,
440     ACECallbackInfo& cbInfo)
441 {
442     if (eventType != eventType_) {
443         return false;
444     }
445     AppExecFwk::ElementName leftElement = want.GetElement();
446     AppExecFwk::ElementName rightElement = want_.GetElement();
447     if (leftElement == rightElement) {
448         return AceIsSameFuncFromJS(cbInfo, cbInfo_);
449     } else {
450         return false;
451     }
452 }
453 
RequestStrictEquals(CallBackType eventType,const AAFwk::Want & want,ACECallbackInfo & cbInfo,const std::shared_ptr<AceJSPluginRequestParam> & param)454 bool JSPluginCallback::RequestStrictEquals(CallBackType eventType, const AAFwk::Want& want,
455     ACECallbackInfo& cbInfo, const std::shared_ptr<AceJSPluginRequestParam>& param)
456 {
457     if (eventType != eventType_) {
458         return false;
459     }
460     AppExecFwk::ElementName leftElement = want.GetElement();
461     AppExecFwk::ElementName rightElement = want_.GetElement();
462     if (!(leftElement == rightElement)) {
463         return false;
464     }
465     if (param == nullptr || requestParam_ == nullptr) {
466         return false;
467     }
468     if (*param != *requestParam_) {
469         return false;
470     }
471     return AceIsSameFuncFromJS(cbInfo, cbInfo_);
472 }
473 }  // namespace OHOS::Ace::Napi
474