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 
16 #include "frameworks/bridge/js_frontend/engine/jsi/jsi_group_js_bridge.h"
17 
18 #include "base/log/event_report.h"
19 #include "frameworks/bridge/js_frontend/engine/jsi/jsi_engine.h"
20 #if defined(PREVIEW)
21 #include "frameworks/bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.h"
22 #include "adapter/preview/entrance/ace_container.h"
23 #include "core/common/ace_engine.h"
24 #endif
25 
26 namespace OHOS::Ace::Framework {
27 namespace {
28 
29 const int32_t PLUGIN_REQUEST_MIN_ARGC_NUM = 4;
30 const int32_t PLUGIN_REQUEST_ARG_RESOLVE_INDEX = 0;
31 const int32_t PLUGIN_REQUEST_ARG_REJECT_INDEX = 1;
32 const int32_t PLUGIN_REQUEST_ARG_GROUP_NAME_INDEX = 2;
33 const int32_t PLUGIN_REQUEST_ARG_FUNCTION_NAME_INDEX = 3;
34 const int32_t PLUGIN_REQUEST_ARG_APP_PARAMS_INDEX = 4;
35 
36 const int32_t PLUGIN_REQUEST_MIN_ARGC_NUM_SYNC = 2;
37 const int32_t PLUGIN_REQUEST_ARG_GROUP_NAME_INDEX_SYNC = 0;
38 const int32_t PLUGIN_REQUEST_ARG_FUNCTION_NAME_INDEX_SYNC = 1;
39 const int32_t PLUGIN_REQUEST_ARG_APP_PARAMS_INDEX_SYNC = 2;
40 
41 } // namespace
42 
InitializeGroupJsBridge(const shared_ptr<JsRuntime> & runtime)43 int32_t JsiGroupJsBridge::InitializeGroupJsBridge(const shared_ptr<JsRuntime>& runtime)
44 {
45     if (!runtime) {
46         LOGE("group module init, context is null");
47         EventReport::SendAPIChannelException(APIChannelExcepType::JS_BRIDGE_INIT_ERR);
48         return JS_CALL_FAIL;
49     }
50     runtime_ = runtime;
51 
52     if (LoadJsBridgeFunction() != JS_CALL_SUCCESS) {
53         LOGE("group module init, load bridge function failed!");
54         EventReport::SendAPIChannelException(APIChannelExcepType::JS_BRIDGE_INIT_ERR);
55         return JS_CALL_FAIL;
56     }
57 
58     eventCallBackFuncs_.clear();
59     moduleCallBackFuncs_.clear();
60     pendingCallbackId_ = 1;
61 
62     return JS_CALL_SUCCESS;
63 }
64 
LoadJsBridgeFunction()65 int32_t JsiGroupJsBridge::LoadJsBridgeFunction()
66 {
67     shared_ptr<JsValue> group = runtime_->NewObject();
68     bool succ = group->SetProperty(runtime_, "sendGroupMessage", runtime_->NewFunction(ProcessJsRequest));
69     if (!succ) {
70         LOGE("bridge function, set sendGroupMessage sending function mapping failed!");
71         EventReport::SendAPIChannelException(APIChannelExcepType::SET_FUNCTION_ERR);
72         return JS_CALL_FAIL;
73     }
74     succ = group->SetProperty(runtime_, "sendGroupMessageSync", runtime_->NewFunction(ProcessJsRequestSync));
75     if (!succ) {
76         LOGE("bridge function, set sendGroupMessageSync sending function mapping failed!");
77         EventReport::SendAPIChannelException(APIChannelExcepType::SET_FUNCTION_ERR);
78         return JS_CALL_FAIL;
79     }
80     succ = runtime_->GetGlobal()->SetProperty(runtime_, "group", group);
81     if (!succ) {
82         LOGE("bridge function, set root node failed!");
83         EventReport::SendAPIChannelException(APIChannelExcepType::SET_FUNCTION_ERR);
84         return JS_CALL_FAIL;
85     }
86     return JS_CALL_SUCCESS;
87 }
88 #if defined(PREVIEW)
ProcessJsRequest(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)89 shared_ptr<JsValue> JsiGroupJsBridge::ProcessJsRequest(const shared_ptr<JsRuntime>& runtime,
90     const shared_ptr<JsValue>& thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
91 {
92     ACE_SCOPED_TRACE("ProcessJsRequest");
93     JsiEngineInstance* instance = nullptr;
94     JsiDeclarativeEngineInstance* declarativeInstance = nullptr;
95     RefPtr<JsiGroupJsBridge> groupJsBridge;
96     auto container = AceType::DynamicCast<OHOS::Ace::Platform::AceContainer>(AceEngine::Get().GetContainer(0));
97     if (!container) {
98         LOGE("ProcessJsRequest container is null!");
99         return runtime->NewUndefined();
100     }
101     auto type = container->GetType();
102     if (type == FrontendType::JS) {
103         instance = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
104         if (instance == nullptr) {
105             LOGE("invalid args, failed to get JsiEngineInstance from the runtime");
106             return runtime->NewUndefined();
107         }
108         groupJsBridge = AceType::DynamicCast<JsiGroupJsBridge>(instance->GetDelegate()->GetGroupJsBridge());
109     } else if (type == FrontendType::DECLARATIVE_JS) {
110         declarativeInstance = static_cast<JsiDeclarativeEngineInstance*>(runtime->GetEmbedderData());
111         if (declarativeInstance == nullptr) {
112             LOGE("invalid args, failed to get JsiDeclarativeEngineInstance from the runtime");
113             return runtime->NewUndefined();
114         }
115         groupJsBridge =
116             AceType::DynamicCast<JsiGroupJsBridge>(declarativeInstance->GetDelegate()->GetGroupJsBridge());
117     } else {
118         LOGE("Frontend type not supported");
119         return runtime->NewUndefined();
120     }
121 
122     if (groupJsBridge == nullptr) {
123         LOGE("invalid args, failed to get GroupJsBridge from the JSContext");
124         return runtime->NewUndefined();
125     }
126 
127     // Should have at least 4 parameters
128     if (argv.size() < PLUGIN_REQUEST_MIN_ARGC_NUM) {
129         LOGE("invalid args number:%{public}d", argc);
130         return runtime->NewUndefined();
131     }
132     int32_t callbackId = groupJsBridge->GetPendingCallbackIdAndIncrement();
133     if (!groupJsBridge->SetModuleGroupCallbackFuncs(argv, PLUGIN_REQUEST_ARG_RESOLVE_INDEX,
134         PLUGIN_REQUEST_ARG_REJECT_INDEX, callbackId)) {
135         LOGE("set module callback function failed!");
136         return runtime->NewUndefined();
137     }
138     std::string groupName  = argv[PLUGIN_REQUEST_ARG_GROUP_NAME_INDEX]->ToString(runtime);
139     if (groupName.empty()) {
140         LOGE("invalid paras, groupName:%{private}s", groupName.c_str());
141         return runtime->NewUndefined();
142     }
143     LOGI("send message, groupName: %{private}s, callbackId: %{private}d", groupName.c_str(), callbackId);
144     std::string strFunctionName = argv[PLUGIN_REQUEST_ARG_FUNCTION_NAME_INDEX]->ToString(runtime);
145     // In the preview scenario, only the fetch interface is available. If other APIs need to be supported in the future,
146     // adaptation is required.
147     if (strFunctionName != "fetch") {
148         LOGE("unsupported function %{private}s", strFunctionName.c_str());
149         return runtime->NewUndefined();
150     }
151     OHOS::Ace::RequestData requestData;
152     ParseJsDataResult parseJsResult = groupJsBridge->ParseRequestData(argc, argv, requestData, callbackId);
153     if (parseJsResult != ParseJsDataResult::PARSE_JS_SUCCESS) {
154         ProcessParseJsError(parseJsResult, runtime, callbackId);
155         return runtime->NewNull();
156     }
157     if ((type == FrontendType::JS && !instance->CallCurlFunction(requestData, callbackId)) ||
158         (type == FrontendType::DECLARATIVE_JS && !declarativeInstance->CallCurlFunction(requestData, callbackId))) {
159         LOGE("CallPlatformFunction fail");
160         groupJsBridge->TriggerModulePluginGetErrorCallback(callbackId, PLUGIN_REQUEST_FAIL, "send message failed");
161         return runtime->NewNull();
162     }
163     return runtime->NewNull();
164 }
165 #else
166 // function callback for groupObj's function: sendGroupMessage
ProcessJsRequest(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)167 shared_ptr<JsValue> JsiGroupJsBridge::ProcessJsRequest(const shared_ptr<JsRuntime>& runtime,
168     const shared_ptr<JsValue>& thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
169 {
170     shared_ptr<JsValue> res = runtime->NewUndefined();
171     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
172     if (engine == nullptr) {
173         LOGE("send message para check, fail to get engine");
174         return res;
175     }
176     auto delegate = engine->GetFrontendDelegate();
177     if (!delegate) {
178         LOGE("send message para check, fail to get front-end delegate");
179         return res;
180     }
181 
182     auto groupJsBridge = AceType::DynamicCast<JsiGroupJsBridge>(delegate->GetGroupJsBridge());
183     if (!groupJsBridge) {
184         LOGE("send message para check, fail to get group-js-bridge");
185         return res;
186     }
187 
188     // Should have at least 4 parameters
189     if (argv.size() < PLUGIN_REQUEST_MIN_ARGC_NUM) {
190         LOGE("send message para check, invalid args number:%{public}u", (uint32_t)argv.size());
191         return res;
192     }
193 
194     std::string strGroupName(argv[PLUGIN_REQUEST_ARG_GROUP_NAME_INDEX]->ToString(runtime));
195     std::string strFunctionName(argv[PLUGIN_REQUEST_ARG_FUNCTION_NAME_INDEX]->ToString(runtime));
196     if (strGroupName.empty()) {
197         LOGE("send message para check, group or function name is null");
198         return res;
199     }
200     int32_t callbackId = groupJsBridge->GetPendingCallbackIdAndIncrement();
201     // the third and fourth parameters are resolve and reject callback function
202     if (!groupJsBridge->SetModuleGroupCallbackFuncs(argv,
203         PLUGIN_REQUEST_ARG_RESOLVE_INDEX, PLUGIN_REQUEST_ARG_REJECT_INDEX, callbackId)) {
204         LOGE("send message, set module callback function failed!");
205         return res;
206     }
207 
208     if (strGroupName.empty()) {
209         groupJsBridge->TriggerModulePluginGetErrorCallback(
210             callbackId, PLUGIN_REQUEST_FAIL, "plugin name can't be null");
211         LOGE("plugin name is null");
212         return res;
213     }
214 
215     LOGI("send message, groupName:%{private}s functionName:%{private}s callbackId:%{private}d", strGroupName.c_str(),
216         strFunctionName.c_str(), callbackId);
217 
218     std::vector<CodecData> arguments;
219     ParseJsDataResult parseJsResult =
220         groupJsBridge->ParseJsPara(runtime, argv, PLUGIN_REQUEST_ARG_APP_PARAMS_INDEX, callbackId, arguments);
221     if (parseJsResult != ParseJsDataResult::PARSE_JS_SUCCESS) {
222         ProcessParseJsError(parseJsResult, runtime, callbackId);
223         return res;
224     }
225 
226     FunctionCall functionCall(strFunctionName, arguments);
227     StandardFunctionCodec codec;
228     std::vector<uint8_t> encodeBuf;
229     if (!codec.EncodeFunctionCall(functionCall, encodeBuf)) {
230         groupJsBridge->TriggerModulePluginGetErrorCallback(
231             callbackId, PLUGIN_REQUEST_FAIL, "encode request message failed");
232         return res;
233     }
234 
235     // CallPlatformFunction
236     auto dispatcher = engine->GetJsMessageDispatcher().Upgrade();
237     if (dispatcher) {
238         dispatcher->Dispatch(strGroupName, std::move(encodeBuf), callbackId);
239     } else {
240         LOGW("Dispatcher Upgrade fail when dispatch request message to platform");
241         groupJsBridge->TriggerModulePluginGetErrorCallback(callbackId, PLUGIN_REQUEST_FAIL, "send message failed");
242     }
243     return res;
244 }
245 #endif
246 // function callback for groupObj's function: sendGroupMessageSync
ProcessJsRequestSync(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)247 shared_ptr<JsValue> JsiGroupJsBridge::ProcessJsRequestSync(const shared_ptr<JsRuntime>& runtime,
248     const shared_ptr<JsValue>& thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
249 {
250     shared_ptr<JsValue> res = runtime->NewUndefined();
251     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
252     if (engine == nullptr) {
253         LOGE("send message para check, fail to get engine");
254         return res;
255     }
256     auto delegate = engine->GetFrontendDelegate();
257     if (!delegate) {
258         LOGE("send message para check, fail to get front-end delegate");
259         return res;
260     }
261 
262     auto groupJsBridge = AceType::DynamicCast<JsiGroupJsBridge>(delegate->GetGroupJsBridge());
263     if (!groupJsBridge) {
264         LOGE("send message para check, fail to get group-js-bridge");
265         return res;
266     }
267 
268     // Should have at least 2 parameters
269     if (argv.size() < PLUGIN_REQUEST_MIN_ARGC_NUM_SYNC) {
270         LOGE("send message para check, invalid args number:%{public}u", (uint32_t)argv.size());
271         return res;
272     }
273 
274     std::string strGroupName(argv[PLUGIN_REQUEST_ARG_GROUP_NAME_INDEX_SYNC]->ToString(runtime));
275     std::string strFunctionName(argv[PLUGIN_REQUEST_ARG_FUNCTION_NAME_INDEX_SYNC]->ToString(runtime));
276     if (strGroupName.empty()) {
277         LOGE("send message para check, group or function name is null");
278         return res;
279     }
280 
281     if (strGroupName.empty()) {
282         LOGE("plugin name is null");
283         return res;
284     }
285 
286     LOGI("send message, groupName:%{private}s functionName:%{private}s", strGroupName.c_str(), strFunctionName.c_str());
287 
288     std::vector<CodecData> arguments;
289     ParseJsDataResult parseJsResult =
290         groupJsBridge->ParseJsPara(runtime, argv, PLUGIN_REQUEST_ARG_APP_PARAMS_INDEX_SYNC, 0, arguments);
291     if (parseJsResult != ParseJsDataResult::PARSE_JS_SUCCESS) {
292         LOGE("encode arguments fail");
293         return res;
294     }
295 
296     FunctionCall functionCall(strFunctionName, arguments);
297     StandardFunctionCodec codec;
298     std::vector<uint8_t> encodeBuf;
299     if (!codec.EncodeFunctionCall(functionCall, encodeBuf)) {
300         LOGE("encode request message failed");
301         return res;
302     }
303 
304     // CallPlatformFunction
305     auto dispatcher = engine->GetJsMessageDispatcher().Upgrade();
306 
307     uint8_t* resData = nullptr;
308     int64_t position = 0;
309     if (dispatcher) {
310         dispatcher->DispatchSync(strGroupName, std::move(encodeBuf), &resData, position);
311     } else {
312         LOGW("Dispatcher Upgrade fail when dispatch request message to platform");
313         return res;
314     }
315     std::vector<uint8_t> messageData = std::vector<uint8_t>(resData, resData + position);
316 
317     shared_ptr<JsValue> callBackResult;
318     CodecData codecResult;
319     if (codec.DecodePlatformMessage(messageData, codecResult)) {
320         std::string resultString = codecResult.GetStringValue();
321         LOGI("sync resultString = %{private}s", resultString.c_str());
322         if (resultString.empty()) {
323             callBackResult = runtime->NewNull();
324         } else {
325             callBackResult = runtime->NewString(resultString);
326         }
327     }
328     return callBackResult;
329 }
330 
SetEventGroupCallBackFuncs(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & localEventCallbackFunc,int32_t callbackId,int32_t requestId)331 bool JsiGroupJsBridge::SetEventGroupCallBackFuncs(const shared_ptr<JsRuntime>& runtime,
332     const shared_ptr<JsValue>& localEventCallbackFunc, int32_t callbackId, int32_t requestId)
333 {
334     if (localEventCallbackFunc->IsNull(runtime) || !localEventCallbackFunc->IsFunction(runtime)) {
335         LOGE("callback function is invalid!");
336         return false;
337     }
338 
339     LOGI("record event callback, requestId:%{private}d, callbackId:%{private}d", requestId, callbackId);
340     auto result = eventCallBackFuncs_.try_emplace(callbackId, localEventCallbackFunc);
341     if (!result.second) {
342         result.first->second = localEventCallbackFunc;
343     }
344     AddRequestIdCallbackIdRelation(callbackId, requestId);
345     return true;
346 }
347 
RemoveEventGroupCallBackFuncs(int32_t callbackId)348 void JsiGroupJsBridge::RemoveEventGroupCallBackFuncs(int32_t callbackId)
349 {
350     LOGI("remove event callback, callbackId:%{private}d", callbackId);
351     auto itFunc = eventCallBackFuncs_.find(callbackId);
352     if (itFunc != eventCallBackFuncs_.end()) {
353         eventCallBackFuncs_.erase(callbackId);
354     }
355 }
356 
AddRequestIdCallbackIdRelation(int32_t eventId,int32_t requestId)357 void JsiGroupJsBridge::AddRequestIdCallbackIdRelation(int32_t eventId, int32_t requestId)
358 {
359     auto result = requestIdCallbackIdMap_.try_emplace(requestId, eventId);
360     if (!result.second) {
361         result.first->second = eventId;
362     }
363 }
364 
RemoveRequestIdCallbackIdRelation(int32_t requestId,bool removeEventCallback)365 void JsiGroupJsBridge::RemoveRequestIdCallbackIdRelation(int32_t requestId, bool removeEventCallback)
366 {
367     auto eventId = requestIdCallbackIdMap_.find(requestId);
368     if (eventId != requestIdCallbackIdMap_.end()) {
369         if (removeEventCallback) {
370             RemoveEventGroupCallBackFuncs(eventId->second);
371         }
372         requestIdCallbackIdMap_.erase(requestId);
373     }
374 }
375 
ProcessParseJsError(ParseJsDataResult errorType,const shared_ptr<JsRuntime> & runtime,int32_t callbackId)376 void JsiGroupJsBridge::ProcessParseJsError(
377     ParseJsDataResult errorType, const shared_ptr<JsRuntime>& runtime, int32_t callbackId)
378 {
379     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
380     if (engine == nullptr) {
381         LOGE("Process parse js error check, fail to get engine");
382         return;
383     }
384     // PluginErrorCallback
385     auto dispatcher = engine->GetJsMessageDispatcher().Upgrade();
386     if (!dispatcher) {
387         LOGW("Dispatcher Upgrade fail at ProcessParseJsError");
388         return;
389     }
390     std::string errMessage;
391     switch (errorType) {
392         case ParseJsDataResult::PARSE_JS_ERR_UNSUPPORTED_TYPE:
393             errMessage = "unsupported js parameter types";
394             dispatcher->DispatchPluginError(callbackId,
395                 static_cast<int32_t>(ParseJsDataResult::PARSE_JS_ERR_UNSUPPORTED_TYPE), std::move(errMessage));
396             break;
397         case ParseJsDataResult::PARSE_JS_ERR_TOO_MANY_PARAM:
398             errMessage = "the number of parameters exceeds 255";
399             dispatcher->DispatchPluginError(callbackId,
400                 static_cast<int32_t>(ParseJsDataResult::PARSE_JS_ERR_TOO_MANY_PARAM), std::move(errMessage));
401             break;
402         default:
403             break;
404     }
405 }
406 
SetModuleGroupCallbackFuncs(const std::vector<shared_ptr<JsValue>> & argv,int32_t resolveCallbackIndex,int32_t rejectCallbackIndex,int32_t callbackId)407 bool JsiGroupJsBridge::SetModuleGroupCallbackFuncs(const std::vector<shared_ptr<JsValue>>& argv,
408     int32_t resolveCallbackIndex, int32_t rejectCallbackIndex, int32_t callbackId)
409 {
410     if (argv[resolveCallbackIndex]->IsNull(runtime_) || !argv[resolveCallbackIndex]->IsFunction(runtime_) ||
411         argv[rejectCallbackIndex]->IsNull(runtime_) || !argv[rejectCallbackIndex]->IsFunction(runtime_)) {
412         LOGE("resolve or reject callback function is invalid");
413         return false;
414     }
415 
416     PromiseCallback promiseCallJsFunc;
417 
418     promiseCallJsFunc.resolveCallback = argv[resolveCallbackIndex];
419     promiseCallJsFunc.rejectCallback = argv[rejectCallbackIndex];
420 
421     auto result = moduleCallBackFuncs_.try_emplace(callbackId, promiseCallJsFunc);
422     if (!result.second) {
423         LOGE("module callback function has been existed!");
424         return false;
425     }
426     return true;
427 }
428 
SerializationObjectToString(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & val)429 std::string JsiGroupJsBridge::SerializationObjectToString(
430     const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& val)
431 {
432     shared_ptr<JsValue> global = runtime->GetGlobal();
433     if (!global->IsObject(runtime)) {
434         LOGE("SerializationObjectToString error: fail to get Global Object");
435         return "";
436     }
437     shared_ptr<JsValue> json = global->GetProperty(runtime, "JSON");
438     if (!json->IsObject(runtime)) {
439         LOGE("SerializationObjectToString error: global has no attribute JsON");
440         return "";
441     }
442     shared_ptr<JsValue> jsFunc = json->GetProperty(runtime, "stringify");
443     if (!jsFunc->IsFunction(runtime)) {
444         LOGE("SerializationObjectToString error: JSON has no attribute stringify");
445         return "";
446     }
447     shared_ptr<JsValue> strValue = jsFunc->Call(runtime, runtime->NewUndefined(), { val }, 1);
448     if (strValue->IsUndefined(runtime)) {
449         LOGE("SerializationObjectToString error: js call error.");
450         return "";
451     }
452     return strValue->ToString(runtime);
453 }
454 
ParseJsPara(const shared_ptr<JsRuntime> & runtime,const std::vector<shared_ptr<JsValue>> & argv,int32_t beginIndex,int32_t requestId,std::vector<CodecData> & arguments)455 ParseJsDataResult JsiGroupJsBridge::ParseJsPara(const shared_ptr<JsRuntime>& runtime,
456     const std::vector<shared_ptr<JsValue>>& argv, int32_t beginIndex, int32_t requestId,
457     std::vector<CodecData>& arguments)
458 {
459     int32_t argc = (int32_t)argv.size();
460     if (argc < beginIndex) { // no others params
461         return ParseJsDataResult::PARSE_JS_SUCCESS;
462     }
463     for (int32_t i = beginIndex; i < argc; i++) {
464         shared_ptr<JsValue> val = argv[i];
465         if (val->IsString(runtime)) {
466             CodecData arg(val->ToString(runtime));
467             arguments.push_back(arg);
468         } else if (val->IsNumber(runtime)) {
469             if (val->WithinInt32(runtime)) {
470                 int32_t valInt = val->ToInt32(runtime);
471                 CodecData arg(valInt);
472                 arguments.push_back(arg);
473             } else {
474                 double valDouble = val->ToDouble(runtime);
475                 CodecData arg(valDouble);
476                 arguments.push_back(arg);
477             }
478         } else if (val->IsBoolean(runtime)) {
479             bool valBool = val->ToBoolean(runtime);
480             CodecData arg(valBool);
481             arguments.push_back(arg);
482         } else if (val->IsNull(runtime)) {
483             CodecData argNull;
484             arguments.push_back(argNull);
485         } else if (val->IsFunction(runtime)) {
486             int32_t functionId = GetPendingCallbackIdAndIncrement();
487             CodecData arg(functionId, BufferDataType::TYPE_FUNCTION);
488             arguments.push_back(arg);
489             SetEventGroupCallBackFuncs(runtime, val, functionId, requestId);
490         } else if (val->IsArray(runtime) || val->IsObject(runtime)) {
491             std::string objStr = SerializationObjectToString(runtime, val);
492             CodecData arg(objStr);
493             arguments.push_back(arg);
494         } else if (val->IsUndefined(runtime)) {
495         } else {
496             LOGE("Process callNative para type: unsupported type");
497             return ParseJsDataResult::PARSE_JS_ERR_UNSUPPORTED_TYPE;
498         }
499     }
500     return ParseJsDataResult::PARSE_JS_SUCCESS;
501 }
502 
TriggerModuleJsCallback(int32_t callbackId,int32_t code,std::vector<uint8_t> && messageData)503 void JsiGroupJsBridge::TriggerModuleJsCallback(int32_t callbackId, int32_t code, std::vector<uint8_t>&& messageData)
504 {
505     shared_ptr<JsValue> callBackResult;
506     CodecData codecResult;
507     StandardFunctionCodec codec;
508     if (codec.DecodePlatformMessage(messageData, codecResult)) {
509         std::string resultString = codecResult.GetStringValue();
510         if (resultString.empty()) {
511             callBackResult = runtime_->NewNull();
512         } else {
513             callBackResult = runtime_->NewString(resultString);
514         }
515     } else {
516         LOGE("trigger JS resolve callback function error, decode message fail, callbackId:%{private}d", callbackId);
517         callBackResult = runtime_->NewString("invalid response data");
518     }
519     CallModuleJsCallback(callbackId, code, callBackResult);
520 
521     messageData.clear();
522 }
523 
CallModuleJsCallback(int32_t callbackId,int32_t code,const shared_ptr<JsValue> & callBackResult)524 void JsiGroupJsBridge::CallModuleJsCallback(int32_t callbackId, int32_t code, const shared_ptr<JsValue>& callBackResult)
525 {
526     RemoveRequestIdCallbackIdRelation(callbackId, code != PLUGIN_REQUEST_SUCCESS);
527 
528     shared_ptr<JsValue> global = runtime_->GetGlobal();
529 
530     auto itFunc = moduleCallBackFuncs_.find(callbackId);
531     if (itFunc != moduleCallBackFuncs_.end()) {
532         shared_ptr<JsValue> jsFunc =
533             (code == PLUGIN_REQUEST_SUCCESS ? itFunc->second.resolveCallback : itFunc->second.rejectCallback);
534         if (jsFunc->IsNull(runtime_) || !jsFunc->IsFunction(runtime_)) {
535             LOGE("trigger JS result function error, it is not a function, callbackId:%{private}d", callbackId);
536             return;
537         }
538         std::vector<shared_ptr<JsValue>> argv = { callBackResult };
539 
540         // Pass only 1 parameter, call promise resolve call back.
541         jsFunc->Call(runtime_, global, argv, 1);
542         itFunc->second.rejectCallback = runtime_->NewUndefined();
543         itFunc->second.resolveCallback = runtime_->NewUndefined();
544         moduleCallBackFuncs_.erase(itFunc);
545     } else {
546         LOGE("trigger JS result function is not exists, callbackId:%{private}d, code:%{private}d", callbackId, code);
547     }
548 }
549 
TriggerModulePluginGetErrorCallback(int32_t callbackId,int32_t errorCode,std::string && errorMessage)550 void JsiGroupJsBridge::TriggerModulePluginGetErrorCallback(
551     int32_t callbackId, int32_t errorCode, std::string&& errorMessage)
552 {
553     RemoveRequestIdCallbackIdRelation(callbackId, true);
554     shared_ptr<JsValue> global = runtime_->GetGlobal();
555 
556     CodecData codecResult;
557     auto itFunc = moduleCallBackFuncs_.find(callbackId);
558     if (itFunc != moduleCallBackFuncs_.end()) {
559         shared_ptr<JsValue> jsFunc = itFunc->second.rejectCallback;
560         if (jsFunc->IsNull(runtime_) || !jsFunc->IsFunction(runtime_)) {
561             LOGE("trigger Js reject callback function error, reject is not a function, callbackId:%{private}d",
562                 callbackId);
563             return;
564         }
565         auto resultJson = JsonUtil::Create(true);
566         resultJson->Put(std::string("code").c_str(), errorCode);
567         resultJson->Put(std::string("data").c_str(), errorMessage.c_str());
568         shared_ptr<JsValue> emptyReplyCallback = runtime_-> NewString(resultJson->ToString().c_str());
569         std::vector<shared_ptr<JsValue>> argv;
570         argv.push_back(emptyReplyCallback);
571         int32_t len = 1;
572         // Pass only 1 parameter, call promise reject call back for error get in plugin.
573         shared_ptr<JsValue> res = jsFunc->Call(runtime_, global, argv, len);
574         if (!res || res->IsUndefined(runtime_)) {
575             LOGW("trigger Js reject callback function fail, callbackId:%{private}d", callbackId);
576         } else {
577             LOGI("trigger Js reject callback function success, callbackId:%{private}d", callbackId);
578         }
579         moduleCallBackFuncs_.erase(itFunc);
580     } else {
581         LOGE("trigger Js reject callback function is not exists, callbackId:%{private}d", callbackId);
582     }
583 }
584 
CallEventJsCallback(int32_t callbackId,std::vector<uint8_t> && eventData)585 void JsiGroupJsBridge::CallEventJsCallback(int32_t callbackId, std::vector<uint8_t>&& eventData)
586 {
587     shared_ptr<JsValue> global = runtime_->GetGlobal();
588 
589     shared_ptr<JsValue> callBackEvent;
590     CodecData codecEvent;
591     StandardFunctionCodec codec;
592     if (codec.DecodePlatformMessage(eventData, codecEvent)) {
593         std::string eventString = codecEvent.GetStringValue();
594         if (eventString.empty()) {
595             callBackEvent = runtime_->NewNull();
596         } else {
597             callBackEvent = runtime_->NewString(eventString);
598         }
599     } else {
600         LOGE("trigger Js callback function error, decode message fail, callbackId:%{private}d", callbackId);
601         return;
602     }
603 
604     auto itFunc = eventCallBackFuncs_.find(callbackId);
605     if (itFunc != eventCallBackFuncs_.end()) {
606         shared_ptr<JsValue> jsFunc = itFunc->second;
607         if (!jsFunc->IsFunction(runtime_) || jsFunc->IsNull(runtime_)) {
608             LOGE("trigger Js callback function error, callback is not a function, callbackId:%{private}d", callbackId);
609             return;
610         }
611 
612         // Pass only 1 parameter
613         int32_t len = 1;
614         std::vector<shared_ptr<JsValue>> argv = { callBackEvent };
615         jsFunc->Call(runtime_, global, argv, len);
616     } else {
617         LOGE("trigger Js callback function error, it is not exists, callbackId:%{private}d", callbackId);
618     }
619     eventData.clear();
620 }
621 
TriggerEventJsCallback(int32_t callbackId,int32_t code,std::vector<uint8_t> && eventData)622 void JsiGroupJsBridge::TriggerEventJsCallback(int32_t callbackId, int32_t code, std::vector<uint8_t>&& eventData)
623 {
624     if (code == PLUGIN_CALLBACK_DESTROY) {
625         RemoveEventGroupCallBackFuncs(callbackId);
626     } else {
627         CallEventJsCallback(callbackId, std::move(eventData));
628     }
629 }
630 
LoadPluginJsCode(std::string && jsCode)631 void JsiGroupJsBridge::LoadPluginJsCode(std::string&& jsCode)
632 {
633     LOGE("Do not support load JsCode in ark vm.");
634 }
635 
LoadPluginJsByteCode(std::vector<uint8_t> && jsCode,std::vector<int32_t> && jsCodeLen)636 void JsiGroupJsBridge::LoadPluginJsByteCode(std::vector<uint8_t>&& jsCode, std::vector<int32_t>&& jsCodeLen)
637 {
638     if (!runtime_) {
639         return;
640     }
641 
642     int32_t countLen = 0;
643     for (auto len : jsCodeLen) {
644         runtime_->EvaluateJsCode(jsCode.data() + countLen, len);
645         countLen += len;
646     }
647 }
648 
Destroy()649 void JsiGroupJsBridge::Destroy()
650 {
651     eventCallBackFuncs_.clear();
652     moduleCallBackFuncs_.clear();
653     runtime_.reset();
654 }
655 #if defined(PREVIEW)
TriggerModuleJsCallbackPreview(int32_t callbackId,int32_t code,ResponseData responseData)656 void JsiGroupJsBridge::TriggerModuleJsCallbackPreview(int32_t callbackId, int32_t code, ResponseData responseData)
657 {
658     shared_ptr<JsValue> callBackResult = runtime_->NewNull();
659     std::string resultString = responseData.GetResultString()->ToString();
660     code = responseData.GetActionCode();
661     if (!resultString.empty()) {
662         callBackResult = runtime_->NewString(resultString);
663     } else {
664         code = PLUGIN_REQUEST_FAIL;
665         callBackResult = runtime_->NewString(std::string("{\"code\":").append(std::to_string(code)).append(",")
666             .append("\"data\":\"invalid response data\"}"));
667     }
668     CallModuleJsCallback(callbackId, code, callBackResult);
669 }
670 
671 const LinearMapNode<void (*)(const char*, OHOS::Ace::RequestData&)> JsiGroupJsBridge::fetchRequestDataMap1[] = {
672     { "data",
__anon98b0c65b0202() 673         [](const char* valStr, OHOS::Ace::RequestData& requestData) { requestData.SetData(valStr); } },
674     { "method",
__anon98b0c65b0302() 675         [](const char* valStr, OHOS::Ace::RequestData& requestData) { requestData.SetMethod(valStr); } },
676     { "responseType", [](const char* valStr,
__anon98b0c65b0402() 677                             OHOS::Ace::RequestData& requestData) { requestData.SetResponseType(valStr); } },
__anon98b0c65b0502() 678     { "url", [](const char* valStr, OHOS::Ace::RequestData& requestData) { requestData.SetUrl(valStr); } },
679 };
680 
681 const LinearMapNode<void (*)(shared_ptr<JsRuntime>, const shared_ptr<JsValue>&, RequestData&)>
682     JsiGroupJsBridge::fetchRequestDataMap2[] = {
683         { "data",
684             [](shared_ptr<JsRuntime> runtime,
__anon98b0c65b0602() 685                 const shared_ptr<JsValue>& val, OHOS::Ace::RequestData& requestData) {
686                 std::string objStr = SerializationObjectToString(runtime, val);
687                 if (objStr.empty()) {
688                     return;
689                 }
690                 requestData.SetData(objStr.c_str());
691             } },
692         { "header",
693             [](shared_ptr<JsRuntime> runtime,
__anon98b0c65b0702() 694                 const shared_ptr<JsValue>& val, OHOS::Ace::RequestData& requestData) {
695                 if (!val->IsObject(runtime)) {
696                     return;
697                 }
698                 int32_t length = 0;
699                 shared_ptr<JsValue> propertyNames;
700                 if (val->GetEnumerablePropertyNames(runtime, propertyNames, length)) {
701                     std::map<std::string, std::string> header;
702                     for (int32_t i = 0; i < length; ++i) {
703                         shared_ptr<JsValue> key = propertyNames->GetElement(runtime, i);
704                         if (key->IsString(runtime)) {
705                             shared_ptr<JsValue> item = val->GetProperty(runtime, key);
706                             if (item->IsString(runtime)) {
707                                 header[key->ToString(runtime)] = item->ToString(runtime);
708                             }
709                         } else {
710                             LOGW("key is null. Ignoring!");
711                         }
712                     }
713                     requestData.SetHeader(header);
714                 }
715             } },
716     };
717 
GetRequestData(const shared_ptr<JsValue> & valObject,RequestData & requestData)718 void JsiGroupJsBridge::GetRequestData(const shared_ptr<JsValue>& valObject, RequestData& requestData)
719 {
720     if (!valObject->IsObject(runtime_)) {
721         return;
722     }
723     int32_t len = 0;
724     shared_ptr<JsValue> propertyNames;
725     valObject->GetEnumerablePropertyNames(runtime_, propertyNames, len);
726     for (int32_t i = 0; i < len; ++i) {
727         shared_ptr<JsValue> key = propertyNames->GetElement(runtime_, i);
728         shared_ptr<JsValue> item = valObject->GetProperty(runtime_, key);
729         if (item->IsString(runtime_)) {
730             auto iter = BinarySearchFindIndex(
731                 fetchRequestDataMap1, ArraySize(fetchRequestDataMap1), key->ToString(runtime_).c_str());
732             if (iter != -1) {
733                 fetchRequestDataMap1[iter].value(item->ToString(runtime_).c_str(), requestData);
734             }
735         } else if (item->IsObject(runtime_)) {
736             auto iter = BinarySearchFindIndex(
737                 fetchRequestDataMap2, ArraySize(fetchRequestDataMap2), key->ToString(runtime_).c_str());
738             if (iter != -1) {
739                 fetchRequestDataMap2[iter].value(runtime_, item, requestData);
740             }
741         }
742     }
743 }
744 
ParseRequestData(int32_t argc,const std::vector<shared_ptr<JsValue>> & argv,OHOS::Ace::RequestData & requestData,int32_t requestId)745 ParseJsDataResult JsiGroupJsBridge::ParseRequestData(
746     int32_t argc, const std::vector<shared_ptr<JsValue>>& argv, OHOS::Ace::RequestData& requestData, int32_t requestId)
747 {
748     if (argc < PLUGIN_REQUEST_ARG_APP_PARAMS_INDEX) {
749         return ParseJsDataResult::PARSE_JS_SUCCESS;
750     }
751     for (int32_t i = PLUGIN_REQUEST_ARG_APP_PARAMS_INDEX; i < argc; i++) {
752         const shared_ptr<JsValue> val = argv[i];
753         if (val->IsObject(runtime_)) {
754             std::string objStr = SerializationObjectToString(runtime_, val);
755             if (objStr.empty()) {
756                 LOGW("Process callNative para is null");
757                 return ParseJsDataResult::PARSE_JS_ERR_UNSUPPORTED_TYPE;
758             }
759             GetRequestData(val, requestData);
760         } else if (val->IsUndefined(runtime_)) {
761         } else {
762             LOGE("Process callNative para type: unsupported type");
763             return ParseJsDataResult::PARSE_JS_ERR_UNSUPPORTED_TYPE;
764         }
765     }
766     return ParseJsDataResult::PARSE_JS_SUCCESS;
767 }
768 #endif
769 
770 } // namespace OHOS::Ace::Framework
771