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