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