1 /*
2  * Copyright (c) 2021-2023 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 "ipc_skeleton.h"
17 #include "js_plugin_callback_mgr.h"
18 #include "js_plugin_util.h"
19 #include "js_plugin_want.h"
20 #include "tokenid_kit.h"
21 
22 #include "core/components/plugin/plugin_component_manager.h"
23 
24 namespace OHOS::Ace::Napi {
25 constexpr int ACE_ARGS_MAX_COUNT = 10;
26 constexpr int ACE_ARGS_TWO = 2;
27 constexpr int ACE_ARGS_THREE = 3;
28 constexpr int ACE_PARAM0 = 0;
29 constexpr int ACE_PARAM1 = 1;
30 constexpr int ACE_PARAM2 = 2;
31 constexpr int NAPI_ACE_ERR_ERROR = 1;
32 
UnwrapStageWantFromJS(napi_env env, napi_value param, ACEAsyncJSCallbackInfo* asyncCallbackInfo)33 bool UnwrapStageWantFromJS(napi_env env, napi_value param, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
34 {
35     if (!AceUnwrapWant(env, param, asyncCallbackInfo->wantStage)) {
36         return false;
37     }
38     return true;
39 }
40 
UnwrapOwnerWantFromJS(napi_env env, napi_value param, ACEAsyncJSCallbackInfo* asyncCallbackInfo)41 bool UnwrapOwnerWantFromJS(napi_env env, napi_value param, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
42 {
43     napi_value jsValue = AceGetPropertyValueByPropertyName(env, param, "owner", napi_object);
44     if (jsValue == nullptr) {
45         return false;
46     }
47 
48     if (!AceUnwrapWant(env, jsValue, asyncCallbackInfo->wantStage)) {
49         return false;
50     }
51 
52     auto selfToken = IPCSkeleton::GetSelfTokenID();
53     if (!Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(selfToken)) {
54         TAG_LOGI(AceLogTag::ACE_PLUGIN_COMPONENT, "This application is not system-app, can not use system-api");
55         return false;
56     }
57 
58     return true;
59 }
60 
UnwrapWantFromJS(napi_env env, napi_value param, ACEAsyncJSCallbackInfo* asyncCallbackInfo)61 bool UnwrapWantFromJS(napi_env env, napi_value param, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
62 {
63     napi_value jsValue = AceGetPropertyValueByPropertyName(env, param, "want", napi_object);
64     if (jsValue == nullptr) {
65         return false;
66     }
67 
68     if (!AceUnwrapWant(env, jsValue, asyncCallbackInfo->jsParamList.want)) {
69         return false;
70     }
71     return true;
72 }
73 
UnwrapTargetFromJS(napi_env env, napi_value param, ACEAsyncJSCallbackInfo* asyncCallbackInfo)74 bool UnwrapTargetFromJS(napi_env env, napi_value param, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
75 {
76     napi_value jsValue = AceGetPropertyValueByPropertyName(env, param, "target", napi_object);
77     if (jsValue == nullptr) {
78         return false;
79     }
80 
81     if (!AceUnwrapWant(env, jsValue, asyncCallbackInfo->jsParamList.want)) {
82         return false;
83     }
84     return true;
85 }
86 
UnwrapNameFromJS(napi_env env, napi_value param, const std::string& key, ACEAsyncJSCallbackInfo* asyncCallbackInfo)87 bool UnwrapNameFromJS(napi_env env, napi_value param, const std::string& key, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
88 {
89     napi_value jsValue = AceGetPropertyValueByPropertyName(env, param, key.c_str(), napi_string);
90     if (jsValue == nullptr) {
91         return false;
92     }
93 
94     std::string strValue = AceUnwrapStringFromJS(env, jsValue);
95     asyncCallbackInfo->jsParamList.paramList.PutStringValue(key, strValue);
96     return true;
97 }
98 
UnwrapKVObjectFromJS( napi_env env, napi_value param, const std::string& key, ACEAsyncJSCallbackInfo* asyncCallbackInfo)99 bool UnwrapKVObjectFromJS(
100     napi_env env, napi_value param, const std::string& key, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
101 {
102     napi_value jsValue = AceGetPropertyValueByPropertyName(env, param, key.c_str(), napi_object);
103     if (jsValue == nullptr) {
104         return false;
105     }
106 
107     std::string jsonString("{}");
108     bool ret = AceKVObjectToString(env, jsValue, jsonString);
109     if (ret) {
110         asyncCallbackInfo->jsParamList.paramList.PutStringValue(key, jsonString);
111     }
112     return ret;
113 }
114 
UnwrapPushParameters(napi_env env, napi_value param, ACEAsyncJSCallbackInfo* asyncCallbackInfo)115 bool UnwrapPushParameters(napi_env env, napi_value param, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
116 {
117     if (!AceIsTypeForNapiValue(env, param, napi_object)) {
118         return false;
119     }
120 
121     bool isStageModelAPI = (asyncCallbackInfo->ability == nullptr);
122     if (isStageModelAPI) {
123         if (!UnwrapOwnerWantFromJS(env, param, asyncCallbackInfo)) {
124             return false;
125         }
126     }
127 
128     if (!UnwrapWantFromJS(env, param, asyncCallbackInfo) && !UnwrapTargetFromJS(env, param, asyncCallbackInfo)) {
129         return false;
130     }
131     if (!UnwrapNameFromJS(env, param, "name", asyncCallbackInfo)) {
132         return false;
133     }
134     if (!UnwrapKVObjectFromJS(env, param, "data", asyncCallbackInfo)) {
135         return false;
136     }
137     if (!UnwrapKVObjectFromJS(env, param, "extraData", asyncCallbackInfo)) {
138         return false;
139     }
140 
141     UnwrapNameFromJS(env, param, "jsonPath", asyncCallbackInfo);
142     return true;
143 }
144 
UnwrapParamForPush(napi_env env, size_t argc, napi_value* argv, ACEAsyncJSCallbackInfo* asyncCallbackInfo)145 bool UnwrapParamForPush(napi_env env, size_t argc, napi_value* argv, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
146 {
147     const size_t argcMax = ACE_ARGS_TWO;
148     if (argc <= 0 || argc > argcMax) {
149         return false;
150     }
151 
152     if (!UnwrapPushParameters(env, argv[ACE_PARAM0], asyncCallbackInfo)) {
153         return false;
154     }
155 
156     if (argc == argcMax) {
157         if (!AceCreateAsyncCallback(env, argv[ACE_PARAM1], asyncCallbackInfo)) {
158             return false;
159         }
160     }
161     return true;
162 }
163 
JSPushCompleteAsyncCallbackWork(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)164 void JSPushCompleteAsyncCallbackWork(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
165 {
166     if (asyncCallbackInfo == nullptr) {
167         return;
168     }
169     PluginComponentManager::GetInstance()->Push(asyncCallbackInfo->jsParamList.want,
170         asyncCallbackInfo->jsParamList.paramList.GetStringValue("name"),
171         asyncCallbackInfo->jsParamList.paramList.GetStringValue("jsonPath"),
172         asyncCallbackInfo->jsParamList.paramList.GetStringValue("data"),
173         asyncCallbackInfo->jsParamList.paramList.GetStringValue("extraData"));
174 
175     asyncCallbackInfo->error_code = 0;
176     AceCompleteAsyncCallbackWork(env, asyncCallbackInfo);
177 }
178 
JSPushCompletePromiseCallbackWork(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)179 void JSPushCompletePromiseCallbackWork(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
180 {
181     if (asyncCallbackInfo == nullptr) {
182         return;
183     }
184 
185     PluginComponentManager::GetInstance()->Push(asyncCallbackInfo->jsParamList.want,
186         asyncCallbackInfo->jsParamList.paramList.GetStringValue("name"),
187         asyncCallbackInfo->jsParamList.paramList.GetStringValue("jsonPath"),
188         asyncCallbackInfo->jsParamList.paramList.GetStringValue("data"),
189         asyncCallbackInfo->jsParamList.paramList.GetStringValue("extraData"));
190 
191     asyncCallbackInfo->error_code = 0;
192     AceCompletePromiseCallbackWork(env, asyncCallbackInfo);
193 }
194 
NAPI_JSPushWrap(napi_env env, napi_callback_info info, ACEAsyncJSCallbackInfo* asyncCallbackInfo)195 napi_value NAPI_JSPushWrap(napi_env env, napi_callback_info info, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
196 {
197     size_t argc = ACE_ARGS_MAX_COUNT;
198     napi_value args[ACE_ARGS_MAX_COUNT] = { nullptr };
199     napi_value jsthis = 0;
200     void* data = nullptr;
201 
202     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &jsthis, &data));
203     if (!UnwrapParamForPush(env, argc, args, asyncCallbackInfo)) {
204         return nullptr;
205     }
206 
207     if (asyncCallbackInfo->cbInfo.callback != nullptr) {
208         JSPushCompleteAsyncCallbackWork(env, asyncCallbackInfo);
209         return AceWrapVoidToJS(env);
210     } else {
211         napi_value promise = 0;
212         NAPI_CALL(env, napi_create_promise(env, &asyncCallbackInfo->deferred, &promise));
213         JSPushCompletePromiseCallbackWork(env, asyncCallbackInfo);
214         return promise;
215     }
216 }
217 
JSPush(napi_env env, napi_callback_info info)218 static napi_value JSPush(napi_env env, napi_callback_info info)
219 {
220     ACEAsyncJSCallbackInfo* asyncCallbackInfo = AceCreateAsyncJSCallbackInfo(env);
221     if (asyncCallbackInfo == nullptr) {
222         return AceWrapVoidToJS(env);
223     }
224 
225     napi_value rev = NAPI_JSPushWrap(env, info, asyncCallbackInfo);
226     if (rev == nullptr) {
227         AceFreeAsyncJSCallbackInfo(&asyncCallbackInfo);
228         rev = AceWrapVoidToJS(env);
229     }
230     return rev;
231 }
232 
UnwrapRequestParameters(napi_env env, napi_value param, ACEAsyncJSCallbackInfo* asyncCallbackInfo)233 bool UnwrapRequestParameters(napi_env env, napi_value param, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
234 {
235     if (!AceIsTypeForNapiValue(env, param, napi_object)) {
236         return false;
237     }
238 
239     bool isStageModelAPI = (asyncCallbackInfo->ability == nullptr);
240     if (isStageModelAPI) {
241         if (!UnwrapOwnerWantFromJS(env, param, asyncCallbackInfo)) {
242             return false;
243         }
244     }
245 
246     if (!UnwrapWantFromJS(env, param, asyncCallbackInfo) && !UnwrapTargetFromJS(env, param, asyncCallbackInfo)) {
247         return false;
248     }
249     if (!UnwrapNameFromJS(env, param, "name", asyncCallbackInfo)) {
250         return false;
251     }
252     if (!UnwrapKVObjectFromJS(env, param, "data", asyncCallbackInfo)) {
253         return false;
254     }
255 
256     UnwrapNameFromJS(env, param, "jsonPath", asyncCallbackInfo);
257     return true;
258 }
259 
UnwrapParamForRequest(napi_env env, size_t argc, napi_value* argv, ACEAsyncJSCallbackInfo* asyncCallbackInfo)260 bool UnwrapParamForRequest(napi_env env, size_t argc, napi_value* argv, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
261 {
262     if (argc <= 0 || argc > ACE_ARGS_TWO) {
263         return false;
264     }
265 
266     if (!UnwrapRequestParameters(env, argv[ACE_PARAM0], asyncCallbackInfo)) {
267         return false;
268     }
269 
270     if (argc == ACE_ARGS_TWO) {
271         if (!AceCreateAsyncCallback(env, argv[ACE_PARAM1], asyncCallbackInfo)) {
272             return false;
273         }
274     }
275     return true;
276 }
277 
AceRequestCompleteAsyncCallbackWork(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)278 void AceRequestCompleteAsyncCallbackWork(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
279 {
280     if (asyncCallbackInfo == nullptr) {
281         return;
282     }
283 
284     if (asyncCallbackInfo->ability != nullptr) {
285         std::shared_ptr<AAFwk::Want> pWant = asyncCallbackInfo->ability->GetWant();
286         asyncCallbackInfo->wantStage = *pWant;
287     } else {
288         int32_t pid = IPCSkeleton::GetCallingPid();
289         asyncCallbackInfo->wantStage.SetBundle("plugin" + std::to_string(pid));
290     }
291 
292     std::shared_ptr<AceJSPluginRequestParam> param = std::make_shared<AceJSPluginRequestParam>(
293         asyncCallbackInfo->jsParamList.want, asyncCallbackInfo->jsParamList.paramList.GetStringValue("name"),
294         asyncCallbackInfo->jsParamList.paramList.GetStringValue("data"),
295         asyncCallbackInfo->jsParamList.paramList.GetStringValue("jsonPath"));
296     if (param != nullptr) {
297         TAG_LOGD(AceLogTag::ACE_PLUGIN_COMPONENT, "Want = %{public}s:%{public}s",
298             asyncCallbackInfo->wantStage.GetElement().GetBundleName().c_str(),
299             asyncCallbackInfo->wantStage.GetElement().GetAbilityName().c_str());
300         bool ret = JSPluginCallbackMgr::Instance().RegisterRequestEvent(
301             env, asyncCallbackInfo->wantStage, asyncCallbackInfo->cbInfo, param);
302         if (ret) {
303             asyncCallbackInfo->cbInfo.callback = nullptr;
304         }
305     }
306 
307     PluginComponentManager::GetInstance()->Request(asyncCallbackInfo->jsParamList.want,
308         asyncCallbackInfo->jsParamList.paramList.GetStringValue("name"),
309         asyncCallbackInfo->jsParamList.paramList.GetStringValue("jsonPath"),
310         asyncCallbackInfo->jsParamList.paramList.GetStringValue("data"));
311 
312     AceFreeAsyncJSCallbackInfo(&asyncCallbackInfo);
313 }
314 
MakePluginTemplateObject(napi_env env, const PluginComponentTemplate& pluginTemplate)315 napi_value MakePluginTemplateObject(napi_env env, const PluginComponentTemplate& pluginTemplate)
316 {
317     napi_value jsPluginTemplate = AceCreateJSObject(env);
318     if (jsPluginTemplate != nullptr) {
319         napi_value jsSource = AceWrapStringToJS(env, pluginTemplate.GetSource());
320         napi_value jsAbility = AceWrapStringToJS(env, pluginTemplate.GetAbility());
321 
322         AceSetPropertyValueByPropertyName(env, jsPluginTemplate, "source", jsSource);
323         AceSetPropertyValueByPropertyName(env, jsPluginTemplate, "ability", jsAbility);
324     }
325     return jsPluginTemplate;
326 }
327 
MakeCallbackParamForRequest( napi_env env, const PluginComponentTemplate& pluginTemplate, const ACEAsyncJSCallbackInfo* asyncCallbackInfo)328 napi_value MakeCallbackParamForRequest(
329     napi_env env, const PluginComponentTemplate& pluginTemplate, const ACEAsyncJSCallbackInfo* asyncCallbackInfo)
330 {
331     napi_value jsObject = AceCreateJSObject(env);
332     if (jsObject == nullptr) {
333         return nullptr;
334     }
335     std::string dataTmp("{}");
336     std::string extraDataTmp("{}");
337     if (!asyncCallbackInfo->requestCallbackData.data.empty()) {
338         dataTmp = asyncCallbackInfo->requestCallbackData.data;
339     }
340     if (!asyncCallbackInfo->requestCallbackData.extraData.empty()) {
341         extraDataTmp = asyncCallbackInfo->requestCallbackData.extraData;
342     }
343 
344     napi_value jsPluginTemplate = MakePluginTemplateObject(env, pluginTemplate);
345     napi_value jsData = AceStringToKVObject(env, dataTmp);
346     napi_value jsExtraData = AceStringToKVObject(env, extraDataTmp);
347 
348     if (jsData != nullptr) {
349         AceSetPropertyValueByPropertyName(env, jsObject, "componentTemplate", jsPluginTemplate);
350     }
351     if (jsData != nullptr) {
352         AceSetPropertyValueByPropertyName(env, jsObject, "data", jsData);
353     }
354     if (jsExtraData != nullptr) {
355         AceSetPropertyValueByPropertyName(env, jsObject, "extraData", jsExtraData);
356     }
357     return jsObject;
358 }
359 
TransferRequestCallBackData(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)360 napi_value TransferRequestCallBackData(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
361 {
362     PluginComponentTemplate componentTemplate;
363     componentTemplate.SetSource(asyncCallbackInfo->requestCallbackData.sourceName);
364     componentTemplate.SetAbility(asyncCallbackInfo->requestCallbackData.abilityName);
365     napi_value jsResult = MakeCallbackParamForRequest(env, componentTemplate, asyncCallbackInfo);
366     return jsResult;
367 }
368 
AceRequestPromiseAsyncCallbackWork(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)369 void AceRequestPromiseAsyncCallbackWork(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
370 {
371     if (asyncCallbackInfo == nullptr) {
372         return;
373     }
374 
375     if (asyncCallbackInfo->ability != nullptr) {
376         std::shared_ptr<AAFwk::Want> pWant = asyncCallbackInfo->ability->GetWant();
377         asyncCallbackInfo->wantStage = *pWant;
378     } else {
379         int32_t pid = IPCSkeleton::GetCallingPid();
380         asyncCallbackInfo->wantStage.SetBundle("plugin" + std::to_string(pid));
381     }
382 
383     std::shared_ptr<AceJSPluginRequestParam> param = std::make_shared<AceJSPluginRequestParam>(
384         asyncCallbackInfo->jsParamList.want, asyncCallbackInfo->jsParamList.paramList.GetStringValue("name"),
385         asyncCallbackInfo->jsParamList.paramList.GetStringValue("data"),
386         asyncCallbackInfo->jsParamList.paramList.GetStringValue("jsonPath"));
387     asyncCallbackInfo->onRequestCallbackOK = false;
388 
389     if (param != nullptr) {
390         TAG_LOGD(AceLogTag::ACE_PLUGIN_COMPONENT, "Want = %{public}s:%{public}s",
391             asyncCallbackInfo->wantStage.GetElement().GetBundleName().c_str(),
392             asyncCallbackInfo->wantStage.GetElement().GetAbilityName().c_str());
393         JSPluginCallbackMgr::Instance().RegisterRequestEvent(
394             env, asyncCallbackInfo->wantStage, asyncCallbackInfo, param);
395     }
396 
397     PluginComponentManager::GetInstance()->Request(asyncCallbackInfo->jsParamList.want,
398         asyncCallbackInfo->jsParamList.paramList.GetStringValue("name"),
399         asyncCallbackInfo->jsParamList.paramList.GetStringValue("jsonPath"),
400         asyncCallbackInfo->jsParamList.paramList.GetStringValue("data"));
401 
402     if (asyncCallbackInfo->onRequestCallbackOK) {
403         asyncCallbackInfo->error_code = 0;
404         napi_resolve_deferred(env, asyncCallbackInfo->deferred, TransferRequestCallBackData(env, asyncCallbackInfo));
405         AceFreeAsyncJSCallbackInfo(&asyncCallbackInfo);
406     } else {
407         asyncCallbackInfo->error_code = NAPI_ACE_ERR_ERROR;
408         AceCompletePromiseCallbackWork(env, asyncCallbackInfo);
409     }
410 }
411 
NAPI_JSRequestWrap(napi_env env, napi_callback_info info, ACEAsyncJSCallbackInfo* asyncCallbackInfo)412 napi_value NAPI_JSRequestWrap(napi_env env, napi_callback_info info, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
413 {
414     size_t argc = ACE_ARGS_MAX_COUNT;
415     napi_value args[ACE_ARGS_MAX_COUNT] = { nullptr };
416     napi_value jsthis = 0;
417     void* data = nullptr;
418 
419     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &jsthis, &data));
420 
421     if (!UnwrapParamForRequest(env, argc, args, asyncCallbackInfo)) {
422         return nullptr;
423     }
424 
425     if (asyncCallbackInfo->cbInfo.callback != nullptr) {
426         AceRequestCompleteAsyncCallbackWork(env, asyncCallbackInfo);
427         return AceWrapVoidToJS(env);
428     } else {
429         napi_value promise = 0;
430         NAPI_CALL(env, napi_create_promise(env, &asyncCallbackInfo->deferred, &promise));
431         AceRequestPromiseAsyncCallbackWork(env, asyncCallbackInfo);
432         return promise;
433     }
434 }
435 
JSRequest(napi_env env, napi_callback_info info)436 static napi_value JSRequest(napi_env env, napi_callback_info info)
437 {
438     ACEAsyncJSCallbackInfo* asyncCallbackInfo = AceCreateAsyncJSCallbackInfo(env);
439     if (asyncCallbackInfo == nullptr) {
440         return AceWrapVoidToJS(env);
441     }
442 
443     napi_value rev = NAPI_JSRequestWrap(env, info, asyncCallbackInfo);
444     if (rev == nullptr) {
445         AceFreeAsyncJSCallbackInfo(&asyncCallbackInfo);
446         rev = AceWrapVoidToJS(env);
447     }
448     return rev;
449 }
450 
UnwrapParamForOn(napi_env env, size_t argc, napi_value* argv, ACEAsyncJSCallbackInfo* asyncCallbackInfo)451 bool UnwrapParamForOn(napi_env env, size_t argc, napi_value* argv, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
452 {
453     const size_t argcMax = ACE_ARGS_THREE;
454     if (argc > argcMax || argc < ACE_ARGS_TWO) {
455         return false;
456     }
457 
458     if (argc == ACE_ARGS_THREE) {
459         if (!UnwrapStageWantFromJS(env, argv[ACE_PARAM0], asyncCallbackInfo)) {
460             return false;
461         }
462 
463         std::string eventName = AceUnwrapStringFromJS(env, argv[ACE_PARAM1]);
464         if (eventName == "push" || eventName == "request") {
465             asyncCallbackInfo->jsParamList.paramList.PutStringValue("eventName", eventName);
466         } else {
467             return false;
468         }
469 
470         if (!AceCreateAsyncCallback(env, argv[ACE_PARAM2], asyncCallbackInfo)) {
471             return false;
472         }
473     } else {
474         std::string eventName = AceUnwrapStringFromJS(env, argv[ACE_PARAM0]);
475         if (eventName == "push" || eventName == "request") {
476             asyncCallbackInfo->jsParamList.paramList.PutStringValue("eventName", eventName);
477         } else {
478             return false;
479         }
480 
481         if (!AceCreateAsyncCallback(env, argv[ACE_PARAM1], asyncCallbackInfo)) {
482             return false;
483         }
484     }
485     return true;
486 }
487 
AceOnCompleteAsyncCallbackWork(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)488 void AceOnCompleteAsyncCallbackWork(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
489 {
490     if (asyncCallbackInfo == nullptr) {
491         return;
492     }
493 
494     std::string eventName = asyncCallbackInfo->jsParamList.paramList.GetStringValue("eventName");
495     CallBackType eventCallbackType = CallBackType::PushEvent;
496     if (eventName == "request") {
497         eventCallbackType = CallBackType::RequestEvent;
498     }
499 
500     if (asyncCallbackInfo->ability != nullptr) {
501         std::shared_ptr<AAFwk::Want> pWant = asyncCallbackInfo->ability->GetWant();
502         asyncCallbackInfo->wantStage = *pWant;
503     } else {
504         int32_t pid = IPCSkeleton::GetCallingPid();
505         asyncCallbackInfo->wantStage.SetBundle("plugin" + std::to_string(pid));
506     }
507 
508     bool ret = JSPluginCallbackMgr::Instance().RegisterOnEvent(
509         env, eventCallbackType, asyncCallbackInfo->wantStage, asyncCallbackInfo->cbInfo);
510     if (ret) {
511         asyncCallbackInfo->cbInfo.callback = nullptr;
512     }
513     AceFreeAsyncJSCallbackInfo(&asyncCallbackInfo);
514 }
515 
NAPI_JSOnWrap(napi_env env, napi_callback_info info, ACEAsyncJSCallbackInfo* asyncCallbackInfo)516 napi_value NAPI_JSOnWrap(napi_env env, napi_callback_info info, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
517 {
518     size_t argc = ACE_ARGS_MAX_COUNT;
519     napi_value args[ACE_ARGS_MAX_COUNT] = { nullptr };
520     napi_value jsthis = 0;
521     void* data = nullptr;
522 
523     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &jsthis, &data));
524 
525     if (!UnwrapParamForOn(env, argc, args, asyncCallbackInfo)) {
526         return nullptr;
527     }
528 
529     if (asyncCallbackInfo->cbInfo.callback != nullptr) {
530         AceOnCompleteAsyncCallbackWork(env, asyncCallbackInfo);
531         return AceWrapVoidToJS(env);
532     } else {
533         return nullptr;
534     }
535 }
536 
JSOn(napi_env env, napi_callback_info info)537 static napi_value JSOn(napi_env env, napi_callback_info info)
538 {
539     ACEAsyncJSCallbackInfo* asyncCallbackInfo = AceCreateAsyncJSCallbackInfo(env);
540     if (asyncCallbackInfo == nullptr) {
541         return AceWrapVoidToJS(env);
542     }
543 
544     napi_value rev = NAPI_JSOnWrap(env, info, asyncCallbackInfo);
545     if (rev == nullptr) {
546         AceFreeAsyncJSCallbackInfo(&asyncCallbackInfo);
547         rev = AceWrapVoidToJS(env);
548     }
549     return rev;
550 }
551 
UnwrapParamForOff(napi_env env, size_t argc, napi_value* argv, ACEAsyncJSCallbackInfo* asyncCallbackInfo)552 bool UnwrapParamForOff(napi_env env, size_t argc, napi_value* argv, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
553 {
554     if (argc != ACE_ARGS_TWO) {
555         return false;
556     }
557 
558     if (!UnwrapStageWantFromJS(env, argv[ACE_PARAM0], asyncCallbackInfo)) {
559         return false;
560     }
561 
562     if (!AceCreateAsyncCallback(env, argv[ACE_PARAM1], asyncCallbackInfo)) {
563         return false;
564     }
565 
566     return true;
567 }
568 
AceOffCompleteAsyncCallbackWork(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)569 void AceOffCompleteAsyncCallbackWork(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
570 {
571     if (asyncCallbackInfo == nullptr) {
572         return;
573     }
574 
575     JSPluginCallbackMgr::Instance().UnregisterCallBack(env, asyncCallbackInfo->wantStage);
576     AceFreeAsyncJSCallbackInfo(&asyncCallbackInfo);
577 }
578 
NAPI_JSOffWrap(napi_env env, napi_callback_info info, ACEAsyncJSCallbackInfo* asyncCallbackInfo)579 napi_value NAPI_JSOffWrap(napi_env env, napi_callback_info info, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
580 {
581     size_t argc = ACE_ARGS_MAX_COUNT;
582     napi_value args[ACE_ARGS_MAX_COUNT] = { nullptr };
583     napi_value jsthis = 0;
584     void* data = nullptr;
585 
586     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &jsthis, &data));
587 
588     if (!UnwrapParamForOff(env, argc, args, asyncCallbackInfo)) {
589         return nullptr;
590     }
591 
592     if (asyncCallbackInfo->cbInfo.callback != nullptr) {
593         AceOffCompleteAsyncCallbackWork(env, asyncCallbackInfo);
594         return AceWrapVoidToJS(env);
595     } else {
596         return nullptr;
597     }
598 }
599 
JSOff(napi_env env, napi_callback_info info)600 static napi_value JSOff(napi_env env, napi_callback_info info)
601 {
602     ACEAsyncJSCallbackInfo* asyncCallbackInfo = AceCreateAsyncJSCallbackInfo(env);
603     if (asyncCallbackInfo == nullptr) {
604         return AceWrapVoidToJS(env);
605     }
606 
607     napi_value rev = NAPI_JSOffWrap(env, info, asyncCallbackInfo);
608     if (rev == nullptr) {
609         AceFreeAsyncJSCallbackInfo(&asyncCallbackInfo);
610         rev = AceWrapVoidToJS(env);
611     }
612     return rev;
613 }
614 
PluginComponentEventTypeInit(napi_env env, napi_value exports)615 napi_value PluginComponentEventTypeInit(napi_env env, napi_value exports)
616 {
617     napi_value obj = nullptr;
618     napi_create_object(env, &obj);
619 
620     AceSetNamedPropertyByString(env, obj, "push", "EVENT_TYPE_PUSH");
621     AceSetNamedPropertyByString(env, obj, "request", "EVENT_TYPE_REQUEST");
622 
623     napi_property_descriptor properties[] = {
624         DECLARE_NAPI_PROPERTY("EventType", obj),
625     };
626 
627     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(properties) / sizeof(properties[0]), properties));
628     return exports;
629 }
630 
PluginComponentInit(napi_env env, napi_value exports)631 napi_value PluginComponentInit(napi_env env, napi_value exports)
632 {
633     napi_property_descriptor properties[] = {
634         DECLARE_NAPI_FUNCTION("push", JSPush),
635         DECLARE_NAPI_FUNCTION("request", JSRequest),
636         DECLARE_NAPI_FUNCTION("on", JSOn),
637         DECLARE_NAPI_FUNCTION("off", JSOff),
638     };
639 
640     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(properties) / sizeof(properties[0]), properties));
641     return exports;
642 }
643 
PluginComponentExport(napi_env env, napi_value exports)644 static napi_value PluginComponentExport(napi_env env, napi_value exports)
645 {
646     PluginComponentEventTypeInit(env, exports);
647     PluginComponentInit(env, exports);
648     return exports;
649 }
650 
651 static napi_module PlugInComonentModule = {
652     .nm_version = 1,
653     .nm_flags = 0,
654     .nm_filename = nullptr,
655     .nm_register_func = PluginComponentExport,
656     .nm_modname = "pluginComponent",
657     .nm_priv = ((void*)0),
658     .reserved = { 0 },
659 };
660 
RegisterPluginComponent()661 extern "C" __attribute__((constructor)) void RegisterPluginComponent()
662 {
663     napi_module_register(&PlugInComonentModule);
664 }
665 } // namespace OHOS::Ace::Napi
666