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