• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "frameworks/bridge/js_frontend/engine/v8/v8_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