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