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