• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "frameworks/bridge/js_frontend/engine/v8/v8_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 "core/common/ace_page.h"
23 #include "core/common/js_message_dispatcher.h"
24 #include "frameworks/bridge/codec/function_call.h"
25 #include "frameworks/bridge/js_frontend/engine/common/js_constants.h"
26 #include "frameworks/bridge/js_frontend/engine/v8/v8_engine.h"
27 #include "frameworks/bridge/js_frontend/engine/v8/v8_utils.h"
28 
29 namespace OHOS::Ace::Framework {
30 namespace {
31 
32 const int32_t PLUGIN_REQUEST_MIN_ARGC_NUM = 4;
33 const int32_t PLUGIN_REQUEST_ARG_RESOLVE_INDEX = 0;
34 const int32_t PLUGIN_REQUEST_ARG_REJECT_INDEX = 1;
35 const int32_t PLUGIN_REQUEST_ARG_GROUP_NAME_INDEX = 2;
36 const int32_t PLUGIN_REQUEST_ARG_FUNCTION_NAME_INDEX = 3;
37 const int32_t PLUGIN_REQUEST_ARG_APP_PARAMS_INDEX = 4;
38 
39 const int32_t PLUGIN_REQUEST_MIN_ARGC_NUM_SYNC = 2;
40 const int32_t PLUGIN_REQUEST_ARG_GROUP_NAME_INDEX_SYNC = 0;
41 const int32_t PLUGIN_REQUEST_ARG_FUNCTION_NAME_INDEX_SYNC = 1;
42 const int32_t PLUGIN_REQUEST_ARG_APP_PARAMS_INDEX_SYNC = 2;
43 
44 } // namespace
45 
V8GroupJsBridge(int32_t instanceId)46 V8GroupJsBridge::V8GroupJsBridge(int32_t instanceId) : instanceId_(instanceId) {}
47 
InitializeGroupJsBridge(v8::Local<v8::Context> context)48 int32_t V8GroupJsBridge::InitializeGroupJsBridge(v8::Local<v8::Context> context)
49 {
50     LOGI("Enter InitializeGroupJsBridge");
51     if (context.IsEmpty()) {
52         LOGE("group module init, context is null");
53         EventReport::SendAPIChannelException(APIChannelExcepType::JS_BRIDGE_INIT_ERR);
54         return JS_CALL_FAIL;
55     }
56 
57     v8::Isolate* isolate = context->GetIsolate();
58     ACE_DCHECK(isolate);
59     v8::HandleScope handleScope(isolate);
60 
61     isolate_ = isolate;
62     context_.Reset(isolate_, context);
63 
64     if (LoadJsBridgeFunction() != JS_CALL_SUCCESS) {
65         LOGE("group module init, load bridge function failed!");
66         EventReport::SendAPIChannelException(APIChannelExcepType::JS_BRIDGE_INIT_ERR);
67         return JS_CALL_FAIL;
68     }
69 
70     eventCallBackFuncs_.clear();
71     moduleCallBackFuncs_.clear();
72     pendingCallbackId_ = 1;
73     return JS_CALL_SUCCESS;
74 }
75 
LoadJsBridgeFunction()76 int32_t V8GroupJsBridge::LoadJsBridgeFunction()
77 {
78     v8::HandleScope handleScope(isolate_);
79     v8::Local<v8::Context> context = context_.Get(isolate_);
80     v8::Local<v8::Object> global = context->Global();
81     v8::Local<v8::Object> group = v8::Object::New(isolate_);
82 
83     bool succ = group->Set(context, v8::String::NewFromUtf8(isolate_, "sendGroupMessage").ToLocalChecked(),
84         v8::Function::New(context, ProcessJsRequest).ToLocalChecked()).ToChecked();
85     if (!succ) {
86         LOGE("bridge function, set group message sending function mapping failed!");
87         EventReport::SendAPIChannelException(APIChannelExcepType::SET_FUNCTION_ERR);
88         return JS_CALL_FAIL;
89     }
90 
91     succ = group->Set(context, v8::String::NewFromUtf8(isolate_, "sendGroupMessageSync").ToLocalChecked(),
92         v8::Function::New(context, ProcessJsRequestSync).ToLocalChecked()).ToChecked();
93     if (!succ) {
94         LOGE("bridge function, set sync group message sending function mapping failed!");
95         EventReport::SendAPIChannelException(APIChannelExcepType::SET_FUNCTION_ERR);
96         return JS_CALL_FAIL;
97     }
98 
99     succ = global->Set(context, v8::String::NewFromUtf8(isolate_, "group").ToLocalChecked(), group).ToChecked();
100     if (!succ) {
101         LOGE("bridge function, set root node failed!");
102         EventReport::SendAPIChannelException(APIChannelExcepType::SET_FUNCTION_ERR);
103         return JS_CALL_FAIL;
104     }
105 
106     context_.Reset(isolate_, context);
107 
108     return JS_CALL_SUCCESS;
109 }
110 
CallEvalBuf(v8::Isolate * isolate,v8::Local<v8::String> src)111 int32_t V8GroupJsBridge::CallEvalBuf(v8::Isolate* isolate, v8::Local<v8::String> src)
112 {
113     if (isolate == nullptr) {
114         LOGE("isolate can't be null!");
115         return JS_CALL_FAIL;
116     }
117 
118     v8::HandleScope handleScope(isolate);
119     v8::TryCatch tryCatch(isolate);
120     v8::Local<v8::Context> context = isolate->GetCurrentContext();
121 
122     v8::Local<v8::Script> script;
123     if (!v8::Script::Compile(context, src).ToLocal(&script)) {
124         LOGE("compile js code failed!");
125         V8Utils::JsStdDumpErrorAce(isolate, &tryCatch, JsErrorType::COMPILE_ERROR, instanceId_);
126         return JS_CALL_FAIL;
127     }
128 
129     v8::Local<v8::Value> res;
130     if (!script->Run(context).ToLocal(&res)) {
131         LOGE("run js code failed!");
132         V8Utils::JsStdDumpErrorAce(isolate, &tryCatch, JsErrorType::RUNTIME_ERROR, instanceId_);
133         return JS_CALL_FAIL;
134     }
135     return JS_CALL_SUCCESS;
136 }
137 
138 // function callback for groupObj's function: sendGroupMessage
ProcessJsRequest(const v8::FunctionCallbackInfo<v8::Value> & args)139 void V8GroupJsBridge::ProcessJsRequest(const v8::FunctionCallbackInfo<v8::Value>& args)
140 {
141     v8::Isolate* isolate = args.GetIsolate();
142     ACE_DCHECK(isolate);
143     v8::HandleScope handleScope(isolate);
144 
145     auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
146     if (delegate == nullptr) {
147         LOGE("send message para check, fail to get front-end delegate");
148         return;
149     }
150 
151     auto groupJsBridge = AceType::DynamicCast<V8GroupJsBridge>((*delegate)->GetGroupJsBridge());
152     if (groupJsBridge == nullptr) {
153         LOGE("send message para check, fail to get group-js-bridge");
154         return;
155     }
156 
157     // Should have at least 4 parameters
158     if (args.Length() < PLUGIN_REQUEST_MIN_ARGC_NUM) {
159         LOGE("send message para check, invalid args number:%{public}d", args.Length());
160         return;
161     }
162 
163     int32_t callbackId = groupJsBridge->GetPendingCallbackIdAndIncrement();
164     if (!groupJsBridge->SetModuleGroupCallbackFuncs(args, PLUGIN_REQUEST_ARG_RESOLVE_INDEX,
165         PLUGIN_REQUEST_ARG_REJECT_INDEX, callbackId)) {
166         LOGE("send message, set module callback function failed!");
167         return;
168     }
169 
170     v8::String::Utf8Value jsGroupName(isolate, args[PLUGIN_REQUEST_ARG_GROUP_NAME_INDEX]);
171     const char* groupName  = *jsGroupName;
172     if (groupName == nullptr) {
173         groupJsBridge->TriggerModulePluginGetErrorCallback(callbackId, PLUGIN_REQUEST_FAIL,
174             "plugin name can't be null");
175         LOGE("plugin name is null");
176         return;
177     }
178 
179     LOGI("send message, groupName: %{private}s, callbackId: %{private}d", groupName, callbackId);
180     std::string strGroupName(groupName);
181 
182     v8::String::Utf8Value jsFunctionName(isolate, args[PLUGIN_REQUEST_ARG_FUNCTION_NAME_INDEX]);
183     const char* functionName = *jsFunctionName;
184     std::string strFunctionName(functionName);
185 
186     std::vector<CodecData> arguments;
187     ParseJsDataResult parseJsResult = groupJsBridge->ParseJsPara(args, PLUGIN_REQUEST_ARG_APP_PARAMS_INDEX,
188         callbackId, arguments);
189     if (parseJsResult != ParseJsDataResult::PARSE_JS_SUCCESS) {
190         ProcessParseJsError(parseJsResult, isolate, callbackId);
191         return;
192     }
193 
194     FunctionCall functionCall(strFunctionName, arguments);
195     StandardFunctionCodec codec;
196     std::vector<uint8_t> encodeBuf;
197     if (!codec.EncodeFunctionCall(functionCall, encodeBuf)) {
198         groupJsBridge->TriggerModulePluginGetErrorCallback(callbackId, PLUGIN_REQUEST_FAIL,
199             "encode request message failed");
200         return;
201     }
202 
203     // CallPlatformFunction
204     auto dispatcher = static_cast<WeakPtr<JsMessageDispatcher>*>(isolate->GetData(V8EngineInstance::DISPATCHER));
205     auto dispatcherUpgrade = (*dispatcher).Upgrade();
206     if (dispatcherUpgrade != nullptr) {
207         dispatcherUpgrade->Dispatch(strGroupName, std::move(encodeBuf), callbackId);
208     } else {
209         LOGW("Dispatcher Upgrade fail when dispatch request message to platform");
210         groupJsBridge->TriggerModulePluginGetErrorCallback(callbackId, PLUGIN_REQUEST_FAIL, "send message failed");
211     }
212 }
213 
214 // function callback for groupObj's function: sendGroupMessageSync
ProcessJsRequestSync(const v8::FunctionCallbackInfo<v8::Value> & args)215 void V8GroupJsBridge::ProcessJsRequestSync(const v8::FunctionCallbackInfo<v8::Value>& args)
216 {
217     v8::Isolate* isolate = args.GetIsolate();
218     ACE_DCHECK(isolate);
219     v8::HandleScope handleScope(isolate);
220 
221     auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
222     if (delegate == nullptr) {
223         LOGE("send message para check, fail to get front-end delegate");
224         return;
225     }
226 
227     auto groupJsBridge = AceType::DynamicCast<V8GroupJsBridge>((*delegate)->GetGroupJsBridge());
228     if (groupJsBridge == nullptr) {
229         LOGE("send message para check, fail to get group-js-bridge");
230         return;
231     }
232 
233     // Should have at least 2 parameters
234     if (args.Length() < PLUGIN_REQUEST_MIN_ARGC_NUM_SYNC) {
235         LOGE("send message para check, invalid args number:%{public}d", args.Length());
236         return;
237     }
238 
239     v8::String::Utf8Value jsGroupName(isolate, args[PLUGIN_REQUEST_ARG_GROUP_NAME_INDEX_SYNC]);
240     const char* groupName  = *jsGroupName;
241     if (groupName == nullptr) {
242         LOGE("plugin name is null");
243         return;
244     }
245     std::string strGroupName(groupName);
246 
247     v8::String::Utf8Value jsFunctionName(isolate, args[PLUGIN_REQUEST_ARG_FUNCTION_NAME_INDEX_SYNC]);
248     const char* functionName = *jsFunctionName;
249     std::string strFunctionName(functionName);
250     LOGI("send message, groupName: %{private}s, functionName: %{private}s", groupName, functionName);
251 
252     std::vector<CodecData> arguments;
253     ParseJsDataResult parseJsResult =
254         groupJsBridge->ParseJsPara(args, PLUGIN_REQUEST_ARG_APP_PARAMS_INDEX_SYNC, 0, arguments);
255     if (parseJsResult != ParseJsDataResult::PARSE_JS_SUCCESS) {
256         LOGE("parse js data error");
257         return;
258     }
259 
260     FunctionCall functionCall(strFunctionName, arguments);
261     StandardFunctionCodec codec;
262     std::vector<uint8_t> encodeBuf;
263     if (!codec.EncodeFunctionCall(functionCall, encodeBuf)) {
264         LOGE("encode arguments fail");
265         return;
266     }
267 
268     // CallPlatformFunction
269     auto dispatcher = static_cast<WeakPtr<JsMessageDispatcher>*>(isolate->GetData(V8EngineInstance::DISPATCHER));
270     auto dispatcherUpgrade = (*dispatcher).Upgrade();
271 
272     uint8_t* resData = nullptr;
273     int64_t position = 0;
274 
275     if (dispatcherUpgrade != nullptr) {
276         dispatcherUpgrade->DispatchSync(strGroupName, std::move(encodeBuf), &resData, position);
277     } else {
278         LOGW("Dispatcher Upgrade fail when dispatch request message to platform");
279         return;
280     }
281 
282     std::vector<uint8_t> messageData = std::vector<uint8_t>(resData, resData + position);
283 
284     v8::Local<v8::Value> callBackResult;
285     CodecData codecResult;
286     if (codec.DecodePlatformMessage(messageData, codecResult)) {
287         std::string resultString = codecResult.GetStringValue();
288         LOGI("sync resultString = %{private}s", resultString.c_str());
289         if (resultString.empty()) {
290             callBackResult = v8::Null(isolate);
291         } else {
292             callBackResult = v8::String::NewFromUtf8(isolate, resultString.c_str()).ToLocalChecked();
293         }
294         args.GetReturnValue().Set(callBackResult);
295     }
296 }
297 
SetEventGroupCallBackFuncs(v8::Isolate * isolate,v8::Local<v8::Value> localEventCallbackFunc,int32_t callbackId,int32_t requestId)298 bool V8GroupJsBridge::SetEventGroupCallBackFuncs(
299     v8::Isolate* isolate, v8::Local<v8::Value> localEventCallbackFunc, int32_t callbackId, int32_t requestId)
300 {
301     if (localEventCallbackFunc->IsNull() || !localEventCallbackFunc->IsFunction()) {
302         LOGE("callback function is invalid!");
303         return false;
304     }
305 
306     LOGI("record event callback, requestId:%{private}d, callbackId:%{private}d", requestId, callbackId);
307     v8::Persistent<v8::Value, v8::CopyablePersistentTraits<v8::Value>> eventCallbackFunc;
308     eventCallbackFunc.Reset(isolate, localEventCallbackFunc);
309     auto result = eventCallBackFuncs_.try_emplace(callbackId, eventCallbackFunc);
310     if (!result.second) {
311         result.first->second.Reset();
312         result.first->second.Reset(isolate, localEventCallbackFunc);
313     }
314 
315     AddRequestIdCallbackIdRelation(callbackId, requestId);
316 
317     return true;
318 }
319 
RemoveEventGroupCallBackFuncs(int32_t callbackId)320 void V8GroupJsBridge::RemoveEventGroupCallBackFuncs(int32_t callbackId)
321 {
322     LOGI("remove event callback, callbackId:%{private}d", callbackId);
323     auto itFunc = eventCallBackFuncs_.find(callbackId);
324     if (itFunc != eventCallBackFuncs_.end()) {
325         itFunc->second.Reset();
326         eventCallBackFuncs_.erase(callbackId);
327     }
328 }
329 
AddRequestIdCallbackIdRelation(int32_t eventId,int32_t requestId)330 void V8GroupJsBridge::AddRequestIdCallbackIdRelation(int32_t eventId, int32_t requestId)
331 {
332     auto result = requestIdCallbackIdMap_.try_emplace(requestId, eventId);
333     if (!result.second) {
334         result.first->second = eventId;
335     }
336 }
337 
RemoveRequestIdCallbackIdRelation(int32_t requestId,bool removeEventCallback)338 void V8GroupJsBridge::RemoveRequestIdCallbackIdRelation(int32_t requestId, bool removeEventCallback)
339 {
340     auto eventId = requestIdCallbackIdMap_.find(requestId);
341     if (eventId != requestIdCallbackIdMap_.end()) {
342         if (removeEventCallback) {
343             RemoveEventGroupCallBackFuncs(eventId->second);
344         }
345         requestIdCallbackIdMap_.erase(requestId);
346     }
347 }
348 
ProcessParseJsError(ParseJsDataResult errorType,v8::Isolate * isolate,int32_t callbackId)349 void V8GroupJsBridge::ProcessParseJsError(ParseJsDataResult errorType, v8::Isolate* isolate, int32_t callbackId)
350 {
351     // PluginErrorCallback
352     auto dispatcher = static_cast<WeakPtr<JsMessageDispatcher>*>(isolate->GetData(V8EngineInstance::DISPATCHER));
353     auto dispatcherUpgrade = (*dispatcher).Upgrade();
354     if (dispatcherUpgrade == nullptr) {
355         LOGW("Dispatcher Upgrade fail at ProcessParseJsError");
356         return;
357     }
358     std::string errMessage;
359     switch (errorType) {
360         case ParseJsDataResult::PARSE_JS_ERR_UNSUPPORTED_TYPE:
361             errMessage = "unsupported js parameter types";
362             dispatcherUpgrade->DispatchPluginError(callbackId,
363                 static_cast<int32_t>(ParseJsDataResult::PARSE_JS_ERR_UNSUPPORTED_TYPE), std::move(errMessage));
364             break;
365         case ParseJsDataResult::PARSE_JS_ERR_TOO_MANY_PARAM:
366             errMessage = "the number of parameters exceeds 255";
367             dispatcherUpgrade->DispatchPluginError(callbackId,
368                 static_cast<int32_t>(ParseJsDataResult::PARSE_JS_ERR_TOO_MANY_PARAM), std::move(errMessage));
369             break;
370         default:
371             break;
372     }
373 }
374 
SetModuleGroupCallbackFuncs(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t resolveCallbackIndex,int32_t rejectCallbackIndex,int32_t callbackId)375 bool V8GroupJsBridge::SetModuleGroupCallbackFuncs(const v8::FunctionCallbackInfo<v8::Value>& args,
376     int32_t resolveCallbackIndex, int32_t rejectCallbackIndex, int32_t callbackId)
377 {
378     v8::Isolate* isolate = args.GetIsolate();
379     ACE_DCHECK(isolate);
380     v8::HandleScope handleScope(isolate);
381 
382     LOGD("Enter SetModuleGroupCallbackFuncs");
383     if (args[resolveCallbackIndex]->IsNull() || !args[resolveCallbackIndex]->IsFunction() ||
384         args[rejectCallbackIndex]->IsNull() || !args[rejectCallbackIndex]->IsFunction()) {
385         LOGE("resolve or reject callback function is invalid");
386         return false;
387     }
388 
389     PromiseCallback promiseCallJsFunc;
390 
391     promiseCallJsFunc.resolveCallback.Reset(isolate, args[resolveCallbackIndex]);
392     promiseCallJsFunc.rejectCallback.Reset(isolate, args[rejectCallbackIndex]);
393 
394     auto result = moduleCallBackFuncs_.try_emplace(callbackId, promiseCallJsFunc);
395     if (!result.second) {
396         LOGE("module callback function has been existed!");
397         return false;
398     }
399     return true;
400 }
401 
SerializationObjectToString(v8::Local<v8::Context> context,v8::Local<v8::Value> val)402 std::string V8GroupJsBridge::SerializationObjectToString(v8::Local<v8::Context> context, v8::Local<v8::Value> val)
403 {
404     v8::Isolate* isolate = context->GetIsolate();
405     ACE_DCHECK(isolate);
406     v8::HandleScope handleScope(isolate);
407     v8::TryCatch tryCatch(isolate);
408 
409     v8::Local<v8::Value> strValue;
410     v8::Local<v8::Value> global;
411     v8::Local<v8::Value> json;
412     v8::Local<v8::Value> func;
413 
414     global = context->Global();
415     if (!global->IsObject()) {
416         LOGE("SerializationObjectToString error: fail to get Global Object");
417         return "";
418     }
419     v8::Local<v8::Object> globalObj = global->ToObject(context).ToLocalChecked();
420     json = globalObj->Get(context, v8::String::NewFromUtf8(isolate, "JSON").ToLocalChecked()).ToLocalChecked();
421     if (!json->IsObject()) {
422         LOGE("SerializationObjectToString error: global has no attribute JSON");
423         return "";
424     }
425     v8::Local<v8::Object> jsonObj = json->ToObject(context).ToLocalChecked();
426     func = jsonObj->Get(context, v8::String::NewFromUtf8(isolate, "stringify").ToLocalChecked()).ToLocalChecked();
427     if (!func->IsFunction()) {
428         LOGE("SerializationObjectToString error: JSON has no attribute stringify");
429         return "";
430     }
431     v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(func);
432     v8::Local<v8::Value> argv[] = { val };
433     bool succ = function->Call(context, globalObj, 1, argv).ToLocal(&strValue);
434     if (!succ) {
435         V8Utils::JsStdDumpErrorAce(isolate, &tryCatch, JsErrorType::STRINGIFY_ERROR);
436         return "";
437     }
438 
439     v8::String::Utf8Value resStr(isolate, strValue);
440     std::string res;
441     if (*resStr) {
442         res = *resStr;
443     }
444     return res;
445 }
446 
ParseJsPara(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t beginIndex,int32_t requestId,std::vector<CodecData> & arguments)447 ParseJsDataResult V8GroupJsBridge::ParseJsPara(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t beginIndex,
448     int32_t requestId, std::vector<CodecData>& arguments)
449 {
450     if (args.Length() < beginIndex) { // no others params
451         return ParseJsDataResult::PARSE_JS_SUCCESS;
452     }
453 
454     v8::Isolate* isolate = args.GetIsolate();
455     ACE_DCHECK(isolate);
456     v8::HandleScope handleScope(isolate);
457     auto context = isolate->GetCurrentContext();
458 
459     for (int32_t i = beginIndex; i < args.Length(); i++) {
460         v8::Local<v8::Value> val = args[i];
461         if (val->IsString()) {
462             v8::String::Utf8Value jsPara(isolate, val);
463             if (*jsPara) {
464                 std::string para(*jsPara);
465                 CodecData arg(para);
466                 arguments.push_back(arg);
467             }
468         } else if (val->IsNumber()) {
469             if (val->IsInt32()) {
470                 int32_t valInt = val->Int32Value(context).ToChecked();
471                 CodecData arg(valInt);
472                 arguments.push_back(arg);
473             } else {
474                 double valDouble = val->NumberValue(context).ToChecked();
475                 CodecData arg(valDouble);
476                 arguments.push_back(arg);
477             }
478         } else if (val->IsBoolean()) {
479             bool valBool = val->BooleanValue(isolate);
480             CodecData arg(valBool);
481             arguments.push_back(arg);
482         } else if (val->IsNull()) {
483             CodecData argNull;
484             arguments.push_back(argNull);
485         } else if (val->IsFunction()) {
486             int32_t functionId = GetPendingCallbackIdAndIncrement();
487             CodecData arg(functionId, BufferDataType::TYPE_FUNCTION);
488             arguments.push_back(arg);
489             SetEventGroupCallBackFuncs(isolate, val, functionId, requestId);
490         } else if (val->IsArray() || val->IsObject()) {
491             std::string objStr = SerializationObjectToString(context, val);
492             CodecData arg(objStr, BufferDataType::TYPE_OBJECT);
493             arguments.push_back(arg);
494         } else if (val->IsUndefined()) {
495             LOGD("Process callNative para type:undefined");
496         } else {
497             LOGE("Process callNative para type: unsupported type");
498             return ParseJsDataResult::PARSE_JS_ERR_UNSUPPORTED_TYPE;
499         }
500     }
501     return ParseJsDataResult::PARSE_JS_SUCCESS;
502 }
503 
TriggerModuleJsCallback(int32_t callbackId,int32_t code,std::vector<uint8_t> && messageData)504 void V8GroupJsBridge::TriggerModuleJsCallback(int32_t callbackId, int32_t code, std::vector<uint8_t>&& messageData)
505 {
506     v8::HandleScope handleScope(isolate_);
507     v8::TryCatch tryCatch(isolate_);
508 
509     v8::Local<v8::Value> callBackResult;
510     CodecData codecResult;
511     StandardFunctionCodec codec;
512     if (codec.DecodePlatformMessage(messageData, codecResult)) {
513         std::string resultString = codecResult.GetStringValue();
514         if (resultString.empty()) {
515             callBackResult = v8::Null(isolate_);
516         } else {
517             callBackResult = v8::String::NewFromUtf8(isolate_, resultString.c_str()).ToLocalChecked();
518         }
519     } else {
520         LOGE("trigger JS result function error, decode message fail, callbackId:%{private}d",
521             callbackId);
522         code = PLUGIN_REQUEST_FAIL;
523         std::string errorString = std::string("{\"code\":").append(std::to_string(code)).append(",")
524             .append("\"data\":\"invalid response data\"}");
525         callBackResult = v8::String::NewFromUtf8(isolate_, errorString.c_str()).ToLocalChecked();
526     }
527     CallModuleJsCallback(callbackId, code, callBackResult);
528 
529     messageData.clear();
530 }
531 
CallModuleJsCallback(int32_t callbackId,int32_t code,v8::Local<v8::Value> callBackResult)532 void V8GroupJsBridge::CallModuleJsCallback(int32_t callbackId, int32_t code, v8::Local<v8::Value> callBackResult)
533 {
534     RemoveRequestIdCallbackIdRelation(callbackId, code != PLUGIN_REQUEST_SUCCESS);
535 
536     v8::HandleScope handleScope(isolate_);
537     v8::Local<v8::Context> context = context_.Get(isolate_);
538     v8::Local<v8::Object> global = context->Global();
539 
540     v8::TryCatch tryCatch(isolate_);
541 
542     auto itFunc = moduleCallBackFuncs_.find(callbackId);
543     if (itFunc != moduleCallBackFuncs_.end()) {
544         v8::Local<v8::Value> jsFunc = (code == PLUGIN_REQUEST_SUCCESS ?
545             itFunc->second.resolveCallback.Get(isolate_) : itFunc->second.rejectCallback.Get(isolate_));
546         if (!jsFunc->IsFunction() || jsFunc->IsNull()) {
547             LOGE("trigger JS result function error, it is not a function, callbackId:%{private}d", callbackId);
548             return;
549         }
550 
551         v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(jsFunc);
552         v8::Local<v8::Value> argv[] = { callBackResult };
553         // Pass only 1 parameter, call promise resolve call back.
554         v8::Local<v8::Value> res;
555         bool succ = func->Call(context, global, 1, argv).ToLocal(&res);
556         if (succ) {
557             LOGI("trigger JS result function success, callbackId:%{private}d, code:%{private}d", callbackId, code);
558         } else {
559             LOGW("trigger JS result function fail, callbackId:%{private}d, code:%{private}d", callbackId, code);
560             V8Utils::JsStdDumpErrorAce(isolate_, &tryCatch);
561         }
562 
563         while (v8::platform::PumpMessageLoop(V8Engine::GetPlatform().get(), isolate_)) {
564             continue;
565         }
566 
567         itFunc->second.rejectCallback.Reset();
568         itFunc->second.resolveCallback.Reset();
569         moduleCallBackFuncs_.erase(itFunc);
570     } else {
571         LOGE("trigger JS result function is not exists, callbackId:%{private}d, code:%{private}d", callbackId, code);
572     }
573 }
574 
TriggerModulePluginGetErrorCallback(int32_t callbackId,int32_t errorCode,std::string && errorMessage)575 void V8GroupJsBridge::TriggerModulePluginGetErrorCallback(
576     int32_t callbackId, int32_t errorCode, std::string&& errorMessage)
577 {
578     RemoveRequestIdCallbackIdRelation(callbackId, true);
579 
580     v8::HandleScope handleScope(isolate_);
581     v8::Local<v8::Context> context = context_.Get(isolate_);
582     v8::Local<v8::Object> global = context->Global();
583 
584     auto itFunc = moduleCallBackFuncs_.find(callbackId);
585     if (itFunc != moduleCallBackFuncs_.end()) {
586         v8::Local<v8::Value> jsFunc = itFunc->second.rejectCallback.Get(isolate_);
587         if (!jsFunc->IsFunction() || jsFunc->IsNull()) {
588             LOGE("trigger JS result function error, reject is not a function, callbackId:%{private}d",
589                 callbackId);
590             return;
591         }
592 
593         auto resultJson = JsonUtil::Create(true);
594         resultJson->Put(std::string("code").c_str(), errorCode);
595         resultJson->Put(std::string("data").c_str(), errorMessage.c_str());
596 
597         v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(jsFunc);
598         v8::Local<v8::String> emptyReplyCallback = v8::String::NewFromUtf8(isolate_,
599             resultJson->ToString().c_str()).ToLocalChecked();
600         v8::Local<v8::Value> argv[] = {emptyReplyCallback};
601         // Pass only 1 parameter, call promise reject call back for error get in plugin.
602         v8::Local<v8::Value> res;
603         bool succ = func->Call(context, global, 1, argv).ToLocal(&res);
604         if (succ) {
605             LOGI("trigger JS result function success, callbackId:%{private}d", callbackId);
606         } else {
607             LOGW("trigger JS result function fail, callbackId:%{private}d", callbackId);
608         }
609 
610         while (v8::platform::PumpMessageLoop(V8Engine::GetPlatform().get(), isolate_)) {
611             continue;
612         }
613 
614         itFunc->second.rejectCallback.Reset();
615         itFunc->second.resolveCallback.Reset();
616         moduleCallBackFuncs_.erase(itFunc);
617     } else {
618         LOGE("trigger JS result function is not exists, callbackId:%{private}d", callbackId);
619     }
620 }
621 
CallEventJsCallback(int32_t callbackId,std::vector<uint8_t> && eventData)622 void V8GroupJsBridge::CallEventJsCallback(int32_t callbackId, std::vector<uint8_t>&& eventData)
623 {
624     v8::HandleScope handleScope(isolate_);
625     v8::Local<v8::Context> context = context_.Get(isolate_);
626     v8::Local<v8::Object> global = context->Global();
627 
628     v8::Local<v8::Value> callBackEvent;
629     CodecData codecEvent;
630     StandardFunctionCodec codec;
631     if (codec.DecodePlatformMessage(eventData, codecEvent)) {
632         std::string eventString = codecEvent.GetStringValue();
633         if (eventString.empty()) {
634             callBackEvent = v8::Null(isolate_);
635         } else {
636             callBackEvent = v8::String::NewFromUtf8(isolate_, eventString.c_str()).ToLocalChecked();
637         }
638     } else {
639         LOGE("trigger JS callback function error, decode message fail, callbackId:%{private}d", callbackId);
640         return;
641     }
642 
643     auto itFunc = eventCallBackFuncs_.find(callbackId);
644     if (itFunc != eventCallBackFuncs_.end()) {
645         v8::Local<v8::Value> jsFunc = itFunc->second.Get(isolate_);
646         if (!jsFunc->IsFunction() || jsFunc->IsNull()) {
647             LOGE("trigger JS callback function error, callback is not a function, callbackId:%{private}d", callbackId);
648             return;
649         }
650 
651         // Pass only 1 parameter
652         v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(jsFunc);
653         v8::Local<v8::Value> argv[] = { callBackEvent };
654         v8::Local<v8::Value> res;
655         bool succ = func->Call(context, global, 1, argv).ToLocal(&res);
656         if (!succ) {
657             LOGW("trigger JS callback function failed, callbackId:%{private}d", callbackId);
658         } else {
659             LOGW("trigger JS callback function success, callbackId:%{private}d", callbackId);
660         }
661 
662         while (v8::platform::PumpMessageLoop(V8Engine::GetPlatform().get(), isolate_)) {
663             continue;
664         }
665     } else {
666         LOGE("trigger JS callback function error, it is not exists, callbackId:%{private}d", callbackId);
667     }
668     eventData.clear();
669 }
670 
TriggerEventJsCallback(int32_t callbackId,int32_t code,std::vector<uint8_t> && eventData)671 void V8GroupJsBridge::TriggerEventJsCallback(int32_t callbackId, int32_t code, std::vector<uint8_t>&& eventData)
672 {
673     if (code == PLUGIN_CALLBACK_DESTROY) {
674         RemoveEventGroupCallBackFuncs(callbackId);
675     } else {
676         CallEventJsCallback(callbackId, std::move(eventData));
677     }
678 }
679 
LoadPluginJsCode(std::string && jsCode)680 void V8GroupJsBridge::LoadPluginJsCode(std::string&& jsCode)
681 {
682     LOGI("Load plugin js code, code len:%{public}d", static_cast<int32_t>(jsCode.length()));
683     jsCode_ = std::move(jsCode);
684     v8::HandleScope handleScope(isolate_);
685     v8::Local<v8::Context> context = context_.Get(isolate_);
686     v8::Context::Scope contextScope(context);
687 
688     v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate_, jsCode_.c_str()).ToLocalChecked();
689     if (CallEvalBuf(isolate_, source) != JS_CALL_SUCCESS) {
690         LOGE("run plugin js code failed!");
691     }
692 }
693 
LoadPluginJsByteCode(std::vector<uint8_t> && jsCode,std::vector<int32_t> && jsCodeLen)694 void V8GroupJsBridge::LoadPluginJsByteCode(std::vector<uint8_t>&& jsCode, std::vector<int32_t>&& jsCodeLen)
695 {
696     LOGW("V8 do not support load js bytecode now.");
697 }
698 
Destroy()699 void V8GroupJsBridge::Destroy()
700 {
701     eventCallBackFuncs_.clear();
702     moduleCallBackFuncs_.clear();
703     requestIdCallbackIdMap_.clear();
704     context_.Reset();
705 }
706 
707 } // namespace OHOS::Ace::Framework
708