• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 
16 #include <sstream>
17 #include "ani.h"
18 #include "ani_common_want.h"
19 #include "ani_plugin_callback.h"
20 #include "ani_plugin_callback_mgr.h"
21 #include "ani_plugin_component_data.h"
22 #include "ani_plugin_component_util.h"
23 #include "core/common/ace_engine.h"
24 #include "core/components/plugin/plugin_component_manager.h"
25 
26 namespace OHOS::Ace::Ani {
27     std::atomic_size_t ANIPluginCallback::uuid_ = 0;
28     constexpr char PLUGINCOMPONENT_TEMPLATE_CLASSNAME[] = "L@ohos/pluginComponent/PluginComponentTemplateImpl;";
29 
operator ==(const AceJSPluginRequestParam & param) const30 bool AceJSPluginRequestParam::operator==(const AceJSPluginRequestParam& param) const
31 {
32     AppExecFwk::ElementName leftElement = want_.GetElement();
33     AppExecFwk::ElementName rightElement = param.want_.GetElement();
34     if (leftElement == rightElement) {
35         if (name_ == param.name_ && data_ == param.data_ && jsonPath_ == param.jsonPath_) {
36             return true;
37         }
38     }
39     return false;
40 }
41 
operator !=(const AceJSPluginRequestParam & param) const42 bool AceJSPluginRequestParam::operator!=(const AceJSPluginRequestParam& param) const
43 {
44     return !operator==(param);
45 }
46 
ANIPluginCallback(CallBackType eventType,ACECallbackInfo & cbInfo,ACEAsyncJSCallbackInfo * jsCallbackInfo)47 ANIPluginCallback::ANIPluginCallback(
48     CallBackType eventType, ACECallbackInfo& cbInfo, ACEAsyncJSCallbackInfo* jsCallbackInfo)
49     : eventType_(eventType), asyncJSCallbackInfo_(jsCallbackInfo)
50 {
51     uuid_++;
52     cbInfo_.env = cbInfo.env;
53     cbInfo_.callback = cbInfo.callback;
54     cbInfo_.containerId = cbInfo.containerId;
55 }
56 
~ANIPluginCallback()57 ANIPluginCallback::~ANIPluginCallback()
58 {
59     if (uuid_ > 0) {
60         uuid_--;
61     }
62     DestroyAllResource();
63 }
64 
DestroyAllResource(void)65 void ANIPluginCallback::DestroyAllResource(void)
66 {
67     if (cbInfo_.env != nullptr && cbInfo_.callback != nullptr) {
68         cbInfo_.env->GlobalReference_Delete(cbInfo_.callback);
69     }
70     cbInfo_.env = nullptr;
71     cbInfo_.callback = nullptr;
72     cbInfo_.containerId = -1;
73     asyncJSCallbackInfo_ = nullptr;
74 }
75 
SetWant(const AAFwk::Want & want)76 void ANIPluginCallback::SetWant(const AAFwk::Want& want)
77 {
78     want_ = want;
79 }
80 
GetWant()81 AAFwk::Want& ANIPluginCallback::GetWant()
82 {
83     return want_;
84 }
85 
SetRequestParam(const std::shared_ptr<AceJSPluginRequestParam> & param)86 void ANIPluginCallback::SetRequestParam(const std::shared_ptr<AceJSPluginRequestParam>& param)
87 {
88     requestParam_ = param;
89 }
90 
GetID(void)91 size_t ANIPluginCallback::GetID(void)
92 {
93     return uuid_;
94 }
95 
RequestStrictEquals(CallBackType eventType,const AAFwk::Want & want,ACECallbackInfo & cbInfo,const std::shared_ptr<AceJSPluginRequestParam> & param)96 bool ANIPluginCallback::RequestStrictEquals(CallBackType eventType, const AAFwk::Want& want, ACECallbackInfo& cbInfo,
97     const std::shared_ptr<AceJSPluginRequestParam>& param)
98 {
99     if (eventType != eventType_) {
100         return false;
101     }
102     AppExecFwk::ElementName leftElement = want.GetElement();
103     AppExecFwk::ElementName rightElement = want_.GetElement();
104     if (!(leftElement == rightElement)) {
105         return false;
106     }
107     if (param == nullptr || requestParam_ == nullptr) {
108         return false;
109     }
110     if (*param != *requestParam_) {
111         return false;
112     }
113     return AceIsSameFuncFromANI(cbInfo, cbInfo_);
114 }
115 
GetContainerId()116 int32_t ANIPluginCallback::GetContainerId()
117 {
118     return cbInfo_.containerId;
119 }
120 
OnEventStrictEquals(CallBackType eventType,const AAFwk::Want & want,ACECallbackInfo & cbInfo)121 bool ANIPluginCallback::OnEventStrictEquals(CallBackType eventType, const AAFwk::Want& want, ACECallbackInfo& cbInfo)
122 {
123     if (eventType != eventType_) {
124         return false;
125     }
126     AppExecFwk::ElementName leftElement = want.GetElement();
127     AppExecFwk::ElementName rightElement = want_.GetElement();
128     if (leftElement == rightElement) {
129         return AceIsSameFuncFromANI(cbInfo, cbInfo_);
130     } else {
131         return false;
132     }
133 }
134 
OnPushEventInner(const OnPluginUvWorkData * workData)135 void ANIPluginCallback::OnPushEventInner(const OnPluginUvWorkData* workData)
136 {
137     LOGI("plugin-ani OnPushEventInner start");
138     PluginComponentTemplate componentTemplate;
139     componentTemplate.SetSource(workData->sourceName);
140     componentTemplate.SetAbility(workData->abilityName);
141     std::vector<ani_ref> vec;
142     auto wantObj = OHOS::AppExecFwk::WrapWant(cbInfo_.env, workData->want);
143     vec.push_back(wantObj);
144     auto param = MakeCallbackParamForRequestOrPush(componentTemplate, workData->data, workData->extraData);
145     vec.push_back(param.pluginTemplateObj);
146     vec.push_back(param.aniData);
147     vec.push_back(param.aniExtraData);
148     ani_ref fnReturnVal;
149     auto status = cbInfo_.env->FunctionalObject_Call(reinterpret_cast<ani_fn_object>(cbInfo_.callback),
150         vec.size(), vec.data(), &fnReturnVal);
151     LOGI("plugin-ani OnPushEventInner end status %{public}d", status);
152 }
153 
OnPushEvent(const AAFwk::Want & want,const PluginComponentTemplate & pluginTemplate,const std::string & data,const std::string & extraData)154 void ANIPluginCallback::OnPushEvent(const AAFwk::Want& want, const PluginComponentTemplate& pluginTemplate,
155     const std::string& data, const std::string& extraData)
156 {
157     LOGI("plugin-ani OnPushEvent start");
158     if (cbInfo_.env == nullptr || cbInfo_.callback == nullptr) {
159         return;
160     }
161 
162     auto container = AceEngine::Get().GetContainer(cbInfo_.containerId);
163     if (!container) {
164         return;
165     }
166 
167     auto taskExecutor = container->GetTaskExecutor();
168     if (!taskExecutor) {
169         return;
170     }
171     std::weak_ptr<PluginComponentCallBack> weak = weak_from_this();
172     taskExecutor->PostTask(
173         [weak, want, sourceName = pluginTemplate.GetSource(), abilityName = pluginTemplate.GetAbility(), data,
174             extraData]() {
175             OnPluginUvWorkData uvWorkData;
176             uvWorkData.want = want;
177             uvWorkData.sourceName = sourceName;
178             uvWorkData.abilityName = abilityName;
179             uvWorkData.data = data;
180             uvWorkData.extraData = extraData;
181             auto callBack = weak.lock();
182             if (callBack) {
183                 auto jsCallback = std::static_pointer_cast<ANIPluginCallback>(callBack);
184                 jsCallback->OnPushEventInner(&uvWorkData);
185             }
186         },
187         TaskExecutor::TaskType::UI, "ArkUIPluginPushEventInner");
188 }
189 
SendRequestEventResult(ani_object aniRef)190 void ANIPluginCallback::SendRequestEventResult(ani_object aniRef)
191 {
192     if (aniRef == nullptr) {
193         LOGE("plugin-ani result of request event is null");
194         return;
195     }
196     struct RequestEventResult {
197         AAFwk::Want want;
198         std::string strTemplate;
199         std::string strData;
200         std::string strExtraData;
201     };
202 
203     std::shared_ptr<RequestEventResult> data = std::make_shared<RequestEventResult>();
204     data->want = want_;
205     GetAniStringPropertyByName(cbInfo_.env, aniRef, "template", data->strTemplate);
206     GetAniKVObjectPropertyByName(cbInfo_.env, aniRef, "data", data->strData);
207     GetAniKVObjectPropertyByName(cbInfo_.env, aniRef, "extraData", data->strExtraData);
208     auto container = AceEngine::Get().GetContainer(cbInfo_.containerId);
209     if (!container) {
210         return;
211     }
212 
213     auto taskExecutor = container->GetTaskExecutor();
214     if (!taskExecutor) {
215         return;
216     }
217     taskExecutor->PostTask(
218         [data]() {
219             PluginComponentManager::GetInstance()->ReturnRequest(
220                 data->want, data->strTemplate, data->strData, data->strExtraData);
221         },
222         TaskExecutor::TaskType::BACKGROUND, "ArkUIPluginReturnRequest");
223 }
224 
OnRequestEventInner(const OnPluginUvWorkData * workData)225 void ANIPluginCallback::OnRequestEventInner(const OnPluginUvWorkData* workData)
226 {
227     LOGI("plugin-ani OnRequestEventInner start");
228     std::vector<ani_ref> vec;
229     auto wantObj = OHOS::AppExecFwk::WrapWant(cbInfo_.env, workData->want);
230     vec.push_back(wantObj);
231     auto nameAni = AceWrapStringToAni(cbInfo_.env, workData->name);
232     vec.push_back(nameAni);
233     ani_ref aniData = AceWrapStringToObject(cbInfo_.env, workData->data);
234     vec.push_back(aniData);
235     ani_ref fnReturnVal;
236     cbInfo_.env->FunctionalObject_Call(reinterpret_cast<ani_fn_object>(cbInfo_.callback), vec.size(), vec.data(),
237         &fnReturnVal);
238     ani_boolean isUndefined = true;
239     if (ANI_OK != cbInfo_.env->Reference_IsUndefined(fnReturnVal, &isUndefined) || isUndefined) {
240         LOGE("plugin-ani result of request event is null");
241         return;
242     }
243     SendRequestEventResult(reinterpret_cast<ani_object>(fnReturnVal));
244 }
245 
OnRequestEvent(const AAFwk::Want & want,const std::string & name,const std::string & data)246 void ANIPluginCallback::OnRequestEvent(const AAFwk::Want& want, const std::string& name, const std::string& data)
247 {
248     LOGI("plugin-ani OnRequestEvent start");
249     if (cbInfo_.env == nullptr || cbInfo_.callback == nullptr) {
250         return;
251     }
252 
253     auto container = AceEngine::Get().GetContainer(cbInfo_.containerId);
254     if (!container) {
255         return;
256     }
257 
258     auto taskExecutor = container->GetTaskExecutor();
259     if (!taskExecutor) {
260         return;
261     }
262 
263     std::weak_ptr<PluginComponentCallBack> weak = weak_from_this();
264     taskExecutor->PostTask(
265         [weak, want, name, data]() {
266             auto callBack = weak.lock();
267             if (callBack) {
268                 OnPluginUvWorkData uvWorkData;
269                 uvWorkData.want = want;
270                 uvWorkData.data = data;
271                 uvWorkData.name = name;
272                 auto jsCallback = std::static_pointer_cast<ANIPluginCallback>(callBack);
273                 jsCallback->OnRequestEventInner(&uvWorkData);
274             }
275         },
276         TaskExecutor::TaskType::JS, "ArkUIPluginRequestEventInner");
277 }
278 
MakePluginTemplateObject(const PluginComponentTemplate & pluginTemplate)279 ani_ref ANIPluginCallback::MakePluginTemplateObject(const PluginComponentTemplate& pluginTemplate)
280 {
281     ani_class pluginTemplateCls;
282     cbInfo_.env->FindClass(PLUGINCOMPONENT_TEMPLATE_CLASSNAME, &pluginTemplateCls);
283     ani_method PTOCtor;
284     cbInfo_.env->Class_FindMethod(pluginTemplateCls, "<ctor>", ":V", &PTOCtor);
285     ani_object PTOObj;
286     cbInfo_.env->Object_New(pluginTemplateCls, PTOCtor, &PTOObj);
287     cbInfo_.env->Object_SetPropertyByName_Ref(PTOObj, "source", AceWrapStringToAni(cbInfo_.env,
288         pluginTemplate.GetSource()));
289     cbInfo_.env->Object_SetPropertyByName_Ref(PTOObj, "ability", AceWrapStringToAni(cbInfo_.env,
290         pluginTemplate.GetAbility()));
291     return PTOObj;
292 }
293 
MakeCallbackParamForRequestOrPush(const PluginComponentTemplate & pluginTemplate,const std::string & data,const std::string & extraData)294 CallbackParamForRequest ANIPluginCallback::MakeCallbackParamForRequestOrPush(
295     const PluginComponentTemplate& pluginTemplate, const std::string& data, const std::string& extraData)
296 {
297     ani_ref pluginTemplateObj = MakePluginTemplateObject(pluginTemplate);
298     ani_ref aniData = AceWrapStringToObject(cbInfo_.env, data);
299     ani_ref aniExtraData = AceWrapStringToObject(cbInfo_.env, extraData);
300     CallbackParamForRequest param {
301         .pluginTemplateObj = pluginTemplateObj,
302         .aniData = aniData,
303         .aniExtraData = aniExtraData
304     };
305     return param;
306 }
307 
OnRequestCallBackInner(const OnPluginUvWorkData * workData)308 void ANIPluginCallback::OnRequestCallBackInner(const OnPluginUvWorkData* workData)
309 {
310     PluginComponentTemplate componentTemplate;
311     componentTemplate.SetSource(workData->sourceName);
312     componentTemplate.SetAbility(workData->abilityName);
313     std::vector<ani_ref> vec;
314     ani_ref fnReturnVal;
315     auto param = CreateInt(cbInfo_.env, ani_int(0));
316     vec.push_back(param);
317     auto paramForRequest = MakeCallbackParamForRequestOrPush(componentTemplate, workData->data, workData->extraData);
318     vec.push_back(paramForRequest.pluginTemplateObj);
319     vec.push_back(paramForRequest.aniData);
320     vec.push_back(paramForRequest.aniExtraData);
321     auto fnObj = reinterpret_cast<ani_fn_object>(cbInfo_.callback);
322     if (fnObj == nullptr) {
323         LOGI("plugin-ani OnRequestCallBackInner fnObj is null");
324         return;
325     }
326     auto status = cbInfo_.env->FunctionalObject_Call(fnObj, vec.size(), vec.data(), &fnReturnVal);
327     LOGI("plugin-ani OnRequestCallBackInner execute status %{public}d", status);
328     cbInfo_.env->GlobalReference_Delete(cbInfo_.callback);
329 }
330 
OnRequestCallBack(const PluginComponentTemplate & pluginTemplate,const std::string & data,const std::string & extraData)331 void ANIPluginCallback::OnRequestCallBack(
332     const PluginComponentTemplate& pluginTemplate, const std::string& data, const std::string& extraData)
333 {
334     ANIPluginCallbackMgr::Instance().UnRegisterEvent(GetID());
335     if (cbInfo_.env == nullptr) {
336         return;
337     }
338     uvWorkData_.sourceName = pluginTemplate.GetSource();
339     uvWorkData_.abilityName = pluginTemplate.GetAbility();
340     uvWorkData_.data = data;
341     uvWorkData_.extraData = extraData;
342 
343     if (getpid() != gettid()) {
344         struct ResultData {
345             ANIPluginCallback* context = nullptr;
346             std::mutex mtx;
347             bool ready = false;
348             std::condition_variable cv;
349         };
350 
351         std::shared_ptr<ResultData> resultData = std::make_shared<ResultData>();
352         resultData->context = this;
353 
354         auto container = AceEngine::Get().GetContainer(cbInfo_.containerId);
355         if (!container) {
356             return;
357         }
358 
359         auto taskExecutor = container->GetTaskExecutor();
360         if (!taskExecutor) {
361             return;
362         }
363         taskExecutor->PostTask(
364             [resultData]() {
365                 resultData->context->OnRequestCallBackInner(&resultData->context->uvWorkData_);
366 
367                 {
368                     std::unique_lock<std::mutex> lock(resultData->mtx);
369                     resultData->ready = true;
370                     resultData->cv.notify_all();
371                 }
372             },
373             TaskExecutor::TaskType::JS, "ArkUIPluginRequestCallbackInner");
374 
375         {
376             std::unique_lock<std::mutex> lock(resultData->mtx);
377             if (!resultData->ready) {
378                 resultData->cv.wait(lock, [&] { return resultData->ready; });
379             }
380         }
381     } else {
382         OnRequestCallBackInner(&uvWorkData_);
383     }
384 }
385 } // namespace OHOS::Ace::Ani