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_engine.h"
17
18 #include <dirent.h>
19 #include <dlfcn.h>
20 #include <regex>
21 #include <unistd.h>
22
23 #include "base/i18n/localization.h"
24 #include "base/json/json_util.h"
25 #include "base/log/ace_trace.h"
26 #include "base/log/event_report.h"
27 #include "base/log/log.h"
28 #include "base/utils/system_properties.h"
29 #include "base/utils/time_util.h"
30 #include "core/common/container.h"
31 #include "core/common/container_scope.h"
32 #include "core/common/thread_checker.h"
33 #include "core/components/common/layout/grid_system_manager.h"
34 #include "frameworks/bridge/common/dom/dom_type.h"
35 #include "frameworks/bridge/common/plugin_adapter/plugin_bridge.h"
36 #include "frameworks/bridge/common/utils/utils.h"
37 #include "frameworks/bridge/common/utils/v8/v8_helper.h"
38 #include "frameworks/bridge/js_frontend/engine/common/js_api_perf.h"
39 #include "frameworks/bridge/js_frontend/engine/common/js_constants.h"
40 #include "frameworks/bridge/js_frontend/engine/common/runtime_constants.h"
41 #include "frameworks/bridge/js_frontend/engine/v8/v8_animation_bridge.h"
42 #include "frameworks/bridge/js_frontend/engine/v8/v8_animator_bridge.h"
43 #include "frameworks/bridge/js_frontend/engine/v8/v8_badge_bridge.h"
44 #include "frameworks/bridge/js_frontend/engine/v8/v8_canvas_bridge.h"
45 #include "frameworks/bridge/js_frontend/engine/v8/v8_chart_bridge.h"
46 #include "frameworks/bridge/js_frontend/engine/v8/v8_clock_bridge.h"
47 #include "frameworks/bridge/js_frontend/engine/v8/v8_component_api_bridge.h"
48 #include "frameworks/bridge/js_frontend/engine/v8/v8_group_js_bridge.h"
49 #include "frameworks/bridge/js_frontend/engine/v8/v8_image_animator_bridge.h"
50 #include "frameworks/bridge/js_frontend/engine/v8/v8_input_bridge.h"
51 #include "frameworks/bridge/js_frontend/engine/v8/v8_list_bridge.h"
52 #include "frameworks/bridge/js_frontend/engine/v8/v8_offscreen_canvas_bridge.h"
53 #include "frameworks/bridge/js_frontend/engine/v8/v8_stepper_bridge.h"
54 #include "frameworks/bridge/js_frontend/engine/v8/v8_utils.h"
55 #include "frameworks/bridge/js_frontend/engine/v8/v8_xcomponent_bridge.h"
56
57 #if !defined(USE_EXTERNAL_V8_SNAPSHOT)
58 extern const char _binary_strip_native_min_js_bin_start[];
59 extern const char _binary_strip_native_min_js_bin_end[];
60 #endif
61
62 namespace OHOS::Ace::Framework {
63 namespace {
64
65 const int32_t CUSTOM_FULL_WINDOW_LENGTH = 2;
66 const int32_t MAX_READ_TEXT_LENGTH = 4096;
67 const std::regex URI_PATTERN("^\\/([a-z0-9A-Z_]+\\/)*[a-z0-9A-Z_]+\\.?[a-z0-9A-Z_]*$");
68 constexpr int32_t V8_MAX_STACK_SIZE = 1 * 1024 * 1024;
69 void* g_debugger = nullptr;
70 bool g_flagNeedDebugBreakPoint = false;
71 static int32_t globalNodeId = 100000;
72 using StartDebug = void (*)(
73 const std::unique_ptr<v8::Platform>& platform, const v8::Local<v8::Context>& context, std::string componentName,
74 const bool isDebugMode, const int32_t instanceId);
75 using WaitingForIde = void (*)();
76 using StopDebug = void (*)();
77
CallEvalBuf(v8::Isolate * isolate,const char * src,int32_t instanceId,const char * filename=nullptr)78 bool CallEvalBuf(v8::Isolate* isolate, const char* src, int32_t instanceId, const char* filename = nullptr)
79 {
80 ACE_DCHECK(isolate);
81 CHECK_RUN_ON(JS);
82 v8::HandleScope handleScope(isolate);
83 auto context = isolate->GetCurrentContext();
84 if (context.IsEmpty()) {
85 LOGE("CallEvalBuf, CurrentContext is empty!");
86 return false;
87 }
88 v8::TryCatch tryCatch(isolate);
89 if (src == nullptr || src[0] == '\0') {
90 LOGE("src is null");
91 return false;
92 }
93
94 const char* origin = filename;
95 if (!origin) {
96 origin = "<anonymous>";
97 }
98
99 v8::ScriptOrigin scriptOrigin(v8::String::NewFromUtf8(isolate, origin).ToLocalChecked());
100
101 v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, src).ToLocalChecked();
102 v8::Local<v8::Script> script;
103 if (!v8::Script::Compile(context, source, &scriptOrigin).ToLocal(&script)) {
104 V8Utils::JsStdDumpErrorAce(isolate, &tryCatch, JsErrorType::COMPILE_ERROR, instanceId);
105 return false;
106 }
107
108 v8::Local<v8::Value> res;
109 if (!script->Run(context).ToLocal(&res)) {
110 V8Utils::JsStdDumpErrorAce(isolate, &tryCatch, JsErrorType::RUNTIME_ERROR, instanceId);
111 return false;
112 }
113 return true;
114 }
115
GetStagingPage()116 RefPtr<JsAcePage> GetStagingPage()
117 {
118 LOGD("Enter GetStagingPage");
119 CHECK_RUN_ON(JS);
120 v8::Isolate* isolate = v8::Isolate::GetCurrent();
121 ACE_DCHECK(isolate);
122 auto stagingPage = static_cast<RefPtr<JsAcePage>*>(isolate->GetData(V8EngineInstance::STAGING_PAGE));
123 return *stagingPage;
124 }
125
GetRunningPage()126 RefPtr<JsAcePage> GetRunningPage()
127 {
128 LOGD("Enter GetRunningPage");
129 CHECK_RUN_ON(JS);
130 v8::Isolate* isolate = v8::Isolate::GetCurrent();
131 ACE_DCHECK(isolate);
132 auto runningPage = static_cast<RefPtr<JsAcePage>*>(isolate->GetData(V8EngineInstance::RUNNING_PAGE));
133 return *runningPage;
134 }
135
GetArrayValue(v8::Local<v8::Context> context,v8::Local<v8::Value> arrayVal,std::string & result)136 void GetArrayValue(v8::Local<v8::Context> context, v8::Local<v8::Value> arrayVal, std::string& result)
137 {
138 LOGD("Enter GetArrayValue");
139 CHECK_RUN_ON(JS);
140 v8::Isolate* isolate = context->GetIsolate();
141 ACE_DCHECK(isolate);
142 v8::HandleScope handleScope(isolate);
143
144 v8::Local<v8::Object> valObj;
145 bool succ = arrayVal->ToObject(context).ToLocal(&valObj);
146 if (!succ) {
147 LOGE("Value to Object fail");
148 return;
149 }
150 v8::Local<v8::Array> properties = valObj->GetOwnPropertyNames(context).ToLocalChecked();
151 uint32_t len = properties->Length();
152 for (uint32_t i = 0; i < len; i++) {
153 if (i != 0) {
154 result.append(1, DOM_PICKER_SPLIT_ARRAY);
155 }
156 v8::Local<v8::Value> itemKey = properties->Get(context, i).ToLocalChecked();
157 v8::Local<v8::Value> itemVal = valObj->Get(context, itemKey).ToLocalChecked();
158 if (itemVal->IsString() || itemVal->IsNumber() || itemVal->IsBoolean()) {
159 v8::String::Utf8Value val(isolate, itemVal);
160 if (*val) {
161 result.append(*val);
162 }
163 continue;
164 }
165 if (itemVal->IsArray()) {
166 v8::Local<v8::Array> itemArray = v8::Local<v8::Array>::Cast(itemVal);
167 uint32_t subLen = itemArray->Length();
168 for (uint32_t j = 0; j < subLen; j++) {
169 if (j != 0) {
170 result.append(1, DOM_PICKER_SPLIT_ITEM);
171 }
172 v8::Local<v8::Value> subItemVal = itemArray->Get(context, j).ToLocalChecked();
173 v8::String::Utf8Value subItemStr(isolate, subItemVal);
174 if (*subItemStr) {
175 result.append(*subItemStr);
176 }
177 }
178 continue;
179 }
180 }
181 }
182
GetAttrImage(v8::Local<v8::Context> context,v8::Local<v8::Value> objectVal,ImageProperties & imageProperties)183 void GetAttrImage(v8::Local<v8::Context> context, v8::Local<v8::Value> objectVal, ImageProperties& imageProperties)
184 {
185 CHECK_RUN_ON(JS);
186 v8::Isolate* isolate = context->GetIsolate();
187 ACE_DCHECK(isolate);
188 v8::HandleScope handleScope(isolate);
189 v8::Local<v8::Object> valObj = objectVal->ToObject(context).ToLocalChecked();
190 v8::Local<v8::Array> valObjProperties = valObj->GetOwnPropertyNames(context).ToLocalChecked();
191 uint32_t objLen = valObjProperties->Length();
192 for (uint32_t i = 0; i < objLen; i++) {
193 v8::Local<v8::Value> valObjKey;
194 bool succ = valObjProperties->Get(context, i).ToLocal(&valObjKey);
195 if (!succ) {
196 LOGW("key is null. Ignoring!");
197 continue;
198 }
199 v8::String::Utf8Value valObjKeyStr(isolate, valObjKey);
200 const char* keyStr = *valObjKeyStr;
201 if (keyStr == nullptr) {
202 continue;
203 }
204 v8::Local<v8::Value> valObjVal = valObj->Get(context, valObjKey).ToLocalChecked();
205 if (valObjVal->IsString() || valObjVal->IsNumber() || valObjVal->IsBoolean()) {
206 v8::String::Utf8Value valObjValStr(isolate, valObjVal);
207 const char* valStr = *valObjValStr;
208 if (valStr == nullptr) {
209 continue;
210 }
211 if (strcmp(keyStr, "src") == 0) {
212 imageProperties.src = valStr;
213 } else if (strcmp(keyStr, "width") == 0) {
214 imageProperties.width = StringToDimension(valStr);
215 } else if (strcmp(keyStr, "height") == 0) {
216 imageProperties.height = StringToDimension(valStr);
217 } else if (strcmp(keyStr, "top") == 0) {
218 imageProperties.top = StringToDimension(valStr);
219 } else if (strcmp(keyStr, "left") == 0) {
220 imageProperties.left = StringToDimension(valStr);
221 } else if (strcmp(keyStr, "duration") == 0) {
222 imageProperties.duration = StringToInt(valStr);
223 } else {
224 LOGD("key : %{public}s unsupported. Ignoring!", keyStr);
225 }
226 } else {
227 LOGD("value of unsupported type. Ignoring!");
228 }
229 }
230 }
231
GetAttrImages(v8::Local<v8::Context> context,v8::Local<v8::Value> arrayVal,std::vector<ImageProperties> & images)232 void GetAttrImages(v8::Local<v8::Context> context, v8::Local<v8::Value> arrayVal, std::vector<ImageProperties>& images)
233 {
234 CHECK_RUN_ON(JS);
235 v8::Isolate* isolate = context->GetIsolate();
236 ACE_DCHECK(isolate);
237 v8::HandleScope handleScope(isolate);
238
239 v8::Local<v8::Object> arrayObj = arrayVal->ToObject(context).ToLocalChecked();
240 v8::Local<v8::Array> properties = arrayObj->GetOwnPropertyNames(context).ToLocalChecked();
241 uint32_t len = properties->Length();
242 for (uint32_t i = 0; i < len; i++) {
243 v8::Local<v8::Value> key = properties->Get(context, i).ToLocalChecked();
244 v8::Local<v8::Value> val = arrayObj->Get(context, key).ToLocalChecked();
245 ImageProperties imageProperties;
246 if (val->IsObject()) {
247 GetAttrImage(context, val, imageProperties);
248 images.push_back(imageProperties);
249 }
250 }
251 }
252
SetDomAttributes(v8::Local<v8::Context> context,v8::Local<v8::Value> fromMap,JsCommandDomElementOperator & command)253 bool SetDomAttributes(
254 v8::Local<v8::Context> context, v8::Local<v8::Value> fromMap, JsCommandDomElementOperator& command)
255 {
256 CHECK_RUN_ON(JS);
257 v8::Isolate* isolate = context->GetIsolate();
258 ACE_DCHECK(isolate);
259 v8::HandleScope handleScope(isolate);
260
261 LOGD("Enter SetDomAttributes");
262 bool hasShowAttr = false;
263 if (fromMap.IsEmpty() || !fromMap->IsObject()) {
264 LOGE("none found attrs");
265 return false;
266 }
267 v8::Local<v8::Object> mapObj;
268 bool succ = fromMap->ToObject(context).ToLocal(&mapObj);
269 if (!succ) {
270 LOGE("Value to Object fail");
271 return false;
272 }
273 v8::Local<v8::Array> properties = mapObj->GetOwnPropertyNames(context).ToLocalChecked();
274
275 // begin to set attributes:
276 std::vector<std::pair<std::string, std::string>> attrs;
277 uint32_t len = properties->Length();
278 for (uint32_t i = 0; i < len; i++) {
279 v8::Local<v8::Value> key;
280 succ = properties->Get(context, i).ToLocal(&key);
281 if (!succ) {
282 LOGW("key is null. Ignoring!");
283 continue;
284 }
285 v8::String::Utf8Value keyV8Str(isolate, key);
286 const char* keyStr = *keyV8Str;
287 if (keyStr == nullptr) {
288 continue;
289 }
290 v8::Local<v8::Value> val = mapObj->Get(context, key).ToLocalChecked();
291 if (val->IsString() || val->IsNumber() || val->IsBoolean()) {
292 v8::String::Utf8Value valV8Str(isolate, val);
293 const char* valStr = *valV8Str;
294 if (valStr == nullptr) {
295 continue;
296 }
297 LOGD("SetDomAttributes: key %{private}s, attr: %{private}s", keyStr, valStr);
298 if (strcmp(keyStr, DOM_ID) == 0) {
299 command.SetId(valStr);
300 } else if (strcmp(keyStr, DOM_TARGET) == 0) {
301 command.SetTarget(valStr);
302 } else if (strcmp(keyStr, DOM_SHARE_ID) == 0) {
303 command.SetShareId(valStr);
304 }
305 attrs.emplace_back(keyStr, valStr);
306 if (strcmp(keyStr, DOM_SHOW) == 0) {
307 hasShowAttr = true;
308 }
309 } else if (val->IsArray()) {
310 if (strcmp(keyStr, "datasets") == 0) {
311 auto chartBridge = AceType::MakeRefPtr<V8ChartBridge>();
312 chartBridge->GetAttrDatasets(context, val);
313 command.SetDatasets(chartBridge->GetDatasets());
314 } else if (strcmp(keyStr, "images") == 0) {
315 std::vector<ImageProperties> images;
316 GetAttrImages(context, val, images);
317 command.SetImagesAttr(std::move(images));
318 } else if (strcmp(keyStr, "segments") == 0) {
319 auto chartBridge = AceType::MakeRefPtr<V8ChartBridge>();
320 chartBridge->ParseAttrSegmentArray(context, val);
321 command.SetSegments(chartBridge->GetSegments());
322 } else if (strcmp(keyStr, "menuoptions") == 0) {
323 auto inputBridge = AceType::MakeRefPtr<V8InputBridge>();
324 inputBridge->ParseInputOptions(context, val);
325 command.SetInputOptions(inputBridge->GetInputOptions());
326 } else {
327 std::string valStr;
328 GetArrayValue(context, val, valStr);
329 LOGD("SetDomAttributes: key: %{private}s, attr: %{private}s", keyStr, valStr.c_str());
330 attrs.emplace_back(keyStr, valStr);
331 }
332 } else if (val->IsObject()) {
333 if (strcmp(keyStr, "options") == 0) {
334 auto chartBridge = AceType::MakeRefPtr<V8ChartBridge>();
335 chartBridge->GetAttrOptionsObject(context, val);
336 command.SetOptions(chartBridge->GetChartOptions());
337 } else if (strcmp(keyStr, DOM_CLOCK_CONFIG) == 0) {
338 auto clockBridge = AceType::MakeRefPtr<V8ClockBridge>();
339 clockBridge->ParseClockConfig(context, val);
340 command.SetClockConfig(clockBridge->GetClockConfig());
341 } else if (strcmp(keyStr, DOM_STEPPER_LABEL) == 0) {
342 auto stepperBridge = AceType::MakeRefPtr<V8StepperBridge>();
343 StepperLabels label;
344 stepperBridge->GetAttrLabel(context, val, label);
345 command.SetStepperLabel(label);
346 } else if (strcmp(keyStr, "segments") == 0) {
347 auto chartBridge = AceType::MakeRefPtr<V8ChartBridge>();
348 chartBridge->ParseAttrSingleSegment(context, val);
349 command.SetSegments(chartBridge->GetSegments());
350 } else if (strcmp(keyStr, DOM_BADGE_CONFIG) == 0) {
351 auto badgeConfig = AceType::MakeRefPtr<V8BadgeBridge>();
352 badgeConfig->ParseBadgeConfig(context, val);
353 command.SetBadgeConfig(badgeConfig->GetBadgeConfig());
354 } else {
355 LOGD("key unsupported. Ignoring!");
356 }
357 } else if (val->IsUndefined()) {
358 LOGE("value of key[%{private}s] is undefined. Ignoring!", keyStr);
359 } else {
360 LOGE("value of key[%{private}s] unsupported type. Ignoring!", keyStr);
361 }
362 }
363
364 command.SetAttributes(std::move(attrs));
365 return hasShowAttr;
366 }
367
GetAndRegisterFamily(v8::Local<v8::Context> context,v8::Local<v8::Value> val,std::string & familyStyle)368 void GetAndRegisterFamily(v8::Local<v8::Context> context, v8::Local<v8::Value> val, std::string& familyStyle)
369 {
370 CHECK_RUN_ON(JS);
371 LOGD("Enter GetAndRegisterFamily");
372 v8::Isolate* isolate = context->GetIsolate();
373 v8::HandleScope handleScope(isolate);
374 v8::Local<v8::Object> valObj = val->ToObject(context).ToLocalChecked();
375 std::string familyVal;
376 std::string srcVal;
377 v8::Local<v8::Array> properties = valObj->GetOwnPropertyNames(context).ToLocalChecked();
378 uint32_t len = properties->Length();
379 for (uint32_t i = 0; i < len; i++) {
380 v8::Local<v8::Value> key;
381 bool succ = properties->Get(context, i).ToLocal(&key);
382 if (!succ) {
383 LOGW("key is null. Ignoring!");
384 continue;
385 }
386 v8::String::Utf8Value keyJsStr(isolate, key);
387 const char* keyStr = *keyJsStr;
388 if (keyStr == nullptr) {
389 continue;
390 }
391 v8::Local<v8::Value> valValue = valObj->Get(context, key).ToLocalChecked();
392 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
393 if (valValue->IsString()) {
394 v8::String::Utf8Value valJsStr(isolate, valValue);
395 const char* valStr = *valJsStr;
396 if (valStr == nullptr) {
397 continue;
398 }
399 if (strcmp(keyStr, "fontFamily") == 0) {
400 familyVal = valStr;
401 if (!srcVal.empty()) {
402 (*delegate)->RegisterFont(familyVal, srcVal);
403 familyVal.erase();
404 srcVal.erase();
405 }
406 if (familyStyle.length() > 0) {
407 familyStyle.append(",");
408 }
409 familyStyle.append(valStr);
410 } else if (strcmp(keyStr, "src") == 0) {
411 srcVal = valStr;
412 // The format of font src is: url("src"), here get the src.
413 srcVal = srcVal.substr(URL_SOURCE_START_IDX, srcVal.length() - URL_SOURCE_SUFFIX_LEN);
414 if (!familyVal.empty()) {
415 (*delegate)->RegisterFont(familyVal, srcVal);
416 familyVal.erase();
417 srcVal.erase();
418 }
419 }
420 }
421 }
422 }
423
GetStyleFamilyValue(v8::Local<v8::Context> context,v8::Local<v8::Value> arrayVal,std::string & familyStyle)424 void GetStyleFamilyValue(v8::Local<v8::Context> context, v8::Local<v8::Value> arrayVal, std::string& familyStyle)
425 {
426 CHECK_RUN_ON(JS);
427 LOGD("Enter GetStyleFamilyValue");
428 v8::Isolate* isolate = context->GetIsolate();
429 v8::HandleScope handleScope(isolate);
430 v8::Local<v8::Object> arrayObj = arrayVal->ToObject(context).ToLocalChecked();
431 v8::Local<v8::Array> properties = arrayObj->GetOwnPropertyNames(context).ToLocalChecked();
432 uint32_t len = properties->Length();
433 for (uint32_t i = 0; i < len; i++) {
434 v8::Local<v8::Value> key = properties->Get(context, i).ToLocalChecked();
435 v8::Local<v8::Value> val = arrayObj->Get(context, key).ToLocalChecked();
436 // ValObj is one row of family object
437 if (val->IsObject()) {
438 GetAndRegisterFamily(context, val, familyStyle);
439 }
440 }
441 }
442
GetStyleAnimationName(v8::Local<v8::Context> context,v8::Local<v8::Value> arrayVal,std::vector<std::unordered_map<std::string,std::string>> & styleVec)443 void GetStyleAnimationName(v8::Local<v8::Context> context, v8::Local<v8::Value> arrayVal,
444 std::vector<std::unordered_map<std::string, std::string>>& styleVec)
445 {
446 CHECK_RUN_ON(JS);
447 LOGD("GetStyleAnimationName");
448 v8::Isolate* isolate = context->GetIsolate();
449 ACE_DCHECK(isolate);
450 v8::HandleScope handleScope(isolate);
451
452 v8::Local<v8::Object> arrayObj = arrayVal->ToObject(context).ToLocalChecked();
453
454 v8::Local<v8::Array> properties = arrayObj->GetOwnPropertyNames(context).ToLocalChecked();
455 uint32_t len = properties->Length();
456 for (uint32_t i = 0; i < len; i++) {
457 std::unordered_map<std::string, std::string> animationNameKeyFrame;
458 v8::Local<v8::Value> key = properties->Get(context, i).ToLocalChecked();
459 v8::Local<v8::Value> val = arrayObj->Get(context, key).ToLocalChecked();
460 if (val->IsObject()) {
461 v8::Local<v8::Object> valObj = val->ToObject(context).ToLocalChecked();
462 v8::Local<v8::Array> valObjProperties = valObj->GetOwnPropertyNames(context).ToLocalChecked();
463 uint32_t objLen = valObjProperties->Length();
464 for (uint32_t j = 0; j < objLen; j++) {
465 v8::Local<v8::Value> valObjKey;
466 bool succ = valObjProperties->Get(context, j).ToLocal(&valObjKey);
467 if (!succ) {
468 LOGW("key is null. Ignoring!");
469 continue;
470 }
471 v8::Local<v8::Value> valObjVal = valObj->Get(context, valObjKey).ToLocalChecked();
472 v8::String::Utf8Value valObjKeyStr(isolate, valObjKey);
473 v8::String::Utf8Value valObjValStr(isolate, valObjVal);
474 const char* keyStr = *valObjKeyStr;
475 const char* valStr = *valObjValStr;
476 if ((keyStr != nullptr) && (valStr != nullptr) && (valObjVal->IsString() || valObjVal->IsNumber())) {
477 animationNameKeyFrame.emplace(keyStr, valStr);
478 } else {
479 LOGD("GetStyleAnimationName: unsupported type :%{public}s", valStr);
480 }
481 }
482 }
483 if (animationNameKeyFrame.size() > 0) {
484 styleVec.emplace_back(animationNameKeyFrame);
485 }
486 }
487 }
488
SetDomStyle(v8::Local<v8::Context> context,v8::Local<v8::Value> fromMap,JsCommandDomElementOperator & command)489 bool SetDomStyle(v8::Local<v8::Context> context, v8::Local<v8::Value> fromMap, JsCommandDomElementOperator& command)
490 {
491 CHECK_RUN_ON(JS);
492 v8::Isolate* isolate = context->GetIsolate();
493 ACE_DCHECK(isolate);
494 v8::HandleScope handleScope(isolate);
495
496 LOGD("Enter SetDomStyle");
497 if (fromMap.IsEmpty() || !fromMap->IsObject()) {
498 LOGE("none found attrs");
499 return false;
500 }
501 v8::Local<v8::Object> mapObj;
502 bool succ = fromMap->ToObject(context).ToLocal(&mapObj);
503 if (!succ) {
504 LOGE("Value to Object fail");
505 return false;
506 }
507 v8::Local<v8::Array> properties = mapObj->GetOwnPropertyNames(context).ToLocalChecked();
508 uint32_t len = properties->Length();
509 // begin to set dom styles:
510 std::vector<std::pair<std::string, std::string>> styles;
511 for (uint32_t i = 0; i < len; i++) {
512 v8::Local<v8::Value> key;
513 succ = properties->Get(context, i).ToLocal(&key);
514 if (!succ) {
515 LOGW("key is null. Ignoring!");
516 continue;
517 }
518 v8::String::Utf8Value keyV8Str(isolate, key);
519 const char* keyStr = *keyV8Str;
520 if (keyStr == nullptr) {
521 continue;
522 }
523 v8::Local<v8::Value> val = mapObj->Get(context, key).ToLocalChecked();
524 if (val->IsString() || val->IsNumber() || val->IsBoolean()) {
525 v8::String::Utf8Value valV8Str(isolate, val);
526 const char* valStr = *valV8Str;
527 if (valStr != nullptr) {
528 LOGD("SetDomStyle: key: %{private}s, style: %{private}s", keyStr, valStr);
529 styles.emplace_back(keyStr, valStr);
530 }
531 } else if (val->IsArray()) {
532 if (strcmp(keyStr, DOM_TEXT_FONT_FAMILY) == 0) {
533 // Deal with special case such as fontFamily, suppose all the keys in the array are the same.
534 std::string familyStyle;
535 GetStyleFamilyValue(context, val, familyStyle);
536 styles.emplace_back(keyStr, familyStyle);
537 } else if (strcmp(keyStr, DOM_ANIMATION_NAME) == 0) {
538 // Deal with special case animationName, it different with fontfamily,
539 // the keys in the array are different.
540 std::vector<std::unordered_map<std::string, std::string>> animationNameStyles;
541 GetStyleAnimationName(context, val, animationNameStyles);
542 command.SetAnimationStyles(std::move(animationNameStyles));
543 } else if (strcmp(keyStr, DOM_TRANSITION_ENTER) == 0) {
544 std::vector<std::unordered_map<std::string, std::string>> transitionEnter;
545 GetStyleAnimationName(context, val, transitionEnter);
546 command.SetTransitionEnter(std::move(transitionEnter));
547 } else if (strcmp(keyStr, DOM_TRANSITION_EXIT) == 0) {
548 std::vector<std::unordered_map<std::string, std::string>> transitionExit;
549 GetStyleAnimationName(context, val, transitionExit);
550 command.SetTransitionExit(std::move(transitionExit));
551 } else if (strcmp(keyStr, DOM_SHARED_TRANSITION_NAME) == 0) {
552 std::vector<std::unordered_map<std::string, std::string>> sharedTransitionName;
553 GetStyleAnimationName(context, val, sharedTransitionName);
554 command.SetSharedTransitionName(std::move(sharedTransitionName));
555 } else {
556 LOGD("value is array, key unsupported. Ignoring!");
557 }
558 } else if (val->IsUndefined()) {
559 LOGD("value is undefined. Ignoring!");
560 } else {
561 LOGD("value of unsupported type. Ignoring!");
562 }
563 }
564 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
565 auto pipelineContext = (*delegate)->GetPipelineContext();
566 command.SetPipelineContext(pipelineContext);
567 command.SetStyles(std::move(styles));
568 return true;
569 }
570
AddDomEvent(v8::Local<v8::Context> context,v8::Local<v8::Value> fromMap,JsCommandDomElementOperator & command)571 void AddDomEvent(v8::Local<v8::Context> context, v8::Local<v8::Value> fromMap, JsCommandDomElementOperator& command)
572 {
573 CHECK_RUN_ON(JS);
574 v8::Isolate* isolate = context->GetIsolate();
575 ACE_DCHECK(isolate);
576 v8::HandleScope handleScope(isolate);
577 LOGD("Enter AddDomEvent");
578
579 if (fromMap.IsEmpty() || !fromMap->IsObject()) {
580 return;
581 }
582 v8::Local<v8::Object> mapObj;
583 bool succ = fromMap->ToObject(context).ToLocal(&mapObj);
584 if (!succ) {
585 LOGE("Value to Object fail");
586 return;
587 }
588
589 v8::Local<v8::Array> properties = mapObj->GetOwnPropertyNames(context).ToLocalChecked();
590 uint32_t len = properties->Length();
591 std::vector<std::string> eventsMap;
592 for (uint32_t i = 0; i < len; i++) {
593 v8::Local<v8::Value> key;
594 succ = properties->Get(context, i).ToLocal(&key);
595 if (!succ) {
596 LOGD("key not exist");
597 continue;
598 }
599 v8::Local<v8::Value> val;
600 succ = mapObj->Get(context, key).ToLocal(&val);
601 if (!succ) {
602 LOGD("val not exist");
603 continue;
604 }
605 if (val->IsString()) {
606 v8::String::Utf8Value valV8Str(isolate, val);
607 const char* valStr = *valV8Str;
608 if (valStr != nullptr) {
609 eventsMap.emplace_back(valStr);
610 }
611 } else {
612 LOGW("value of unsupported type. Ignoring!");
613 }
614 }
615 command.AddEvents(std::move(eventsMap));
616 }
617
GetAppInfo(const v8::FunctionCallbackInfo<v8::Value> & args)618 void GetAppInfo(const v8::FunctionCallbackInfo<v8::Value>& args)
619 {
620 CHECK_RUN_ON(JS);
621 LOGD("Enter GetAppInfo");
622 v8::Isolate* isolate = args.GetIsolate();
623 ACE_DCHECK(isolate);
624 v8::HandleScope handleScope(isolate);
625 auto context = isolate->GetCurrentContext();
626 if (context.IsEmpty()) {
627 LOGE("get app info, context is empty!");
628 return;
629 }
630
631 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
632 v8::Local<v8::String> appID = v8::String::NewFromUtf8(isolate, (*delegate)->GetAppID().c_str()).ToLocalChecked();
633 v8::Local<v8::String> appName =
634 v8::String::NewFromUtf8(isolate, (*delegate)->GetAppName().c_str()).ToLocalChecked();
635 v8::Local<v8::String> versionName =
636 v8::String::NewFromUtf8(isolate, (*delegate)->GetVersionName().c_str()).ToLocalChecked();
637 v8::Local<v8::Integer> versionCode = v8::Integer::New(isolate, (*delegate)->GetVersionCode());
638
639 // return the result as an object
640 v8::Local<v8::Object> res = v8::Object::New(isolate);
641 res->Set(context, v8::String::NewFromUtf8(isolate, "appID").ToLocalChecked(), appID).ToChecked();
642 res->Set(context, v8::String::NewFromUtf8(isolate, "appName").ToLocalChecked(), appName).ToChecked();
643 res->Set(context, v8::String::NewFromUtf8(isolate, "versionName").ToLocalChecked(), versionName).ToChecked();
644 res->Set(context, v8::String::NewFromUtf8(isolate, "versionCode").ToLocalChecked(), versionCode).ToChecked();
645 args.GetReturnValue().Set(res);
646 }
647
Terminate(const v8::FunctionCallbackInfo<v8::Value> & args)648 void Terminate(const v8::FunctionCallbackInfo<v8::Value>& args)
649 {
650 CHECK_RUN_ON(JS);
651 v8::Isolate* isolate = args.GetIsolate();
652 v8::HandleScope handleScope(isolate);
653
654 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
655 WeakPtr<PipelineContext> pipelineContextWeak = (*delegate)->GetPipelineContext();
656 auto uiTaskExecutor = (*delegate)->GetUiTask();
657 uiTaskExecutor.PostTask([pipelineContextWeak]() mutable {
658 auto pipelineContext = pipelineContextWeak.Upgrade();
659 if (pipelineContext) {
660 pipelineContext->Finish();
661 }
662 });
663 }
664
RequestFullWindow(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)665 void RequestFullWindow(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
666 {
667 CHECK_RUN_ON(JS);
668 v8::Isolate* isolate = args.GetIsolate();
669 v8::HandleScope handleScope(isolate);
670
671 auto context = isolate->GetCurrentContext();
672 if (context.IsEmpty()) {
673 LOGE("context is empty!");
674 return;
675 }
676
677 int32_t duration = -1; // default scene
678 if (args[index]->IsArray()) {
679 v8::Local<v8::Array> arrayVal = v8::Local<v8::Array>::Cast(args[index]);
680 uint32_t len = arrayVal->Length();
681 if (len == CUSTOM_FULL_WINDOW_LENGTH) {
682 v8::Local<v8::Value> jsParam = arrayVal->Get(context, 0).ToLocalChecked();
683 if (jsParam->IsObject()) {
684 v8::Local<v8::Object> valObj = jsParam->ToObject(context).ToLocalChecked();
685 v8::Local<v8::Array> valObjProperties = valObj->GetOwnPropertyNames(context).ToLocalChecked();
686 v8::Local<v8::Value> valObjKey;
687 bool succ = valObjProperties->Get(context, 0).ToLocal(&valObjKey);
688 v8::String::Utf8Value jsDurationKey(isolate, valObjKey);
689 if (succ && *jsDurationKey && (std::strcmp(*jsDurationKey, APP_REQUEST_FULL_WINDOW_DURATION) == 0)) {
690 v8::Local<v8::Value> valObjVal = valObj->Get(context, valObjKey).ToLocalChecked();
691 v8::String::Utf8Value jsDurationValue(isolate, valObjVal);
692 if (*jsDurationValue) {
693 duration = StringToInt(*jsDurationValue);
694 }
695 }
696 }
697 if (duration < 0) {
698 duration = -1; // default scene
699 }
700 }
701 }
702 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
703 WeakPtr<PipelineContext> pipelineContextWeak = (*delegate)->GetPipelineContext();
704 auto uiTaskExecutor = (*delegate)->GetUiTask();
705 uiTaskExecutor.PostTask([pipelineContextWeak, duration]() mutable {
706 auto pipelineContext = pipelineContextWeak.Upgrade();
707 if (pipelineContext) {
708 pipelineContext->RequestFullWindow(duration);
709 }
710 });
711 }
712
GetPackageInfoCallback(v8::Local<v8::Context> context,const v8::Local<v8::Value> & jsMessage,const char * callbackId)713 void GetPackageInfoCallback(
714 v8::Local<v8::Context> context, const v8::Local<v8::Value>& jsMessage, const char* callbackId)
715 {
716 CHECK_RUN_ON(JS);
717 LOGD("Enter GetPackageInfoCallback");
718 v8::Isolate* isolate = context->GetIsolate();
719 ACE_DCHECK(isolate);
720 v8::HandleScope handleScope(isolate);
721 v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>> pContext;
722 pContext.Reset(isolate, context);
723
724 if (jsMessage.IsEmpty() || !jsMessage->IsObject()) {
725 LOGE("GetPackageInfoCallback: jsMessage is not Object");
726 V8EngineInstance::CallJs(isolate, pContext, callbackId,
727 std::string("{\"arguments\":[\"jsMessage is not Object\",200],\"method\":\"fail\"}"), false);
728 return;
729 }
730
731 auto messageObject = jsMessage->ToObject(context).ToLocalChecked();
732 v8::Local<v8::String> tempStr;
733 if (messageObject->Get(context, v8::String::NewFromUtf8(isolate, APP_PACKAGE_NAME).ToLocalChecked())
734 .ToLocalChecked()
735 ->IsString()) {
736 tempStr = messageObject->Get(context, v8::String::NewFromUtf8(isolate, APP_PACKAGE_NAME).ToLocalChecked())
737 .ToLocalChecked()
738 ->ToString(context)
739 .ToLocalChecked();
740 } else {
741 V8EngineInstance::CallJs(isolate, pContext, callbackId,
742 std::string("{\"arguments\":[\"packageName is not available string\",202],\"method\":\"fail\"}"), false);
743 return;
744 }
745
746 v8::String::Utf8Value utf8Str(isolate, tempStr);
747 if (*utf8Str == nullptr) {
748 V8EngineInstance::CallJs(isolate, pContext, callbackId,
749 std::string("{\"arguments\":[\"packageName is not available string\",202],\"method\":\"fail\"}"), false);
750 return;
751 }
752 std::string packageName(*utf8Str);
753 AceBundleInfo bundleInfo;
754 if (AceApplicationInfo::GetInstance().GetBundleInfo(packageName, bundleInfo)) {
755 auto infoList = JsonUtil::Create(true);
756 infoList->Put("versionName", bundleInfo.versionName.c_str());
757 infoList->Put("versionCode", std::to_string(bundleInfo.versionCode).c_str());
758 V8EngineInstance::CallJs(isolate, pContext, callbackId,
759 std::string("{\"arguments\":[").append(infoList->ToString()).append("],\"method\":\"success\"}"), false);
760 } else {
761 LOGE("can not get info by GetBundleInfo");
762 V8EngineInstance::CallJs(isolate, pContext, callbackId,
763 std::string("{\"arguments\":[\"can not get info\",200],\"method\":\"fail\"}"), false);
764 }
765 }
766
GetPackageInfo(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)767 void GetPackageInfo(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
768 {
769 CHECK_RUN_ON(JS);
770 LOGD("Enter GetPackageInfo");
771 if (!args[index]->IsObject()) {
772 LOGE("GetPackageInfo: argv is not Object");
773 return;
774 }
775
776 if (!args[index]->IsArray()) {
777 LOGE("GetPackageInfo: argv is not Array");
778 return;
779 }
780
781 v8::Isolate* isolate = args.GetIsolate();
782 ACE_DCHECK(isolate);
783 v8::HandleScope handleScope(isolate);
784 auto context = isolate->GetCurrentContext();
785 if (context.IsEmpty()) {
786 LOGE("GetPackageInfo, context is empty!");
787 return;
788 }
789 v8::Local<v8::Array> arrayVal = v8::Local<v8::Array>::Cast(args[index]);
790 uint32_t len = arrayVal->Length();
791 if (len < PAG_INFO_ARGS_LEN) {
792 LOGE("GetPackageInfo: invalid callback value");
793 return;
794 }
795 v8::Local<v8::Value> jsMessage = arrayVal->Get(context, PAG_INFO_ARGS_MSG_IDX).ToLocalChecked();
796 v8::Local<v8::Value> jsCallBackId = arrayVal->Get(context, 1).ToLocalChecked();
797 v8::String::Utf8Value callbackId(isolate, jsCallBackId);
798 LOGD("system app getPackageInfo callBackID is %{public}s", *callbackId);
799
800 if (*callbackId != nullptr) {
801 GetPackageInfoCallback(context, jsMessage, *callbackId);
802 }
803 }
804
SetScreenOnVisible(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)805 void SetScreenOnVisible(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
806 {
807 CHECK_RUN_ON(JS);
808 v8::Isolate* isolate = args.GetIsolate();
809 if (isolate == nullptr) {
810 LOGE("SetScreenOnVisible: isolate is nullptr");
811 return;
812 }
813 v8::HandleScope handleScope(isolate);
814 auto context = isolate->GetCurrentContext();
815 if (context.IsEmpty()) {
816 LOGE("SetScreenOnVisible, context is empty!");
817 return;
818 }
819 std::map<std::string, std::string> params;
820 std::string callbackId;
821 if (!GetParamsWithCallbackId(context, v8::Local<v8::Array>::Cast(args[index]), params, callbackId)) {
822 LOGE("SetScreenOnVisible, get params or callbackId failed!");
823 return;
824 }
825 v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>> pContext;
826 pContext.Reset(isolate, context);
827 std::string flag = "fail";
828 auto iter = params.find(APP_SCREEN_ON_VISIBLE_FLAG);
829 if (iter != params.end()) {
830 flag = iter->second;
831 }
832 if (!StringToBool(flag)) {
833 V8EngineInstance::CallJs(isolate, pContext, callbackId,
834 R"({"arguments":["fail to set false flag in rich platform", 200],"method":"fail"})");
835 } else {
836 V8EngineInstance::CallJs(isolate, pContext, callbackId, R"({"arguments":[],"method":"success"})");
837 }
838 pContext.Reset();
839 }
840
SetSwipeToDismiss(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)841 void SetSwipeToDismiss(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
842 {
843 CHECK_RUN_ON(JS);
844 v8::Isolate* isolate = args.GetIsolate();
845 if (isolate == nullptr) {
846 LOGE("SetSwipeToDismiss: isolate is nullptr");
847 return;
848 }
849 v8::HandleScope handleScope(isolate);
850 auto context = isolate->GetCurrentContext();
851 if (context.IsEmpty()) {
852 LOGE("SetSwipeToDismiss, context is empty!");
853 return;
854 }
855
856 if (!args[index]->IsArray()) {
857 LOGE("SetSwipeToDismiss: argv is not Array");
858 return;
859 }
860
861 v8::Local<v8::Array> arrayVal = v8::Local<v8::Array>::Cast(args[index]);
862 uint32_t len = arrayVal->Length();
863 if (len < 2) {
864 LOGE("SetSwipeToDismiss: invalid callback value");
865 return;
866 }
867
868 bool forbidQuit = false;
869 v8::Local<v8::Value> flag = arrayVal->Get(context, 0).ToLocalChecked();
870 if (flag->IsBoolean()) {
871 forbidQuit = flag->BooleanValue(isolate);
872 }
873
874 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
875 WeakPtr<PipelineContext> pipelineContextWeak = (*delegate)->GetPipelineContext();
876 auto uiTaskExecutor = (*delegate)->GetUiTask();
877 uiTaskExecutor.PostTask([pipelineContextWeak, forbidQuit]() mutable {
878 auto pipelineContext = pipelineContextWeak.Upgrade();
879 if (pipelineContext) {
880 pipelineContext->SetForbidPlatformQuit(forbidQuit);
881 }
882 });
883 }
884
JsHandleAppApi(const v8::FunctionCallbackInfo<v8::Value> & args,const std::string & methodName,int32_t index)885 void JsHandleAppApi(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName, int32_t index)
886 {
887 LOGD("Enter JsHandleAppApi");
888 if (methodName == APP_GET_INFO) {
889 GetAppInfo(args);
890 } else if (methodName == APP_TERMINATE) {
891 Terminate(args);
892 } else if (methodName == APP_GET_PACKAGE_INFO) {
893 GetPackageInfo(args, index);
894 } else if (methodName == APP_REQUEST_FULL_WINDOW) {
895 RequestFullWindow(args, index);
896 } else if (methodName == APP_SCREEN_ON_VISIBLE) {
897 SetScreenOnVisible(args, index);
898 } else if (methodName == APP_SET_SWIPE_TO_DISMISS) {
899 SetSwipeToDismiss(args, index);
900 } else {
901 LOGW("system.app not support method = %{public}s", methodName.c_str());
902 }
903 }
904
GetLocale(const v8::FunctionCallbackInfo<v8::Value> & args)905 void GetLocale(const v8::FunctionCallbackInfo<v8::Value>& args)
906 {
907 CHECK_RUN_ON(JS);
908 LOGD("Enter GetLocale");
909 v8::Isolate* isolate = args.GetIsolate();
910 ACE_DCHECK(isolate);
911 v8::HandleScope handleScope(isolate);
912 auto context = isolate->GetCurrentContext();
913 if (context.IsEmpty()) {
914 LOGW("get configuration, context is empty!");
915 return;
916 }
917
918 v8::Local<v8::String> language =
919 v8::String::NewFromUtf8(isolate, AceApplicationInfo::GetInstance().GetLanguage().c_str()).ToLocalChecked();
920 v8::Local<v8::String> countryOrRegion =
921 v8::String::NewFromUtf8(isolate, AceApplicationInfo::GetInstance().GetCountryOrRegion().c_str())
922 .ToLocalChecked();
923
924 v8::Local<v8::String> dir = v8::String::NewFromUtf8(
925 isolate, AceApplicationInfo::GetInstance().IsRightToLeft() ? LOCALE_TEXT_DIR_RTL : LOCALE_TEXT_DIR_LTR)
926 .ToLocalChecked();
927 v8::Local<v8::String> unicodeSetting =
928 v8::String::NewFromUtf8(isolate, AceApplicationInfo::GetInstance().GetUnicodeSetting().c_str())
929 .ToLocalChecked();
930
931 v8::Local<v8::Object> res = v8::Object::New(isolate);
932 res->Set(context, v8::String::NewFromUtf8(isolate, LOCALE_LANGUAGE).ToLocalChecked(), language).ToChecked();
933 res->Set(context, v8::String::NewFromUtf8(isolate, LOCALE_COUNTRY_OR_REGION).ToLocalChecked(), countryOrRegion)
934 .ToChecked();
935 res->Set(context, v8::String::NewFromUtf8(isolate, LOCALE_TEXT_DIR).ToLocalChecked(), dir).ToChecked();
936 res->Set(context, v8::String::NewFromUtf8(isolate, LOCALE_UNICODE_SETTING).ToLocalChecked(), unicodeSetting)
937 .ToChecked();
938 args.GetReturnValue().Set(res);
939 }
940
JsSetLocale(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)941 void JsSetLocale(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
942 {
943 CHECK_RUN_ON(JS);
944 LOGD("Enter JsGetLocale");
945 v8::Isolate* isolate = args.GetIsolate();
946 ACE_DCHECK(isolate);
947 v8::HandleScope handleScope(isolate);
948
949 v8::String::Utf8Value argStr(isolate, args[index]);
950 if (!(*argStr)) {
951 return;
952 }
953 std::unique_ptr<JsonValue> localeJson = JsonUtil::ParseJsonString(*argStr);
954
955 if (localeJson) {
956 std::string language;
957 if (localeJson->GetValue(LOCALE_LANGUAGE) != nullptr && localeJson->GetValue(LOCALE_LANGUAGE)->IsString()) {
958 language = localeJson->GetValue(LOCALE_LANGUAGE)->GetString();
959 }
960 std::string countryOrRegion;
961 if (localeJson->GetValue(LOCALE_COUNTRY_OR_REGION) != nullptr &&
962 localeJson->GetValue(LOCALE_COUNTRY_OR_REGION)->IsString()) {
963 countryOrRegion = localeJson->GetValue(LOCALE_COUNTRY_OR_REGION)->GetString();
964 }
965 if (!countryOrRegion.empty() && !language.empty()) {
966 auto delegate =
967 static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
968 (*delegate)->ChangeLocale(language, countryOrRegion);
969 }
970 }
971 }
972
JsSetTimer(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index,bool isInterval)973 void JsSetTimer(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index, bool isInterval)
974 {
975 CHECK_RUN_ON(JS);
976 LOGD("Enter JsSetTimer");
977 v8::Isolate* isolate = args.GetIsolate();
978 ACE_DCHECK(isolate);
979 v8::HandleScope handleScope(isolate);
980 auto context = isolate->GetCurrentContext();
981 if (context.IsEmpty()) {
982 LOGE("set time out or interval, context is empty!");
983 return;
984 }
985
986 if (args[index]->IsArray()) {
987 v8::Local<v8::Array> arrayVal = v8::Local<v8::Array>::Cast(args[index]);
988 uint32_t len = arrayVal->Length();
989 if (len < 2) {
990 LOGW("JsSetTimer: invalid callback value");
991 return;
992 }
993 v8::Local<v8::Value> jsCallBackId = arrayVal->Get(context, 0).ToLocalChecked();
994 v8::Local<v8::Value> jsDelay = arrayVal->Get(context, 1).ToLocalChecked();
995 v8::String::Utf8Value callBackId(isolate, jsCallBackId);
996 v8::String::Utf8Value delay(isolate, jsDelay);
997 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
998 if (*callBackId && *delay) {
999 (*delegate)->WaitTimer(*callBackId, *delay, isInterval, true);
1000 }
1001 }
1002 }
1003
JsClearTimeout(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)1004 void JsClearTimeout(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
1005 {
1006 CHECK_RUN_ON(JS);
1007 LOGD("Enter JsClearTimeout");
1008 v8::Isolate* isolate = args.GetIsolate();
1009 ACE_DCHECK(isolate);
1010 v8::HandleScope handleScope(isolate);
1011 auto context = isolate->GetCurrentContext();
1012 if (context.IsEmpty()) {
1013 LOGE("clear timeout or clear interval, context is empty!");
1014 return;
1015 }
1016
1017 if (args[index]->IsArray()) {
1018 v8::Local<v8::Array> arrayVal = v8::Local<v8::Array>::Cast(args[index]);
1019 uint32_t len = arrayVal->Length();
1020 if (len < 1) {
1021 LOGW("JsClearTimeout: invalid callback value");
1022 return;
1023 }
1024 v8::Local<v8::Value> jsCallBackId = arrayVal->Get(context, 0).ToLocalChecked();
1025 v8::String::Utf8Value callBackId(isolate, jsCallBackId);
1026 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1027 if (*callBackId) {
1028 (*delegate)->ClearTimer(*callBackId);
1029 }
1030 }
1031 }
1032
JsAddListener(v8::Local<v8::Context> context,v8::Local<v8::Value> val)1033 void JsAddListener(v8::Local<v8::Context> context, v8::Local<v8::Value> val)
1034 {
1035 CHECK_RUN_ON(JS);
1036 v8::Isolate* isolate = context->GetIsolate();
1037 ACE_DCHECK(isolate);
1038 v8::HandleScope handleScope(isolate);
1039 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1040
1041 if (val->IsObject() && val->IsArray()) {
1042 v8::Local<v8::Array> valArray = v8::Local<v8::Array>::Cast(val);
1043 uint32_t len = valArray->Length();
1044 if (len == 0) {
1045 return;
1046 }
1047 v8::Local<v8::Value> jsListenerId = valArray->Get(context, 0).ToLocalChecked();
1048 v8::String::Utf8Value listenerIdStr(isolate, jsListenerId);
1049 auto mediaQuery = (*delegate)->GetMediaQueryInfoInstance();
1050 if (mediaQuery && *listenerIdStr) {
1051 mediaQuery->SetListenerId(std::string(*listenerIdStr));
1052 }
1053 }
1054 }
1055
JsParseRouteUrl(const v8::FunctionCallbackInfo<v8::Value> & args,const std::string & key,int32_t index)1056 std::string JsParseRouteUrl(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& key, int32_t index)
1057 {
1058 CHECK_RUN_ON(JS);
1059 LOGD("Enter JsParseRouteUrl");
1060 std::string pageRoute;
1061 v8::Isolate* isolate = args.GetIsolate();
1062 ACE_DCHECK(isolate);
1063 v8::HandleScope handleScope(isolate);
1064
1065 v8::String::Utf8Value argsJsStr(isolate, args[index]);
1066 if (!(*argsJsStr)) {
1067 return "";
1068 }
1069 std::string argsStr(*argsJsStr);
1070 std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(argsStr);
1071
1072 if (argsPtr != nullptr && argsPtr->GetValue(key) != nullptr && argsPtr->GetValue(key)->IsString()) {
1073 pageRoute = argsPtr->GetValue(key)->GetString();
1074 }
1075 LOGD("JsParseRouteUrl pageRoute = %{private}s", pageRoute.c_str());
1076
1077 return pageRoute;
1078 }
1079
JsParseRouteUrlSpecial(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)1080 std::string JsParseRouteUrlSpecial(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
1081 {
1082 CHECK_RUN_ON(JS);
1083 std::string pageRoute;
1084 v8::Isolate* isolate = args.GetIsolate();
1085 ACE_DCHECK(isolate);
1086 v8::HandleScope handleScope(isolate);
1087
1088 v8::String::Utf8Value argsJsStr(isolate, args[index]);
1089 if (!(*argsJsStr)) {
1090 return "";
1091 }
1092 std::string argsStr(*argsJsStr);
1093 std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(argsStr);
1094
1095 if (argsPtr->Contains(ROUTE_KEY_URI)) {
1096 pageRoute = argsPtr->GetValue(ROUTE_KEY_URI)->GetString();
1097 } else if (argsPtr->Contains(ROUTE_KEY_PATH)) {
1098 pageRoute = argsPtr->GetValue(ROUTE_KEY_PATH)->GetString();
1099 }
1100 LOGD("JsParseRouteUrl pageRoute = %{private}s", pageRoute.c_str());
1101
1102 return pageRoute;
1103 }
1104
JsParseRouteOverwrite(const v8::FunctionCallbackInfo<v8::Value> & args,const std::string & key,int32_t index)1105 bool JsParseRouteOverwrite(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& key, int32_t index)
1106 {
1107 CHECK_RUN_ON(JS);
1108 v8::Isolate* isolate = args.GetIsolate();
1109 ACE_DCHECK(isolate);
1110 v8::HandleScope handleScope(isolate);
1111 v8::String::Utf8Value argsJsStr(isolate, args[index]);
1112 if (!(*argsJsStr)) {
1113 return false;
1114 }
1115
1116 std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(*argsJsStr);
1117 if (argsPtr != nullptr && argsPtr->Contains(key)) {
1118 return true;
1119 }
1120 return false;
1121 }
1122
JsParseRouteParams(const v8::FunctionCallbackInfo<v8::Value> & args,const std::string & key,int32_t index)1123 std::string JsParseRouteParams(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& key, int32_t index)
1124 {
1125 CHECK_RUN_ON(JS);
1126 v8::Isolate* isolate = args.GetIsolate();
1127 ACE_DCHECK(isolate);
1128 v8::HandleScope handleScope(isolate);
1129 v8::String::Utf8Value argsJsStr(isolate, args[index]);
1130 if (!(*argsJsStr)) {
1131 return "";
1132 }
1133
1134 std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(*argsJsStr);
1135 std::string params;
1136 if (argsPtr != nullptr && argsPtr->Contains(key) && argsPtr->GetValue(key)->IsObject()) {
1137 params = argsPtr->GetValue(key)->ToString();
1138 }
1139 return params;
1140 }
1141
JsParseIntParams(const v8::FunctionCallbackInfo<v8::Value> & args,const std::string & key,int32_t index)1142 int32_t JsParseIntParams(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& key, int32_t index)
1143 {
1144 CHECK_RUN_ON(JS);
1145 v8::Isolate* isolate = args.GetIsolate();
1146 ACE_DCHECK(isolate);
1147 v8::HandleScope handleScope(isolate);
1148 v8::String::Utf8Value argsJsStr(isolate, args[index]);
1149 if (!(*argsJsStr)) {
1150 return 0;
1151 }
1152
1153 std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(*argsJsStr);
1154 if (argsPtr != nullptr && argsPtr->Contains(key) && argsPtr->GetValue(key)->IsNumber()) {
1155 return argsPtr->GetValue(key)->GetInt();
1156 }
1157 return 0;
1158 }
1159
EnableAlertBeforeBackPage(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)1160 void EnableAlertBeforeBackPage(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
1161 {
1162 CHECK_RUN_ON(JS);
1163 LOGD("Enter EnableAlertBeforeBackPage");
1164 v8::Isolate* isolate = args.GetIsolate();
1165 ACE_DCHECK(isolate);
1166 v8::HandleScope handleScope(isolate);
1167
1168 v8::String::Utf8Value argsJsStr(isolate, args[index]);
1169 if (!(*argsJsStr)) {
1170 LOGE("disableAlertBeforeBackPage args is null");
1171 return;
1172 }
1173
1174 v8::Local<v8::External> data = v8::Local<v8::External>::Cast(args.Data());
1175 V8EngineInstance* engineInstance = static_cast<V8EngineInstance*>(data->Value());
1176
1177 std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(*argsJsStr);
1178 if (argsPtr != nullptr && argsPtr->IsObject()) {
1179 if (argsPtr->GetValue(PROMPT_KEY_MESSAGE) == nullptr || !argsPtr->GetValue(PROMPT_KEY_MESSAGE)->IsString()) {
1180 LOGE("enableAlertBeforeBackPage message is null");
1181 const std::string fail = JsParseRouteUrl(args, COMMON_FAIL, index);
1182 const std::string complete = JsParseRouteUrl(args, COMMON_COMPLETE, index);
1183 engineInstance->CallJs(fail, R"({"errMsg":"enableAlertBeforeBackPage:massage is null"})", false);
1184 engineInstance->CallJs(complete, R"({"errMsg":"enableAlertBeforeBackPage:massage is null"})", false);
1185 return;
1186 }
1187 } else {
1188 LOGE("enableAlertBeforeBackPage message is null");
1189 std::string callBackStr(*argsJsStr);
1190 // Get callbackId and clear redundant symbols
1191 if (callBackStr.size() > 2 && callBackStr.front() == '\"' && callBackStr.back() == '\"') {
1192 callBackStr = callBackStr.substr(1, callBackStr.size() - 2);
1193 engineInstance->CallJs(callBackStr,
1194 R"({"arguments":[{"errMsg":"enableAlertBeforeBackPage:massage is null"}],"method":"fail"})", false);
1195 }
1196 return;
1197 }
1198
1199 const std::string message = JsParseRouteUrl(args, PROMPT_KEY_MESSAGE, index);
1200 const std::string success = JsParseRouteUrl(args, COMMON_SUCCESS, index);
1201 const std::string fail = JsParseRouteUrl(args, COMMON_FAIL, index);
1202 const std::string complete = JsParseRouteUrl(args, COMMON_COMPLETE, index);
1203 auto callback = [engineInstance, success, fail, complete](int32_t callbackType) {
1204 switch (callbackType) {
1205 case 1:
1206 engineInstance->CallJs(success, R"({"errMsg":"enableAlertBeforeBackPage:ok"})", false);
1207 engineInstance->CallJs(complete, R"({"errMsg":"enableAlertBeforeBackPage:ok"})", false);
1208 break;
1209 case 0:
1210 engineInstance->CallJs(fail, R"({"errMsg":"enableAlertBeforeBackPage:fail cancel"})", false);
1211 engineInstance->CallJs(complete, R"({"errMsg":"enableAlertBeforeBackPage:fail cancel"})", false);
1212 break;
1213 default:
1214 LOGE("callbackType is invalid");
1215 break;
1216 }
1217 };
1218
1219 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1220 (*delegate)->EnableAlertBeforeBackPage(message, std::move(callback));
1221 }
1222
DisableAlertBeforeBackPage(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)1223 void DisableAlertBeforeBackPage(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
1224 {
1225 CHECK_RUN_ON(JS);
1226 LOGD("Enter EnableAlertBeforeBackPage");
1227 v8::Isolate* isolate = args.GetIsolate();
1228 ACE_DCHECK(isolate);
1229 v8::HandleScope handleScope(isolate);
1230 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1231 (*delegate)->DisableAlertBeforeBackPage();
1232
1233 v8::String::Utf8Value argsJsStr(isolate, args[index]);
1234 if (!(*argsJsStr)) {
1235 LOGE("disableAlertBeforeBackPage args is null");
1236 return;
1237 }
1238 std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(*argsJsStr);
1239
1240 v8::Local<v8::External> data = v8::Local<v8::External>::Cast(args.Data());
1241 V8EngineInstance* engineInstance = static_cast<V8EngineInstance*>(data->Value());
1242 if (argsPtr->IsObject()) {
1243 const std::string success = JsParseRouteUrl(args, COMMON_SUCCESS, index);
1244 const std::string complete = JsParseRouteUrl(args, COMMON_COMPLETE, index);
1245 engineInstance->CallJs(success, R"({"errMsg":"disableAlertBeforeBackPage:ok"})", false);
1246 engineInstance->CallJs(complete, R"({"errMsg":"disableAlertBeforeBackPage:ok"})", false);
1247 return;
1248 }
1249
1250 std::string callBackStr(*argsJsStr);
1251 // Get callbackId and clear redundant symbols
1252 if (callBackStr.size() > 2 && callBackStr.front() == '\"' && callBackStr.back() == '\"') {
1253 callBackStr = callBackStr.substr(1, callBackStr.size() - 2);
1254 engineInstance->CallJs(
1255 callBackStr, R"({"arguments":[{"errMsg":"disableAlertBeforeBackPage:ok"}],"method":"success"})", false);
1256 }
1257 }
1258
PostponePageTransition(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)1259 void PostponePageTransition(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
1260 {
1261 CHECK_RUN_ON(JS);
1262 LOGD("Enter PostponePageTransition");
1263 v8::Isolate* isolate = args.GetIsolate();
1264 ACE_DCHECK(isolate);
1265 v8::HandleScope handleScope(isolate);
1266 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1267 (*delegate)->PostponePageTransition();
1268 }
1269
LaunchPageTransition(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)1270 void LaunchPageTransition(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
1271 {
1272 CHECK_RUN_ON(JS);
1273 LOGD("Enter LaunchPageTransition");
1274 v8::Isolate* isolate = args.GetIsolate();
1275 ACE_DCHECK(isolate);
1276 v8::HandleScope handleScope(isolate);
1277 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1278 (*delegate)->LaunchPageTransition();
1279 }
1280
JsHandlePageRoute(const v8::FunctionCallbackInfo<v8::Value> & args,const std::string & methodName,int32_t index)1281 void JsHandlePageRoute(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName, int32_t index)
1282 {
1283 CHECK_RUN_ON(JS);
1284 LOGD("Enter JsHandlePageRoute");
1285 v8::Isolate* isolate = args.GetIsolate();
1286 ACE_DCHECK(isolate);
1287 v8::HandleScope handleScope(isolate);
1288
1289 std::string uri;
1290 if (methodName == ROUTE_PAGE_BACK) {
1291 uri = JsParseRouteUrlSpecial(args, index);
1292 } else {
1293 uri = JsParseRouteUrl(args, ROUTE_KEY_URI, index);
1294 }
1295
1296 std::string params = JsParseRouteParams(args, ROUTE_KEY_PARAMS, index);
1297 bool dontOverwrite = JsParseRouteOverwrite(args, ROUTE_KEY_DONT_OVERWRITE, index);
1298
1299 std::unique_ptr<JsonValue> routerParamsData = JsonUtil::Create(true);
1300 routerParamsData->Put("paramsData", JsonUtil::ParseJsonString(params));
1301 routerParamsData->Put("dontOverwrite", dontOverwrite);
1302 params = routerParamsData->ToString();
1303
1304 static const std::unordered_map<std::string,
1305 void (*)(const v8::FunctionCallbackInfo<v8::Value>&, const std::string&, const std::string&, v8::Isolate*)>
1306 pageRouteOperators = {
1307 { ROUTE_PAGE_PUSH,
1308 [](const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& uri, const std::string& params,
1309 v8::Isolate* isolate) {
1310 LOGD("JsPushRoute uri = %{private}s", uri.c_str());
1311 ACE_DCHECK(isolate);
1312 auto delegate =
1313 static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1314 (*delegate)->Push(uri, params);
1315 } },
1316 { ROUTE_PAGE_REPLACE,
1317 [](const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& uri, const std::string& params,
1318 v8::Isolate* isolate) {
1319 LOGD("JsReplaceRoute uri = %{private}s", uri.c_str());
1320 ACE_DCHECK(isolate);
1321 auto delegate =
1322 static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1323 (*delegate)->Replace(uri, params);
1324 } },
1325 { ROUTE_PAGE_BACK,
1326 [](const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& uri, const std::string& params,
1327 v8::Isolate* isolate) {
1328 LOGD("JsBackRoute uri = %{private}s", uri.c_str());
1329 ACE_DCHECK(isolate);
1330 auto delegate =
1331 static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1332 (*delegate)->Back(uri);
1333 } },
1334 { ROUTE_PAGE_CLEAR,
1335 [](const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& uri, const std::string& params,
1336 v8::Isolate* isolate) {
1337 LOGD("JsClearPageRoute");
1338 ACE_DCHECK(isolate);
1339 auto delegate =
1340 static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1341 (*delegate)->Clear();
1342 } },
1343 { ROUTE_PAGE_GET_LENGTH,
1344 [](const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& uri, const std::string& params,
1345 v8::Isolate* isolate) {
1346 ACE_DCHECK(isolate);
1347 auto delegate =
1348 static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1349 int32_t routeLength = (*delegate)->GetStackSize();
1350 std::string indexLength = std::to_string(routeLength);
1351 LOGD("JsGetLengthRoute routeLength = %{private}s", indexLength.c_str());
1352 v8::Local<v8::String> lenStr =
1353 v8::String::NewFromUtf8(isolate, indexLength.c_str()).ToLocalChecked();
1354 args.GetReturnValue().Set(lenStr);
1355 } },
1356 { ROUTE_PAGE_GET_STATE,
1357 [](const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& uri, const std::string& params,
1358 v8::Isolate* isolate) {
1359 int32_t routeIndex = 0;
1360 std::string routeName;
1361 std::string routePath;
1362 ACE_DCHECK(isolate);
1363 auto delegate =
1364 static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1365 (*delegate)->GetState(routeIndex, routeName, routePath);
1366 LOGD("JsGetStateRoute index=%{private}d name=%{private}s path=%{private}s", routeIndex,
1367 routeName.c_str(), routePath.c_str());
1368 auto context = isolate->GetCurrentContext();
1369 if (context.IsEmpty()) {
1370 LOGE("get router state, context is empty!");
1371 return;
1372 }
1373 v8::Local<v8::Object> res = v8::Object::New(isolate);
1374 v8::Local<v8::Integer> index = v8::Integer::New(isolate, routeIndex);
1375 v8::Local<v8::String> name = v8::String::NewFromUtf8(isolate, routeName.c_str()).ToLocalChecked();
1376 v8::Local<v8::String> path = v8::String::NewFromUtf8(isolate, routePath.c_str()).ToLocalChecked();
1377 res->Set(context, v8::String::NewFromUtf8(isolate, "index").ToLocalChecked(), index).ToChecked();
1378 res->Set(context, v8::String::NewFromUtf8(isolate, "name").ToLocalChecked(), name).ToChecked();
1379 res->Set(context, v8::String::NewFromUtf8(isolate, "path").ToLocalChecked(), path).ToChecked();
1380 args.GetReturnValue().Set(res);
1381 } },
1382 };
1383 // execute the page operation according to the actions defined at pageRouteOperators.
1384 auto operatorIter = pageRouteOperators.find(methodName);
1385 if (operatorIter != pageRouteOperators.end()) {
1386 operatorIter->second(args, uri, params, isolate);
1387 } else if (methodName == ROUTE_ENABLE_ALERT_BEFORE_BACK_PAGE) {
1388 EnableAlertBeforeBackPage(args, index);
1389 } else if (methodName == ROUTE_DISABLE_ALERT_BEFORE_BACK_PAGE) {
1390 DisableAlertBeforeBackPage(args, index);
1391 } else if (methodName == ROUTE_POSTPONE) {
1392 PostponePageTransition(args, index);
1393 } else if (methodName == ROUTE_LAUNCH) {
1394 LaunchPageTransition(args, index);
1395 } else {
1396 LOGW("system.router not support method = %{private}s", methodName.c_str());
1397 }
1398 }
1399
JsParseDialogButtons(const v8::FunctionCallbackInfo<v8::Value> & args,const std::string & key,int32_t index)1400 std::vector<ButtonInfo> JsParseDialogButtons(
1401 const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& key, int32_t index)
1402 {
1403 CHECK_RUN_ON(JS);
1404 LOGD("Enter ParseDialogButtons");
1405 v8::Isolate* isolate = args.GetIsolate();
1406 ACE_DCHECK(isolate);
1407 v8::HandleScope handleScope(isolate);
1408
1409 std::vector<ButtonInfo> dialogButtons;
1410 v8::String::Utf8Value argsJsStr(isolate, args[index]);
1411 if (!(*argsJsStr)) {
1412 return dialogButtons;
1413 }
1414 std::string argsStr(*argsJsStr);
1415
1416 std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(argsStr);
1417 if (argsPtr != nullptr && argsPtr->GetValue(key) != nullptr && argsPtr->GetValue(key)->IsArray()) {
1418 for (int32_t i = 0; i < argsPtr->GetValue(key)->GetArraySize(); i++) {
1419 auto button = argsPtr->GetValue(key)->GetArrayItem(i);
1420 if (!button->GetValue("text")->IsString()) {
1421 continue;
1422 }
1423 ButtonInfo buttonInfo;
1424 if (button->GetValue("text")) {
1425 buttonInfo.text = button->GetValue("text")->GetString();
1426 }
1427 if (button->GetValue("color")) {
1428 buttonInfo.textColor = button->GetValue("color")->GetString();
1429 }
1430 dialogButtons.emplace_back(buttonInfo);
1431 }
1432 }
1433 return dialogButtons;
1434 }
1435
JsShowToast(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)1436 void JsShowToast(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
1437 {
1438 CHECK_RUN_ON(JS);
1439 LOGD("Enter JsShowToast");
1440 v8::Isolate* isolate = args.GetIsolate();
1441 ACE_DCHECK(isolate);
1442 v8::HandleScope handleScope(isolate);
1443
1444 v8::String::Utf8Value argsJsStr(isolate, args[index]);
1445 if (!(*argsJsStr)) {
1446 return;
1447 }
1448 std::string argsStr(*argsJsStr);
1449
1450 std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(argsStr);
1451 std::string message;
1452 int32_t duration = 0;
1453 std::string bottom;
1454 if (argsPtr != nullptr) {
1455 if (argsPtr->GetValue(PROMPT_KEY_MESSAGE) != nullptr) {
1456 if (argsPtr->GetValue(PROMPT_KEY_MESSAGE)->IsString()) {
1457 message = argsPtr->GetValue(PROMPT_KEY_MESSAGE)->GetString();
1458 } else {
1459 message = argsPtr->GetValue(PROMPT_KEY_MESSAGE)->ToString();
1460 }
1461 }
1462 if (argsPtr->GetValue(PROMPT_KEY_DURATION) != nullptr && argsPtr->GetValue(PROMPT_KEY_DURATION)->IsNumber()) {
1463 duration = argsPtr->GetValue(PROMPT_KEY_DURATION)->GetInt();
1464 }
1465 if (argsPtr->GetValue(PROMPT_KEY_BOTTOM) != nullptr) {
1466 if (argsPtr->GetValue(PROMPT_KEY_BOTTOM)->IsString()) {
1467 bottom = argsPtr->GetValue(PROMPT_KEY_BOTTOM)->GetString();
1468 } else if (argsPtr->GetValue(PROMPT_KEY_BOTTOM)->IsNumber()) {
1469 bottom = std::to_string(argsPtr->GetValue(PROMPT_KEY_BOTTOM)->GetInt());
1470 }
1471 }
1472 }
1473 LOGD("JsShowToast message = %{private}s duration = %{private}d bottom = %{private}s", message.c_str(), duration,
1474 bottom.c_str());
1475
1476 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1477 (*delegate)->ShowToast(message, duration, bottom);
1478 }
1479
JsShowDialog(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)1480 void JsShowDialog(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
1481 {
1482 CHECK_RUN_ON(JS);
1483 LOGD("Enter JsShowDialog");
1484 v8::Isolate* isolate = args.GetIsolate();
1485 ACE_DCHECK(isolate);
1486 v8::HandleScope handleScope(isolate);
1487
1488 const std::string title = JsParseRouteUrl(args, PROMPT_KEY_TITLE, index);
1489 const std::string message = JsParseRouteUrl(args, PROMPT_KEY_MESSAGE, index);
1490 std::vector<ButtonInfo> buttons = JsParseDialogButtons(args, PROMPT_KEY_BUTTONS, index);
1491 const std::string success = JsParseRouteUrl(args, COMMON_SUCCESS, index);
1492 const std::string cancel = JsParseRouteUrl(args, COMMON_CANCEL, index);
1493 const std::string complete = JsParseRouteUrl(args, COMMON_COMPLETE, index);
1494 bool autoCancel = true;
1495
1496 v8::String::Utf8Value argsJsStr(isolate, args[index]);
1497 if (!(*argsJsStr)) {
1498 return;
1499 }
1500 std::string argsStr(*argsJsStr);
1501
1502 std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(argsStr);
1503 if (argsPtr != nullptr && argsPtr->GetValue(PROMPT_DIALOG_AUTO_CANCEL) != nullptr &&
1504 argsPtr->GetValue(PROMPT_DIALOG_AUTO_CANCEL)->IsBool()) {
1505 autoCancel = argsPtr->GetValue(PROMPT_DIALOG_AUTO_CANCEL)->GetBool();
1506 }
1507
1508 std::set<std::string> callbacks;
1509 if (!success.empty()) {
1510 callbacks.emplace(COMMON_SUCCESS);
1511 }
1512 if (!cancel.empty()) {
1513 callbacks.emplace(COMMON_CANCEL);
1514 }
1515 if (!complete.empty()) {
1516 callbacks.emplace(COMMON_COMPLETE);
1517 }
1518
1519 v8::Local<v8::External> data = v8::Local<v8::External>::Cast(args.Data());
1520 V8EngineInstance* engineInstance = static_cast<V8EngineInstance*>(data->Value());
1521
1522 auto callback = [engineInstance, success, cancel, complete](int32_t callbackType, int32_t successType) {
1523 switch (callbackType) {
1524 case 0:
1525 engineInstance->CallJs(success.c_str(),
1526 std::string("{\"index\":").append(std::to_string(successType)).append("}").c_str(), false);
1527 break;
1528 case 1:
1529 engineInstance->CallJs(cancel.c_str(), std::string("\"cancel\",null").c_str(), false);
1530 break;
1531 case 2:
1532 engineInstance->CallJs(complete.c_str(), std::string("\"complete\",null").c_str(), false);
1533 break;
1534 default:
1535 break;
1536 }
1537 };
1538
1539 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1540 (*delegate)->ShowDialog(title, message, buttons, autoCancel, std::move(callback), callbacks);
1541 }
1542
JsShowActionMenu(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)1543 void JsShowActionMenu(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
1544 {
1545 CHECK_RUN_ON(JS);
1546 LOGD("Enter JsShowActionMenu");
1547 v8::Isolate* isolate = args.GetIsolate();
1548 ACE_DCHECK(isolate);
1549 v8::HandleScope handleScope(isolate);
1550
1551 v8::Local<v8::External> data = v8::Local<v8::External>::Cast(args.Data());
1552 V8EngineInstance* engineInstance = static_cast<V8EngineInstance*>(data->Value());
1553
1554 v8::String::Utf8Value argsJsStr(isolate, args[index]);
1555 if (!(*argsJsStr)) {
1556 LOGE("JsShowActionMenu args is null");
1557 return;
1558 }
1559 std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(*argsJsStr);
1560 if (argsPtr == nullptr) {
1561 LOGE("argsPtr is nullptr");
1562 return;
1563 }
1564
1565 std::vector<ButtonInfo> buttons = JsParseDialogButtons(args, PROMPT_KEY_BUTTONS, index);
1566 if (buttons.empty() || buttons.size() > 6) { // The number of buttons cannot be zero or more than six
1567 LOGE("buttons is invalid");
1568 if (argsPtr->IsObject()) {
1569 const std::string fail = JsParseRouteUrl(args, COMMON_FAIL, index);
1570 const std::string complete = JsParseRouteUrl(args, COMMON_COMPLETE, index);
1571 engineInstance->CallJs(fail, R"({"errMsg":"enableAlertBeforeBackPage:buttons is invalid"})", false);
1572 engineInstance->CallJs(complete, R"({"errMsg":"enableAlertBeforeBackPage:buttons is invalid"})", false);
1573 } else {
1574 std::string callBackStr(*argsJsStr);
1575 // Get callbackId and clear redundant symbols
1576 if (callBackStr.size() > 2 && callBackStr.front() == '\"' && callBackStr.back() == '\"') {
1577 callBackStr = callBackStr.substr(1, callBackStr.size() - 2);
1578 engineInstance->CallJs(callBackStr,
1579 R"({"arguments":[{"errMsg":"enableAlertBeforeBackPage:buttons is invalid"}],"method":"fail"})",
1580 false);
1581 }
1582 }
1583 return;
1584 }
1585
1586 const std::string title = JsParseRouteUrl(args, PROMPT_KEY_TITLE, index);
1587 const std::string success = JsParseRouteUrl(args, COMMON_SUCCESS, index);
1588 const std::string fail = JsParseRouteUrl(args, COMMON_FAIL, index);
1589 const std::string complete = JsParseRouteUrl(args, COMMON_COMPLETE, index);
1590 auto callback = [engineInstance, success, fail, complete](int32_t callbackType, int32_t successType) {
1591 switch (callbackType) {
1592 case 0:
1593 engineInstance->CallJs(success,
1594 std::string(R"({"errMsg":"showActionMenu:ok","tapIndex":)")
1595 .append(std::to_string(successType))
1596 .append("}")
1597 .c_str(),
1598 false);
1599 engineInstance->CallJs(complete,
1600 std::string(R"({"errMsg":"showActionMenu:ok","tapIndex":)")
1601 .append(std::to_string(successType))
1602 .append("}")
1603 .c_str(),
1604 false);
1605 break;
1606 case 1:
1607 engineInstance->CallJs(fail, R"({"errMsg":"showActionMenu:fail cancel"})", false);
1608 engineInstance->CallJs(complete, R"({"errMsg\":\"showActionMenu:fail cancel"})", false);
1609 break;
1610 default:
1611 LOGE("callbackType is invalid");
1612 break;
1613 }
1614 };
1615
1616 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1617 (*delegate)->ShowActionMenu(title, buttons, std::move(callback));
1618 }
1619
1620 void JsHandlePrompt(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName, int32_t index)
1621 {
1622 CHECK_RUN_ON(JS);
1623 LOGD("Enter JsHandlePrompt");
1624 if (methodName == PROMPT_SHOW_TOAST) {
1625 JsShowToast(args, index);
1626 } else if (methodName == PROMPT_SHOW_DIALOG) {
1627 JsShowDialog(args, index);
1628 } else if (methodName == PROMPT_SHOW_ACTION_MENU) {
1629 JsShowActionMenu(args, index);
1630 } else {
1631 LOGW("system.prompt not support method = %{private}s", methodName.c_str());
1632 }
1633 }
1634
1635 void JsParseCallbackResult(const v8::FunctionCallbackInfo<v8::Value>& args, v8::Local<v8::Value> jsResult,
1636 const std::string& key, std::string& result)
1637 {
1638 CHECK_RUN_ON(JS);
1639 v8::Isolate* isolate = args.GetIsolate();
1640 ACE_DCHECK(isolate);
1641 v8::HandleScope handleScope(isolate);
1642
1643 v8::String::Utf8Value argsJsStr(isolate, jsResult);
1644 if (!(*argsJsStr)) {
1645 return;
1646 }
1647 std::string argsStr(*argsJsStr);
1648 std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(argsStr);
1649 if (argsPtr && argsPtr->GetValue(key) != nullptr) {
1650 if (argsPtr->GetValue(key)->IsString()) {
1651 result = argsPtr->GetValue(key)->GetString();
1652 } else if (argsPtr->GetValue(key)->IsNumber()) {
1653 result = argsPtr->GetValue(key)->ToString();
1654 }
1655 }
1656 }
1657
1658 void JsHandleCallback(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName, int32_t index)
1659 {
1660 CHECK_RUN_ON(JS);
1661 LOGD("Enter JsHandleCallback");
1662 v8::Isolate* isolate = args.GetIsolate();
1663 ACE_DCHECK(isolate);
1664 v8::HandleScope handleScope(isolate);
1665 auto context = isolate->GetCurrentContext();
1666 if (context.IsEmpty()) {
1667 LOGE("internal js result, context is empty!");
1668 return;
1669 }
1670
1671 if (methodName == CALLBACK_NATIVE) {
1672 if (args[index]->IsObject() && args[index]->IsArray()) {
1673 v8::Local<v8::Object> obj = args[index]->ToObject(context).ToLocalChecked();
1674 v8::Local<v8::Array> properties = obj->GetOwnPropertyNames(context).ToLocalChecked();
1675 if (properties->Length() < PROPERTIES_ARGS_LEN) {
1676 LOGW("JsHandleCallback: invalid callback value");
1677 return;
1678 }
1679 v8::Local<v8::Value> jsCallBackIdKey = properties->Get(context, PROPERTIES_ARGS_CBID_IDX).ToLocalChecked();
1680 v8::Local<v8::Value> jsCallBackId = obj->Get(context, jsCallBackIdKey).ToLocalChecked();
1681 v8::Local<v8::Value> jsResultKey = properties->Get(context, PROPERTIES_ARGS_RST_IDX).ToLocalChecked();
1682 v8::Local<v8::Value> jsResult = obj->Get(context, jsResultKey).ToLocalChecked();
1683
1684 v8::String::Utf8Value callBackIdJsStr(isolate, jsCallBackId);
1685 v8::String::Utf8Value resultJsStr(isolate, jsResult);
1686 if (!(*callBackIdJsStr) || !(*resultJsStr)) {
1687 return;
1688 }
1689 std::string callBackId(*callBackIdJsStr);
1690 std::string result(*resultJsStr);
1691
1692 JsParseCallbackResult(args, jsResult, KEY_STEPPER_PENDING_INDEX, result);
1693 auto delegate =
1694 static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1695 (*delegate)->SetCallBackResult(callBackId, result);
1696
1697 } else if (methodName == APP_DESTROY_FINISH) {
1698 LOGD("JsHandleCallback: appDestroyFinish should release resource here");
1699 } else {
1700 LOGW("internal.jsResult not support method = %{private}s", methodName.c_str());
1701 }
1702 }
1703 }
1704
1705 void JsHandleAnimationFrame(
1706 const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName, int32_t index)
1707 {
1708 CHECK_RUN_ON(JS);
1709 v8::Isolate* isolate = args.GetIsolate();
1710 ACE_DCHECK(isolate);
1711 v8::HandleScope handleScope(isolate);
1712 auto context = isolate->GetCurrentContext();
1713 if (context.IsEmpty()) {
1714 LOGE("animation frame, context is empty!");
1715 return;
1716 }
1717 v8::String::Utf8Value callbackIdJsStr(isolate, args[index]);
1718 if (!(*callbackIdJsStr)) {
1719 LOGW("system animation callbackId is null");
1720 return;
1721 }
1722 if (methodName == ANIMATION_REQUEST_ANIMATION_FRAME) {
1723 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1724 (*delegate)->RequestAnimationFrame(std::string(*callbackIdJsStr));
1725 } else if (methodName == ANIMATION_CANCEL_ANIMATION_FRAME) {
1726 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1727 (*delegate)->CancelAnimationFrame(std::string(*callbackIdJsStr));
1728 } else {
1729 LOGW("animationFrame not support method = %{private}s", methodName.c_str());
1730 }
1731 }
1732
1733 void JsHandleAnimator(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName, int32_t index)
1734 {
1735 CHECK_RUN_ON(JS);
1736 v8::Isolate* isolate = args.GetIsolate();
1737 v8::String::Utf8Value jsArguments(isolate, args[index]);
1738 if (!(*jsArguments)) {
1739 LOGE("args is invalid");
1740 return;
1741 }
1742 std::string arguments(*jsArguments);
1743 auto page = GetStagingPage();
1744
1745 if (page == nullptr) {
1746 LOGE("GetStagingPage is nullptr");
1747 return;
1748 }
1749 auto context = isolate->GetCurrentContext();
1750 if (methodName == ANIMATOR_CREATE_ANIMATOR || methodName == ANIMATOR_CREATE) {
1751 int32_t bridgeId = V8AnimatorBridgeUtils::JsCreateBridgeId();
1752 auto resultAnimator = V8AnimatorBridgeUtils::CreateAnimatorContext(context, page->GetPageId(), bridgeId);
1753 auto animatorBridge = AceType::MakeRefPtr<V8AnimatorBridge>(context, isolate, resultAnimator);
1754 auto task = AceType::MakeRefPtr<V8AnimatorTaskCreate>(isolate, animatorBridge, arguments);
1755 page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimator>(bridgeId, task));
1756 args.GetReturnValue().Set(resultAnimator);
1757 }
1758 }
1759
1760 void JsHandleImage(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
1761 {
1762 CHECK_RUN_ON(JS);
1763 LOGD("JsHandleImage");
1764 v8::Isolate* isolate = args.GetIsolate();
1765 ACE_DCHECK(isolate);
1766 v8::HandleScope handleScope(isolate);
1767
1768 auto src = JsParseRouteUrl(args, "src", index);
1769 auto success = JsParseRouteUrl(args, "success", index);
1770 auto fail = JsParseRouteUrl(args, "fail", index);
1771
1772 v8::Local<v8::External> data = v8::Local<v8::External>::Cast(args.Data());
1773 V8EngineInstance* engineInstance = static_cast<V8EngineInstance*>(data->Value());
1774
1775 auto&& callback = [engineInstance, success, fail](bool callbackType, int32_t width, int32_t height) {
1776 if (callbackType) {
1777 engineInstance->CallJs(success,
1778 std::string("{\"width\":")
1779 .append(std::to_string(width))
1780 .append(", \"height\":")
1781 .append(std::to_string(height))
1782 .append("}"),
1783 false);
1784 } else {
1785 engineInstance->CallJs(fail, std::string("\"fail\",null"), false);
1786 }
1787 };
1788 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1789 (*delegate)->HandleImage(src, std::move(callback));
1790 }
1791
ParseResourceStringParam(std::string & str,const char * paramName,const std::map<std::string,std::string> & params)1792 bool ParseResourceStringParam(std::string& str, const char* paramName, const std::map<std::string, std::string>& params)
1793 {
1794 std::string strName(paramName);
1795 auto iter = params.find(strName);
1796 if (iter != params.end()) {
1797 str = iter->second;
1798 return true;
1799 }
1800 return false;
1801 }
1802
ParseResourceNumberParam(int32_t & num,const char * paramName,const std::map<std::string,std::string> & params)1803 bool ParseResourceNumberParam(int32_t& num, const char* paramName, const std::map<std::string, std::string>& params)
1804 {
1805 std::string numName(paramName);
1806 auto iter = params.find(numName);
1807 if (iter != params.end()) {
1808 num = ParseResourceInputNumberParam(iter->second);
1809 return true;
1810 }
1811 return false;
1812 }
1813
ParseResourceParam(std::string & uri,int32_t & position,int32_t & length,const std::map<std::string,std::string> & params)1814 void ParseResourceParam(
1815 std::string& uri, int32_t& position, int32_t& length, const std::map<std::string, std::string>& params)
1816 {
1817 ParseResourceStringParam(uri, READ_KEY_URI, params);
1818 ParseResourceNumberParam(position, READ_KEY_POSITION, params);
1819 ParseResourceNumberParam(length, READ_KEY_LENGTH, params);
1820 }
1821
JsReadArrayBuffer(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)1822 void JsReadArrayBuffer(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
1823 {
1824 CHECK_RUN_ON(JS);
1825 v8::Isolate* isolate = args.GetIsolate();
1826 ACE_DCHECK(isolate);
1827 v8::HandleScope handleScope(isolate);
1828 auto context = isolate->GetCurrentContext();
1829 if (context.IsEmpty()) {
1830 LOGE("JsReadArrayBuffer, context is empty!");
1831 return;
1832 }
1833
1834 std::map<std::string, std::string> params;
1835 std::string callbackId;
1836 if (!GetParamsWithCallbackId(context, v8::Local<v8::Array>::Cast(args[index]), params, callbackId)) {
1837 LOGE("JsReadArrayBuffer, get params or callbackId failed!");
1838 return;
1839 }
1840 std::string uri;
1841 int32_t position = 1;
1842 int32_t length = MAX_READ_TEXT_LENGTH;
1843 ParseResourceParam(uri, position, length, params);
1844 v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>> pContext;
1845 pContext.Reset(isolate, context);
1846 std::smatch result;
1847 if (!std::regex_match(uri, result, URI_PATTERN)) {
1848 LOGE("JsReadArrayBuffer uri regex match failed");
1849 V8EngineInstance::CallJs(
1850 isolate, pContext, callbackId, R"({"arguments":["file uri pattern not correct", 200],"method":"fail"})");
1851 args.GetReturnValue().SetNull();
1852 return;
1853 }
1854
1855 std::vector<uint8_t> binaryContent;
1856 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1857 if (!((*delegate)->GetResourceData(uri, binaryContent))) {
1858 LOGE("JsReadArrayBuffer get buffer data failed");
1859 V8EngineInstance::CallJs(
1860 isolate, pContext, callbackId, R"({"arguments":["get buffer data failed", 301],"method":"fail"})");
1861 args.GetReturnValue().SetNull();
1862 return;
1863 }
1864
1865 auto fileLength = static_cast<int32_t>(binaryContent.size());
1866 if (position > fileLength || position <= 0 || length <= 0) {
1867 LOGE("JsReadText position fileLength failed");
1868 V8EngineInstance::CallJs(isolate, pContext, callbackId,
1869 R"({"arguments":["wrong start position or wrong read length", 301],"method":"fail"})");
1870 args.GetReturnValue().SetNull();
1871 return;
1872 }
1873
1874 length = position + length - 1 > fileLength ? fileLength - position + 1 : length;
1875 auto binaryData = v8::Object::New(isolate);
1876 std::unique_ptr<v8::BackingStore> backStore = v8::ArrayBuffer::NewBackingStore(
1877 &binaryContent[position - 1], length, [](void*, size_t, void*) {}, nullptr);
1878 v8::Local<v8::ArrayBuffer> binaryArray = v8::ArrayBuffer::New(isolate, std::move(backStore));
1879 binaryData->Set(context, v8::String::NewFromUtf8(isolate, "buffer").ToLocalChecked(), binaryArray).ToChecked();
1880 args.GetReturnValue().Set(binaryData);
1881 V8EngineInstance::CallJs(
1882 isolate, pContext, callbackId, R"({"arguments":["read array buffer success"],"method":"success"})");
1883 pContext.Reset();
1884 }
1885
JsReadText(const v8::FunctionCallbackInfo<v8::Value> & args,int32_t index)1886 void JsReadText(const v8::FunctionCallbackInfo<v8::Value>& args, int32_t index)
1887 {
1888 CHECK_RUN_ON(JS);
1889 v8::Isolate* isolate = args.GetIsolate();
1890 ACE_DCHECK(isolate);
1891 v8::HandleScope handleScope(isolate);
1892 auto context = isolate->GetCurrentContext();
1893 if (context.IsEmpty()) {
1894 LOGE("JsReadText, context is empty!");
1895 return;
1896 }
1897
1898 std::map<std::string, std::string> params;
1899 std::string callbackId;
1900 if (!GetParamsWithCallbackId(context, v8::Local<v8::Array>::Cast(args[index]), params, callbackId)) {
1901 LOGE("JsReadText, get params or callbackId failed!");
1902 return;
1903 }
1904 std::string uri;
1905 ParseResourceStringParam(uri, READ_KEY_URI, params);
1906 v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>> pContext;
1907 pContext.Reset(isolate, context);
1908 std::smatch result;
1909 if (!std::regex_match(uri, result, URI_PATTERN)) {
1910 LOGE("JsReadText uri regex match failed");
1911 V8EngineInstance::CallJs(
1912 isolate, pContext, callbackId, R"({"arguments":["file uri pattern not correct", 202],"method":"fail"})");
1913 return;
1914 }
1915
1916 std::string fileText;
1917 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1918 if (!((*delegate)->GetResourceData(uri, fileText))) {
1919 LOGE("JsReadText get text data failed");
1920 V8EngineInstance::CallJs(
1921 isolate, pContext, callbackId, R"({"arguments":["get text data failed", 301],"method":"fail"})");
1922 return;
1923 }
1924
1925 auto fileLength = ParseUtf8TextLength(fileText);
1926 int32_t position = 0;
1927 int32_t length = 0;
1928 if (!ParseResourceNumberParam(position, READ_KEY_POSITION, params)) {
1929 position = 1;
1930 }
1931
1932 if (!ParseResourceNumberParam(length, READ_KEY_LENGTH, params) || (length > fileLength - position + 1)) {
1933 length = (fileLength - position + 1 <= 0) ? 0 : fileLength - position + 1;
1934 }
1935
1936 if (fileLength == 0) {
1937 if ((position <= 0) || (length < 0)) {
1938 V8EngineInstance::CallJs(isolate, pContext, callbackId,
1939 R"({"arguments":["wrong start position or wrong read length", 202],"method":"fail"})");
1940 return;
1941 }
1942 } else {
1943 if ((position > fileLength) || (position <= 0) || (length < 0)) {
1944 V8EngineInstance::CallJs(isolate, pContext, callbackId,
1945 R"({"arguments":["wrong start position or wrong read length", 202],"method":"fail"})");
1946 return;
1947 }
1948
1949 auto substrPos = ParseUtf8TextSubstrStartPos(fileText, position);
1950 auto substrEndPos = ParseUtf8TextSubstrEndPos(fileText, position + length - 1);
1951 fileText = fileText.substr(substrPos - 1, substrEndPos - substrPos + 1);
1952 HandleEscapeCharaterInUtf8TextForJson(fileText);
1953 }
1954
1955 V8EngineInstance::CallJs(isolate, pContext, callbackId,
1956 std::string("{\"arguments\":[").append("{\"text\":\"").append(fileText).append("\"}],\"method\":\"success\"}"),
1957 false);
1958 pContext.Reset();
1959 }
1960
JsHandleReadResource(const v8::FunctionCallbackInfo<v8::Value> & args,const std::string & methodName,int32_t index)1961 void JsHandleReadResource(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName, int32_t index)
1962 {
1963 LOGD("JsHandleReadResource");
1964 if (methodName == READ_TEXT) {
1965 JsReadText(args, index);
1966 } else if (methodName == READ_ARRAY_BUFFER) {
1967 JsReadArrayBuffer(args, index);
1968 } else {
1969 LOGW("system.resource not support method = %{private}s", methodName.c_str());
1970 }
1971 }
1972
JsHandleOffscreenCanvas(const v8::FunctionCallbackInfo<v8::Value> & args,const std::string & methodName,int32_t index)1973 void JsHandleOffscreenCanvas(
1974 const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName, int32_t index)
1975 {
1976 auto page = GetRunningPage();
1977 if (page == nullptr) {
1978 LOGE("GetRunningPage is nullptr");
1979 return;
1980 }
1981
1982 if (methodName == OFFSCREEN_CANVAS_CREATE) {
1983 int32_t width = JsParseIntParams(args, "width", index);
1984 int32_t height = JsParseIntParams(args, "height", index);
1985
1986 v8::Isolate* isolate = args.GetIsolate();
1987 ACE_DCHECK(isolate);
1988 v8::HandleScope handleScope(isolate);
1989
1990 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
1991 auto pipelineContext = (*delegate)->GetPipelineContext();
1992 auto bridge = AceType::MakeRefPtr<V8OffscreenCanvasBridge>(pipelineContext, width, height);
1993 page->PushOffscreenCanvasBridge(bridge->GetBridgeId(), bridge);
1994 bridge->GetBridge(args);
1995 }
1996 }
1997
JsCallConfiguration(const v8::FunctionCallbackInfo<v8::Value> & args,const std::string & methodName,int32_t index)1998 void JsCallConfiguration(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName, int32_t index)
1999 {
2000 LOGD("Enter JsCallConfiguration");
2001 if (methodName == CONFIGURATION_GET_LOCALE) {
2002 GetLocale(args);
2003 } else if (methodName == CONFIGURATION_SET_LOCALE) {
2004 JsSetLocale(args, index);
2005 }
2006 }
2007
JsHandleSetTimeout(const v8::FunctionCallbackInfo<v8::Value> & args,const std::string & methodName,int32_t index)2008 void JsHandleSetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName, int32_t index)
2009 {
2010 LOGD("Enter JsHandleSetTimeout");
2011 if (methodName == SET_TIMEOUT) {
2012 JsSetTimer(args, index, false);
2013 } else if (methodName == CLEAR_TIMEOUT || methodName == CLEAR_INTERVAL) {
2014 JsClearTimeout(args, index);
2015 } else if (methodName == SET_INTERVAL) {
2016 JsSetTimer(args, index, true);
2017 } else {
2018 LOGW("unsupported method for timer module!");
2019 }
2020 }
2021
JsGetDeviceInfo(const v8::FunctionCallbackInfo<v8::Value> & args,const std::string & methodName,int32_t index)2022 void JsGetDeviceInfo(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName, int32_t index)
2023 {
2024 CHECK_RUN_ON(JS);
2025 if (methodName != "getInfo") {
2026 LOGW("system.device module not support method:%{public}s!", methodName.c_str());
2027 return;
2028 }
2029
2030 LOGD("Enter JsGetDeviceInfo");
2031 v8::Isolate* isolate = args.GetIsolate();
2032 ACE_DCHECK(isolate);
2033 v8::HandleScope handleScope(isolate);
2034 auto context = isolate->GetCurrentContext();
2035 if (context.IsEmpty()) {
2036 LOGE("get device info, context is empty!");
2037 return;
2038 }
2039
2040 v8::String::Utf8Value callBackIdJsStr(isolate, args[index]);
2041 const char* callBackId = *callBackIdJsStr;
2042 if (callBackId == nullptr) {
2043 LOGE("device.system device getInfo callBackID is null");
2044 } else {
2045 LOGD("system device getInfo callBackID = %{private}s", callBackId);
2046 std::pair<std::string, bool> ret = PluginBridge::GetDeviceInfo();
2047 v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>> pContext;
2048 pContext.Reset(isolate, context);
2049 if (ret.second) {
2050 V8EngineInstance::CallJs(isolate, pContext, callBackId,
2051 std::string("{\"arguments\":[").append(ret.first).append("],\"method\":\"success\"}"), false);
2052 } else {
2053 V8EngineInstance::CallJs(isolate, pContext, callBackId,
2054 std::string("{\"arguments\":[").append(ret.first).append(",200],\"method\":\"fail\"}"), false);
2055 }
2056 pContext.Reset();
2057 }
2058 }
2059
JsHandleGridLayout(const v8::FunctionCallbackInfo<v8::Value> & args,const std::string & methodName)2060 void JsHandleGridLayout(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName)
2061 {
2062 CHECK_RUN_ON(JS);
2063 v8::Isolate* isolate = args.GetIsolate();
2064 ACE_DCHECK(isolate);
2065 v8::HandleScope handleScope(isolate);
2066 auto context = isolate->GetCurrentContext();
2067 if (context.IsEmpty()) {
2068 LOGE("grid api, context is empty!");
2069 return;
2070 }
2071 if (methodName == GRID_GET_SYSTEM_LAYOUT_INFO) {
2072 v8::Local<v8::String> gridInfo =
2073 v8::String::NewFromUtf8(isolate, GridSystemManager::GetInstance().GetCurrentGridInfo().ToString().c_str())
2074 .ToLocalChecked();
2075 args.GetReturnValue().Set(v8::JSON::Parse(context, gridInfo).ToLocalChecked());
2076 } else {
2077 LOGW("grid not support method = %{public}s", methodName.c_str());
2078 }
2079 }
2080
JsHandleMediaQuery(const v8::FunctionCallbackInfo<v8::Value> & args,const std::string & methodName,int32_t index)2081 void JsHandleMediaQuery(const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName, int32_t index)
2082 {
2083 CHECK_RUN_ON(JS);
2084 v8::Isolate* isolate = args.GetIsolate();
2085 ACE_DCHECK(isolate);
2086 v8::HandleScope handleScope(isolate);
2087 auto context = isolate->GetCurrentContext();
2088 if (context.IsEmpty()) {
2089 LOGE("media query, context is empty!");
2090 return;
2091 }
2092 if (methodName == ADD_LISTENER) {
2093 JsAddListener(context, args[index]);
2094 } else if (methodName == GET_DEVICE_TYPE) {
2095 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
2096 auto mediaQuery = (*delegate)->GetMediaQueryInfoInstance();
2097 if (mediaQuery) {
2098 v8::Local<v8::String> res =
2099 v8::String::NewFromUtf8(isolate, mediaQuery->GetDeviceType().c_str()).ToLocalChecked();
2100 args.GetReturnValue().Set(res);
2101 }
2102 } else {
2103 LOGW("system.mediaquery not support method = %{public}s", methodName.c_str());
2104 }
2105 }
2106
2107 // function callback for aceObj's function: domCreateBody
JsDomCreateBody(const v8::FunctionCallbackInfo<v8::Value> & args)2108 void JsDomCreateBody(const v8::FunctionCallbackInfo<v8::Value>& args)
2109 {
2110 CHECK_RUN_ON(JS);
2111 LOGD("Enter JsDomCreateBody");
2112 if (args.Length() != CREATE_BODY_ARGS_LEN) {
2113 LOGE("The arg is wrong, it is supposed to have 5 arguments");
2114 return;
2115 }
2116
2117 v8::Isolate* isolate = args.GetIsolate();
2118 ACE_DCHECK(isolate);
2119 v8::Isolate::Scope isolateScope(isolate);
2120 v8::HandleScope handleScope(isolate);
2121 auto context = isolate->GetCurrentContext();
2122 if (context.IsEmpty()) {
2123 LOGE("dom create body, context is empty!");
2124 return;
2125 }
2126
2127 auto page = GetStagingPage();
2128 if (page == nullptr) {
2129 LOGE("GetStagingPage return nullptr");
2130 return;
2131 }
2132
2133 const int32_t pageId = page->GetPageId();
2134 int32_t nodeId = DOM_ROOT_NODE_ID_BASE + pageId;
2135 LOGD("JsDomCreateBody: pageId: %{private}d, nodeId: %{private}d:", pageId, nodeId);
2136 v8::String::Utf8Value tagJsStr(isolate, args[CREATE_BODY_TAG_IDX]);
2137 if (!(*tagJsStr)) {
2138 return;
2139 }
2140 std::string tag(*tagJsStr);
2141 auto command = Referenced::MakeRefPtr<JsCommandCreateDomBody>(tag.c_str(), nodeId);
2142 SetDomAttributes(context, args[CREATE_BODY_ATTR_IDX], *command);
2143 SetDomStyle(context, args[CREATE_BODY_STYLE_IDX], *command);
2144 AddDomEvent(context, args[CREATE_BODY_EVENT_IDX], *command);
2145 page->PushCommand(command);
2146 }
2147
2148 // function callback for aceObj's function: domAddElement
JsDomAddElement(const v8::FunctionCallbackInfo<v8::Value> & args)2149 void JsDomAddElement(const v8::FunctionCallbackInfo<v8::Value>& args)
2150 {
2151 CHECK_RUN_ON(JS);
2152 LOGD("Enter JsDomAddElement");
2153 if (args.Length() != ADD_ELEMENT_ARGS_LEN) {
2154 LOGE("The arg is wrong, it is supposed to have 9 arguments");
2155 return;
2156 }
2157
2158 v8::Isolate* isolate = args.GetIsolate();
2159 ACE_DCHECK(isolate);
2160 v8::Isolate::Scope isolateScope(isolate);
2161 v8::HandleScope handleScope(isolate);
2162 auto context = isolate->GetCurrentContext();
2163 if (context.IsEmpty()) {
2164 LOGE("Dom Add Element, context is empty");
2165 return;
2166 }
2167 auto page = GetStagingPage();
2168 if (page == nullptr) {
2169 LOGE("GetStagingPage return nullptr");
2170 return;
2171 }
2172
2173 const int32_t instanceId = args[ADD_ELEMENT_INSTANCE_ID]->Int32Value(context).ToChecked();
2174 if (page->GetPageId() != instanceId) {
2175 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
2176 page = (*delegate)->GetPage(instanceId);
2177 if (page == nullptr) {
2178 LOGE("JsDomAddElement fail to get page, pageId: %{public}d", instanceId);
2179 return;
2180 }
2181 }
2182
2183 const int32_t pageId = page->GetPageId();
2184 int32_t parentNodeId = args[ADD_ELEMENT_PARID_IDX]->Int32Value(context).ToChecked();
2185 parentNodeId = parentNodeId == 0 ? (DOM_ROOT_NODE_ID_BASE + pageId) : parentNodeId;
2186
2187 int32_t nodeId = args[ADD_ELEMENT_NODEID_IDX]->Int32Value(context).ToChecked();
2188 v8::String::Utf8Value tagJsStr(isolate, args[ADD_ELEMENT_TAG_IDX]);
2189 if (!(*tagJsStr)) {
2190 return;
2191 }
2192 std::string tag(*tagJsStr);
2193 LOGD("JsDomAddElement: pageId: %{private}d, parentNodeId: %{private}d, nodeId: %{private}d, tag: %{private}s",
2194 pageId, parentNodeId, nodeId, tag.c_str());
2195 auto command = Referenced::MakeRefPtr<JsCommandAddDomElement>(tag.c_str(), nodeId, parentNodeId);
2196 SetDomAttributes(context, args[ADD_ELEMENT_ATTR_IDX], *command);
2197 SetDomStyle(context, args[ADD_ELEMENT_STYLE_IDX], *command);
2198 AddDomEvent(context, args[ADD_ELEMENT_EVENT_INDEX], *command);
2199 int32_t itemIndex = args[ADD_ELEMENT_ITEM_INDEX]->Int32Value(context).ToChecked();
2200 if (args[ADD_ELEMENT_CUSTOM_INDEX]->IsBoolean()) {
2201 bool isCustomComponent = args[ADD_ELEMENT_CUSTOM_INDEX]->ToBoolean(isolate)->Value();
2202 command->SetIsCustomComponent(isCustomComponent);
2203 }
2204 command->SetForIndex(itemIndex);
2205 page->PushCommand(command);
2206 // Flush command as fragment immediately when pushed too many commands.
2207 if (!page->CheckPageCreated() && page->GetCommandSize() > FRAGMENT_SIZE) {
2208 page->FlushCommands();
2209 }
2210 }
2211
2212 // function callback for aceObj's function: updateElementAttrs
JsUpdateElementAttrs(const v8::FunctionCallbackInfo<v8::Value> & args)2213 void JsUpdateElementAttrs(const v8::FunctionCallbackInfo<v8::Value>& args)
2214 {
2215 CHECK_RUN_ON(JS);
2216 LOGD("Enter JsUpdateElementsAttrs");
2217
2218 if (args.Length() != UPLOAD_ELEMENT_ARGS_LEN) {
2219 LOGE("The arg is wrong, it is supposed to have 3 arguments");
2220 return;
2221 }
2222
2223 v8::Isolate* isolate = args.GetIsolate();
2224 ACE_DCHECK(isolate);
2225 v8::Isolate::Scope isolateScope(isolate);
2226 v8::HandleScope handleScope(isolate);
2227 auto context = isolate->GetCurrentContext();
2228 if (context.IsEmpty()) {
2229 LOGE("Upload Element Attrs, context is empty");
2230 return;
2231 }
2232 auto page = GetStagingPage();
2233 if (page == nullptr) {
2234 LOGE("GetStagingPage return nullptr");
2235 return;
2236 }
2237
2238 const int32_t instanceId = args[UPLOAD_ELEMENT_INSTANCE_ID]->Int32Value(context).ToChecked();
2239 if (page->GetPageId() != instanceId) {
2240 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
2241 page = (*delegate)->GetPage(instanceId);
2242 if (page == nullptr) {
2243 LOGE("JsUpdateElementAttrs fail to get page, pageId :%{public}d", instanceId);
2244 return;
2245 }
2246 }
2247
2248 int32_t nodeId = args[UPLOAD_ELEMENT_NID_IDX]->Int32Value(context).ToChecked();
2249 nodeId = (nodeId == 0) ? DOM_ROOT_NODE_ID_BASE + page->GetPageId() : nodeId;
2250 auto command = Referenced::MakeRefPtr<JsCommandUpdateDomElementAttrs>(nodeId);
2251 if (SetDomAttributes(context, args[UPLOAD_ELEMENT_DOM_IDX], *command)) {
2252 page->ReserveShowCommand(command);
2253 }
2254 page->PushCommand(command);
2255 }
2256
2257 // function callback for aceObj's function: updateElementStyles
JsUpdateElementStyles(const v8::FunctionCallbackInfo<v8::Value> & args)2258 void JsUpdateElementStyles(const v8::FunctionCallbackInfo<v8::Value>& args)
2259 {
2260 CHECK_RUN_ON(JS);
2261 LOGD("Enter JsUpdateElementStyles");
2262
2263 if (args.Length() != UPLOAD_ELEMENT_ARGS_LEN) {
2264 LOGE("The arg is wrong, it is supposed to have 3 arguments");
2265 return;
2266 }
2267
2268 v8::Isolate* isolate = args.GetIsolate();
2269 ACE_DCHECK(isolate);
2270 v8::Isolate::Scope isolateScope(isolate);
2271 v8::HandleScope handleScope(isolate);
2272 auto context = isolate->GetCurrentContext();
2273 if (context.IsEmpty()) {
2274 LOGE("Upload element styles, context is empty");
2275 return;
2276 }
2277 auto page = GetStagingPage();
2278 if (page == nullptr) {
2279 LOGE("GetStagingPage return nullptr");
2280 return;
2281 }
2282
2283 const int32_t instanceId = args[UPLOAD_ELEMENT_INSTANCE_ID]->Int32Value(context).ToChecked();
2284 if (page->GetPageId() != instanceId) {
2285 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
2286 page = (*delegate)->GetPage(instanceId);
2287 if (page == nullptr) {
2288 LOGE("JsUpdateElementStyles fail to get page, pageId :%{public}d", instanceId);
2289 return;
2290 }
2291 }
2292
2293 int32_t nodeId = args[UPLOAD_ELEMENT_NID_IDX]->Int32Value(context).ToChecked();
2294 nodeId = (nodeId == 0) ? DOM_ROOT_NODE_ID_BASE + page->GetPageId() : nodeId;
2295 auto command = Referenced::MakeRefPtr<JsCommandUpdateDomElementStyles>(nodeId);
2296 SetDomStyle(context, args[UPLOAD_ELEMENT_DOM_IDX], *command);
2297 page->PushCommand(command);
2298 }
2299
2300 // function callback for aceObj's function: onCreateFinish
JsOnCreateFinish(const v8::FunctionCallbackInfo<v8::Value> & args)2301 void JsOnCreateFinish(const v8::FunctionCallbackInfo<v8::Value>& args)
2302 {
2303 CHECK_RUN_ON(JS);
2304 LOGD("Enter JsOnCreateFinish");
2305 v8::Isolate* isolate = args.GetIsolate();
2306 ACE_DCHECK(isolate);
2307 v8::Isolate::Scope isolateScope(isolate);
2308 v8::HandleScope handleScope(isolate);
2309
2310 auto page = GetStagingPage();
2311 if (page == nullptr) {
2312 LOGE("GetStagingPage return nullptr");
2313 return;
2314 }
2315
2316 page->SetPageCreated();
2317 }
2318
CharToV8String(v8::Isolate * isolate,const char * str,bool isInternalized=false)2319 v8::Local<v8::String> CharToV8String(v8::Isolate* isolate, const char* str, bool isInternalized = false)
2320 {
2321 if (str != nullptr && strlen(str) != 0) {
2322 v8::NewStringType type = isInternalized ? v8::NewStringType::kInternalized : v8::NewStringType::kNormal;
2323 v8::MaybeLocal<v8::String> ret = v8::String::NewFromUtf8(isolate, str, type);
2324 if (!ret.IsEmpty()) {
2325 return ret.ToLocalChecked();
2326 }
2327 }
2328 return v8::String::Empty(isolate);
2329 }
2330
JsCompileAndRunBundle(const v8::FunctionCallbackInfo<v8::Value> & args)2331 void JsCompileAndRunBundle(const v8::FunctionCallbackInfo<v8::Value>& args)
2332 {
2333 CHECK_RUN_ON(JS);
2334 if (g_debugger != nullptr) {
2335 WaitingForIde waitingForIde = (WaitingForIde)dlsym(g_debugger, "WaitingForIde");
2336 if (waitingForIde != nullptr) {
2337 waitingForIde();
2338 }
2339 }
2340
2341 LOGI("JsCompileAndRunBundle");
2342 v8::Isolate* isolate = args.GetIsolate();
2343 ACE_DCHECK(isolate);
2344 v8::HandleScope handleScope(isolate);
2345 int len = args.Length();
2346 if (len <= 0 || !args[0]->IsString()) {
2347 LOGE("len %d", len);
2348 args.GetReturnValue().SetUndefined();
2349 return;
2350 }
2351 v8::String::Utf8Value tagJsStr(isolate, args[0]);
2352 if (!(*tagJsStr)) {
2353 args.GetReturnValue().SetUndefined();
2354 return;
2355 }
2356 std::string tag(*tagJsStr);
2357 v8::Local<v8::String> source =
2358 v8::String::NewFromUtf8(isolate, tag.c_str(), v8::NewStringType::kNormal).ToLocalChecked();
2359 if (source.IsEmpty()) {
2360 LOGE("source.IsEmpty");
2361 args.GetReturnValue().SetUndefined();
2362 return;
2363 }
2364 v8::Isolate::Scope isolateScope(isolate);
2365 v8::Context::Scope ctxScope(v8::Local<v8::Context>::New(isolate, isolate->GetCurrentContext()));
2366 v8::TryCatch tryCatch(isolate);
2367
2368 v8::String::Utf8Value pageStr(isolate, args[1]);
2369 if (!(*pageStr)) {
2370 args.GetReturnValue().SetUndefined();
2371 return;
2372 }
2373 std::string page(*pageStr);
2374
2375 v8::Local<v8::String> name = CharToV8String(isolate, page.c_str(), true);
2376 v8::ScriptOrigin origin(name);
2377 v8::MaybeLocal<v8::Script> maybeScript = v8::Script::Compile(isolate->GetCurrentContext(), source, &origin);
2378 if (maybeScript.IsEmpty()) {
2379 LOGE("Compile maybeScript.IsEmpty");
2380 return;
2381 }
2382 v8::Local<v8::Script> script = maybeScript.ToLocalChecked();
2383 v8::MaybeLocal<v8::Value> maybeResult = script->Run(isolate->GetCurrentContext());
2384 if (maybeResult.IsEmpty()) {
2385 LOGE("Run maybeResult.IsEmpty");
2386 return;
2387 }
2388 v8::Local<v8::Value> result = maybeResult.ToLocalChecked();
2389 args.GetReturnValue().Set(result);
2390 }
2391
2392 // function callback for aceObj's function: onUpdateFinish
JsOnUpdateFinish(const v8::FunctionCallbackInfo<v8::Value> & args)2393 void JsOnUpdateFinish(const v8::FunctionCallbackInfo<v8::Value>& args)
2394 {
2395 CHECK_RUN_ON(JS);
2396 LOGD("Enter JsOnUpdateFinish");
2397 v8::Isolate* isolate = args.GetIsolate();
2398 ACE_DCHECK(isolate);
2399 v8::Isolate::Scope isolateScope(isolate);
2400 v8::HandleScope handleScope(isolate);
2401
2402 auto page = GetStagingPage();
2403 if (page == nullptr) {
2404 LOGE("GetStagingPage return nullptr");
2405 return;
2406 }
2407
2408 if (page->CheckPageCreated()) {
2409 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
2410 (*delegate)->TriggerPageUpdate(page->GetPageId());
2411 }
2412 }
2413
JsHandleModule(std::string moduleName,std::string methodName,const v8::FunctionCallbackInfo<v8::Value> & args)2414 void JsHandleModule(std::string moduleName, std::string methodName, const v8::FunctionCallbackInfo<v8::Value>& args)
2415 {
2416 static const std::unordered_map<std::string,
2417 void (*)(const v8::FunctionCallbackInfo<v8::Value>&, const std::string&)>
2418 jsHandleMap = { { "system.app", [](const v8::FunctionCallbackInfo<v8::Value>& args,
2419 const std::string& methodName) { JsHandleAppApi(args, methodName, 1); } },
2420 { "system.router", [](const v8::FunctionCallbackInfo<v8::Value>& args,
2421 const std::string& methodName) { JsHandlePageRoute(args, methodName, 1); } },
2422 { "system.prompt", [](const v8::FunctionCallbackInfo<v8::Value>& args,
2423 const std::string& methodName) { JsHandlePrompt(args, methodName, 1); } },
2424 { "internal.jsResult", [](const v8::FunctionCallbackInfo<v8::Value>& args,
2425 const std::string& methodName) { JsHandleCallback(args, methodName, 1); } },
2426 { "system.configuration",
2427 [](const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName) {
2428 JsCallConfiguration(args, methodName, 1);
2429 } },
2430 { "system.image", [](const v8::FunctionCallbackInfo<v8::Value>& args,
2431 const std::string& methodName) { JsHandleImage(args, 1); } },
2432 { "timer", [](const v8::FunctionCallbackInfo<v8::Value>& args,
2433 const std::string& methodName) { JsHandleSetTimeout(args, methodName, 1); } },
2434 { "system.device", [](const v8::FunctionCallbackInfo<v8::Value>& args,
2435 const std::string& methodName) { JsGetDeviceInfo(args, methodName, 1); } },
2436 { "system.grid", [](const v8::FunctionCallbackInfo<v8::Value>& args,
2437 const std::string& methodName) { JsHandleGridLayout(args, methodName); } },
2438 { "system.mediaquery", [](const v8::FunctionCallbackInfo<v8::Value>& args,
2439 const std::string& methodName) { JsHandleMediaQuery(args, methodName, 1); } },
2440 { "animation", [](const v8::FunctionCallbackInfo<v8::Value>& args,
2441 const std::string& methodName) { JsHandleAnimationFrame(args, methodName, 1); } },
2442 { "system.resource", [](const v8::FunctionCallbackInfo<v8::Value>& args,
2443 const std::string& methodName) { JsHandleReadResource(args, methodName, 1); } },
2444 { "system.offscreenCanvas",
2445 [](const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName) {
2446 JsHandleOffscreenCanvas(args, methodName, 1);
2447 } },
2448 { "ohos.animator", [](const v8::FunctionCallbackInfo<v8::Value>& args, const std::string& methodName) {
2449 JsHandleAnimator(args, methodName, 1);
2450 } } };
2451
2452 auto jsHandleIter = jsHandleMap.find(moduleName);
2453 if (jsHandleIter != jsHandleMap.end()) {
2454 jsHandleIter->second(args, methodName);
2455 return;
2456 }
2457
2458 return;
2459 }
2460
2461 // function callback for aceObj's function: removeElement
JsRemoveElement(const v8::FunctionCallbackInfo<v8::Value> & args)2462 void JsRemoveElement(const v8::FunctionCallbackInfo<v8::Value>& args)
2463 {
2464 CHECK_RUN_ON(JS);
2465 LOGD("Enter JsRemoveElement");
2466 if (args.Length() != REMOVE_ELEMENT_ARGS_LEN) {
2467 LOGE("The arg is wrong, it is supposed to have 2 arguments");
2468 return;
2469 }
2470
2471 v8::Isolate* isolate = args.GetIsolate();
2472 ACE_DCHECK(isolate);
2473 v8::Isolate::Scope isolateScope(isolate);
2474 v8::HandleScope handleScope(isolate);
2475 auto context = isolate->GetCurrentContext();
2476 if (context.IsEmpty()) {
2477 LOGE("Remove element, context is empty");
2478 return;
2479 }
2480 auto page = GetStagingPage();
2481 if (page == nullptr) {
2482 LOGE("GetStagingPage return nullptr");
2483 return;
2484 }
2485
2486 const int32_t instanceId = args[REMOVE_ELEMENT_INSTANCE_ID]->Int32Value(context).ToChecked();
2487 if (page->GetPageId() != instanceId) {
2488 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
2489 page = (*delegate)->GetPage(instanceId);
2490 if (page == nullptr) {
2491 LOGE("JsRemoveElement fail to get page, pageId: %{public}d", instanceId);
2492 return;
2493 }
2494 }
2495
2496 int32_t nodeId = args[REMOVE_ELEMENT_ID_IDX]->Int32Value(context).ToChecked();
2497 nodeId = (nodeId == 0) ? DOM_ROOT_NODE_ID_BASE + page->GetPageId() : nodeId;
2498 page->PushCommand(Referenced::MakeRefPtr<JsCommandRemoveDomElement>(nodeId));
2499 }
2500
2501 // function callback for aceObj's function: callNative
JsCallNative(const v8::FunctionCallbackInfo<v8::Value> & args)2502 void JsCallNative(const v8::FunctionCallbackInfo<v8::Value>& args)
2503 {
2504 CHECK_RUN_ON(JS);
2505 LOGD("Enter JsCallNative");
2506 if (args.Length() != NATIVE_ARGS_LEN) {
2507 LOGE("The arg is wrong, it is supposed to have 2 arguments");
2508 return;
2509 }
2510
2511 v8::Isolate* isolate = args.GetIsolate();
2512 ACE_DCHECK(isolate);
2513 v8::Isolate::Scope isolateScope(isolate);
2514 v8::HandleScope handleScope(isolate);
2515
2516 v8::String::Utf8Value moduleAndMethodJsStr(isolate, args[NATIVE_ARGS_METHOD_IDX]);
2517 v8::String::Utf8Value argumentsJsStr(isolate, args[NATIVE_ARGS_IDX]);
2518 if (!(*moduleAndMethodJsStr) || !(*argumentsJsStr)) {
2519 return;
2520 }
2521 std::string moduleAndMethod(*moduleAndMethodJsStr);
2522 std::string arguments(*argumentsJsStr);
2523 LOGD(
2524 "JsCallNative moduleAndMethod = %{private}s arguments=%{private}s", moduleAndMethod.c_str(), arguments.c_str());
2525
2526 std::unique_ptr<JsonValue> moduleAndMethodPtr = JsonUtil::ParseJsonString(moduleAndMethod);
2527 if (moduleAndMethodPtr == nullptr) {
2528 LOGE("Get moduleAndMethod from argv failed");
2529 return;
2530 }
2531
2532 std::unique_ptr<JsonValue> modulePtr = moduleAndMethodPtr->GetValue("module");
2533 if (modulePtr == nullptr) {
2534 LOGE("Get module from moduleAndMethodPtr failed");
2535 return;
2536 }
2537
2538 std::unique_ptr<JsonValue> methodPtr = moduleAndMethodPtr->GetValue("method");
2539 if (methodPtr == nullptr) {
2540 LOGE("Get method from moduleAndMethodPtr failed");
2541 return;
2542 }
2543
2544 const std::string moduleName = modulePtr->GetString();
2545 const std::string methodName = methodPtr->GetString();
2546
2547 JsHandleModule(moduleName, methodName, args);
2548 }
2549
2550 // function callback for aceObj's function: callComponent
JsCallComponent(const v8::FunctionCallbackInfo<v8::Value> & args)2551 void JsCallComponent(const v8::FunctionCallbackInfo<v8::Value>& args)
2552 {
2553 CHECK_RUN_ON(JS);
2554 LOGD("Enter JsCallComponent");
2555 if (args.Length() != COMPONENT_ARGS_LEN) {
2556 LOGE("argc error, argc = %{private}d", args.Length());
2557 return;
2558 }
2559 v8::Isolate* isolate = args.GetIsolate();
2560 ACE_DCHECK(isolate);
2561 v8::Isolate::Scope isolateScope(isolate);
2562 v8::HandleScope handleScope(isolate);
2563 auto context = isolate->GetCurrentContext();
2564 if (context.IsEmpty()) {
2565 LOGE("Call Component, context is empty");
2566 return;
2567 }
2568 auto page = GetRunningPage();
2569 if (page == nullptr) {
2570 LOGE("GetRunningPage is nullptr");
2571 return;
2572 }
2573 int32_t nodeId = args[COMPONENT_ARGS_ID_IDX]->Int32Value(context).ToChecked();
2574 nodeId = (nodeId == 0) ? DOM_ROOT_NODE_ID_BASE + page->GetPageId() : nodeId;
2575 v8::String::Utf8Value jsMethodName(isolate, args[COMPONENT_ARGS_METHOD_IDX]);
2576 v8::String::Utf8Value jsArguments(isolate, args[COMPONENT_ARGS_IDX]);
2577 if (!(*jsMethodName) || !(*jsArguments)) {
2578 return;
2579 }
2580 std::string methodName(*jsMethodName);
2581 std::string arguments(*jsArguments);
2582 LOGD("nodeId = %{private}d, methodName = %{private}s, args = %{private}s", nodeId, methodName.c_str(),
2583 arguments.c_str());
2584 auto engine = reinterpret_cast<V8EngineInstance*>(args.Data().As<v8::External>()->Value());
2585 if (std::strcmp(methodName.c_str(), "getContext") == 0) {
2586 auto bridge = AceType::DynamicCast<V8CanvasBridge>(page->GetBridgeById(nodeId));
2587 if (bridge) {
2588 bridge->HandleContext(context, nodeId, arguments, engine);
2589 args.GetReturnValue().Set(bridge->GetRenderContext());
2590 return;
2591 }
2592 } else if (std::strcmp(methodName.c_str(), "getXComponentContext") == 0) {
2593 auto bridge = AceType::DynamicCast<V8XComponentBridge>(page->GetXComponentBridgeById(nodeId));
2594 if (bridge) {
2595 bridge->HandleContext(context, nodeId, arguments, engine);
2596 args.GetReturnValue().Set(bridge->GetRenderContext());
2597 return;
2598 }
2599 } else if (std::strcmp(methodName.c_str(), "getXComponentSurfaceId") == 0) {
2600 auto surfaceId = V8XComponentBridge::JsGetXComponentSurfaceId(isolate, nodeId);
2601 args.GetReturnValue().Set(surfaceId);
2602 } else if (std::strcmp(methodName.c_str(), "setXComponentSurfaceSize") == 0) {
2603 V8XComponentBridge::JsSetXComponentSurfaceSize(args, arguments, nodeId);
2604 } else if (std::strcmp(methodName.c_str(), "toDataURL") == 0) {
2605 auto bridge = AceType::DynamicCast<V8CanvasBridge>(page->GetBridgeById(nodeId));
2606 if (bridge) {
2607 bridge->HandleToDataURL(context, nodeId, arguments);
2608 args.GetReturnValue().Set(bridge->GetDataURL());
2609 return;
2610 }
2611 } else if (std::strcmp(methodName.c_str(), "getBoundingClientRect") == 0) {
2612 auto rect = V8ComponentApiBridge::JsGetBoundingRect(isolate, nodeId);
2613 args.GetReturnValue().Set(rect);
2614 } else if (std::strcmp(methodName.c_str(), "getScrollOffset") == 0) {
2615 // handle getScrollOffset method of scroll view, like div, stack and list.
2616 auto offset = V8ComponentApiBridge::JsGetScrollOffset(isolate, nodeId);
2617 args.GetReturnValue().Set(offset);
2618 } else if (std::strcmp(methodName.c_str(), "scrollTo") == 0) {
2619 V8ComponentApiBridge::JsScrollTo(args, arguments, nodeId);
2620 }
2621
2622 if (std::strcmp(methodName.c_str(), "animate") == 0) {
2623 LOGD("animate args = %{private}s", arguments.c_str());
2624 auto resultValue = V8AnimationBridgeUtils::CreateAnimationContext(context, page->GetPageId(), nodeId);
2625 auto animationBridge = AceType::MakeRefPtr<V8AnimationBridge>(context, isolate, resultValue, nodeId);
2626 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
2627 auto task = AceType::MakeRefPtr<V8AnimationBridgeTaskCreate>(*delegate, animationBridge, arguments);
2628 page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimation>(nodeId, task));
2629 args.GetReturnValue().Set(resultValue);
2630 } else if (std::strcmp(methodName.c_str(), "currentOffset") == 0) {
2631 // handle list currentOffset method
2632 auto offset = V8ListBridge::JsGetCurrentOffset(isolate, nodeId);
2633 args.GetReturnValue().Set(offset);
2634 } else if (std::strcmp(methodName.c_str(), "createIntersectionObserver") == 0) {
2635 auto visibleObserver = V8ComponentApiBridge::JsAddVisibleListener(args, arguments, nodeId);
2636 args.GetReturnValue().Set(visibleObserver);
2637 } else if (std::strcmp(methodName.c_str(), "getState") == 0) {
2638 // handle image-animator getState method
2639 auto state = V8ImageAnimatorBridge::JsGetState(isolate, nodeId);
2640 args.GetReturnValue().Set(state);
2641 } else if (std::strcmp(methodName.c_str(), "addChild") == 0) {
2642 auto sPage = GetStagingPage();
2643 if (sPage == nullptr) {
2644 LOGE("GetStagingPage return nullptr");
2645 return;
2646 }
2647 std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(arguments);
2648 if (!argsValue || !argsValue->IsArray()) {
2649 LOGE("argsValue is nullptr or not array");
2650 return;
2651 }
2652 std::unique_ptr<JsonValue> indexValue = argsValue->GetArrayItem(0)->GetValue("__nodeId");
2653 if (!indexValue || !indexValue->IsNumber()) {
2654 LOGE("indexValue is nullptr or not number");
2655 return;
2656 }
2657 int32_t childId = indexValue->GetInt();
2658 auto domDocument = sPage->GetDomDocument();
2659 if (domDocument) {
2660 RefPtr<DOMNode> node = domDocument->GetDOMNodeById(childId);
2661 if (node == nullptr) {
2662 LOGE("node is nullptr");
2663 return;
2664 }
2665 auto command = Referenced::MakeRefPtr<JsCommandAppendElement>(node->GetTag(), node->GetNodeId(), nodeId);
2666 sPage->PushCommand(command);
2667 if (!sPage->CheckPageCreated() && sPage->GetCommandSize() > FRAGMENT_SIZE) {
2668 sPage->FlushCommands();
2669 }
2670 }
2671 } else {
2672 page->PushCommand(Referenced::MakeRefPtr<JsCommandCallDomElementMethod>(nodeId, methodName, arguments));
2673 }
2674 // focus method should be delayed util show attribute update.
2675 if (page->CheckPageCreated() && strcmp(DOM_FOCUS, methodName.c_str()) != 0) {
2676 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
2677 (*delegate)->TriggerPageUpdate(page->GetPageId(), true);
2678 }
2679 }
2680
ParseLogContent(const std::vector<std::string> & params)2681 std::string ParseLogContent(const std::vector<std::string>& params)
2682 {
2683 std::string ret;
2684 if (params.empty()) {
2685 return ret;
2686 }
2687 std::string formatStr = params[0];
2688 int32_t size = params.size();
2689 int32_t len = formatStr.size();
2690 int32_t pos = 0;
2691 int32_t count = 1;
2692 for (; pos < len; ++pos) {
2693 if (count >= size) {
2694 break;
2695 }
2696 if (formatStr[pos] == '%') {
2697 if (pos + 1 >= len) {
2698 break;
2699 }
2700 switch (formatStr[pos + 1]) {
2701 case 's':
2702 case 'j':
2703 case 'd':
2704 case 'O':
2705 case 'o':
2706 case 'i':
2707 case 'f':
2708 case 'c':
2709 ret += params[count++];
2710 ++pos;
2711 break;
2712 case '%':
2713 ret += formatStr[pos];
2714 ++pos;
2715 break;
2716 default:
2717 ret += formatStr[pos];
2718 break;
2719 }
2720 } else {
2721 ret += formatStr[pos];
2722 }
2723 }
2724 if (pos < len) {
2725 ret += formatStr.substr(pos, len - pos);
2726 }
2727 return ret;
2728 }
2729
GetLogLevelAndContent(const v8::FunctionCallbackInfo<v8::Value> & args,JsLogLevel & logLevel,std::string & content)2730 void GetLogLevelAndContent(const v8::FunctionCallbackInfo<v8::Value>& args, JsLogLevel& logLevel, std::string& content)
2731 {
2732 CHECK_RUN_ON(JS);
2733 v8::Isolate* isolate = args.GetIsolate();
2734 ACE_DCHECK(isolate);
2735 v8::Isolate::Scope isolateScope(isolate);
2736 v8::HandleScope handleScope(isolate);
2737 auto context = isolate->GetCurrentContext();
2738 if (context.IsEmpty() || args.Length() == 0) {
2739 LOGE("Get LogLevel and Content, context is empty");
2740 return;
2741 }
2742 if (args.Length() == 1) {
2743 v8::Local<v8::Value> str;
2744 if (args[0]->ToString(context).ToLocal(&str)) {
2745 v8::String::Utf8Value utf8(isolate, str);
2746 if (*utf8) {
2747 content += *utf8;
2748 }
2749 } else {
2750 content += "Error converting argument 1";
2751 }
2752 } else {
2753 std::vector<std::string> params;
2754 for (int32_t i = 0; i < args.Length(); i++) {
2755 v8::Local<v8::Value> str;
2756 if (args[i]->ToString(context).ToLocal(&str)) {
2757 v8::String::Utf8Value utf8(isolate, str);
2758 if (*utf8) {
2759 params.emplace_back(*utf8);
2760 }
2761 }
2762 }
2763 content = ParseLogContent(params);
2764 }
2765 logLevel = static_cast<JsLogLevel>(args.Data()->Int32Value(context).ToChecked());
2766 }
2767
AppLogPrint(const v8::FunctionCallbackInfo<v8::Value> & args)2768 void AppLogPrint(const v8::FunctionCallbackInfo<v8::Value>& args)
2769 {
2770 JsLogLevel logLevel = JsLogLevel::INFO;
2771 std::string fullString;
2772 GetLogLevelAndContent(args, logLevel, fullString);
2773 switch (logLevel) {
2774 case JsLogLevel::DEBUG:
2775 APP_LOGD("app Log: %{public}s", fullString.c_str());
2776 break;
2777 case JsLogLevel::INFO:
2778 APP_LOGI("app Log: %{public}s", fullString.c_str());
2779 break;
2780 case JsLogLevel::WARNING:
2781 APP_LOGW("app Log: %{public}s", fullString.c_str());
2782 break;
2783 case JsLogLevel::ERROR:
2784 APP_LOGE("app Log: %{public}s", fullString.c_str());
2785 break;
2786 default:
2787 LOGE("the log level is error");
2788 }
2789 }
2790
JsLogPrint(const v8::FunctionCallbackInfo<v8::Value> & args)2791 void JsLogPrint(const v8::FunctionCallbackInfo<v8::Value>& args)
2792 {
2793 JsLogLevel logLevel = JsLogLevel::INFO;
2794 std::string fullString;
2795 GetLogLevelAndContent(args, logLevel, fullString);
2796 switch (logLevel) {
2797 case JsLogLevel::DEBUG:
2798 LOGD("ace Log: %{public}s", fullString.c_str());
2799 break;
2800 case JsLogLevel::INFO:
2801 LOGI("ace Log: %{public}s", fullString.c_str());
2802 break;
2803 case JsLogLevel::WARNING:
2804 LOGW("ace Log: %{public}s", fullString.c_str());
2805 break;
2806 case JsLogLevel::ERROR:
2807 LOGE("ace Log: %{public}s", fullString.c_str());
2808 break;
2809 default:
2810 break;
2811 }
2812 }
2813
JsPerfEnd(const v8::FunctionCallbackInfo<v8::Value> & args)2814 void JsPerfEnd(const v8::FunctionCallbackInfo<v8::Value>& args)
2815 {
2816 CHECK_RUN_ON(JS);
2817 LOGD("Enter JsPerfEnd");
2818 if (args.Length() != PERF_ARGS_LEN) {
2819 LOGE("argc error, argc = %{private}d", args.Length());
2820 return;
2821 }
2822
2823 v8::Isolate* isolate = args.GetIsolate();
2824 ACE_DCHECK(isolate);
2825 v8::HandleScope handleScope(isolate);
2826 auto context = isolate->GetCurrentContext();
2827 if (context.IsEmpty()) {
2828 LOGE("JsPerfEnd, CurrentContext is empty!");
2829 return;
2830 }
2831
2832 v8::String::Utf8Value jsMethodName(isolate, args[PERF_ARGS_METHOD_IDX]);
2833 if (!(*jsMethodName)) {
2834 return;
2835 }
2836 std::string methodName(*jsMethodName);
2837
2838 int64_t currentTime = GetMicroTickCount();
2839 JsApiPerf::GetInstance().InsertJsEndLog(methodName, currentTime);
2840 }
2841
JsPerfBegin(const v8::FunctionCallbackInfo<v8::Value> & args)2842 void JsPerfBegin(const v8::FunctionCallbackInfo<v8::Value>& args)
2843 {
2844 CHECK_RUN_ON(JS);
2845 LOGD("Enter JsPerfEnd");
2846 if (args.Length() != PERF_ARGS_LEN) {
2847 LOGE("argc error, argc = %{private}d", args.Length());
2848 return;
2849 }
2850
2851 v8::Isolate* isolate = args.GetIsolate();
2852 ACE_DCHECK(isolate);
2853 v8::HandleScope handleScope(isolate);
2854 auto context = isolate->GetCurrentContext();
2855 if (context.IsEmpty()) {
2856 LOGE("JsPerfBegin, CurrentContext is empty!");
2857 return;
2858 }
2859
2860 v8::String::Utf8Value jsMethodName(isolate, args[PERF_ARGS_METHOD_IDX]);
2861 if (!(*jsMethodName)) {
2862 return;
2863 }
2864 std::string methodName(*jsMethodName);
2865
2866 int64_t currentTime = GetMicroTickCount();
2867 JsApiPerf::GetInstance().InsertJsBeginLog(methodName, currentTime);
2868 }
2869
JsPerfSleep(const v8::FunctionCallbackInfo<v8::Value> & args)2870 void JsPerfSleep(const v8::FunctionCallbackInfo<v8::Value>& args)
2871 {
2872 CHECK_RUN_ON(JS);
2873 LOGD("Enter JsPerfEnd");
2874 if (args.Length() != 1) {
2875 LOGE("argc error, argc = %{private}d", args.Length());
2876 return;
2877 }
2878
2879 v8::Isolate* isolate = args.GetIsolate();
2880 ACE_DCHECK(isolate);
2881 v8::HandleScope handleScope(isolate);
2882 auto context = isolate->GetCurrentContext();
2883 if (context.IsEmpty()) {
2884 LOGE("CurrentContext is empty!");
2885 return;
2886 }
2887
2888 int32_t valInt = args[0]->Int32Value(context).ToChecked();
2889 usleep(valInt);
2890 }
2891
JsPerfPrint(const v8::FunctionCallbackInfo<v8::Value> & args)2892 void JsPerfPrint(const v8::FunctionCallbackInfo<v8::Value>& args)
2893 {
2894 CHECK_RUN_ON(JS);
2895 v8::Isolate* isolate = args.GetIsolate();
2896 ACE_DCHECK(isolate);
2897
2898 v8::HandleScope handleScope(isolate);
2899 auto context = isolate->GetCurrentContext();
2900 if (context.IsEmpty()) {
2901 LOGE("JsPerfPrint, CurrentContext is empty!");
2902 return;
2903 }
2904
2905 // return the result
2906 std::string ret = JsApiPerf::GetInstance().PrintToLogs();
2907 v8::Local<v8::String> dataValue = v8::String::NewFromUtf8(isolate, ret.c_str()).ToLocalChecked();
2908 args.GetReturnValue().Set(dataValue);
2909 }
2910
2911 // function callback for hiViewObj's function: report
JsHiViewReport(const v8::FunctionCallbackInfo<v8::Value> & args)2912 void JsHiViewReport(const v8::FunctionCallbackInfo<v8::Value>& args)
2913 {
2914 CHECK_RUN_ON(JS);
2915 LOGD("Enter JsHiViewReport");
2916 v8::Isolate* isolate = args.GetIsolate();
2917 ACE_DCHECK(isolate);
2918 v8::Isolate::Scope isolateScope(isolate);
2919 v8::HandleScope handleScope(isolate);
2920
2921 if (args.Length() != HIVIEW_ARGS_LEN) {
2922 LOGE("argc error, argc = %{private}d", args.Length());
2923 return;
2924 }
2925 if (args[HIVIEW_ARGS_ID_IDX]->IsNumber() && args[HIVIEW_ARGS_JSON_IDX]->IsString()) {
2926 v8::String::Utf8Value eventId(isolate, args[HIVIEW_ARGS_ID_IDX]);
2927 v8::String::Utf8Value eventJsonStr(isolate, args[HIVIEW_ARGS_JSON_IDX]);
2928 if (*eventId && *eventJsonStr) {
2929 EventReport::JsEventReport(StringToInt(*eventId), *eventJsonStr);
2930 LOGD("JsEventReport success");
2931 }
2932 } else {
2933 LOGE("parameter type error");
2934 }
2935 }
2936
2937 // function callback for JsPluralRulesFormat's function: select
JsPluralRulesFormat(const v8::FunctionCallbackInfo<v8::Value> & args)2938 void JsPluralRulesFormat(const v8::FunctionCallbackInfo<v8::Value>& args)
2939 {
2940 CHECK_RUN_ON(JS);
2941 LOGD("Enter JsPluralRulesFormat");
2942 v8::Isolate* isolate = args.GetIsolate();
2943 ACE_DCHECK(isolate);
2944 v8::Isolate::Scope isolateScope(isolate);
2945 v8::HandleScope handleScope(isolate);
2946
2947 if (args.Length() != 1) {
2948 LOGE("argc error, argc = %{private}d", args.Length());
2949 return;
2950 }
2951 if (args[0]->IsNumber()) {
2952 v8::String::Utf8Value choice(isolate, args[0]);
2953 if (*choice) {
2954 const char* result = Localization::GetInstance()->PluralRulesFormat(StringToDouble(*choice)).c_str();
2955 if (result == nullptr) {
2956 LOGE("result == nullptr");
2957 v8::Local<v8::Value> val = v8::Null(isolate);
2958 args.GetReturnValue().Set(val);
2959 return;
2960 }
2961 v8::Local<v8::String> resultV8 = v8::String::NewFromUtf8(isolate, result).ToLocalChecked();
2962 args.GetReturnValue().Set(resultV8);
2963 LOGD("JsPluralRulesFormat success");
2964 }
2965 } else {
2966 LOGE("parameter type error");
2967 }
2968 }
2969
GetNodeId(const v8::Local<v8::Context> & ctx,v8::Local<v8::Object> value)2970 inline int32_t GetNodeId(const v8::Local<v8::Context>& ctx, v8::Local<v8::Object> value)
2971 {
2972 v8::Isolate* isolate = ctx->GetIsolate();
2973 v8::HandleScope handleScope(isolate);
2974 int32_t id = value->Get(ctx, v8::String::NewFromUtf8(isolate, "__nodeId").ToLocalChecked())
2975 .ToLocalChecked()
2976 ->Int32Value(ctx)
2977 .ToChecked();
2978 return id < 0 ? 0 : id;
2979 }
2980
JsFocus(const v8::FunctionCallbackInfo<v8::Value> & args)2981 void JsFocus(const v8::FunctionCallbackInfo<v8::Value>& args)
2982 {
2983 v8::Isolate* isolate = args.GetIsolate();
2984 v8::HandleScope handleScope(isolate);
2985 auto page = GetStagingPage();
2986 if (page == nullptr) {
2987 LOGE("GetStagingPage return nullptr");
2988 return;
2989 }
2990 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
2991 (*delegate)->TriggerPageUpdate(page->GetPageId(), true);
2992 }
2993
JsAnimate(const v8::FunctionCallbackInfo<v8::Value> & args)2994 void JsAnimate(const v8::FunctionCallbackInfo<v8::Value>& args)
2995 {
2996 v8::Isolate* isolate = args.GetIsolate();
2997 v8::HandleScope handleScope(isolate);
2998 auto context = isolate->GetCurrentContext();
2999 if (context.IsEmpty()) {
3000 LOGE("JsAnimate, CurrentContext is empty!");
3001 return;
3002 }
3003 auto page = GetStagingPage();
3004 if (page == nullptr) {
3005 LOGE("GetStagingPage return nullptr");
3006 return;
3007 }
3008 v8::String::Utf8Value jsArguments(isolate, args[0]);
3009 if (!(*jsArguments)) {
3010 return;
3011 }
3012 std::string arguments(*jsArguments);
3013 int32_t nodeId = GetNodeId(context, args.Holder());
3014 auto resultValue = V8AnimationBridgeUtils::CreateAnimationContext(context, page->GetPageId(), nodeId);
3015 auto animationBridge = AceType::MakeRefPtr<V8AnimationBridge>(context, isolate, resultValue, nodeId);
3016 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
3017 auto task = AceType::MakeRefPtr<V8AnimationBridgeTaskCreate>(*delegate, animationBridge, arguments);
3018 page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimation>(nodeId, task));
3019 args.GetReturnValue().Set(resultValue);
3020 }
3021
JsGetBoundingClientRect(const v8::FunctionCallbackInfo<v8::Value> & args)3022 void JsGetBoundingClientRect(const v8::FunctionCallbackInfo<v8::Value>& args)
3023 {
3024 v8::Isolate* isolate = args.GetIsolate();
3025 v8::HandleScope handleScope(isolate);
3026 auto context = isolate->GetCurrentContext();
3027 if (context.IsEmpty()) {
3028 LOGE("JsGetBoundingClientRect, CurrentContext is empty!");
3029 return;
3030 }
3031 auto page = GetStagingPage();
3032 if (page == nullptr) {
3033 LOGE("GetStagingPage return nullptr");
3034 return;
3035 }
3036 int32_t nodeId = GetNodeId(context, args.Holder());
3037 auto rect = V8ComponentApiBridge::JsGetBoundingRect(isolate, nodeId);
3038 args.GetReturnValue().Set(rect);
3039 }
3040
3041
JsSetAttribute(const v8::FunctionCallbackInfo<v8::Value> & args)3042 void JsSetAttribute(const v8::FunctionCallbackInfo<v8::Value>& args)
3043 {
3044 v8::Isolate* isolate = args.GetIsolate();
3045 v8::HandleScope handleScope(isolate);
3046 auto context = isolate->GetCurrentContext();
3047 if (context.IsEmpty()) {
3048 LOGE("JsSetAttribute, CurrentContext is empty!");
3049 return;
3050 }
3051 auto page = GetStagingPage();
3052 if (page == nullptr) {
3053 LOGE("GetStagingPage return nullptr");
3054 return;
3055 }
3056 auto attr = v8::Object::New(isolate);
3057 attr->Set(context, args[0], args[1]).ToChecked();
3058 int32_t nodeId = GetNodeId(context, args.Holder());
3059 auto command = Referenced::MakeRefPtr<JsCommandUpdateDomElementAttrs>(nodeId);
3060 if (SetDomAttributes(context, attr, *command)) {
3061 page->ReserveShowCommand(command);
3062 }
3063 page->PushCommand(command);
3064 }
3065
JsSetStyle(const v8::FunctionCallbackInfo<v8::Value> & args)3066 void JsSetStyle(const v8::FunctionCallbackInfo<v8::Value>& args)
3067 {
3068 v8::Isolate* isolate = args.GetIsolate();
3069 v8::HandleScope handleScope(isolate);
3070 auto context = isolate->GetCurrentContext();
3071 if (context.IsEmpty()) {
3072 LOGE("JsSetStyle, CurrentContext is empty!");
3073 return;
3074 }
3075 auto page = GetStagingPage();
3076 if (page == nullptr) {
3077 LOGE("GetStagingPage return nullptr");
3078 return;
3079 }
3080 if (!args[0]->IsString() || !args[1]->IsString()) {
3081 LOGE("args is not string ");
3082 return;
3083 }
3084 auto style = v8::Object::New(isolate);
3085 style->Set(context, args[0], args[1]).ToChecked();
3086 int32_t nodeId = GetNodeId(context, args.Holder());
3087 auto command = Referenced::MakeRefPtr<JsCommandUpdateDomElementStyles>(nodeId);
3088 SetDomStyle(context, style, *command);
3089 page->PushCommand(command);
3090 }
3091
JsAppendChild(const v8::FunctionCallbackInfo<v8::Value> & args)3092 void JsAppendChild(const v8::FunctionCallbackInfo<v8::Value>& args)
3093 {
3094 v8::Isolate* isolate = args.GetIsolate();
3095 v8::HandleScope handleScope(isolate);
3096 auto context = isolate->GetCurrentContext();
3097 if (context.IsEmpty()) {
3098 LOGE("JsAppendChild, CurrentContext is empty!");
3099 return;
3100 }
3101 auto page = GetStagingPage();
3102 if (page == nullptr) {
3103 LOGE("GetStagingPage return nullptr");
3104 return;
3105 }
3106 int32_t parentNodeId = GetNodeId(context, args.Holder());
3107 auto object = args[0]->ToObject(context).ToLocalChecked();
3108 int32_t id = object->Get(context, v8::String::NewFromUtf8(isolate, "__nodeId").ToLocalChecked())
3109 .ToLocalChecked()->Int32Value(context).ToChecked();
3110 int32_t childId = id < 0 ? 0 : id;
3111 auto domDocument = page->GetDomDocument();
3112 if (domDocument) {
3113 RefPtr<DOMNode> node = domDocument->GetDOMNodeById(childId);
3114 if (node == nullptr) {
3115 LOGE("node is nullptr");
3116 return;
3117 }
3118 auto command = Referenced::MakeRefPtr<JsCommandAppendElement>(node->GetTag(), node->GetNodeId(), parentNodeId);
3119 page->PushCommand(command);
3120 if (!page->CheckPageCreated() && page->GetCommandSize() > FRAGMENT_SIZE) {
3121 page->FlushCommands();
3122 }
3123 }
3124 }
3125
CreateDomElement(const v8::FunctionCallbackInfo<v8::Value> & args)3126 void CreateDomElement(const v8::FunctionCallbackInfo<v8::Value>& args)
3127 {
3128 CHECK_RUN_ON(JS);
3129 LOGD("Enter CreateDomElement");
3130 v8::Isolate* isolate = args.GetIsolate();
3131 v8::Isolate::Scope isolateScope(isolate);
3132 v8::HandleScope handleScope(isolate);
3133 ACE_SCOPED_TRACE("CreateDomElement");
3134 if (args.Length() != 1) {
3135 LOGE("argc error, argc = %{private}d", args.Length());
3136 return;
3137 }
3138 auto page = GetStagingPage();
3139 if (page == nullptr) {
3140 LOGE("GetStagingPage return nullptr");
3141 return;
3142 }
3143 int32_t nodeId = ++globalNodeId;
3144 v8::String::Utf8Value tagJsStr(isolate, args[0]);
3145 if (!(*tagJsStr)) {
3146 return;
3147 }
3148 std::string tag(*tagJsStr);
3149 auto command = Referenced::MakeRefPtr<JsCommandCreateDomElement>(tag.c_str(), nodeId);
3150 page->PushCommand(command);
3151 // Flush command as fragment immediately when pushed too many commands.
3152 if (!page->CheckPageCreated() && page->GetCommandSize() > FRAGMENT_SIZE) {
3153 page->FlushCommands();
3154 }
3155 }
3156
JsCreateElement(const v8::FunctionCallbackInfo<v8::Value> & args)3157 void JsCreateElement(const v8::FunctionCallbackInfo<v8::Value>& args)
3158 {
3159 CreateDomElement(args);
3160 v8::Isolate* isolate = args.GetIsolate();
3161 v8::Isolate::Scope isolateScope(isolate);
3162 v8::HandleScope handleScope(isolate);
3163 auto context = isolate->GetCurrentContext();
3164 if (context.IsEmpty()) {
3165 LOGE("JsPerfBegin, CurrentContext is empty!");
3166 return;
3167 }
3168 auto nodeObj = v8::Object::New(isolate);
3169 nodeObj->Set(context, v8::String::NewFromUtf8(isolate, "__nodeId").ToLocalChecked(),
3170 v8::Int32::New(isolate, globalNodeId)).ToChecked();
3171 nodeObj->Set(context, v8::String::NewFromUtf8(isolate, "setAttribute").ToLocalChecked(),
3172 v8::Function::New(context, JsSetAttribute, v8::Local<v8::Value>(), 1).ToLocalChecked())
3173 .ToChecked();
3174 nodeObj->Set(context, v8::String::NewFromUtf8(isolate, "setStyle").ToLocalChecked(),
3175 v8::Function::New(context, JsSetStyle, v8::Local<v8::Value>(), 1).ToLocalChecked())
3176 .ToChecked();
3177 nodeObj->Set(context, v8::String::NewFromUtf8(isolate, "addChild").ToLocalChecked(),
3178 v8::Function::New(context, JsAppendChild, v8::Local<v8::Value>(), 1).ToLocalChecked())
3179 .ToChecked();
3180 nodeObj->Set(context, v8::String::NewFromUtf8(isolate, "focus").ToLocalChecked(),
3181 v8::Function::New(context, JsFocus, v8::Local<v8::Value>(), 1).ToLocalChecked())
3182 .ToChecked();
3183 nodeObj->Set(context, v8::String::NewFromUtf8(isolate, "animate").ToLocalChecked(),
3184 v8::Function::New(context, JsAnimate, v8::Local<v8::Value>(), 1).ToLocalChecked())
3185 .ToChecked();
3186 nodeObj->Set(context, v8::String::NewFromUtf8(isolate, "getBoundingClientRect").ToLocalChecked(),
3187 v8::Function::New(context, JsGetBoundingClientRect, v8::Local<v8::Value>(), 1).ToLocalChecked())
3188 .ToChecked();
3189 args.GetReturnValue().Set(nodeObj);
3190 }
3191 } // namespace
3192
3193 // -----------------------
3194 // Start V8EngineInstance
3195 // -----------------------
FlushCommandBuffer(void * context,const std::string & command)3196 void V8EngineInstance::FlushCommandBuffer(void* context, const std::string& command)
3197 {
3198 CHECK_RUN_ON(JS);
3199 LOGI("flush command buffer");
3200 auto v8Context = *(static_cast<v8::Local<v8::Context>*>(context));
3201 v8::Isolate* isolate = v8Context->GetIsolate();
3202 ACE_DCHECK(isolate);
3203 bool result = CallEvalBuf(isolate, command.c_str(), instanceId_);
3204 if (!result) {
3205 LOGE("failed to flush command");
3206 }
3207 }
3208
CallJs(const std::string & callbackId,const std::string & args,bool keepAlive,bool isGlobal)3209 void V8EngineInstance::CallJs(const std::string& callbackId, const std::string& args, bool keepAlive, bool isGlobal)
3210 {
3211 CHECK_RUN_ON(JS);
3212 v8::Isolate* isolate = GetV8Isolate();
3213 v8::HandleScope handleScope(isolate);
3214 v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>> pContext;
3215 pContext.Reset(isolate, GetV8Context());
3216 V8EngineInstance::CallJs(isolate, pContext, callbackId, args, keepAlive, isGlobal);
3217 pContext.Reset();
3218 }
3219
CallJs(v8::Isolate * isolate,v8::Persistent<v8::Context,v8::CopyablePersistentTraits<v8::Context>> pcontext,const std::string & callbackId,const std::string & args,bool keepAlive,bool isGlobal)3220 void V8EngineInstance::CallJs(v8::Isolate* isolate,
3221 v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>> pcontext, const std::string& callbackId,
3222 const std::string& args, bool keepAlive, bool isGlobal)
3223 {
3224 CHECK_RUN_ON(JS);
3225 std::string keepAliveStr = keepAlive ? "true" : "false";
3226 std::string callBuff = std::string("[{\"args\": [\"")
3227 .append(callbackId)
3228 .append("\",")
3229 .append(args)
3230 .append(",")
3231 .append(keepAliveStr)
3232 .append("], \"method\":\"callback\"}]");
3233 ACE_DCHECK(isolate);
3234 v8::HandleScope handleScope(isolate);
3235 v8::Local<v8::Context> context = pcontext.Get(isolate);
3236 if (context.IsEmpty()) {
3237 LOGE("CallJs, context Is Empty");
3238 return;
3239 }
3240
3241 v8::Context::Scope contextScope(context);
3242 v8::Local<v8::Object> global = context->Global();
3243 v8::Local<v8::String> funcName = v8::String::NewFromUtf8(isolate, "callJS").ToLocalChecked();
3244 v8::Local<v8::Value> jsFuncVal;
3245 bool succ = global->Get(context, funcName).ToLocal(&jsFuncVal);
3246 if (!succ) {
3247 LOGE("cannot find 'callJS' function from global object, this should not happen!");
3248 return;
3249 }
3250
3251 v8::Local<v8::Function> jsFunc = v8::Local<v8::Function>::Cast(jsFuncVal);
3252
3253 auto stagingPage = static_cast<RefPtr<JsAcePage>*>(isolate->GetData(V8EngineInstance::STAGING_PAGE));
3254 int32_t instanceId = isGlobal ? DEFAULT_APP_ID : (*stagingPage)->GetPageId();
3255
3256 v8::TryCatch tryCatch(isolate);
3257 v8::Local<v8::String> callBufStr = v8::String::NewFromUtf8(isolate, callBuff.c_str()).ToLocalChecked();
3258 v8::Local<v8::Value> jsonBuf;
3259 if (!v8::JSON::Parse(context, callBufStr).ToLocal(&jsonBuf)) {
3260 LOGE("Cannot parse callBuf to json format correctly, CallJs stop!");
3261 return;
3262 }
3263 v8::Local<v8::Value> argv[] = { v8::Integer::New(isolate, instanceId), jsonBuf };
3264 int32_t len = sizeof(argv) / sizeof(argv[0]);
3265 v8::Local<v8::Value> res;
3266 succ = jsFunc->Call(context, global, len, argv).ToLocal(&res);
3267 if (succ) {
3268 LOGD("func callJs success!");
3269 } else {
3270 V8Utils::JsStdDumpErrorAce(isolate, &tryCatch, JsErrorType::FIRE_EVENT_ERROR, instanceId, *stagingPage);
3271 LOGD("func callJs fail!");
3272 }
3273
3274 while (v8::platform::PumpMessageLoop(V8Engine::GetPlatform().get(), isolate)) {
3275 continue;
3276 }
3277 }
3278
InitJsEnv()3279 bool V8EngineInstance::InitJsEnv()
3280 {
3281 CHECK_RUN_ON(JS);
3282 LOGI("Enter InitJsEnv");
3283 // create Isolate
3284 create_params_.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
3285 #if defined(USE_EXTERNAL_V8_SNAPSHOT)
3286 #else
3287 static v8::StartupData snapshotBlob = {
3288 .data = _binary_strip_native_min_js_bin_start,
3289 .raw_size = _binary_strip_native_min_js_bin_end - _binary_strip_native_min_js_bin_start,
3290 };
3291 create_params_.snapshot_blob = &snapshotBlob;
3292 #endif
3293 isolate_ = v8::Isolate::New(create_params_);
3294 if (isolate_ == nullptr) {
3295 LOGE("JS Engine cannot allocate JS runtime");
3296 EventReport::SendJsException(JsExcepType::JS_ENGINE_INIT_ERR);
3297 return false;
3298 }
3299
3300 isolate_->SetStackLimit(V8_MAX_STACK_SIZE);
3301 isolate_->SetData(V8EngineInstance::FRONTEND_DELEGATE, static_cast<void*>(&frontendDelegate_));
3302 isolate_->SetData(V8EngineInstance::RUNNING_PAGE, static_cast<void*>(&runningPage_));
3303 isolate_->SetData(V8EngineInstance::STAGING_PAGE, static_cast<void*>(&stagingPage_));
3304 isolate_->SetData(V8EngineInstance::DISPATCHER, static_cast<void*>(&dispatcher_));
3305
3306 // create context
3307 InitJsContext();
3308 return true;
3309 }
3310
InitJsContext()3311 void V8EngineInstance::InitJsContext()
3312 {
3313 CHECK_RUN_ON(JS);
3314 LOGI("Enter InitJsContext");
3315 v8::Isolate::Scope isolateScope(isolate_);
3316 v8::HandleScope handleScope(isolate_);
3317
3318 InitGlobalObjectTemplate();
3319
3320 v8::Local<v8::Context> localContext = v8::Context::New(isolate_, nullptr, globalObjectTemplate_.Get(isolate_));
3321
3322 v8::Context::Scope contextScope(localContext);
3323
3324 InitJsConsoleObject(localContext, isolate_);
3325 InitJsDocumentObject(localContext, isolate_);
3326 InitJsPerfUtilObject(localContext);
3327
3328 const char* str = "var global = globalThis;\n"
3329 "global.callNative = ace.callNative;\n";
3330 const char* debugStr = "global.compileAndRunBundle = ace.compileAndRunBundle;\n";
3331 const std::string& addStr = std::string(str) + std::string(debugStr);
3332 str = addStr.c_str();
3333
3334 bool evalAceModule = CallEvalBuf(isolate_, str, instanceId_);
3335 if (!evalAceModule) {
3336 LOGW("JS Engine created JS context but failed to init Ace modules!");
3337 }
3338
3339 auto groupJsBridge = DynamicCast<V8GroupJsBridge>(frontendDelegate_->GetGroupJsBridge());
3340 if (groupJsBridge == nullptr || groupJsBridge->InitializeGroupJsBridge(localContext) == JS_CALL_FAIL) {
3341 LOGE("JS Engine Initialize GroupJsBridge failed!");
3342 EventReport::SendJsException(JsExcepType::JS_ENGINE_INIT_ERR);
3343 }
3344
3345 context_.Reset(isolate_, localContext);
3346 }
3347
InitJsConsoleObject(v8::Local<v8::Context> & localContext,v8::Isolate * isolate)3348 void V8EngineInstance::InitJsConsoleObject(v8::Local<v8::Context>& localContext, v8::Isolate* isolate)
3349 {
3350 if (isolate == nullptr) {
3351 LOGE("isolate is nullptr");
3352 return;
3353 }
3354 v8::Local<v8::Object> global = localContext->Global();
3355 // app log method
3356 v8::Local<v8::Value> console =
3357 global->Get(localContext, v8::String::NewFromUtf8(isolate, "console").ToLocalChecked()).ToLocalChecked();
3358 v8::Local<v8::Object> consoleObj = console->ToObject(localContext).ToLocalChecked();
3359 consoleObj
3360 ->Set(localContext, v8::String::NewFromUtf8(isolate, "log").ToLocalChecked(),
3361 v8::Function::New(
3362 localContext, AppLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::INFO)))
3363 .ToLocalChecked())
3364 .ToChecked();
3365 consoleObj
3366 ->Set(localContext, v8::String::NewFromUtf8(isolate, "debug").ToLocalChecked(),
3367 v8::Function::New(
3368 localContext, AppLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::DEBUG)))
3369 .ToLocalChecked())
3370 .ToChecked();
3371 consoleObj
3372 ->Set(localContext, v8::String::NewFromUtf8(isolate, "info").ToLocalChecked(),
3373 v8::Function::New(
3374 localContext, AppLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::INFO)))
3375 .ToLocalChecked())
3376 .ToChecked();
3377 consoleObj
3378 ->Set(localContext, v8::String::NewFromUtf8(isolate, "warn").ToLocalChecked(),
3379 v8::Function::New(
3380 localContext, AppLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::WARNING)))
3381 .ToLocalChecked())
3382 .ToChecked();
3383 consoleObj
3384 ->Set(localContext, v8::String::NewFromUtf8(isolate, "error").ToLocalChecked(),
3385 v8::Function::New(
3386 localContext, AppLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::ERROR)))
3387 .ToLocalChecked())
3388 .ToChecked();
3389 // js framework log method
3390 auto aceConsoleObj = v8::Object::New(isolate);
3391 global->Set(localContext, v8::String::NewFromUtf8(isolate, "aceConsole").ToLocalChecked(), aceConsoleObj)
3392 .ToChecked();
3393 aceConsoleObj
3394 ->Set(localContext, v8::String::NewFromUtf8(isolate, "log").ToLocalChecked(),
3395 v8::Function::New(
3396 localContext, JsLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::INFO)))
3397 .ToLocalChecked())
3398 .ToChecked();
3399 aceConsoleObj
3400 ->Set(localContext, v8::String::NewFromUtf8(isolate, "debug").ToLocalChecked(),
3401 v8::Function::New(
3402 localContext, JsLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::DEBUG)))
3403 .ToLocalChecked())
3404 .ToChecked();
3405 aceConsoleObj
3406 ->Set(localContext, v8::String::NewFromUtf8(isolate, "info").ToLocalChecked(),
3407 v8::Function::New(
3408 localContext, JsLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::INFO)))
3409 .ToLocalChecked())
3410 .ToChecked();
3411 aceConsoleObj
3412 ->Set(localContext, v8::String::NewFromUtf8(isolate, "warn").ToLocalChecked(),
3413 v8::Function::New(
3414 localContext, JsLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::WARNING)))
3415 .ToLocalChecked())
3416 .ToChecked();
3417 aceConsoleObj
3418 ->Set(localContext, v8::String::NewFromUtf8(isolate, "error").ToLocalChecked(),
3419 v8::Function::New(
3420 localContext, JsLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::ERROR)))
3421 .ToLocalChecked())
3422 .ToChecked();
3423 }
3424
InitJsDocumentObject(v8::Local<v8::Context> & localContext,v8::Isolate * isolate)3425 void V8EngineInstance::InitJsDocumentObject(v8::Local<v8::Context>& localContext, v8::Isolate* isolate)
3426 {
3427 v8::Local<v8::Object> global = localContext->Global();
3428 auto documentObj = v8::Object::New(isolate);
3429 global->Set(localContext, v8::String::NewFromUtf8(isolate, "dom").ToLocalChecked(), documentObj).ToChecked();
3430 documentObj
3431 ->Set(localContext, v8::String::NewFromUtf8(isolate, "createElement").ToLocalChecked(),
3432 v8::Function::New(
3433 localContext, JsCreateElement, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::ERROR)))
3434 .ToLocalChecked())
3435 .ToChecked();
3436 }
3437
InitJsPerfUtilObject(v8::Local<v8::Context> & localContext)3438 void V8EngineInstance::InitJsPerfUtilObject(v8::Local<v8::Context>& localContext)
3439 {
3440 v8::Local<v8::Object> global = localContext->Global();
3441
3442 auto perfUtilObj = v8::Object::New(isolate_);
3443 global->Set(localContext, v8::String::NewFromUtf8(isolate_, "perfutil").ToLocalChecked(), perfUtilObj).ToChecked();
3444 perfUtilObj
3445 ->Set(localContext, v8::String::NewFromUtf8(isolate_, "printlog").ToLocalChecked(),
3446 v8::Function::New(localContext, JsPerfPrint).ToLocalChecked())
3447 .ToChecked();
3448 perfUtilObj
3449 ->Set(localContext, v8::String::NewFromUtf8(isolate_, "sleep").ToLocalChecked(),
3450 v8::Function::New(localContext, JsPerfSleep).ToLocalChecked())
3451 .ToChecked();
3452 perfUtilObj
3453 ->Set(localContext, v8::String::NewFromUtf8(isolate_, "begin").ToLocalChecked(),
3454 v8::Function::New(localContext, JsPerfBegin).ToLocalChecked())
3455 .ToChecked();
3456 perfUtilObj
3457 ->Set(localContext, v8::String::NewFromUtf8(isolate_, "end").ToLocalChecked(),
3458 v8::Function::New(localContext, JsPerfEnd).ToLocalChecked())
3459 .ToChecked();
3460 }
3461
InitGlobalObjectTemplate()3462 void V8EngineInstance::InitGlobalObjectTemplate()
3463 {
3464 v8::Isolate::Scope isolateScope(isolate_);
3465 v8::HandleScope handleScope(isolate_);
3466 v8::Local<v8::ObjectTemplate> globalObj = v8::ObjectTemplate::New(isolate_);
3467
3468 // Add ace modules
3469 v8::Local<v8::External> engineInstance = v8::External::New(isolate_, static_cast<void*>(this));
3470 v8::Local<v8::ObjectTemplate> aceObj = v8::ObjectTemplate::New(isolate_);
3471 aceObj->Set(v8::String::NewFromUtf8(isolate_, "domCreateBody").ToLocalChecked(),
3472 v8::FunctionTemplate::New(isolate_, JsDomCreateBody));
3473 aceObj->Set(v8::String::NewFromUtf8(isolate_, "domAddElement").ToLocalChecked(),
3474 v8::FunctionTemplate::New(isolate_, JsDomAddElement));
3475 aceObj->Set(v8::String::NewFromUtf8(isolate_, "updateElementAttrs").ToLocalChecked(),
3476 v8::FunctionTemplate::New(isolate_, JsUpdateElementAttrs));
3477 aceObj->Set(v8::String::NewFromUtf8(isolate_, "updateElementStyles").ToLocalChecked(),
3478 v8::FunctionTemplate::New(isolate_, JsUpdateElementStyles));
3479 aceObj->Set(v8::String::NewFromUtf8(isolate_, "onCreateFinish").ToLocalChecked(),
3480 v8::FunctionTemplate::New(isolate_, JsOnCreateFinish));
3481 aceObj->Set(v8::String::NewFromUtf8(isolate_, "onUpdateFinish").ToLocalChecked(),
3482 v8::FunctionTemplate::New(isolate_, JsOnUpdateFinish));
3483 aceObj->Set(v8::String::NewFromUtf8(isolate_, "removeElement").ToLocalChecked(),
3484 v8::FunctionTemplate::New(isolate_, JsRemoveElement));
3485 aceObj->Set(v8::String::NewFromUtf8(isolate_, "callNative").ToLocalChecked(),
3486 v8::FunctionTemplate::New(isolate_, JsCallNative, engineInstance));
3487 aceObj->Set(v8::String::NewFromUtf8(isolate_, "callComponent").ToLocalChecked(),
3488 v8::FunctionTemplate::New(isolate_, JsCallComponent, engineInstance));
3489 aceObj->Set(v8::String::NewFromUtf8(isolate_, "compileAndRunBundle").ToLocalChecked(),
3490 v8::FunctionTemplate::New(isolate_, JsCompileAndRunBundle));
3491
3492 globalObj->Set(v8::String::NewFromUtf8(isolate_, "ace").ToLocalChecked(), aceObj);
3493
3494 // Add hiview
3495 v8::Local<v8::ObjectTemplate> hiViewObj = v8::ObjectTemplate::New(isolate_);
3496 hiViewObj->Set(v8::String::NewFromUtf8(isolate_, "report").ToLocalChecked(),
3497 v8::FunctionTemplate::New(isolate_, JsHiViewReport));
3498 globalObj->Set(v8::String::NewFromUtf8(isolate_, "hiView").ToLocalChecked(), hiViewObj);
3499
3500 // Add i18nPluralRules
3501 v8::Local<v8::ObjectTemplate> i18nPluralRulesObj = v8::ObjectTemplate::New(isolate_);
3502 i18nPluralRulesObj->Set(v8::String::NewFromUtf8(isolate_, "select").ToLocalChecked(),
3503 v8::FunctionTemplate::New(isolate_, JsPluralRulesFormat));
3504 globalObj->Set(v8::String::NewFromUtf8(isolate_, "i18nPluralRules").ToLocalChecked(), i18nPluralRulesObj);
3505
3506 globalObjectTemplate_.Reset(isolate_, globalObj);
3507 }
3508
FireJsEvent(const std::string & param)3509 bool V8EngineInstance::FireJsEvent(const std::string& param)
3510 {
3511 CHECK_RUN_ON(JS);
3512 LOGI("Enter FireJsEvent");
3513 v8::Isolate* isolate = v8::Isolate::GetCurrent();
3514 ACE_DCHECK(isolate);
3515 v8::HandleScope handleScope(isolate);
3516 auto context = GetV8Context();
3517 if (context.IsEmpty()) {
3518 LOGE("FireJsEvent, context Is Empty");
3519 return false;
3520 }
3521 v8::Context::Scope contextScope(context);
3522
3523 v8::TryCatch tryCatch(isolate);
3524
3525 v8::Local<v8::Object> global = context->Global();
3526 v8::Local<v8::String> funcName = v8::String::NewFromUtf8(isolate, "callJS").ToLocalChecked();
3527 v8::Local<v8::Value> jsFuncVal;
3528 bool succ = global->Get(context, funcName).ToLocal(&jsFuncVal);
3529 if (!succ) {
3530 LOGE("cannot find 'callJS' function from global object, this should not happen!");
3531 return false;
3532 }
3533 v8::Local<v8::Function> jsFunc = v8::Local<v8::Function>::Cast(jsFuncVal);
3534
3535 if (runningPage_ == nullptr) {
3536 LOGE("runningPage_ is null!");
3537 return false;
3538 }
3539 std::string pageId = std::to_string(runningPage_->GetPageId());
3540 v8::Local<v8::String> jsParam = v8::String::NewFromUtf8(isolate_, param.c_str()).ToLocalChecked();
3541 v8::Local<v8::Value> jsParamJson;
3542 if (!v8::JSON::Parse(context, jsParam).ToLocal(&jsParamJson)) {
3543 LOGE("Cannot parse jsParam to json format correctly, callJS stop!");
3544 return false;
3545 }
3546 v8::Local<v8::Value> argv[] = { v8::String::NewFromUtf8(isolate_, pageId.c_str()).ToLocalChecked(), jsParamJson };
3547 int32_t len = sizeof(argv) / sizeof(argv[0]);
3548
3549 v8::Local<v8::Value> res;
3550 succ = jsFunc->Call(context, global, len, argv).ToLocal(&res);
3551 if (!succ) {
3552 V8Utils::JsStdDumpErrorAce(isolate, &tryCatch, JsErrorType::FIRE_EVENT_ERROR, instanceId_, runningPage_);
3553 return false;
3554 }
3555
3556 while (v8::platform::PumpMessageLoop(V8Engine::GetPlatform().get(), isolate)) {
3557 continue;
3558 }
3559
3560 return succ;
3561 }
3562
~V8EngineInstance()3563 V8EngineInstance::~V8EngineInstance()
3564 {
3565 CHECK_RUN_ON(JS);
3566 if (runningPage_) {
3567 runningPage_->OnJsEngineDestroy();
3568 }
3569
3570 if (stagingPage_) {
3571 stagingPage_->OnJsEngineDestroy();
3572 }
3573 context_.Reset();
3574 globalObjectTemplate_.Reset();
3575 delete create_params_.array_buffer_allocator;
3576
3577 // Destroy group bridge
3578 auto groupJsBridge = frontendDelegate_->GetGroupJsBridge();
3579 if (groupJsBridge != nullptr) {
3580 groupJsBridge->Destroy();
3581 }
3582 isolate_->Dispose();
3583 }
3584
LoadDebuggerSo()3585 void LoadDebuggerSo()
3586 {
3587 LOGI("LoadDebuggerSo");
3588 const std::string soDir = "libv8_debugger.z.so";
3589 g_debugger = dlopen(soDir.c_str(), RTLD_LAZY);
3590 if (g_debugger == nullptr) {
3591 LOGE("cannot find debugger so");
3592 }
3593 }
3594
StartDebuggerAgent(const std::unique_ptr<v8::Platform> & platform,const v8::Local<v8::Context> & context,std::string componentName,const bool isDebugMode,const int32_t instanceId)3595 void StartDebuggerAgent(
3596 const std::unique_ptr<v8::Platform>& platform, const v8::Local<v8::Context>& context, std::string componentName,
3597 const bool isDebugMode, const int32_t instanceId)
3598 {
3599 LOGI("StartAgent");
3600 if (g_debugger == nullptr) {
3601 LOGE("g_debugger is null");
3602 return;
3603 }
3604
3605 StartDebug startDebug = (StartDebug)dlsym(g_debugger, "StartDebug");
3606 if (startDebug == nullptr) {
3607 LOGE("StartDebug=NULL, dlerror=%s", dlerror());
3608 return;
3609 }
3610 startDebug(platform, context, componentName, isDebugMode, instanceId);
3611 }
3612
3613 // -----------------------
3614 // Start V8Engine
3615 // -----------------------
V8Engine(int32_t instanceId)3616 V8Engine::V8Engine(int32_t instanceId) : instanceId_(instanceId) {}
3617
GetPlatform()3618 std::unique_ptr<v8::Platform>& V8Engine::GetPlatform()
3619 {
3620 return V8Helper::GetPlatform();
3621 }
3622
Initialize(const RefPtr<FrontendDelegate> & delegate)3623 bool V8Engine::Initialize(const RefPtr<FrontendDelegate>& delegate)
3624 {
3625 ACE_SCOPED_TRACE("V8Engine::Initialize");
3626 LOGI("V8Engine initialize");
3627 ACE_DCHECK(delegate);
3628 CHECK_RUN_ON(JS);
3629
3630 // Initialize V8 engine
3631 GetPlatform();
3632
3633 // if load debugger.so successfully, debug mode
3634 if (IsDebugVersion()) {
3635 LoadDebuggerSo();
3636 LOGI("debug mode");
3637 }
3638 // Initialize engine instance
3639 engineInstance_ = AceType::MakeRefPtr<V8EngineInstance>(delegate, instanceId_);
3640 bool res = engineInstance_->InitJsEnv();
3641 if (!res) {
3642 return false;
3643 }
3644
3645 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
3646 {
3647 ACE_DCHECK(isolate);
3648 v8::Isolate::Scope isolateScope(isolate);
3649 v8::HandleScope handleScope(isolate);
3650 auto context = engineInstance_->GetV8Context();
3651 if (context.IsEmpty()) {
3652 LOGE("Initialize, context Is Empty");
3653 return false;
3654 }
3655 // debug mode
3656 if (g_debugger != nullptr) {
3657 std::string instanceName = GetInstanceName();
3658 if (instanceName.empty()) {
3659 LOGE("GetInstanceName fail, %s", instanceName.c_str());
3660 return false;
3661 }
3662 StartDebuggerAgent(GetPlatform(), context, instanceName, NeedDebugBreakPoint(), instanceId_);
3663 }
3664 }
3665 nativeEngine_ = std::make_shared<V8NativeEngine>(
3666 GetPlatform().get(), isolate, engineInstance_->GetContext(), static_cast<void*>(this));
3667 engineInstance_->SetV8NativeEngine(nativeEngine_);
3668 SetPostTask();
3669 #if !defined(PREVIEW)
3670 nativeEngine_->CheckUVLoop();
3671 #endif
3672 RegisterWorker();
3673 if (delegate && delegate->GetAssetManager()) {
3674 std::vector<std::string> packagePath = delegate->GetAssetManager()->GetLibPath();
3675 if (!packagePath.empty()) {
3676 nativeEngine_->SetPackagePath(packagePath);
3677 }
3678 }
3679
3680 return true;
3681 }
3682
SetPostTask()3683 void V8Engine::SetPostTask()
3684 {
3685 LOGI("SetPostTask");
3686 auto weakDelegate = AceType::WeakClaim(AceType::RawPtr(engineInstance_->GetDelegate()));
3687 auto&& postTask = [weakDelegate, weakEngine = AceType::WeakClaim(this), id = instanceId_](bool needSync) {
3688 auto delegate = weakDelegate.Upgrade();
3689 if (delegate == nullptr) {
3690 LOGE("delegate is nullptr");
3691 return;
3692 }
3693 delegate->PostJsTask([weakEngine, needSync, id]() {
3694 auto jsEngine = weakEngine.Upgrade();
3695 if (jsEngine == nullptr) {
3696 LOGW("jsEngine is nullptr");
3697 return;
3698 }
3699 auto nativeEngine = jsEngine->GetNativeEngine();
3700 ContainerScope scope(id);
3701 if (!nativeEngine) {
3702 LOGE("native v8 engine weak pointer invalid");
3703 return;
3704 }
3705 nativeEngine->Loop(LOOP_NOWAIT, needSync);
3706 });
3707 };
3708 nativeEngine_->SetPostTask(postTask);
3709 }
3710
RegisterInitWorkerFunc()3711 void V8Engine::RegisterInitWorkerFunc()
3712 {
3713 auto weakInstance = AceType::WeakClaim(AceType::RawPtr(engineInstance_));
3714 auto&& initWorkerFunc = [weakInstance](NativeEngine* nativeEngine) {
3715 LOGI("WorkerCore RegisterInitWorkerFunc called");
3716 if (nativeEngine == nullptr) {
3717 LOGE("nativeEngine is nullptr");
3718 return;
3719 }
3720 auto v8NativeEngine = static_cast<V8NativeEngine*>(nativeEngine);
3721 if (v8NativeEngine == nullptr) {
3722 LOGE("v8NativeEngine is nullptr");
3723 return;
3724 }
3725 auto instance = weakInstance.Upgrade();
3726 if (instance == nullptr) {
3727 LOGE("instance is nullptr");
3728 return;
3729 }
3730 v8::Isolate* isolate = v8NativeEngine->GetIsolate();
3731 if (isolate == nullptr) {
3732 LOGE("isolate is nullptr");
3733 return;
3734 }
3735 v8::HandleScope handleScope(isolate);
3736 v8::Local<v8::Context> localContext = v8NativeEngine->GetContext();
3737 auto dispatcher = instance->GetJsMessageDispatcher();
3738 isolate->SetData(V8EngineInstance::DISPATCHER, static_cast<void*>(&dispatcher));
3739 instance->InitJsConsoleObject(localContext, isolate);
3740 };
3741 nativeEngine_->SetInitWorkerFunc(initWorkerFunc);
3742 }
3743
RegisterAssetFunc()3744 void V8Engine::RegisterAssetFunc()
3745 {
3746 auto weakDelegate = AceType::WeakClaim(AceType::RawPtr(engineInstance_->GetDelegate()));
3747 auto&& assetFunc = [weakDelegate](const std::string& uri, std::vector<uint8_t>& content, std::string& ami) {
3748 LOGI("WorkerCore RegisterAssetFunc called");
3749 auto delegate = weakDelegate.Upgrade();
3750 if (delegate == nullptr) {
3751 LOGE("delegate is nullptr");
3752 return;
3753 }
3754 delegate->GetResourceData(uri, content);
3755 };
3756 nativeEngine_->SetGetAssetFunc(assetFunc);
3757 }
3758
RegisterOffWorkerFunc()3759 void V8Engine::RegisterOffWorkerFunc()
3760 {
3761 auto&& offWorkerFunc = [](NativeEngine* nativeEngine) {
3762 LOGI("WorkerCore RegisterOffWorkerFunc called");
3763 };
3764 nativeEngine_->SetOffWorkerFunc(offWorkerFunc);
3765 }
3766
RegisterWorker()3767 void V8Engine::RegisterWorker()
3768 {
3769 RegisterInitWorkerFunc();
3770 RegisterAssetFunc();
3771 RegisterOffWorkerFunc();
3772 }
3773
~V8Engine()3774 V8Engine::~V8Engine()
3775 {
3776 CHECK_RUN_ON(JS);
3777 if (g_debugger != nullptr) {
3778 StopDebug stopDebug = (StopDebug)dlsym(g_debugger, "StopDebug");
3779 if (stopDebug != nullptr) {
3780 stopDebug();
3781 }
3782 }
3783
3784 #if !defined(PREVIEW)
3785 if (nativeEngine_) {
3786 nativeEngine_->CancelCheckUVLoop();
3787 }
3788 #endif
3789
3790 if (g_debugger != nullptr) {
3791 dlclose(g_debugger);
3792 }
3793 }
3794
GetLoadOptions(std::string & optionStr,bool isMainPage,const RefPtr<JsAcePage> & page)3795 void V8Engine::GetLoadOptions(std::string& optionStr, bool isMainPage, const RefPtr<JsAcePage>& page)
3796 {
3797 CHECK_RUN_ON(JS);
3798 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
3799 ACE_DCHECK(isolate);
3800 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
3801
3802 auto mediaQuery = engineInstance_->GetDelegate()->GetMediaQueryInfoInstance();
3803 auto renderOption = MediaQueryInfo::GetMediaQueryJsonInfo();
3804 if (mediaQuery) {
3805 renderOption->Put("isInit", mediaQuery->GetIsInit());
3806 renderOption->Put("bundleUrl", page->GetUrl().c_str());
3807 }
3808 renderOption->Put("pcPreview", PC_PREVIEW);
3809 renderOption->Put("appInstanceId", "10002");
3810 renderOption->Put("packageName", (*delegate)->GetAppID().c_str());
3811
3812 // get resourceConfig
3813 (*delegate)->GetResourceConfiguration(renderOption);
3814
3815 // get i18n message
3816 (*delegate)->GetI18nData(renderOption);
3817 std::string language = AceApplicationInfo::GetInstance().GetLanguage();
3818 std::string region = AceApplicationInfo::GetInstance().GetCountryOrRegion();
3819 std::string local = language + "_" + region;
3820 renderOption->Put("language", local.c_str());
3821
3822 if (isMainPage) {
3823 std::string commonsJsContent;
3824 if ((*delegate)->GetAssetContent("commons.js", commonsJsContent)) {
3825 bool commonsJsResult = CallEvalBuf(isolate, commonsJsContent.c_str(), instanceId_, "commons.js");
3826 if (!commonsJsResult) {
3827 LOGE("fail to execute load commonsjs script commonsJsResult");
3828 }
3829 }
3830 std::string vendorsJsContent;
3831 if ((*delegate)->GetAssetContent("vendors.js", vendorsJsContent)) {
3832 bool vendorsJsResult = CallEvalBuf(isolate, vendorsJsContent.c_str(), instanceId_, "vendors.js");
3833 if (!vendorsJsResult) {
3834 LOGE("fail to execute load vendorsjs script");
3835 }
3836 }
3837 std::string code;
3838 if ((*delegate)->GetAssetContent("app.js", code)) {
3839 renderOption->Put("appCreate", "true");
3840 renderOption->Put("appCode", code.c_str());
3841 } else {
3842 LOGE("app.js is missing!");
3843 }
3844 std::string appMap;
3845 if ((*delegate)->GetAssetContent("app.js.map", appMap)) {
3846 page->SetAppMap(appMap);
3847 } else {
3848 LOGI("app map is missing!");
3849 }
3850 } else {
3851 renderOption->Put("appCreate", "false");
3852 }
3853 optionStr = renderOption->ToString();
3854 }
3855
LoadJs(const std::string & url,const RefPtr<JsAcePage> & page,bool isMainPage)3856 void V8Engine::LoadJs(const std::string& url, const RefPtr<JsAcePage>& page, bool isMainPage)
3857 {
3858 CHECK_RUN_ON(JS);
3859 LOGI("Enter LoadJs");
3860 ACE_SCOPED_TRACE("V8Engine::LoadJs");
3861 ACE_DCHECK(engineInstance_);
3862 engineInstance_->SetStagingPage(page);
3863 if (isMainPage) {
3864 ACE_DCHECK(!engineInstance_->GetRunningPage());
3865 engineInstance_->SetRunningPage(page);
3866 }
3867
3868 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
3869 ACE_DCHECK(isolate);
3870 v8::Isolate::Scope isolateScope(isolate);
3871 v8::HandleScope handleScope(isolate);
3872 auto context = engineInstance_->GetV8Context();
3873 v8::Context::Scope contextScope(context);
3874 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
3875 v8::TryCatch tryCatch(isolate);
3876
3877 v8::Local<v8::Object> global = context->Global();
3878 v8::Local<v8::String> funcName = v8::String::NewFromUtf8(isolate, "createInstance").ToLocalChecked();
3879 v8::Local<v8::Value> jsFuncVal;
3880 bool succ = global->Get(context, funcName).ToLocal(&jsFuncVal);
3881 if (!succ) {
3882 LOGD("no property named \"createInstance\" in global object");
3883 return;
3884 }
3885 if (!jsFuncVal->IsFunction()) {
3886 LOGD("property \"createInstance\" is not a function");
3887 return;
3888 }
3889 v8::Local<v8::Function> jsFunc = v8::Local<v8::Function>::Cast(jsFuncVal);
3890
3891 std::string jsContent;
3892 if (!(*delegate)->GetAssetContent(url, jsContent)) {
3893 LOGE("js file load failed!");
3894 return;
3895 }
3896
3897 std::string jsSourceMap;
3898 if ((*delegate)->GetAssetContent(url + ".map", jsSourceMap)) {
3899 page->SetPageMap(jsSourceMap);
3900 } else {
3901 LOGI("js source map load failed!");
3902 }
3903
3904 std::string jsonData = page->GetPageParams();
3905 if (jsonData.empty()) {
3906 jsonData = "{}";
3907 }
3908 std::string optionStr;
3909 GetLoadOptions(optionStr, isMainPage, page);
3910
3911 v8::Local<v8::String> instanceId =
3912 v8::String::NewFromUtf8(isolate, std::to_string(page->GetPageId()).c_str()).ToLocalChecked();
3913 v8::Local<v8::String> jsSrc = v8::String::NewFromUtf8(isolate, jsContent.c_str()).ToLocalChecked();
3914 v8::Local<v8::String> optionJsStr = v8::String::NewFromUtf8(isolate, optionStr.c_str()).ToLocalChecked();
3915 v8::Local<v8::Value> renderOptions;
3916 if (!v8::JSON::Parse(context, optionJsStr).ToLocal(&renderOptions)) {
3917 LOGE("Cannot parse renderOption to json format correctly, createInstance stop!");
3918 return;
3919 }
3920 v8::Local<v8::String> dataJsStr = v8::String::NewFromUtf8(isolate, jsonData.c_str()).ToLocalChecked();
3921 v8::Local<v8::Value> data;
3922 if (!v8::JSON::Parse(context, dataJsStr).ToLocal(&data)) {
3923 LOGE("Cannot parse data to json format correctly, createInstance stop!");
3924 return;
3925 }
3926 v8::Local<v8::Value> info = v8::Object::New(isolate);
3927
3928 v8::Local<v8::Value> argv[] = { instanceId, jsSrc, renderOptions, data, info };
3929 int32_t len = sizeof(argv) / sizeof(argv[0]);
3930
3931 v8::Local<v8::Value> res;
3932 succ = jsFunc->Call(context, global, len, argv).ToLocal(&res);
3933 if (!succ) {
3934 LOGE("JS framework load js bundle failed! instanceId: %{public}d", instanceId_);
3935 V8Utils::JsStdDumpErrorAce(isolate, &tryCatch, JsErrorType::LOAD_JS_BUNDLE_ERROR, instanceId_, page);
3936 return;
3937 }
3938
3939 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
3940 continue;
3941 }
3942 }
3943
UpdateRunningPage(const RefPtr<JsAcePage> & page)3944 void V8Engine::UpdateRunningPage(const RefPtr<JsAcePage>& page)
3945 {
3946 ACE_DCHECK(engineInstance_);
3947 LOGD("Enter UpdateRunningPage");
3948 engineInstance_->SetRunningPage(page);
3949 }
3950
UpdateStagingPage(const RefPtr<JsAcePage> & page)3951 void V8Engine::UpdateStagingPage(const RefPtr<JsAcePage>& page)
3952 {
3953 LOGD("Enter UpdateStagingPage");
3954 ACE_DCHECK(engineInstance_);
3955 engineInstance_->SetStagingPage(page);
3956 }
3957
ResetStagingPage()3958 void V8Engine::ResetStagingPage()
3959 {
3960 ACE_DCHECK(engineInstance_);
3961 LOGD("Enter ResetStagingPage");
3962 auto runningPage = engineInstance_->GetRunningPage();
3963 engineInstance_->ResetStagingPage(runningPage);
3964 }
3965
DestroyPageInstance(int32_t pageId)3966 void V8Engine::DestroyPageInstance(int32_t pageId)
3967 {
3968 CHECK_RUN_ON(JS);
3969 LOGI("Enter DestroyPageInstance");
3970 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
3971 ACE_DCHECK(isolate);
3972 v8::HandleScope handleScope(isolate);
3973 v8::Isolate::Scope isolateScope(isolate);
3974 auto context = engineInstance_->GetV8Context();
3975 v8::Context::Scope contextScope(context);
3976
3977 v8::TryCatch tryCatch(isolate);
3978
3979 v8::Local<v8::Object> global = context->Global();
3980 v8::Local<v8::String> funcName = v8::String::NewFromUtf8(isolate, "destroyInstance").ToLocalChecked();
3981 v8::Local<v8::Value> jsFuncVal;
3982 bool succ = global->Get(context, funcName).ToLocal(&jsFuncVal);
3983 if (!succ) {
3984 LOGD("no property named \"destroyInstance\" in global object");
3985 return;
3986 }
3987 if (!jsFuncVal->IsFunction()) {
3988 LOGD("property \"destroyInstance\" is not a function");
3989 return;
3990 }
3991 v8::Local<v8::Function> jsFunc = v8::Local<v8::Function>::Cast(jsFuncVal);
3992 v8::Local<v8::String> instanceId =
3993 v8::String::NewFromUtf8(isolate, std::to_string(pageId).c_str()).ToLocalChecked();
3994 v8::Local<v8::Value> argv[] = { instanceId };
3995 int32_t len = sizeof(argv) / sizeof(argv[0]);
3996
3997 v8::Local<v8::Value> res;
3998 succ = jsFunc->Call(context, global, len, argv).ToLocal(&res);
3999 if (!succ) {
4000 LOGE("JS Engine DestroyPageInstance FAILED!");
4001
4002 auto page = engineInstance_->GetDelegate()->GetPage(pageId);
4003 if (page) {
4004 V8Utils::JsStdDumpErrorAce(isolate, &tryCatch, JsErrorType::DESTROY_PAGE_ERROR, instanceId_, page);
4005 } else {
4006 V8Utils::JsStdDumpErrorAce(
4007 isolate, &tryCatch, JsErrorType::DESTROY_PAGE_ERROR, instanceId_, engineInstance_->GetStagingPage());
4008 }
4009 return;
4010 }
4011
4012 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
4013 continue;
4014 }
4015 }
4016
UpdateApplicationState(const std::string & packageName,Frontend::State state)4017 void V8Engine::UpdateApplicationState(const std::string& packageName, Frontend::State state)
4018 {
4019 CHECK_RUN_ON(JS);
4020 LOGI("Enter UpdateApplicationState: update app instance state from jsfwk, packageName %{public}s",
4021 packageName.c_str());
4022 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
4023 ACE_DCHECK(isolate);
4024 v8::HandleScope handleScope(isolate);
4025 v8::Isolate::Scope isolateScope(isolate);
4026 auto context = engineInstance_->GetV8Context();
4027 if (context.IsEmpty()) {
4028 LOGE("Update Application State, context Is Empty");
4029 return;
4030 }
4031 v8::Context::Scope contextScope(context);
4032
4033 v8::TryCatch tryCatch(isolate);
4034
4035 std::string stateType;
4036 switch (state) {
4037 case Frontend::State::ON_CREATE:
4038 break;
4039 case Frontend::State::ON_DESTROY:
4040 stateType = "appDestroy";
4041 break;
4042 case Frontend::State::ON_SHOW:
4043 stateType = "appShow";
4044 break;
4045 case Frontend::State::ON_HIDE:
4046 stateType = "appHide";
4047 break;
4048 default:
4049 LOGE("error State: %d", state);
4050 break;
4051 }
4052
4053 v8::Local<v8::Object> global = context->Global();
4054 v8::Local<v8::String> funcName = v8::String::NewFromUtf8(isolate, stateType.c_str()).ToLocalChecked();
4055 v8::Local<v8::Value> jsFuncVal;
4056 bool succ = global->Get(context, funcName).ToLocal(&jsFuncVal);
4057 if (!succ) {
4058 LOGD("no property named \"destroyInstance\" in global object");
4059 return;
4060 }
4061 if (!jsFuncVal->IsFunction()) {
4062 LOGD("property \"destroyInstance\" is not a function");
4063 return;
4064 }
4065 v8::Local<v8::Function> jsFunc = v8::Local<v8::Function>::Cast(jsFuncVal);
4066 v8::Local<v8::String> name = v8::String::NewFromUtf8(isolate, packageName.c_str()).ToLocalChecked();
4067 v8::Local<v8::Value> argv[] = { name };
4068 int32_t len = sizeof(argv) / sizeof(argv[0]);
4069
4070 v8::Local<v8::Value> res;
4071 succ = jsFunc->Call(context, global, len, argv).ToLocal(&res);
4072 if (!succ) {
4073 LOGE("JS Engine appDestroyFunc FAILED!");
4074 V8Utils::JsStdDumpErrorAce(
4075 isolate, &tryCatch, JsErrorType::DESTROY_APP_ERROR, instanceId_, engineInstance_->GetStagingPage());
4076 return;
4077 }
4078
4079 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
4080 continue;
4081 }
4082 }
4083
TimerCallback(const std::string & callbackId,const std::string & delay,bool isInterval)4084 void V8Engine::TimerCallback(const std::string& callbackId, const std::string& delay, bool isInterval)
4085 {
4086 CHECK_RUN_ON(JS);
4087 LOGD("Enter TimerCallback");
4088 ACE_DCHECK(engineInstance_);
4089 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
4090 ACE_DCHECK(isolate);
4091 v8::Isolate::Scope isolateScope(isolate);
4092 v8::HandleScope handleScope(isolate);
4093 auto context = engineInstance_->GetV8Context();
4094
4095 v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>> pContext;
4096 pContext.Reset(isolate, context);
4097
4098 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
4099 if (isInterval) {
4100 V8EngineInstance::CallJs(isolate, pContext, callbackId.c_str(), std::string("{}").c_str(), true, true);
4101 (*delegate)->WaitTimer(callbackId, delay, isInterval, false);
4102 } else {
4103 V8EngineInstance::CallJs(isolate, pContext, callbackId.c_str(), std::string("{}").c_str(), false, true);
4104 (*delegate)->ClearTimer(callbackId);
4105 }
4106 pContext.Reset();
4107 }
4108
MediaQueryCallback(const std::string & callbackId,const std::string & args)4109 void V8Engine::MediaQueryCallback(const std::string& callbackId, const std::string& args)
4110 {
4111 JsEngine::MediaQueryCallback(callbackId, args);
4112 JsCallback(callbackId, args);
4113 }
4114
JsCallback(const std::string & callbackId,const std::string & args)4115 void V8Engine::JsCallback(const std::string& callbackId, const std::string& args)
4116 {
4117 CHECK_RUN_ON(JS);
4118 LOGD("Enter JsCallback args: %{private}s", args.c_str());
4119 ACE_DCHECK(engineInstance_);
4120 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
4121 ACE_DCHECK(isolate);
4122 v8::Isolate::Scope isolateScope(isolate);
4123 v8::HandleScope handleScope(isolate);
4124 auto context = engineInstance_->GetV8Context();
4125
4126 v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>> pContext;
4127 pContext.Reset(isolate, context);
4128
4129 V8EngineInstance::CallJs(isolate, pContext, callbackId.c_str(), args.c_str(), true, false);
4130 pContext.Reset();
4131 }
4132
RequestAnimationCallback(const std::string & callbackId,uint64_t timeStamp)4133 void V8Engine::RequestAnimationCallback(const std::string& callbackId, uint64_t timeStamp)
4134 {
4135 CHECK_RUN_ON(JS);
4136 ACE_DCHECK(engineInstance_);
4137 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
4138 ACE_DCHECK(isolate);
4139 v8::Isolate::Scope isolateScope(isolate);
4140 v8::HandleScope handleScope(isolate);
4141 auto context = engineInstance_->GetV8Context();
4142
4143 v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>> pContext;
4144 pContext.Reset(isolate, context);
4145 V8EngineInstance::CallJs(isolate, pContext, callbackId.c_str(), std::to_string(timeStamp).c_str(), false, true);
4146 auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
4147 (*delegate)->CancelAnimationFrame(callbackId);
4148 pContext.Reset();
4149 }
4150
FireAsyncEvent(const std::string & eventId,const std::string & param)4151 void V8Engine::FireAsyncEvent(const std::string& eventId, const std::string& param)
4152 {
4153 CHECK_RUN_ON(JS);
4154 LOGD("Enter FireAsyncEvent");
4155 std::string callBuf = std::string("[{\"args\": [\"")
4156 .append(eventId)
4157 .append("\",")
4158 .append(param)
4159 .append("], \"method\":\"fireEvent\"}]");
4160 LOGD("FireAsyncEvent string: %{private}s", callBuf.c_str());
4161
4162 ACE_DCHECK(engineInstance_);
4163 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
4164 ACE_DCHECK(isolate);
4165 v8::Isolate::Scope isolateScope(isolate);
4166
4167 bool succ = engineInstance_->FireJsEvent(callBuf.c_str());
4168 if (!succ) {
4169 LOGE("JS Engine FireAsyncEvent FAILED !! jsCall: %{private}s", callBuf.c_str());
4170 return;
4171 }
4172 }
4173
FireSyncEvent(const std::string & eventId,const std::string & param)4174 void V8Engine::FireSyncEvent(const std::string& eventId, const std::string& param)
4175 {
4176 CHECK_RUN_ON(JS);
4177 LOGD("Enter FireSyncEvent");
4178 std::string callBuf = std::string("[{\"args\": [\"")
4179 .append(eventId)
4180 .append("\",")
4181 .append(param)
4182 .append("], \"method\":\"fireEventSync\"}]");
4183 LOGD("FireSyncEvent string: %{private}s", callBuf.c_str());
4184
4185 ACE_DCHECK(engineInstance_);
4186 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
4187 ACE_DCHECK(isolate);
4188 v8::Isolate::Scope isolateScope(isolate);
4189
4190 bool succ = engineInstance_->FireJsEvent(callBuf.c_str());
4191 if (!succ) {
4192 LOGE("JS Engine FireSyncEvent FAILED !! jsCall: %{private}s", callBuf.c_str());
4193 return;
4194 }
4195 }
4196
FireExternalEvent(const std::string & componentId,const uint32_t nodeId,const bool isDestroy)4197 void V8Engine::FireExternalEvent(const std::string& componentId, const uint32_t nodeId, const bool isDestroy)
4198 {
4199 CHECK_RUN_ON(JS);
4200 ACE_DCHECK(engineInstance_);
4201 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
4202 ACE_DCHECK(isolate);
4203 v8::Isolate::Scope isolateScope(isolate);
4204 v8::HandleScope handleScope(isolate);
4205 if (isDestroy) {
4206 return;
4207 }
4208 auto context = isolate->GetCurrentContext();
4209 if (context.IsEmpty()) {
4210 LOGE("FireExternalEvent context is empty");
4211 return;
4212 }
4213 auto page = GetRunningPage();
4214 if (page == nullptr) {
4215 LOGE("FireExternalEvent GetRunningPage is nullptr");
4216 return;
4217 }
4218 std::string arguments;
4219 auto engine = AceType::RawPtr(engineInstance_);
4220 auto bridge = AceType::DynamicCast<V8XComponentBridge>(page->GetXComponentBridgeById(nodeId));
4221 if (bridge) {
4222 bridge->HandleContext(context, nodeId, arguments, engine);
4223 return;
4224 }
4225 }
4226
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher)4227 void V8Engine::SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher)
4228 {
4229 ACE_DCHECK(engineInstance_);
4230 LOGD("Enter SetJsMessageDispatcher");
4231 engineInstance_->SetJsMessageDispatcher(dispatcher);
4232 }
4233
RunGarbageCollection()4234 void V8Engine::RunGarbageCollection()
4235 {
4236 CHECK_RUN_ON(JS);
4237 if (engineInstance_) {
4238 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
4239 if (isolate != nullptr) {
4240 isolate->LowMemoryNotification();
4241 }
4242 }
4243 }
4244
GetGroupJsBridge()4245 RefPtr<GroupJsBridge> V8Engine::GetGroupJsBridge()
4246 {
4247 return AceType::MakeRefPtr<V8GroupJsBridge>(instanceId_);
4248 }
4249
4250 } // namespace OHOS::Ace::Framework
4251