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/declarative_frontend/engine/v8/v8_declarative_engine.h"
17
18 #include <dirent.h>
19 #include <dlfcn.h>
20 #include <fstream>
21 #include <streambuf>
22 #include <unistd.h>
23
24 #include "native_engine/impl/v8/v8_native_engine.h"
25 #include "base/i18n/localization.h"
26 #include "base/json/json_util.h"
27 #include "base/log/ace_trace.h"
28 #include "base/log/event_report.h"
29 #include "base/utils/system_properties.h"
30 #include "base/utils/time_util.h"
31 #include "core/common/thread_checker.h"
32 #include "frameworks/bridge/common/dom/dom_type.h"
33 #include "frameworks/bridge/common/utils/utils.h"
34 #include "frameworks/bridge/common/utils/v8/v8_helper.h"
35 #include "frameworks/bridge/declarative_frontend/engine/bindings_implementation.h"
36 #include "frameworks/bridge/declarative_frontend/engine/js_ref_ptr.h"
37 #include "frameworks/bridge/declarative_frontend/engine/js_types.h"
38 #include "frameworks/bridge/declarative_frontend/engine/v8/v8_bindings.h"
39 #include "frameworks/bridge/declarative_frontend/engine/v8/v8_declarative_group_js_bridge.h"
40 #include "frameworks/bridge/declarative_frontend/engine/v8/v8_function_destroy_helper.h"
41 #include "frameworks/bridge/declarative_frontend/engine/v8/v8_module_manager.h"
42 #include "frameworks/bridge/declarative_frontend/engine/v8/v8_types.h"
43 #include "frameworks/bridge/declarative_frontend/jsview/js_view_register.h"
44 #include "frameworks/bridge/declarative_frontend/jsview/js_xcomponent.h"
45 #include "frameworks/bridge/js_frontend/engine/common/js_api_perf.h"
46 #include "frameworks/bridge/js_frontend/engine/common/js_constants.h"
47 #include "frameworks/bridge/js_frontend/engine/common/runtime_constants.h"
48 #include "frameworks/core/common/ace_view.h"
49 #include "frameworks/core/common/container.h"
50 #include "frameworks/core/components/xcomponent/xcomponent_component_client.h"
51
52 extern const char _binary_stateMgmt_js_start[];
53 extern const char _binary_stateMgmt_js_end[];
54 extern const char _binary_jsEnumStyle_js_start[];
55 extern const char _binary_jsEnumStyle_js_end[];
56
57 namespace OHOS::Ace::Framework {
58 namespace {
59
60 constexpr int32_t V8_MAX_STACK_SIZE = 1 * 1024 * 1024;
61 void* g_debugger = nullptr;
62 using StartDebug = void (*)(
63 const std::unique_ptr<v8::Platform>& platform, const v8::Local<v8::Context>& context, std::string componentName,
64 const bool isDebugMode, const int32_t instanceId);
65 using WaitingForIde = void (*)();
66 using StopDebug = void (*)();
67
CallEvalBuf(v8::Isolate * isolate,const char * src,int32_t length=-1,const char * filename=nullptr)68 bool CallEvalBuf(v8::Isolate* isolate, const char* src, int32_t length = -1, const char* filename = nullptr)
69 {
70 CHECK_RUN_ON(JS);
71 ACE_DCHECK(isolate);
72 v8::HandleScope handleScope(isolate);
73 auto context = isolate->GetCurrentContext();
74 if (context.IsEmpty()) {
75 LOGE("CallEvalBuf, CurrentContext is empty!");
76 return false;
77 }
78 v8::TryCatch tryCatch(isolate);
79 if (src == nullptr || src[0] == '\0') {
80 LOGE("src is null");
81 return false;
82 }
83
84 const char* origin = filename;
85 if (!origin) {
86 origin = "<anonymous>";
87 }
88
89 v8::ScriptOrigin scriptOrigin(v8::String::NewFromUtf8(isolate, origin).ToLocalChecked());
90
91 v8::Local<v8::String> source =
92 v8::String::NewFromUtf8(isolate, src, v8::NewStringType::kNormal, length).ToLocalChecked();
93 v8::Local<v8::Script> script;
94 if (!v8::Script::Compile(context, source, &scriptOrigin).ToLocal(&script)) {
95 LOGE("Compilation failed");
96 V8Utils::JsStdDumpErrorAce(isolate, &tryCatch);
97 return false;
98 }
99
100 v8::Local<v8::Value> res;
101 if (!script->Run(context).ToLocal(&res)) {
102 LOGE("Run failed");
103 V8Utils::JsStdDumpErrorAce(isolate, &tryCatch);
104 return false;
105 }
106 return true;
107 }
108
ParseLogContent(const std::vector<std::string> & params)109 std::string ParseLogContent(const std::vector<std::string>& params)
110 {
111 std::string ret;
112 if (params.empty()) {
113 return ret;
114 }
115 std::string formatStr = params[0];
116 int32_t size = params.size();
117 int32_t len = formatStr.size();
118 int32_t pos = 0;
119 int32_t count = 1;
120 for (; pos < len; ++pos) {
121 if (count >= size) {
122 break;
123 }
124 if (formatStr[pos] == '%') {
125 if (pos + 1 >= len) {
126 break;
127 }
128 switch (formatStr[pos + 1]) {
129 case 's':
130 case 'j':
131 case 'd':
132 case 'O':
133 case 'o':
134 case 'i':
135 case 'f':
136 case 'c':
137 ret += params[count++];
138 ++pos;
139 break;
140 case '%':
141 ret += formatStr[pos];
142 ++pos;
143 break;
144 default:
145 ret += formatStr[pos];
146 break;
147 }
148 } else {
149 ret += formatStr[pos];
150 }
151 }
152 if (pos < len) {
153 ret += formatStr.substr(pos, len - pos);
154 }
155 return ret;
156 }
157
GetLogLevelAndContent(const v8::FunctionCallbackInfo<v8::Value> & args,JsLogLevel & logLevel,std::string & content)158 void GetLogLevelAndContent(const v8::FunctionCallbackInfo<v8::Value>& args, JsLogLevel& logLevel, std::string& content)
159 {
160 v8::Isolate* isolate = args.GetIsolate();
161 ACE_DCHECK(isolate);
162 v8::Isolate::Scope isolateScope(isolate);
163 v8::HandleScope handleScope(isolate);
164 auto context = isolate->GetCurrentContext();
165 if (context.IsEmpty() || args.Length() == 0) {
166 LOGE("Get LogLevel and Content, context is empty");
167 return;
168 }
169 if (args.Length() == 1) {
170 v8::Local<v8::Value> str;
171 if (args[0]->ToString(context).ToLocal(&str)) {
172 v8::String::Utf8Value utf8(isolate, str);
173 if (*utf8) {
174 content += *utf8;
175 }
176 } else {
177 content += "Error converting argument 1";
178 }
179 } else {
180 std::vector<std::string> params;
181 for (int32_t i = 0; i < args.Length(); i++) {
182 v8::Local<v8::Value> str;
183 if (args[i]->ToString(context).ToLocal(&str)) {
184 v8::String::Utf8Value utf8(isolate, str);
185 if (*utf8) {
186 params.emplace_back(*utf8);
187 }
188 }
189 }
190 content = ParseLogContent(params);
191 }
192 logLevel = static_cast<JsLogLevel>(args.Data()->Int32Value(context).ToChecked());
193 }
194
AppLogPrint(const v8::FunctionCallbackInfo<v8::Value> & args)195 void AppLogPrint(const v8::FunctionCallbackInfo<v8::Value>& args)
196 {
197 JsLogLevel logLevel = JsLogLevel::INFO;
198 std::string fullString;
199 GetLogLevelAndContent(args, logLevel, fullString);
200 switch (logLevel) {
201 case JsLogLevel::DEBUG:
202 APP_LOGD("app Log: %{public}s", fullString.c_str());
203 break;
204 case JsLogLevel::INFO:
205 APP_LOGI("app Log: %{public}s", fullString.c_str());
206 break;
207 case JsLogLevel::WARNING:
208 APP_LOGW("app Log: %{public}s", fullString.c_str());
209 break;
210 case JsLogLevel::ERROR:
211 APP_LOGE("app Log: %{public}s", fullString.c_str());
212 break;
213 }
214 }
215
JsLogPrint(const v8::FunctionCallbackInfo<v8::Value> & args)216 void JsLogPrint(const v8::FunctionCallbackInfo<v8::Value>& args)
217 {
218 JsLogLevel logLevel = JsLogLevel::INFO;
219 std::string fullString;
220 GetLogLevelAndContent(args, logLevel, fullString);
221 switch (logLevel) {
222 case JsLogLevel::DEBUG:
223 LOGD("ace Log: %{public}s", fullString.c_str());
224 break;
225 case JsLogLevel::INFO:
226 LOGI("ace Log: %{public}s", fullString.c_str());
227 break;
228 case JsLogLevel::WARNING:
229 LOGW("ace Log: %{public}s", fullString.c_str());
230 break;
231 case JsLogLevel::ERROR:
232 LOGE("ace Log: %{public}s", fullString.c_str());
233 break;
234 }
235 }
236
JsPerfEnd(const v8::FunctionCallbackInfo<v8::Value> & args)237 void JsPerfEnd(const v8::FunctionCallbackInfo<v8::Value>& args)
238 {
239 LOGD("Enter JsPerfEnd");
240 if (args.Length() != PERF_ARGS_LEN) {
241 LOGE("argc error, argc = %{private}d", args.Length());
242 return;
243 }
244
245 v8::Isolate* isolate = args.GetIsolate();
246 ACE_DCHECK(isolate);
247 v8::HandleScope handleScope(isolate);
248 auto context = isolate->GetCurrentContext();
249 if (context.IsEmpty()) {
250 LOGE("JsPerfEnd, CurrentContext is empty!");
251 return;
252 }
253
254 v8::String::Utf8Value jsMethodName(isolate, args[PERF_ARGS_METHOD_IDX]);
255 if (!(*jsMethodName)) {
256 return;
257 }
258 std::string methodName(*jsMethodName);
259
260 int64_t currentTime = GetMicroTickCount();
261 JsApiPerf::GetInstance().InsertJsEndLog(methodName, currentTime);
262 }
263
JsPerfBegin(const v8::FunctionCallbackInfo<v8::Value> & args)264 void JsPerfBegin(const v8::FunctionCallbackInfo<v8::Value>& args)
265 {
266 LOGD("Enter JsPerfEnd");
267 if (args.Length() != PERF_ARGS_LEN) {
268 LOGE("argc error, argc = %{private}d", args.Length());
269 return;
270 }
271
272 v8::Isolate* isolate = args.GetIsolate();
273 ACE_DCHECK(isolate);
274 v8::HandleScope handleScope(isolate);
275 auto context = isolate->GetCurrentContext();
276 if (context.IsEmpty()) {
277 LOGE("JsPerfBegin, CurrentContext is empty!");
278 return;
279 }
280
281 v8::String::Utf8Value jsMethodName(isolate, args[PERF_ARGS_METHOD_IDX]);
282 if (!(*jsMethodName)) {
283 return;
284 }
285 std::string methodName(*jsMethodName);
286
287 int64_t currentTime = GetMicroTickCount();
288 JsApiPerf::GetInstance().InsertJsBeginLog(methodName, currentTime);
289 }
290
JsPerfSleep(const v8::FunctionCallbackInfo<v8::Value> & args)291 void JsPerfSleep(const v8::FunctionCallbackInfo<v8::Value>& args)
292 {
293 LOGD("Enter JsPerfEnd");
294 if (args.Length() != 1) {
295 LOGE("argc error, argc = %{private}d", args.Length());
296 return;
297 }
298
299 v8::Isolate* isolate = args.GetIsolate();
300 ACE_DCHECK(isolate);
301 v8::HandleScope handleScope(isolate);
302 auto context = isolate->GetCurrentContext();
303 if (context.IsEmpty()) {
304 LOGE("CurrentContext is empty!");
305 return;
306 }
307
308 int32_t valInt = args[0]->Int32Value(context).ToChecked();
309 usleep(valInt);
310 }
311
JsPerfPrint(const v8::FunctionCallbackInfo<v8::Value> & args)312 void JsPerfPrint(const v8::FunctionCallbackInfo<v8::Value>& args)
313 {
314 v8::Isolate* isolate = args.GetIsolate();
315 ACE_DCHECK(isolate);
316
317 v8::HandleScope handleScope(isolate);
318 auto context = isolate->GetCurrentContext();
319 if (context.IsEmpty()) {
320 LOGE("JsPerfPrint, CurrentContext is empty!");
321 return;
322 }
323
324 // return the result
325 std::string ret = JsApiPerf::GetInstance().PrintToLogs();
326 v8::Local<v8::String> dataValue = v8::String::NewFromUtf8(isolate, ret.c_str()).ToLocalChecked();
327 args.GetReturnValue().Set(dataValue);
328 }
329
330 } // namespace
331
332 thread_local IsolateWrapper V8DeclarativeEngineInstance::isolate_;
333
GetCurrentPage()334 RefPtr<JsAcePage> V8DeclarativeEngineInstance::GetCurrentPage()
335 {
336 LOGD("Enter GetRunningPage");
337 v8::Isolate* isolate = v8::Isolate::GetCurrent();
338 ACE_DCHECK(isolate);
339 auto stagingPage = static_cast<RefPtr<JsAcePage>*>(isolate->GetData(V8DeclarativeEngineInstance::STAGING_PAGE));
340 return *stagingPage;
341 }
342
GetRunningPage(v8::Isolate * isolate)343 RefPtr<JsAcePage> V8DeclarativeEngineInstance::GetRunningPage(v8::Isolate* isolate)
344 {
345 LOGD("Enter GetRunningPage");
346 ACE_DCHECK(isolate);
347 auto runningPage = static_cast<RefPtr<JsAcePage>*>(isolate->GetData(V8DeclarativeEngineInstance::RUNNING_PAGE));
348 return *runningPage;
349 }
350
GetStagingPage(v8::Isolate * isolate)351 RefPtr<JsAcePage> V8DeclarativeEngineInstance::GetStagingPage(v8::Isolate* isolate)
352 {
353 LOGD("Enter GetStagingPage");
354 ACE_DCHECK(isolate);
355 auto stagingPage = static_cast<RefPtr<JsAcePage>*>(isolate->GetData(V8DeclarativeEngineInstance::STAGING_PAGE));
356 return *stagingPage;
357 }
358
TriggerPageUpdate()359 void V8DeclarativeEngineInstance::TriggerPageUpdate()
360 {
361 v8::Isolate* isolate = v8::Isolate::GetCurrent();
362 ACE_DCHECK(isolate);
363 auto delegate =
364 static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8DeclarativeEngineInstance::FRONTEND_DELEGATE));
365 auto pipelineContext = (*delegate)->GetPipelineContext();
366 pipelineContext->AddPageUpdateTask([] {});
367 }
368
PostJsTask(std::function<void ()> && task)369 void V8DeclarativeEngineInstance::PostJsTask(std::function<void()>&& task)
370 {
371 v8::Isolate* isolate = v8::Isolate::GetCurrent();
372 ACE_DCHECK(isolate);
373 auto delegate =
374 static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8DeclarativeEngineInstance::FRONTEND_DELEGATE));
375 (*delegate)->PostJsTask(std::move(task));
376 }
377
GetPipelineContext()378 RefPtr<PipelineContext> V8DeclarativeEngineInstance::GetPipelineContext()
379 {
380 v8::Isolate* isolate = v8::Isolate::GetCurrent();
381 ACE_DCHECK(isolate);
382 auto delegate =
383 static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8DeclarativeEngineInstance::FRONTEND_DELEGATE));
384 return (*delegate)->GetPipelineContext();
385 }
386
FlushCommandBuffer(void * context,const std::string & command)387 void V8DeclarativeEngineInstance::FlushCommandBuffer(void* context, const std::string& command)
388 {
389 LOGI("flush command buffer");
390 auto v8Context = *(static_cast<v8::Local<v8::Context>*>(context));
391 v8::Isolate* isolate = v8Context->GetIsolate();
392 ACE_DCHECK(isolate);
393 bool result = CallEvalBuf(isolate, command.c_str());
394 if (!result) {
395 LOGE("failed to flush command");
396 }
397 }
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)398 void V8DeclarativeEngineInstance::CallJs(v8::Isolate* isolate,
399 v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>> pcontext, const std::string& callbackId,
400 const std::string& args, bool keepAlive, bool isGlobal)
401 {
402 CHECK_RUN_ON(JS);
403 LOGD("Enter CallJs");
404 std::string keepAliveStr = keepAlive ? "true" : "false";
405 std::string callBuff = std::string("[{\"args\": [\"")
406 .append(callbackId)
407 .append("\",")
408 .append(args)
409 .append(",")
410 .append(keepAliveStr)
411 .append("], \"method\":\"callback\"}]");
412 LOGD("CallJs string: %{private}s", callBuff.c_str());
413
414 ACE_DCHECK(isolate);
415 v8::HandleScope handleScope(isolate);
416 v8::Local<v8::Context> context = pcontext.Get(isolate);
417 if (context.IsEmpty()) {
418 LOGE("CallJs, context Is Empty");
419 return;
420 }
421
422 v8::Context::Scope contextScope(context);
423 v8::Local<v8::Object> global = context->Global();
424 v8::Local<v8::String> funcName = v8::String::NewFromUtf8(isolate, "callJS").ToLocalChecked();
425 v8::Local<v8::Value> jsFuncVal;
426 bool succ = global->Get(context, funcName).ToLocal(&jsFuncVal);
427 if (!succ) {
428 LOGE("cannot find 'callJS' function from global object, this should not happen!");
429 return;
430 }
431
432 v8::Local<v8::Function> jsFunc = v8::Local<v8::Function>::Cast(jsFuncVal);
433
434 auto runningPage = static_cast<RefPtr<JsAcePage>*>(isolate->GetData(V8DeclarativeEngineInstance::RUNNING_PAGE));
435 int32_t instanceId = isGlobal ? DEFAULT_APP_ID : (*runningPage)->GetPageId();
436
437 v8::Local<v8::String> callBufStr = v8::String::NewFromUtf8(isolate, callBuff.c_str()).ToLocalChecked();
438 v8::Local<v8::Value> jsonBuf;
439 if (!v8::JSON::Parse(context, callBufStr).ToLocal(&jsonBuf)) {
440 LOGE("Cannot parse callBuf to json format correctly, CallJs stop!");
441 return;
442 }
443 v8::Local<v8::Value> argv[] = { v8::Integer::New(isolate, instanceId), jsonBuf };
444 int32_t len = sizeof(argv) / sizeof(argv[0]);
445 v8::Local<v8::Value> res;
446 succ = jsFunc->Call(context, global, len, argv).ToLocal(&res);
447 if (succ) {
448 LOGD("func callJs success!");
449 } else {
450 LOGD("func callJs fail!");
451 }
452
453 while (v8::platform::PumpMessageLoop(V8DeclarativeEngine::GetPlatform().get(), isolate)) {
454 continue;
455 }
456 }
457
458 std::map<std::string, std::string> V8DeclarativeEngineInstance::mediaResourceFileMap_;
459
460 std::unique_ptr<JsonValue> V8DeclarativeEngineInstance::currentConfigResourceData_;
461
InitJSEnv()462 bool V8DeclarativeEngineInstance::InitJSEnv()
463 {
464 CHECK_RUN_ON(JS);
465 LOGI("Enter InitJSEnv");
466
467 // create Isolate
468 create_params_.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
469 isolate_.Wrap(v8::Isolate::New(create_params_));
470 if (isolate_.IsEmpty()) {
471 EventInfo eventInfo;
472 eventInfo.eventType = EXCEPTION_JS;
473 eventInfo.errorType = static_cast<int32_t>(JsExcepType::JS_RUNTIME_OBJ_ERR);
474 EventReport::SendEvent(eventInfo);
475 LOGE("JS Engine cannot allocate JS runtime");
476 return false;
477 }
478
479 isolate_->SetStackLimit(V8_MAX_STACK_SIZE);
480 isolate_->SetData(V8DeclarativeEngineInstance::FRONTEND_DELEGATE, static_cast<void*>(&frontendDelegate_));
481 isolate_->SetData(V8DeclarativeEngineInstance::RUNNING_PAGE, static_cast<void*>(&runningPage_));
482 isolate_->SetData(V8DeclarativeEngineInstance::STAGING_PAGE, static_cast<void*>(&stagingPage_));
483 isolate_->SetData(V8DeclarativeEngineInstance::DISPATCHER, static_cast<void*>(&dispatcher_));
484 isolate_->SetCaptureStackTraceForUncaughtExceptions(true);
485 // create context
486 InitJSContext();
487 return true;
488 }
489
InitJSContext()490 void V8DeclarativeEngineInstance::InitJSContext()
491 {
492 CHECK_RUN_ON(JS);
493 LOGI("Enter InitJSContext");
494 v8::Isolate::Scope isolateScope(isolate_.Get());
495 v8::HandleScope handleScope(isolate_.Get());
496
497 InitGlobalObjectTemplate();
498
499 v8::Local<v8::Context> localContext =
500 v8::Context::New(isolate_.Get(), nullptr, globalObjectTemplate_.Get(isolate_.Get()));
501
502 v8::Context::Scope contextScope(localContext);
503
504 InitJsConsoleObject(localContext, isolate_.Get());
505 InitJsPerfUtilObject(localContext);
506 InitJsNativeModuleObject(localContext);
507 InitJsExportsUtilObject(localContext);
508
509 LOGE("Loading State Mgmt JS lib for full and partial update combined");
510 InitAceModules(_binary_stateMgmt_js_start, _binary_stateMgmt_js_end, isolate_.Get());
511
512 InitAceModules(_binary_jsEnumStyle_js_start, _binary_jsEnumStyle_js_end, isolate_.Get());
513
514 auto groupJsBridge = DynamicCast<V8DeclarativeGroupJsBridge>(frontendDelegate_->GetGroupJsBridge());
515 if (groupJsBridge == nullptr || groupJsBridge->InitializeGroupJsBridge(localContext) == JS_CALL_FAIL) {
516 LOGE("JS Engine Initialize GroupJsBridge failed!");
517 EventReport::SendJsException(JsExcepType::JS_ENGINE_INIT_ERR);
518 }
519
520 context_.Reset(isolate_.Get(), localContext);
521
522 // load resourceConfig
523 currentConfigResourceData_ = JsonUtil::CreateArray(true);
524 frontendDelegate_->LoadResourceConfiguration(mediaResourceFileMap_, currentConfigResourceData_);
525 }
526
InitAceModules(const char * start,const char * end,v8::Isolate * isolate)527 void V8DeclarativeEngineInstance::InitAceModules(const char* start, const char* end, v8::Isolate* isolate)
528 {
529 if (start == nullptr || end == nullptr) {
530 LOGE("Failed to init Ace modules, start or end can not be null!");
531 return;
532 }
533 bool evalAceModule = CallEvalBuf(isolate, start, end - start);
534 if (!evalAceModule) {
535 EventInfo eventInfo;
536 eventInfo.eventType = EXCEPTION_JS;
537 eventInfo.errorType = static_cast<int32_t>(JsExcepType::JS_CONTEXT_INIT_ERR);
538 EventReport::SendEvent(eventInfo);
539 LOGE("JS Engine created JS context but failed to init Ace modules!");
540 }
541 }
542
InitJsConsoleObject(v8::Local<v8::Context> & localContext,v8::Isolate * isolate)543 void V8DeclarativeEngineInstance::InitJsConsoleObject(v8::Local<v8::Context>& localContext, v8::Isolate* isolate)
544 {
545 v8::Local<v8::Object> global = localContext->Global();
546 // app log method
547 v8::Local<v8::Value> console =
548 global->Get(localContext, v8::String::NewFromUtf8(isolate, "console").ToLocalChecked()).ToLocalChecked();
549 v8::Local<v8::Object> consoleObj = console->ToObject(localContext).ToLocalChecked();
550 consoleObj
551 ->Set(localContext, v8::String::NewFromUtf8(isolate, "log").ToLocalChecked(),
552 v8::Function::New(
553 localContext, AppLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::INFO)))
554 .ToLocalChecked())
555 .ToChecked();
556 consoleObj
557 ->Set(localContext, v8::String::NewFromUtf8(isolate, "debug").ToLocalChecked(),
558 v8::Function::New(
559 localContext, AppLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::DEBUG)))
560 .ToLocalChecked())
561 .ToChecked();
562 consoleObj
563 ->Set(localContext, v8::String::NewFromUtf8(isolate, "info").ToLocalChecked(),
564 v8::Function::New(
565 localContext, AppLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::INFO)))
566 .ToLocalChecked())
567 .ToChecked();
568 consoleObj
569 ->Set(localContext, v8::String::NewFromUtf8(isolate, "warn").ToLocalChecked(),
570 v8::Function::New(
571 localContext, AppLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::WARNING)))
572 .ToLocalChecked())
573 .ToChecked();
574 consoleObj
575 ->Set(localContext, v8::String::NewFromUtf8(isolate, "error").ToLocalChecked(),
576 v8::Function::New(
577 localContext, AppLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::ERROR)))
578 .ToLocalChecked())
579 .ToChecked();
580 // js framework log method
581 auto aceConsoleObj = v8::Object::New(isolate);
582 global->Set(localContext, v8::String::NewFromUtf8(isolate, "aceConsole").ToLocalChecked(), aceConsoleObj)
583 .ToChecked();
584 aceConsoleObj
585 ->Set(localContext, v8::String::NewFromUtf8(isolate, "log").ToLocalChecked(),
586 v8::Function::New(
587 localContext, JsLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::INFO)))
588 .ToLocalChecked())
589 .ToChecked();
590 aceConsoleObj
591 ->Set(localContext, v8::String::NewFromUtf8(isolate, "debug").ToLocalChecked(),
592 v8::Function::New(
593 localContext, JsLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::DEBUG)))
594 .ToLocalChecked())
595 .ToChecked();
596 aceConsoleObj
597 ->Set(localContext, v8::String::NewFromUtf8(isolate, "info").ToLocalChecked(),
598 v8::Function::New(
599 localContext, JsLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::INFO)))
600 .ToLocalChecked())
601 .ToChecked();
602 aceConsoleObj
603 ->Set(localContext, v8::String::NewFromUtf8(isolate, "warn").ToLocalChecked(),
604 v8::Function::New(
605 localContext, JsLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::WARNING)))
606 .ToLocalChecked())
607 .ToChecked();
608 aceConsoleObj
609 ->Set(localContext, v8::String::NewFromUtf8(isolate, "error").ToLocalChecked(),
610 v8::Function::New(
611 localContext, JsLogPrint, v8::Integer::New(isolate, static_cast<int32_t>(JsLogLevel::ERROR)))
612 .ToLocalChecked())
613 .ToChecked();
614 }
615
InitJsPerfUtilObject(v8::Local<v8::Context> & localContext)616 void V8DeclarativeEngineInstance::InitJsPerfUtilObject(v8::Local<v8::Context>& localContext)
617 {
618 v8::Local<v8::Object> global = localContext->Global();
619
620 auto perfUtilObj = v8::Object::New(isolate_.Get());
621 global->Set(localContext, v8::String::NewFromUtf8(isolate_.Get(), "perfutil").ToLocalChecked(), perfUtilObj)
622 .ToChecked();
623 perfUtilObj
624 ->Set(localContext, v8::String::NewFromUtf8(isolate_.Get(), "printlog").ToLocalChecked(),
625 v8::Function::New(localContext, JsPerfPrint).ToLocalChecked())
626 .ToChecked();
627 perfUtilObj
628 ->Set(localContext, v8::String::NewFromUtf8(isolate_.Get(), "sleep").ToLocalChecked(),
629 v8::Function::New(localContext, JsPerfSleep).ToLocalChecked())
630 .ToChecked();
631 perfUtilObj
632 ->Set(localContext, v8::String::NewFromUtf8(isolate_.Get(), "begin").ToLocalChecked(),
633 v8::Function::New(localContext, JsPerfBegin).ToLocalChecked())
634 .ToChecked();
635 perfUtilObj
636 ->Set(localContext, v8::String::NewFromUtf8(isolate_.Get(), "end").ToLocalChecked(),
637 v8::Function::New(localContext, JsPerfEnd).ToLocalChecked())
638 .ToChecked();
639 }
640
641 thread_local std::unordered_map<int32_t, CopyablePersistent<v8::Object>>
642 V8DeclarativeEngineInstance::persistentRootViewMap_;
643
PersistRootViewHandle(v8::Isolate * isolate,v8::Local<v8::Object> obj)644 void V8DeclarativeEngineInstance::PersistRootViewHandle(v8::Isolate* isolate, v8::Local<v8::Object> obj)
645 {
646 V8DeclarativeEngineInstance::persistentRootViewMap_.emplace(
647 V8DeclarativeEngineInstance::GetStagingPage(isolate)->GetPageId(),
648 CopyablePersistent<v8::Object>(isolate, obj));
649 }
650
DestroyPersistRootViewHandle(int32_t pageId)651 void V8DeclarativeEngineInstance::DestroyPersistRootViewHandle(int32_t pageId)
652 {
653 CHECK_RUN_ON(JS);
654 if (V8DeclarativeEngineInstance::persistentRootViewMap_.count(pageId) != 0) {
655 v8::Isolate* isolate = GetV8Isolate();
656 ACE_DCHECK(isolate);
657 v8::Isolate::Scope isolateScope(isolate);
658 v8::HandleScope handleScope(isolate);
659 CopyablePersistent<v8::Object> rootView = V8DeclarativeEngineInstance::persistentRootViewMap_[pageId];
660 if (!rootView.IsEmpty()) {
661 v8::Local<v8::Object> previousRootObj = rootView.Get(isolate);
662 JSView* previousView = static_cast<JSView*>(previousRootObj->GetAlignedPointerFromInternalField(0));
663 previousView->Destroy(nullptr);
664 }
665 rootView.Reset();
666
667 V8DeclarativeEngineInstance::persistentRootViewMap_.erase(pageId);
668 }
669 }
670
DestroyAllPersistRootViewHandle()671 void V8DeclarativeEngineInstance::DestroyAllPersistRootViewHandle()
672 {
673 CHECK_RUN_ON(JS);
674 if (persistentRootViewMap_.size() > 0) {
675 LOGI("DestroyAllPersistRootViewHandle release left %zu views ", persistentRootViewMap_.size());
676 }
677 for (const auto& pair : persistentRootViewMap_) {
678 v8::Isolate* isolate = GetV8Isolate();
679 ACE_DCHECK(isolate);
680 v8::Isolate::Scope isolateScope(isolate);
681 v8::HandleScope handleScope(isolate);
682 CopyablePersistent<v8::Object> rootView = pair.second;
683 if (!rootView.IsEmpty()) {
684 v8::Local<v8::Object> previousRootObj = rootView.Get(isolate);
685 JSView* previousView = static_cast<JSView*>(previousRootObj->GetAlignedPointerFromInternalField(0));
686 previousView->Destroy(nullptr);
687 }
688 rootView.Reset();
689 }
690 persistentRootViewMap_.clear();
691 }
692
RequireNativeModule(const v8::FunctionCallbackInfo<v8::Value> & args)693 void RequireNativeModule(const v8::FunctionCallbackInfo<v8::Value>& args)
694 {
695 v8::Isolate* isolate = args.GetIsolate();
696 v8::HandleScope handleScope(isolate);
697 auto localContext = isolate->GetCurrentContext();
698 if (localContext.IsEmpty()) {
699 LOGE("context is empty!");
700 return;
701 }
702 v8::String::Utf8Value value(isolate, args[0]->ToString(localContext).ToLocalChecked());
703 if (!(*value)) {
704 return;
705 }
706 std::string moduleName(*value);
707
708 // init method
709 v8::Local<v8::Object> global = localContext->Global();
710 v8::Local<v8::Value> moduleObj =
711 global->Get(localContext, v8::String::NewFromUtf8(isolate, moduleName.c_str()).ToLocalChecked())
712 .ToLocalChecked();
713 if (!moduleObj->IsUndefined()) {
714 args.GetReturnValue().Set(moduleObj);
715 return;
716 }
717
718 auto newObj = v8::Object::New(isolate);
719 if (ModuleManager::GetInstance()->InitModule(newObj, moduleName, isolate)) {
720 global->Set(localContext, v8::String::NewFromUtf8(isolate, moduleName.c_str()).ToLocalChecked(), newObj)
721 .ToChecked();
722 args.GetReturnValue().Set(newObj);
723 }
724 }
725
InitJsNativeModuleObject(v8::Local<v8::Context> & localContext)726 void V8DeclarativeEngineInstance::InitJsNativeModuleObject(v8::Local<v8::Context>& localContext)
727 {
728 v8::Local<v8::Object> global = localContext->Global();
729
730 global
731 ->Set(localContext, v8::String::NewFromUtf8(isolate_.Get(), "requireNativeModule").ToLocalChecked(),
732 v8::Function::New(localContext, RequireNativeModule).ToLocalChecked())
733 .ToChecked();
734
735 ModuleManager::GetInstance()->InitTimerModule(localContext);
736 }
737
InitJsExportsUtilObject(v8::Local<v8::Context> & localContext)738 void V8DeclarativeEngineInstance::InitJsExportsUtilObject(v8::Local<v8::Context>& localContext)
739 {
740 v8::Local<v8::Object> global = localContext->Global();
741
742 auto exportsUtilObj = v8::Object::New(isolate_.Get());
743 global->Set(localContext, v8::String::NewFromUtf8(isolate_.Get(), "exports").ToLocalChecked(), exportsUtilObj)
744 .ToChecked();
745 }
746
InitGlobalObjectTemplate()747 void V8DeclarativeEngineInstance::InitGlobalObjectTemplate()
748 {
749 v8::Isolate::Scope isolateScope(isolate_.Get());
750 v8::HandleScope handleScope(isolate_.Get());
751 v8::Local<v8::ObjectTemplate> globalObj = v8::ObjectTemplate::New(isolate_.Get());
752 JsRegisterViews(globalObj);
753
754 globalObjectTemplate_.Reset(isolate_.Get(), globalObj);
755 }
756
FireJsEvent(const std::string & param)757 bool V8DeclarativeEngineInstance::FireJsEvent(const std::string& param)
758 {
759 return true;
760 }
761
GetI18nStringResource(const std::string & targetStringKey,const std::string & targetStringValue)762 std::unique_ptr<JsonValue> V8DeclarativeEngineInstance::GetI18nStringResource(
763 const std::string& targetStringKey, const std::string& targetStringValue)
764 {
765 auto resourceI18nFileNum = currentConfigResourceData_->GetArraySize();
766 for (int i = 0; i < resourceI18nFileNum; i++) {
767 auto priorResource = currentConfigResourceData_->GetArrayItem(i);
768 if ((priorResource->Contains(targetStringKey))) {
769 auto valuePair = priorResource->GetValue(targetStringKey);
770 if (valuePair->Contains(targetStringValue)) {
771 return valuePair->GetValue(targetStringValue);
772 }
773 }
774 }
775
776 return JsonUtil::Create(true);
777 }
778
GetMediaResource(const std::string & targetFileName)779 std::string V8DeclarativeEngineInstance::GetMediaResource(const std::string& targetFileName)
780 {
781 auto iter = mediaResourceFileMap_.find(targetFileName);
782
783 if (iter != mediaResourceFileMap_.end()) {
784 return iter->second;
785 }
786
787 return std::string();
788 }
789
~V8DeclarativeEngineInstance()790 V8DeclarativeEngineInstance::~V8DeclarativeEngineInstance()
791 {
792 CHECK_RUN_ON(JS);
793 LOG_DESTROY();
794 DestroyAllPersistRootViewHandle();
795 globalObjectTemplate_.Reset();
796 delete create_params_.array_buffer_allocator;
797
798 // Destroy group bridge
799 auto groupJsBridge = DynamicCast<V8DeclarativeGroupJsBridge>(frontendDelegate_->GetGroupJsBridge());
800 if (groupJsBridge != nullptr) {
801 groupJsBridge->Destroy(GetV8Isolate());
802 }
803 // Force GC before dispose v8 isolate
804 auto* isolate = isolate_.Get();
805 if (isolate != nullptr) {
806 v8::Isolate::Scope isolateScope(isolate);
807 isolate->LowMemoryNotification();
808 }
809 // delete function template
810 V8FunctionDestroyCallbackHelper::DeleteFunctionTemplate(isolate_.Get());
811 // Just invalidate it, isolate_ will dispose when js-thread finished.
812 ModuleManager::GetInstance()->ClearTimerIsolate(isolate_.Get());
813 isolate_.Invalidate();
814 }
815
LoadDebuggerSo()816 void LoadDebuggerSo()
817 {
818 LOGI("LoadDebuggerSo");
819 const std::string soDir = "libv8_debugger.z.so";
820 g_debugger = dlopen(soDir.c_str(), RTLD_LAZY);
821 if (g_debugger == nullptr) {
822 LOGE("cannot find debugger so");
823 }
824 }
825
StartDebuggerAgent(const std::unique_ptr<v8::Platform> & platform,const v8::Local<v8::Context> & context,std::string componentName,const bool isDebugMode,const int32_t instanceId)826 void StartDebuggerAgent(
827 const std::unique_ptr<v8::Platform>& platform, const v8::Local<v8::Context>& context, std::string componentName,
828 const bool isDebugMode, const int32_t instanceId)
829 {
830 LOGI("StartAgent");
831 if (g_debugger == nullptr) {
832 LOGE("g_debugger is null");
833 return;
834 }
835 StartDebug startDebug = (StartDebug)dlsym(g_debugger, "StartDebug");
836 if (startDebug == nullptr) {
837 LOGE("StartDebug=NULL, dlerror=%s", dlerror());
838 return;
839 }
840 startDebug(platform, context, componentName, isDebugMode, instanceId);
841 }
842
843 // -----------------------
844 // Start V8DeclarativeEngine
845 // -----------------------
846
GetPlatform()847 std::unique_ptr<v8::Platform>& V8DeclarativeEngine::GetPlatform()
848 {
849 return V8Helper::GetPlatform();
850 }
851
Initialize(const RefPtr<FrontendDelegate> & delegate)852 bool V8DeclarativeEngine::Initialize(const RefPtr<FrontendDelegate>& delegate)
853 {
854 CHECK_RUN_ON(JS);
855 ACE_SCOPED_TRACE("V8DeclarativeEngine::Initialize");
856 LOGI("V8DeclarativeEngine initialize");
857 ACE_DCHECK(delegate);
858
859 // Initialize V8 engine
860 GetPlatform();
861
862 // if load debugger.so successfully, debug mode
863 if (IsDebugVersion()) {
864 if (NeedDebugBreakPoint()) {
865 LOGI("NeedDebugBreakPoint = TRUE");
866 } else {
867 LOGI("NeedDebugBreakPoint = FALSE");
868 }
869 LoadDebuggerSo();
870 LOGI("debug mode in V8DeclarativeEngine");
871 }
872 // Initialize engine instance
873 engineInstance_ = AceType::MakeRefPtr<V8DeclarativeEngineInstance>(delegate);
874 bool res = engineInstance_->InitJSEnv();
875 if (!res) {
876 LOGE("V8DeclarativeEngine initialize failed: %{public}d", instanceId_);
877 return false;
878 }
879
880 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
881 ACE_DCHECK(isolate);
882 {
883 v8::Isolate::Scope isolateScope(isolate);
884 v8::HandleScope handleScope(isolate);
885 auto context = engineInstance_->GetV8Context();
886 if (context.IsEmpty()) {
887 LOGE("Initialize, context Is Empty");
888 return false;
889 }
890 // debug mode
891 if (g_debugger != nullptr) {
892 std::string instanceName = GetInstanceName();
893 if (instanceName.empty()) {
894 LOGE("GetInstanceName fail, %s", instanceName.c_str());
895 return false;
896 }
897 StartDebuggerAgent(GetPlatform(), context, instanceName, NeedDebugBreakPoint(), instanceId_);
898 }
899 }
900 nativeEngine_ =
901 new V8NativeEngine(GetPlatform().get(), isolate, engineInstance_->GetContext(), static_cast<void*>(this));
902 engineInstance_->SetNativeEngine(nativeEngine_);
903 SetPostTask(nativeEngine_);
904 #if !defined(PREVIEW)
905 nativeEngine_->CheckUVLoop();
906 #endif
907 if (delegate && delegate->GetAssetManager()) {
908 std::vector<std::string> packagePath = delegate->GetAssetManager()->GetLibPath();
909 if (!packagePath.empty()) {
910 auto v8NativeEngine = static_cast<V8NativeEngine*>(nativeEngine_);
911 v8NativeEngine->SetPackagePath(packagePath);
912 }
913 }
914 RegisterWorker();
915
916 return true;
917 }
918
SetPostTask(NativeEngine * nativeEngine)919 void V8DeclarativeEngine::SetPostTask(NativeEngine* nativeEngine)
920 {
921 LOGI("SetPostTask");
922 auto weakDelegate = AceType::WeakClaim(AceType::RawPtr(engineInstance_->GetDelegate()));
923 auto&& postTask = [weakDelegate, nativeEngine = nativeEngine_, id = instanceId_](bool needSync) {
924 auto delegate = weakDelegate.Upgrade();
925 if (delegate == nullptr) {
926 LOGE("delegate is nullptr");
927 return;
928 }
929 delegate->PostJsTask([nativeEngine, needSync, id]() {
930 if (nativeEngine == nullptr) {
931 return;
932 }
933 ContainerScope scope(id);
934 nativeEngine->Loop(LOOP_NOWAIT, needSync);
935 });
936 };
937 nativeEngine_->SetPostTask(postTask);
938 }
939
RegisterInitWorkerFunc()940 void V8DeclarativeEngine::RegisterInitWorkerFunc()
941 {
942 WeakPtr<GroupJsBridge> weakJsBridge = engineInstance_->GetDelegate()->GetGroupJsBridge();
943 auto&& initWorkerFunc = [weakJsBridge, delegate = engineInstance_->GetDelegateForV8Data(),
944 dispatch = engineInstance_->GetJsMessageDispatcherForV8Data()](NativeEngine* nativeEngine) {
945 LOGI("WorkerCore RegisterInitWorkerFunc called");
946 if (nativeEngine == nullptr) {
947 LOGE("nativeEngine is nullptr");
948 return;
949 }
950 auto v8NativeEngine = static_cast<V8NativeEngine*>(nativeEngine);
951 if (v8NativeEngine == nullptr) {
952 LOGE("v8NativeEngine is nullptr");
953 return;
954 }
955 auto isolate = v8NativeEngine->GetIsolate();
956 if (isolate == nullptr) {
957 LOGE("isolate is nullptr");
958 return;
959 }
960
961 v8::HandleScope handleScope(isolate);
962 v8::Local<v8::Context> localContext = v8NativeEngine->GetContext();
963 isolate->SetStackLimit(V8_MAX_STACK_SIZE);
964 isolate->SetData(V8DeclarativeEngineInstance::DISPATCHER, dispatch);
965 isolate->SetData(V8DeclarativeEngineInstance::FRONTEND_DELEGATE, delegate);
966 V8DeclarativeEngineInstance::InitJsConsoleObject(localContext, isolate);
967 V8DeclarativeEngineInstance::InitAceModules(_binary_jsEnumStyle_js_start, _binary_jsEnumStyle_js_end, isolate);
968 ModuleManager::InitTimerModule(localContext);
969
970 auto jsBridge = DynamicCast<V8DeclarativeGroupJsBridge>(weakJsBridge.Upgrade());
971 if (jsBridge != nullptr) {
972 jsBridge->AddIsolateNativeEngineRelation(isolate, nativeEngine);
973 auto source = v8::String::NewFromUtf8(isolate, jsBridge->GetJsCode().c_str()).ToLocalChecked();
974 if (!CallEvalBuf(isolate, "var global = globalThis;\n")
975 || jsBridge->InitializeGroupJsBridge(localContext) == JS_CALL_FAIL
976 || jsBridge->CallEvalBuf(isolate, source) == JS_CALL_FAIL) {
977 LOGE("Worker Initialize GroupJsBridge failed!");
978 }
979 } else {
980 LOGE("Worker Initialize GroupJsBridge failed, jsBridge is nullptr");
981 }
982 };
983 nativeEngine_->SetInitWorkerFunc(initWorkerFunc);
984 }
985
RegisterAssetFunc()986 void V8DeclarativeEngine::RegisterAssetFunc()
987 {
988 auto weakAsset = WeakPtr<AssetManager>(engineInstance_->GetDelegate()->GetAssetManager());
989 auto&& assetFunc = [weakAsset](const std::string& uri, std::vector<uint8_t>& content, std::string& ami) {
990 LOGI("WorkerCore RegisterAssetFunc called");
991 auto asset = weakAsset.Upgrade();
992 if (!asset) {
993 LOGE("delegate is nullptr");
994 return;
995 }
996 FrontendDelegate::GetResourceData(uri, asset, content);
997 };
998 nativeEngine_->SetGetAssetFunc(assetFunc);
999 }
1000
RegisterOffWorkerFunc()1001 void V8DeclarativeEngine::RegisterOffWorkerFunc()
1002 {
1003 WeakPtr<GroupJsBridge> weakJsBridge = engineInstance_->GetDelegate()->GetGroupJsBridge();
1004 auto&& offWorkerFunc = [weakJsBridge](NativeEngine* nativeEngine) {
1005 LOGI("WorkerCore RegisterOffWorkerFunc called");
1006 if (nativeEngine == nullptr) {
1007 LOGE("nativeEngine is nullptr");
1008 return;
1009 }
1010 auto v8NativeEngine = static_cast<V8NativeEngine*>(nativeEngine);
1011 if (v8NativeEngine == nullptr) {
1012 LOGE("v8NativeEngine is nullptr");
1013 return;
1014 }
1015 auto jsBridge = DynamicCast<V8DeclarativeGroupJsBridge>(weakJsBridge.Upgrade());
1016 if (jsBridge == nullptr) {
1017 LOGE("jsBridge is nullptr");
1018 return;
1019 }
1020 auto isolate = v8NativeEngine->GetIsolate();
1021 if (isolate == nullptr) {
1022 LOGE("isolate is nullptr");
1023 return;
1024 }
1025
1026 jsBridge->Destroy(isolate, true);
1027 };
1028 nativeEngine_->SetOffWorkerFunc(offWorkerFunc);
1029 }
1030
RegisterWorker()1031 void V8DeclarativeEngine::RegisterWorker()
1032 {
1033 nativeEngine_->SetWorkerAsyncWorkFunc(V8DeclarativeGroupJsBridge::NativeAsyncExecuteCallback,
1034 V8DeclarativeGroupJsBridge::NativeAsyncCompleteCallback);
1035 RegisterInitWorkerFunc();
1036 RegisterAssetFunc();
1037 RegisterOffWorkerFunc();
1038 }
1039
~V8DeclarativeEngine()1040 V8DeclarativeEngine::~V8DeclarativeEngine()
1041 {
1042 CHECK_RUN_ON(JS);
1043 if (g_debugger != nullptr) {
1044 StopDebug stopDebug = (StopDebug)dlsym(g_debugger, "StopDebug");
1045 if (stopDebug != nullptr) {
1046 stopDebug();
1047 }
1048 }
1049 LOG_DESTROY();
1050 if (nativeEngine_ != nullptr) {
1051 #if !defined(PREVIEW)
1052 nativeEngine_->CancelCheckUVLoop();
1053 #endif
1054 delete nativeEngine_;
1055 }
1056 if (g_debugger != nullptr) {
1057 dlclose(g_debugger);
1058 }
1059 }
1060
CallAppFunc(v8::Isolate * isolate,const v8::Local<v8::Context> & context,std::string appFuncName)1061 void V8DeclarativeEngine::CallAppFunc(
1062 v8::Isolate* isolate, const v8::Local<v8::Context>& context, std::string appFuncName)
1063 {
1064 (void)CallAppFunc(isolate, context, appFuncName, 0, nullptr);
1065 }
1066
CallAppFunc(v8::Isolate * isolate,const v8::Local<v8::Context> & context,std::string appFuncName,int argc,v8::Local<v8::Value> * argv)1067 bool V8DeclarativeEngine::CallAppFunc(v8::Isolate* isolate, const v8::Local<v8::Context>& context,
1068 std::string appFuncName, int argc, v8::Local<v8::Value>* argv)
1069 {
1070 v8::Local<v8::Object> global = context->Global();
1071 v8::Local<v8::String> exportName = v8::String::NewFromUtf8(isolate, "exports").ToLocalChecked();
1072 v8::Local<v8::Value> exportval;
1073 bool succ = global->Get(context, exportName).ToLocal(&exportval);
1074 if (!succ) {
1075 LOGD("no property named \"export\" in global object");
1076 return false;
1077 }
1078 if (!exportval->IsObject()) {
1079 LOGD("property \"exports\" is not a object");
1080 return false;
1081 }
1082
1083 v8::Local<v8::Object> exportobj = exportval->ToObject(context).ToLocalChecked();
1084 v8::Local<v8::String> defaultName = v8::String::NewFromUtf8(isolate, "default").ToLocalChecked();
1085 v8::Local<v8::Value> defaultval;
1086 succ = exportobj->Get(context, defaultName).ToLocal(&defaultval);
1087 if (!succ) {
1088 LOGD("no property named \"default\" in export object");
1089 return false;
1090 }
1091 if (!defaultval->IsObject()) {
1092 LOGD("property \"defaultval\" is not a object");
1093 return false;
1094 }
1095
1096 v8::Local<v8::Object> defaultobj = defaultval->ToObject(context).ToLocalChecked();
1097 v8::Local<v8::String> funcName = v8::String::NewFromUtf8(isolate, appFuncName.c_str()).ToLocalChecked();
1098 v8::Local<v8::Value> jsFuncVal;
1099 succ = defaultobj->Get(context, funcName).ToLocal(&jsFuncVal);
1100 if (!succ) {
1101 LOGD("no property named \"%{public}s\" in global object", appFuncName.c_str());
1102 return false;
1103 }
1104 if (!jsFuncVal->IsFunction()) {
1105 LOGD("property \"%{public}s\" is not a function", appFuncName.c_str());
1106 return false;
1107 }
1108
1109 v8::Local<v8::Function> jsFunc = v8::Local<v8::Function>::Cast(jsFuncVal);
1110 v8::Local<v8::Value> res;
1111 succ = jsFunc->Call(context, defaultobj, argc, argv).ToLocal(&res);
1112 if (!succ) {
1113 LOGD("call failed");
1114 return false;
1115 }
1116 return res->IsTrue();
1117 }
1118
LoadJs(const std::string & url,const RefPtr<JsAcePage> & page,bool isMainPage)1119 void V8DeclarativeEngine::LoadJs(const std::string& url, const RefPtr<JsAcePage>& page, bool isMainPage)
1120 {
1121 LOGI("Enter LoadJs");
1122 ACE_SCOPED_TRACE("V8DeclarativeEngine::LoadJS");
1123 ACE_DCHECK(engineInstance_);
1124
1125 if (g_debugger != nullptr) {
1126 WaitingForIde waitingForIde = (WaitingForIde)dlsym(g_debugger, "WaitingForIde");
1127 if (waitingForIde != nullptr) {
1128 waitingForIde();
1129 }
1130 }
1131
1132 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1133 ACE_DCHECK(isolate);
1134 v8::Isolate::Scope isolateScope(isolate);
1135 v8::HandleScope handleScope(isolate);
1136 auto context = engineInstance_->GetV8Context();
1137 v8::Context::Scope contextScope(context);
1138
1139 engineInstance_->SetStagingPage(page);
1140 if (isMainPage) {
1141 ACE_DCHECK(!engineInstance_->GetRunningPage());
1142 engineInstance_->SetRunningPage(page);
1143 }
1144
1145 auto delegate =
1146 static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8DeclarativeEngineInstance::FRONTEND_DELEGATE));
1147 v8::TryCatch tryCatch(isolate);
1148
1149 if (isMainPage) {
1150 std::string commonsJsContent;
1151 if ((*delegate)->GetAssetContent("commons.js", commonsJsContent)) {
1152 bool commonsJsResult = CallEvalBuf(isolate, commonsJsContent.c_str(), -1, "commons.js");
1153 if (!commonsJsResult) {
1154 LOGE("fail to execute load commonsjs script");
1155 return;
1156 }
1157 }
1158 std::string vendorsJsContent;
1159 if ((*delegate)->GetAssetContent("vendors.js", vendorsJsContent)) {
1160 bool vendorsJsResult = CallEvalBuf(isolate, vendorsJsContent.c_str(), -1, "vendors.js");
1161 if (!vendorsJsResult) {
1162 LOGE("fail to execute load vendorsjs script");
1163 return;
1164 }
1165 }
1166 std::string appjsContent;
1167 if (!(*delegate)->GetAssetContent("app.js", appjsContent)) {
1168 LOGE("js file load failed!");
1169 return;
1170 }
1171 std::string appMap;
1172 if ((*delegate)->GetAssetContent("app.js.map", appMap)) {
1173 page->SetAppMap(appMap);
1174 } else {
1175 LOGI("app map is missing!");
1176 }
1177 bool result = CallEvalBuf(isolate, appjsContent.c_str(), -1, "app.js");
1178 if (!result) {
1179 LOGE("failed to execute Loadjs script");
1180 return;
1181 }
1182 auto container = Container::Current();
1183 if (container && container->IsMainWindow()) {
1184 CallAppFunc(isolate, context, "onCreate");
1185 }
1186 }
1187
1188 if (g_debugger != nullptr) {
1189 WaitingForIde waitingForIde = (WaitingForIde)dlsym(g_debugger, "WaitingForIde");
1190 if (waitingForIde != nullptr) {
1191 waitingForIde();
1192 }
1193 }
1194
1195 std::string jsContent;
1196 LOGI("Enter LoadJs file:%s", url.c_str());
1197 if (!(*delegate)->GetAssetContent(url, jsContent)) {
1198 LOGE("js file load failed!");
1199 return;
1200 }
1201
1202 std::string jsSourceMap;
1203 if ((*delegate)->GetAssetContent(url + ".map", jsSourceMap)) {
1204 page->SetPageMap(jsSourceMap);
1205 } else {
1206 LOGI("js source map load failed!");
1207 }
1208 bool result = CallEvalBuf(isolate, jsContent.c_str(), -1, url.c_str());
1209 if (!result) {
1210 LOGE("failed to execute Loadjs script");
1211 return;
1212 }
1213
1214 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1215 continue;
1216 }
1217 }
1218
UpdateRunningPage(const RefPtr<JsAcePage> & page)1219 void V8DeclarativeEngine::UpdateRunningPage(const RefPtr<JsAcePage>& page)
1220 {
1221 ACE_DCHECK(engineInstance_);
1222 LOGD("Enter UpdateRunningPage %d", page->GetPageId());
1223 engineInstance_->SetRunningPage(page);
1224 }
1225
UpdateStagingPage(const RefPtr<JsAcePage> & page)1226 void V8DeclarativeEngine::UpdateStagingPage(const RefPtr<JsAcePage>& page)
1227 {
1228 LOGD("Enter UpdateStagingPage %d", page->GetPageId());
1229 ACE_DCHECK(engineInstance_);
1230 engineInstance_->SetStagingPage(page);
1231 }
1232
ResetStagingPage()1233 void V8DeclarativeEngine::ResetStagingPage()
1234 {
1235 ACE_DCHECK(engineInstance_);
1236 LOGD("Enter ResetStagingPage");
1237 auto runningPage = engineInstance_->GetRunningPage();
1238 engineInstance_->ResetStagingPage(runningPage);
1239 }
1240
DestroyPageInstance(int32_t pageId)1241 void V8DeclarativeEngine::DestroyPageInstance(int32_t pageId)
1242 {
1243 LOGI("Enter DestroyPageInstance %d", pageId);
1244 ACE_DCHECK(engineInstance_);
1245
1246 engineInstance_->DestroyPersistRootViewHandle(pageId);
1247 }
1248
DestroyApplication(const std::string & packageName)1249 void V8DeclarativeEngine::DestroyApplication(const std::string& packageName)
1250 {
1251 LOGI("Enter DestroyApplication: destroy, packageName %{public}s", packageName.c_str());
1252 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1253 ACE_DCHECK(isolate);
1254 v8::HandleScope handleScope(isolate);
1255 v8::Isolate::Scope isolateScope(isolate);
1256 auto context = engineInstance_->GetV8Context();
1257 if (context.IsEmpty()) {
1258 LOGE("Destroy Application, context Is Empty");
1259 return;
1260 }
1261 v8::Context::Scope contextScope(context);
1262
1263 v8::TryCatch tryCatch(isolate);
1264
1265 auto container = Container::Current();
1266 if (container && container->IsMainWindow()) {
1267 CallAppFunc(isolate, context, "onDestroy");
1268 }
1269
1270 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1271 continue;
1272 }
1273 }
1274
UpdateApplicationState(const std::string & packageName,Frontend::State state)1275 void V8DeclarativeEngine::UpdateApplicationState(const std::string& packageName, Frontend::State state)
1276 {
1277 LOGD("Enter UpdateApplicationState: destroy, packageName %{public}s", packageName.c_str());
1278 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1279 ACE_DCHECK(isolate);
1280 v8::HandleScope handleScope(isolate);
1281 auto context = engineInstance_->GetV8Context();
1282 if (context.IsEmpty()) {
1283 LOGE("Destroy Application, context Is Empty");
1284 return;
1285 }
1286
1287 if (state == Frontend::State::ON_SHOW) {
1288 CallAppFunc(isolate, context, "onShow");
1289 } else if (state == Frontend::State::ON_HIDE) {
1290 CallAppFunc(isolate, context, "onHide");
1291 }
1292
1293 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1294 continue;
1295 }
1296 }
1297
OnWindowDisplayModeChanged(bool isShownInMultiWindow,const std::string & data)1298 void V8DeclarativeEngine::OnWindowDisplayModeChanged(bool isShownInMultiWindow, const std::string& data)
1299 {
1300 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1301 ACE_DCHECK(isolate);
1302 v8::HandleScope handleScope(isolate);
1303 auto context = engineInstance_->GetV8Context();
1304 if (context.IsEmpty()) {
1305 LOGE("Destroy Application, context Is Empty");
1306 return;
1307 }
1308
1309 v8::Local<v8::Boolean> v8Bool = v8::Boolean::New(isolate, isShownInMultiWindow);
1310 v8::Local<v8::String> v8Data = v8::String::NewFromUtf8(isolate, data.c_str()).ToLocalChecked();
1311 auto jsonValue = v8::JSON::Parse(context, v8Data);
1312 if (jsonValue.IsEmpty()) {
1313 LOGE("jsonValue is empty");
1314 return;
1315 }
1316 v8::Local<v8::Value> v8Config = jsonValue.ToLocalChecked();
1317 v8::Local<v8::Value> argv[] = { v8Bool, v8Config };
1318 int32_t argc = 2;
1319 (void)CallAppFunc(isolate, context, "onWindowDisplayModeChanged", argc, argv);
1320 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1321 continue;
1322 }
1323 }
1324
OnNewWant(const std::string & data)1325 void V8DeclarativeEngine::OnNewWant(const std::string& data)
1326 {
1327 LOGD("V8DeclarativeEngine::OnNewWant");
1328 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1329 ACE_DCHECK(isolate);
1330 v8::HandleScope handleScope(isolate);
1331 v8::Isolate::Scope isolateScope(isolate);
1332 auto context = engineInstance_->GetV8Context();
1333 if (context.IsEmpty()) {
1334 LOGE("AceAbility Sava date, context Is Empty");
1335 return;
1336 }
1337 v8::Context::Scope contextScope(context);
1338 v8::TryCatch tryCatch(isolate);
1339 v8::Local<v8::String> v8Data = v8::String::NewFromUtf8(isolate, data.c_str()).ToLocalChecked();
1340 auto jsonValue = v8::JSON::Parse(context, v8Data);
1341 if (jsonValue.IsEmpty()) {
1342 v8::Local<v8::Object> tmpData = v8::Object::New(isolate);
1343 v8::Local<v8::Value> argv[] = { tmpData };
1344 int len = 1;
1345 if (!CallAppFunc(isolate, context, "onNewWant", len, argv)) {
1346 return;
1347 }
1348 } else {
1349 v8::Local<v8::Value> dataValue = jsonValue.ToLocalChecked();
1350 v8::Local<v8::Value> argv[] = { dataValue };
1351 int32_t len = 1;
1352 if (!CallAppFunc(isolate, context, "onNewWant", len, argv)) {
1353 return;
1354 }
1355 }
1356
1357 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1358 continue;
1359 }
1360 }
1361
OnSaveAbilityState(std::string & saveData)1362 void V8DeclarativeEngine::OnSaveAbilityState(std::string& saveData)
1363 {
1364 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1365 ACE_DCHECK(isolate);
1366 v8::HandleScope handleScope(isolate);
1367 v8::Isolate::Scope isolateScope(isolate);
1368 auto context = engineInstance_->GetV8Context();
1369 if (context.IsEmpty()) {
1370 LOGE("AceAbility Sava data, context Is Empty");
1371 return;
1372 }
1373
1374 v8::Local<v8::Object> data = v8::Object::New(isolate);
1375 v8::Local<v8::Value> argv[] = { data };
1376 int len = 1;
1377 CallAppFunc(isolate, context, "onSaveAbilityState", len, argv);
1378 v8::Local<v8::String> propertyEntries = v8::JSON::Stringify(context, data).ToLocalChecked();
1379 v8::String::Utf8Value utf8Value(isolate, propertyEntries);
1380 if (*utf8Value) {
1381 saveData = *utf8Value;
1382 }
1383 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1384 continue;
1385 }
1386 }
1387
OnRestoreAbilityState(const std::string & data)1388 void V8DeclarativeEngine::OnRestoreAbilityState(const std::string& data)
1389 {
1390 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1391 ACE_DCHECK(isolate);
1392 v8::HandleScope handleScope(isolate);
1393 v8::Isolate::Scope isolateScope(isolate);
1394 auto context = engineInstance_->GetV8Context();
1395 if (context.IsEmpty()) {
1396 LOGE("AceAbility Restore data, context Is Empty");
1397 return;
1398 }
1399 v8::Context::Scope contextScope(context);
1400
1401 v8::TryCatch tryCatch(isolate);
1402
1403 v8::Local<v8::String> v8Data = v8::String::NewFromUtf8(isolate, data.c_str()).ToLocalChecked();
1404 auto jsonValue = v8::JSON::Parse(context, v8Data);
1405 if (jsonValue.IsEmpty()) {
1406 LOGE("AceAbility RestoreAbility, data Is Empty");
1407 return;
1408 }
1409 v8::Local<v8::Value> dataValue = v8::JSON::Parse(context, v8Data).ToLocalChecked();
1410 v8::Local<v8::Value> argv[] = { dataValue };
1411 int32_t len = 1;
1412
1413 if (!CallAppFunc(isolate, context, "onRestoreAbilityState", len, argv)) {
1414 return;
1415 }
1416
1417 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1418 continue;
1419 }
1420 }
1421
OnActive()1422 void V8DeclarativeEngine::OnActive()
1423 {
1424 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1425 ACE_DCHECK(isolate);
1426 v8::HandleScope handleScope(isolate);
1427 v8::Isolate::Scope isolateScope(isolate);
1428 auto context = engineInstance_->GetV8Context();
1429 if (context.IsEmpty()) {
1430 LOGE("AceAbility OnActive, context Is Empty");
1431 return;
1432 }
1433 v8::Context::Scope contextScope(context);
1434
1435 v8::TryCatch tryCatch(isolate);
1436
1437 CallAppFunc(isolate, context, "onActive");
1438 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1439 continue;
1440 }
1441 }
1442
OnInactive()1443 void V8DeclarativeEngine::OnInactive()
1444 {
1445 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1446 ACE_DCHECK(isolate);
1447 v8::HandleScope handleScope(isolate);
1448 v8::Isolate::Scope isolateScope(isolate);
1449 auto context = engineInstance_->GetV8Context();
1450 if (context.IsEmpty()) {
1451 LOGE("AceAbility OnInactive, context Is Empty");
1452 return;
1453 }
1454 v8::Context::Scope contextScope(context);
1455
1456 v8::TryCatch tryCatch(isolate);
1457
1458 CallAppFunc(isolate, context, "onInactive");
1459 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1460 continue;
1461 }
1462 }
1463
OnMemoryLevel(const int32_t level)1464 void V8DeclarativeEngine::OnMemoryLevel(const int32_t level)
1465 {
1466 LOGD("AceAbility Enter OnMemoryLevel");
1467 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1468 ACE_DCHECK(isolate);
1469 v8::HandleScope handleScope(isolate);
1470 v8::Isolate::Scope isolateScope(isolate);
1471 auto context = engineInstance_->GetV8Context();
1472 if (context.IsEmpty()) {
1473 LOGE("AceAbility OnMemoryLevel, context Is Empty");
1474 return;
1475 }
1476 v8::Context::Scope contextScope(context);
1477
1478 v8::TryCatch tryCatch(isolate);
1479
1480 v8::Local<v8::Integer> v8Integer = v8::Uint32::NewFromUnsigned(isolate, level);
1481 v8::Local<v8::Value> argv[] = { v8Integer };
1482 int32_t len = 1;
1483
1484 if (!CallAppFunc(isolate, context, "onMemoryLevel", len, argv)) {
1485 return;
1486 }
1487 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1488 continue;
1489 }
1490 }
1491
OnConfigurationUpdated(const std::string & data)1492 void V8DeclarativeEngine::OnConfigurationUpdated(const std::string& data)
1493 {
1494 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1495 ACE_DCHECK(isolate);
1496 v8::HandleScope handleScope(isolate);
1497 auto context = engineInstance_->GetV8Context();
1498 if (context.IsEmpty()) {
1499 LOGE("Destroy Application, context Is Empty");
1500 return;
1501 }
1502
1503 v8::Local<v8::String> v8Data = v8::String::NewFromUtf8(isolate, data.c_str()).ToLocalChecked();
1504 auto jsonValue = v8::JSON::Parse(context, v8Data);
1505 if (jsonValue.IsEmpty()) {
1506 LOGE("jsonValue is empty");
1507 return;
1508 }
1509 v8::Local<v8::Value> ResourceConfiguration = jsonValue.ToLocalChecked();
1510 v8::Local<v8::Value> argv[] = { ResourceConfiguration };
1511 int32_t argc = 1;
1512 (void)CallAppFunc(isolate, context, "onConfigurationUpdated", argc, argv);
1513 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1514 continue;
1515 }
1516 }
1517
OnRemoteTerminated()1518 void V8DeclarativeEngine::OnRemoteTerminated()
1519 {
1520 LOGD("AceAbility Enter OnRemoteTerminated");
1521 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1522 ACE_DCHECK(isolate);
1523 v8::HandleScope handleScope(isolate);
1524 v8::Isolate::Scope isolateScope(isolate);
1525 auto context = engineInstance_->GetV8Context();
1526 if (context.IsEmpty()) {
1527 LOGE("AceAbility OnRemoteTerminated, context Is Empty");
1528 return;
1529 }
1530 v8::Context::Scope contextScope(context);
1531
1532 v8::TryCatch tryCatch(isolate);
1533
1534 CallAppFunc(isolate, context, "onRemoteTerminated");
1535 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1536 continue;
1537 }
1538 }
1539
OnCompleteContinuation(const int32_t code)1540 void V8DeclarativeEngine::OnCompleteContinuation(const int32_t code)
1541 {
1542 LOGD("AceAbility Enter OnCompleteContinuation");
1543 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1544 ACE_DCHECK(isolate);
1545 v8::HandleScope handleScope(isolate);
1546 v8::Isolate::Scope isolateScope(isolate);
1547 auto context = engineInstance_->GetV8Context();
1548 if (context.IsEmpty()) {
1549 LOGE("AceAbility OnCompleteContinuation, context Is Empty");
1550 return;
1551 }
1552 v8::Context::Scope contextScope(context);
1553
1554 v8::TryCatch tryCatch(isolate);
1555
1556 v8::Local<v8::Integer> v8Integer = v8::Uint32::NewFromUnsigned(isolate, code);
1557 v8::Local<v8::Value> argv[] = { v8Integer };
1558 int32_t len = 1;
1559
1560 (void)CallAppFunc(isolate, context, "onCompleteContinuation", len, argv);
1561 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1562 continue;
1563 }
1564 }
1565
1566
OnRestoreData(const std::string & data)1567 bool V8DeclarativeEngine::OnRestoreData(const std::string& data)
1568 {
1569 LOGD("AceAbility Enter OnRestoreData");
1570 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1571 ACE_DCHECK(isolate);
1572 v8::HandleScope handleScope(isolate);
1573 v8::Isolate::Scope isolateScope(isolate);
1574 auto context = engineInstance_->GetV8Context();
1575 if (context.IsEmpty()) {
1576 LOGE("AceAbility OnRestoreData, context Is Empty");
1577 return false;
1578 }
1579 v8::Context::Scope contextScope(context);
1580
1581 v8::TryCatch tryCatch(isolate);
1582
1583 v8::Local<v8::String> v8Data = v8::String::NewFromUtf8(isolate, data.c_str()).ToLocalChecked();
1584 auto jsonValue = v8::JSON::Parse(context, v8Data);
1585 if (jsonValue.IsEmpty()) {
1586 LOGE("jsonValue is empty");
1587 return false;
1588 }
1589 v8::Local<v8::Value> dataValue = jsonValue.ToLocalChecked();
1590 v8::Local<v8::Value> argv[] = { dataValue };
1591 int32_t len = 1;
1592
1593 if (!CallAppFunc(isolate, context, "onRestoreData", len, argv)) {
1594 return false;
1595 }
1596
1597 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1598 continue;
1599 }
1600
1601 return true;
1602 }
1603
OnStartContinuation()1604 bool V8DeclarativeEngine::OnStartContinuation()
1605 {
1606 LOGE("AceAbility Enter OnStartContinuation");
1607 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1608 ACE_DCHECK(isolate);
1609 v8::HandleScope handleScope(isolate);
1610 v8::Isolate::Scope isolateScope(isolate);
1611 auto context = engineInstance_->GetV8Context();
1612 if (context.IsEmpty()) {
1613 LOGE("AceAbility OnStartContinuation, context Is Empty");
1614 return false;
1615 }
1616 v8::Context::Scope contextScope(context);
1617
1618 v8::TryCatch tryCatch(isolate);
1619
1620 int len = 0;
1621 auto argv = nullptr;
1622 if (!CallAppFunc(isolate, context, "onStartContinuation", len, argv)) {
1623 return false;
1624 }
1625
1626 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1627 continue;
1628 }
1629
1630 return true;
1631 }
1632
OnSaveData(std::string & saveData)1633 void V8DeclarativeEngine::OnSaveData(std::string& saveData)
1634 {
1635 LOGE("AceAbility Enter save data");
1636 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1637 ACE_DCHECK(isolate);
1638 v8::HandleScope handleScope(isolate);
1639 v8::Isolate::Scope isolateScope(isolate);
1640 auto context = engineInstance_->GetV8Context();
1641 if (context.IsEmpty()) {
1642 LOGE("AceAbility Sava date, context Is Empty");
1643 return;
1644 }
1645 v8::Context::Scope contextScope(context);
1646
1647 v8::TryCatch tryCatch(isolate);
1648
1649 v8::Local<v8::Object> data = v8::Object::New(isolate);
1650 v8::Local<v8::Value> argv[] = { data };
1651 int len = 1;
1652
1653 if (CallAppFunc(isolate, context, "onSaveData", len, argv)) {
1654 v8::Local<v8::String> propertyEntries = v8::JSON::Stringify(context, data).ToLocalChecked();
1655 v8::String::Utf8Value utf8Value(isolate, propertyEntries);
1656 saveData = *utf8Value;
1657 }
1658
1659 while (v8::platform::PumpMessageLoop(GetPlatform().get(), isolate)) {
1660 continue;
1661 }
1662 }
1663
TimerCallback(const std::string & callbackId,const std::string & delay,bool isInterval)1664 void V8DeclarativeEngine::TimerCallback(const std::string& callbackId, const std::string& delay, bool isInterval)
1665 {
1666 LOGD("Enter TimerCallback");
1667 ACE_DCHECK(engineInstance_);
1668 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1669 ACE_DCHECK(isolate);
1670 v8::Isolate::Scope isolateScope(isolate);
1671 v8::HandleScope handleScope(isolate);
1672 auto context = engineInstance_->GetV8Context();
1673 v8::Context::Scope contextScope(context);
1674
1675 auto delegate =
1676 static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8DeclarativeEngineInstance::FRONTEND_DELEGATE));
1677 if (isInterval) {
1678 TimerCallJs(callbackId, isInterval);
1679 (*delegate)->WaitTimer(callbackId, delay, isInterval, false);
1680 } else {
1681 TimerCallJs(callbackId, isInterval);
1682 ModuleManager::GetInstance()->RemoveCallbackFunc(std::stoi(callbackId), isInterval);
1683 (*delegate)->ClearTimer(callbackId);
1684 }
1685 }
1686
TimerCallJs(const std::string & callbackId,bool isInterval)1687 void V8DeclarativeEngine::TimerCallJs(const std::string& callbackId, bool isInterval)
1688 {
1689 ACE_DCHECK(engineInstance_);
1690 v8::Isolate* isolate = ModuleManager::GetInstance()->GetCallbackIsolate(std::stoi(callbackId), isInterval);
1691 ACE_DCHECK(isolate);
1692 if (isolate == nullptr) {
1693 LOGW("CallbackIsolate is null when TimerCallJs is called.");
1694 return;
1695 }
1696 v8::Isolate::Scope isolateScope(isolate);
1697 v8::HandleScope handleScope(isolate);
1698 auto context = isolate->GetCurrentContext();
1699 v8::Context::Scope contextScope(context);
1700
1701 v8::TryCatch tryCatch(isolate);
1702 v8::Local<v8::Function> jsFunc =
1703 ModuleManager::GetInstance()->GetCallbackFunc(std::stoi(callbackId), isInterval).Get(isolate);
1704 if (!jsFunc->IsFunction()) {
1705 LOGE("timer jsFunc callbackId = %s is not a function", callbackId.c_str());
1706 return;
1707 }
1708 std::vector<CopyablePersistent<v8::Value>> jsargv =
1709 ModuleManager::GetInstance()->GetCallbackArray(std::stoi(callbackId), isInterval);
1710 v8::Local<v8::Value> res;
1711 if (jsargv.empty()) {
1712 LOGI("jsargv is empty");
1713 v8::Local<v8::Value> argv[] = {};
1714 bool succ = jsFunc->Call(context, context->Global(), 0, argv).ToLocal(&res);
1715 if (succ) {
1716 LOGI("call timer callback success");
1717 } else {
1718 V8Utils::JsStdDumpErrorAce(isolate, &tryCatch);
1719 LOGE("call timer callback fail");
1720 }
1721 } else {
1722 LOGI("jsargv's size is %{private}zu", jsargv.size());
1723 v8::Local<v8::Value>* argv = new v8::Local<v8::Value>[jsargv.size()];
1724 uint32_t index = 0;
1725 while (index < jsargv.size()) {
1726 argv[index] = jsargv[index].Get(isolate);
1727 ++index;
1728 }
1729
1730 bool succ = jsFunc->Call(context, context->Global(), jsargv.size(), argv).ToLocal(&res);
1731 if (succ) {
1732 LOGI("call timer callback success");
1733 } else {
1734 V8Utils::JsStdDumpErrorAce(isolate, &tryCatch);
1735 LOGE("call timer callback fail");
1736 }
1737 delete[] argv;
1738 }
1739 }
1740
MediaQueryCallback(const std::string & callbackId,const std::string & args)1741 void V8DeclarativeEngine::MediaQueryCallback(const std::string& callbackId, const std::string& args)
1742 {
1743 JsEngine::MediaQueryCallback(callbackId, args);
1744 }
1745
RequestAnimationCallback(const std::string & callbackId,uint64_t timeStamp)1746 void V8DeclarativeEngine::RequestAnimationCallback(const std::string& callbackId, uint64_t timeStamp)
1747 {
1748 LOGD("Enter RequestAnimationCallback");
1749 }
1750
JsCallback(const std::string & callbackId,const std::string & args)1751 void V8DeclarativeEngine::JsCallback(const std::string& callbackId, const std::string& args)
1752 {
1753 LOGD("Enter JSCallback");
1754 }
1755
FireAsyncEvent(const std::string & eventId,const std::string & param)1756 void V8DeclarativeEngine::FireAsyncEvent(const std::string& eventId, const std::string& param)
1757 {
1758 LOGW("V8DeclarativeEngine FireAsyncEvent is unusable");
1759 }
1760
FireSyncEvent(const std::string & eventId,const std::string & param)1761 void V8DeclarativeEngine::FireSyncEvent(const std::string& eventId, const std::string& param)
1762 {
1763 LOGW("V8DeclarativeEngine FireAsyncEvent is unusable");
1764 }
1765
InitXComponent()1766 void V8DeclarativeEngine::InitXComponent()
1767 {
1768 ACE_DCHECK(engineInstance_);
1769 isolateXComp_ = engineInstance_->GetV8Isolate();
1770 if (!isolateXComp_) {
1771 LOGE("InitXComponent isolateXComp_ is null.");
1772 return;
1773 }
1774 ACE_DCHECK(isolateXComp_);
1775 v8::Isolate::Scope isolateScope(isolateXComp_);
1776 v8::HandleScope handleScope(isolateXComp_);
1777 auto context = isolateXComp_->GetCurrentContext();
1778 if (context.IsEmpty()) {
1779 LOGE("InitXComponent context is empty");
1780 return;
1781 }
1782 ctxXComp_.Reset(isolateXComp_, context);
1783 }
1784
FireExternalEvent(const std::string & componentId,const uint32_t nodeId,const bool isDestroy)1785 void V8DeclarativeEngine::FireExternalEvent(const std::string& componentId, const uint32_t nodeId, const bool isDestroy)
1786 {
1787 CHECK_RUN_ON(JS);
1788 if (isDestroy) {
1789 XComponentComponentClient::GetInstance().DeleteFromXcomponentsMapById(componentId);
1790 XComponentClient::GetInstance().DeleteControllerFromJSXComponentControllersMap(componentId);
1791 XComponentClient::GetInstance().DeleteFromNativeXcomponentsMapById(componentId);
1792 XComponentClient::GetInstance().DeleteFromJsValMapById(componentId);
1793 return;
1794 }
1795 InitXComponent();
1796 std::tie(nativeXComponentImpl_, nativeXComponent_) =
1797 XComponentClient::GetInstance().GetNativeXComponentFromXcomponentsMap(componentId);
1798 RefPtr<XComponentComponent> xcomponent =
1799 XComponentComponentClient::GetInstance().GetXComponentFromXcomponentsMap(componentId);
1800 if (!xcomponent) {
1801 LOGE("FireExternalEvent xcomponent is null.");
1802 return;
1803 }
1804 auto textureId = static_cast<int64_t>(xcomponent->GetTextureId());
1805 auto container = Container::Current();
1806 if (!container) {
1807 LOGE("FireExternalEvent Current container null");
1808 return;
1809 }
1810 auto nativeView = static_cast<AceView*>(container->GetView());
1811 if (!nativeView) {
1812 LOGE("FireExternalEvent nativeView null");
1813 return;
1814 }
1815 auto nativeWindow = const_cast<void*>(nativeView->GetNativeWindowById(textureId));
1816 if (!nativeWindow) {
1817 LOGE("FireExternalEvent nativeWindow invalid");
1818 return;
1819 }
1820
1821 nativeXComponentImpl_->SetSurface(nativeWindow);
1822 nativeXComponentImpl_->SetXComponentId(xcomponent->GetId());
1823 auto v8NativeEngine = static_cast<V8NativeEngine*>(nativeEngine_);
1824 if (v8NativeEngine == nullptr) {
1825 LOGE("FireExternalEvent v8NativeEngine is nullptr");
1826 return;
1827 }
1828 std::string arguments;
1829 v8::Local<v8::Object> renderContext = v8NativeEngine->LoadModuleByName(xcomponent->GetLibraryName(), true,
1830 arguments, OH_NATIVE_XCOMPONENT_OBJ,
1831 reinterpret_cast<void*>(nativeXComponent_));
1832 renderContextXComp_.Reset(isolateXComp_, renderContext);
1833 auto objContext = V8Object(renderContext);
1834 JSRef<JSObject> obj = JSRef<JSObject>::Make(objContext);
1835 XComponentClient::GetInstance().AddJsValToJsValMap(componentId, obj);
1836 auto delegate =
1837 static_cast<RefPtr<FrontendDelegate>*>(isolateXComp_->GetData(V8DeclarativeEngineInstance::FRONTEND_DELEGATE));
1838 v8::TryCatch tryCatch(isolateXComp_);
1839 auto task = [weak = WeakClaim(this), xcomponent]() {
1840 auto pool = xcomponent->GetTaskPool();
1841 if (!pool) {
1842 return;
1843 }
1844 auto bridge = weak.Upgrade();
1845 if (bridge) {
1846 pool->NativeXComponentInit(
1847 bridge->nativeXComponent_, AceType::WeakClaim(AceType::RawPtr(bridge->nativeXComponentImpl_)));
1848 }
1849 };
1850 if (*delegate == nullptr) {
1851 LOGE("FireExternalEvent delegate is null.");
1852 return;
1853 }
1854 (*delegate)->PostSyncTaskToPage(task);
1855 }
1856
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher)1857 void V8DeclarativeEngine::SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher)
1858 {
1859 ACE_DCHECK(engineInstance_);
1860 LOGD("Enter SetJsMessageDispatcher");
1861 engineInstance_->SetJsMessageDispatcher(dispatcher);
1862 }
1863
RunGarbageCollection()1864 void V8DeclarativeEngine::RunGarbageCollection()
1865 {
1866 if (engineInstance_) {
1867 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1868 if (isolate != nullptr) {
1869 v8::Isolate::Scope isolateScope(isolate);
1870 LOGD("Sending LowMemoryNotification to V8");
1871 isolate->LowMemoryNotification();
1872 }
1873 }
1874 }
1875
GetGroupJsBridge()1876 RefPtr<GroupJsBridge> V8DeclarativeEngine::GetGroupJsBridge()
1877 {
1878 return AceType::MakeRefPtr<V8DeclarativeGroupJsBridge>();
1879 }
1880
NotifyAppStorage(const std::string & key,const std::string & value)1881 void V8DeclarativeEngine::NotifyAppStorage(const std::string& key, const std::string& value)
1882 {
1883 if (engineInstance_) {
1884 v8::Isolate* isolate = engineInstance_->GetV8Isolate();
1885 if (isolate != nullptr) {
1886 v8::Isolate::Scope isolateScope(isolate);
1887 std::string str = "notifyAppStorageChange('" + key + "', '" + value + "');\n";
1888 bool result = CallEvalBuf(isolate, str.c_str());
1889 if (!result) {
1890 LOGE("failed to notify AppStorage");
1891 }
1892 }
1893 }
1894 }
1895
1896 } // namespace OHOS::Ace::Framework
1897