• 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 
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