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