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 "js_runtime.h"
17
18 #include <cerrno>
19 #include <climits>
20 #include <cstdlib>
21 #include <regex>
22
23 #include <atomic>
24 #include <sys/epoll.h>
25 #include <unistd.h>
26
27 #include "ability_constants.h"
28 #include "connect_server_manager.h"
29 #include "ecmascript/napi/include/jsnapi.h"
30 #include "event_handler.h"
31 #include "file_path_utils.h"
32 #include "hdc_register.h"
33 #include "hilog_wrapper.h"
34 #include "hot_reloader.h"
35 #include "js_console_log.h"
36 #include "js_module_reader.h"
37 #include "js_module_searcher.h"
38 #include "js_runtime_utils.h"
39 #include "js_timer.h"
40 #include "js_worker.h"
41 #include "native_engine/impl/ark/ark_native_engine.h"
42 #include "parameters.h"
43 #include "runtime_extractor.h"
44 #include "systemcapability.h"
45
46 #ifdef SUPPORT_GRAPHICS
47 #include "declarative_module_preloader.h"
48 #endif
49
50 namespace OHOS {
51 namespace AbilityRuntime {
52 namespace {
53 constexpr uint8_t SYSCAP_MAX_SIZE = 64;
54 constexpr int64_t DEFAULT_GC_POOL_SIZE = 0x10000000; // 256MB
55 const std::string SANDBOX_ARK_CACHE_PATH = "/data/storage/ark-cache/";
56 const std::string SANDBOX_ARK_PROIFILE_PATH = "/data/storage/ark-profile";
57 #ifdef APP_USE_ARM
58 constexpr char ARK_DEBUGGER_LIB_PATH[] = "/system/lib/libark_debugger.z.so";
59 #else
60 constexpr char ARK_DEBUGGER_LIB_PATH[] = "/system/lib64/libark_debugger.z.so";
61 #endif
62
63 constexpr char TIMER_TASK[] = "uv_timer_task";
64 constexpr char MERGE_ABC_PATH[] = "/ets/modules.abc";
65 constexpr char BUNDLE_INSTALL_PATH[] = "/data/storage/el1/bundle/";
66
67 class ArkJsRuntime : public JsRuntime {
68 public:
ArkJsRuntime()69 ArkJsRuntime()
70 {
71 isArkEngine_ = true;
72 }
73
~ArkJsRuntime()74 ~ArkJsRuntime() override
75 {
76 Deinitialize();
77
78 if (vm_ != nullptr) {
79 if (debugMode_) {
80 ConnectServerManager::Get().RemoveInstance(instanceId_);
81 panda::JSNApi::StopDebugger(vm_);
82 }
83
84 panda::JSNApi::DestroyJSVM(vm_);
85 vm_ = nullptr;
86 }
87 }
88
StartDebugMode(bool needBreakPoint)89 void StartDebugMode(bool needBreakPoint) override
90 {
91 if (vm_ == nullptr) {
92 HILOG_ERROR("Virtual machine does not exist");
93 return;
94 }
95
96 if (debugMode_) {
97 HILOG_INFO("Already in debug mode");
98 return;
99 }
100
101 // Set instance id to tid after the first instance.
102 if (ArkJsRuntime::hasInstance.exchange(true, std::memory_order_relaxed)) {
103 instanceId_ = static_cast<uint32_t>(gettid());
104 }
105
106 HILOG_INFO("Ark VM is starting debug mode [%{public}s]", needBreakPoint ? "break" : "normal");
107
108 HdcRegister::Get().StartHdcRegister(bundleName_);
109 ConnectServerManager::Get().StartConnectServer(bundleName_);
110 ConnectServerManager::Get().AddInstance(instanceId_);
111 StartDebuggerInWorkerModule();
112
113 auto debuggerPostTask = [eventHandler = eventHandler_](std::function<void()>&& task) {
114 eventHandler->PostTask(task);
115 };
116 panda::JSNApi::StartDebugger(ARK_DEBUGGER_LIB_PATH, vm_, needBreakPoint, instanceId_, debuggerPostTask);
117
118 debugMode_ = true;
119 }
120
RunScript(const std::string & srcPath,const std::string & hapPath,bool useCommonChunk)121 bool RunScript(const std::string& srcPath, const std::string& hapPath, bool useCommonChunk) override
122 {
123 std::string commonsPath = std::string(Constants::LOCAL_CODE_PATH) + "/" + moduleName_ + "/ets/commons.abc";
124 std::string vendorsPath = std::string(Constants::LOCAL_CODE_PATH) + "/" + moduleName_ + "/ets/vendors.abc";
125
126 if (hapPath.empty()) {
127 if (useCommonChunk) {
128 (void)nativeEngine_->RunScriptPath(commonsPath.c_str());
129 (void)nativeEngine_->RunScriptPath(vendorsPath.c_str());
130 }
131 return nativeEngine_->RunScriptPath(srcPath.c_str()) != nullptr;
132 }
133
134 std::shared_ptr<RuntimeExtractor> runtimeExtractor;
135 if (runtimeExtractorMap_.find(hapPath) == runtimeExtractorMap_.end()) {
136 runtimeExtractor = RuntimeExtractor::Create(hapPath);
137 if (runtimeExtractor == nullptr) {
138 return false;
139 }
140 runtimeExtractor->SetRuntimeFlag(true);
141 runtimeExtractorMap_.insert(make_pair(hapPath, runtimeExtractor));
142 panda::JSNApi::LoadAotFile(vm_, hapPath);
143 } else {
144 runtimeExtractor = runtimeExtractorMap_.at(hapPath);
145 }
146
147 auto func = [&](std::string modulePath, const std::string abcPath) {
148 std::ostringstream outStream;
149 if (!runtimeExtractor->GetFileBuffer(modulePath, outStream)) {
150 HILOG_ERROR("Get Module abc file failed");
151 return false;
152 }
153
154 const auto& outStr = outStream.str();
155 std::vector<uint8_t> buffer;
156 buffer.assign(outStr.begin(), outStr.end());
157
158 return nativeEngine_->RunScriptBuffer(abcPath.c_str(), buffer, isBundle_) != nullptr;
159 };
160
161 if (useCommonChunk) {
162 (void)func(commonsPath, commonsPath);
163 (void)func(vendorsPath, vendorsPath);
164 }
165
166 std::string path = srcPath;
167 if (!isBundle_) {
168 if (!vm_ || moduleName_.empty()) {
169 HILOG_ERROR("vm is nullptr or moduleName is hole");
170 return false;
171 }
172 path = BUNDLE_INSTALL_PATH + moduleName_ + MERGE_ABC_PATH;
173 panda::JSNApi::SetAssetPath(vm_, path);
174 panda::JSNApi::SetModuleName(vm_, moduleName_);
175 }
176 return func(path, srcPath);
177 }
178
LoadJsModule(const std::string & path,const std::string & hapPath)179 NativeValue* LoadJsModule(const std::string& path, const std::string& hapPath) override
180 {
181 if (!RunScript(path, hapPath, false)) {
182 HILOG_ERROR("Failed to run script: %{private}s", path.c_str());
183 return nullptr;
184 }
185
186 panda::Local<panda::ObjectRef> exportObj = panda::JSNApi::GetExportObject(vm_, path, "default");
187 if (exportObj->IsNull()) {
188 HILOG_ERROR("Get export object failed");
189 return nullptr;
190 }
191
192 return ArkNativeEngine::ArkValueToNativeValue(
193 static_cast<ArkNativeEngine*>(nativeEngine_.get()), exportObj);
194 }
195
LoadRepairPatch(const std::string & hqfFile,const std::string & hapPath)196 bool LoadRepairPatch(const std::string& hqfFile, const std::string& hapPath) override
197 {
198 HILOG_DEBUG("LoadRepairPatch function called.");
199 if (vm_ == nullptr) {
200 HILOG_ERROR("LoadRepairPatch, vm is nullptr.");
201 return false;
202 }
203
204 AbilityRuntime::RuntimeExtractor extractor(hqfFile);
205 if (!extractor.Init()) {
206 HILOG_ERROR("LoadRepairPatch, Extractor of %{private}s init failed.", hqfFile.c_str());
207 return false;
208 }
209
210 std::vector<std::string> fileNames;
211 extractor.GetSpecifiedTypeFiles(fileNames, ".abc");
212 if (fileNames.empty()) {
213 HILOG_WARN("LoadRepairPatch, There's no abc file in hqf %{private}s.", hqfFile.c_str());
214 return true;
215 }
216
217 for (const auto &fileName : fileNames) {
218 std::string patchFile = hqfFile + "/" + fileName;
219 std::string baseFile = hapPath + "/" + fileName;
220 std::ostringstream outStream;
221 if (!extractor.ExtractByName(fileName, outStream)) {
222 HILOG_ERROR("LoadRepairPatch, Extract %{public}s failed.", patchFile.c_str());
223 return false;
224 }
225
226 const auto &outStr = outStream.str();
227 std::vector<uint8_t> buffer;
228 buffer.assign(outStr.begin(), outStr.end());
229 HILOG_DEBUG("LoadRepairPatch, LoadPatch, patchFile: %{private}s, baseFile: %{private}s.",
230 patchFile.c_str(), baseFile.c_str());
231 bool ret = panda::JSNApi::LoadPatch(vm_, patchFile, buffer.data(), buffer.size(), baseFile);
232 if (!ret) {
233 HILOG_ERROR("LoadRepairPatch, LoadPatch failed.");
234 return false;
235 }
236 HILOG_DEBUG("LoadRepairPatch, Load patch %{private}s succeed.", patchFile.c_str());
237 }
238
239 return true;
240 }
241
UnLoadRepairPatch(const std::string & hqfFile)242 bool UnLoadRepairPatch(const std::string& hqfFile) override
243 {
244 HILOG_DEBUG("UnLoadRepairPatch function called.");
245 if (vm_ == nullptr) {
246 HILOG_ERROR("UnLoadRepairPatch vm is nullptr.");
247 return false;
248 }
249
250 AbilityRuntime::RuntimeExtractor extractor(hqfFile);
251 if (!extractor.Init()) {
252 HILOG_ERROR("UnLoadRepairPatch, Extractor of %{private}s init failed.", hqfFile.c_str());
253 return false;
254 }
255
256 std::vector<std::string> fileNames;
257 extractor.GetSpecifiedTypeFiles(fileNames, ".abc");
258 if (fileNames.empty()) {
259 HILOG_WARN("UnLoadRepairPatch, There's no abc file in hqf %{private}s.", hqfFile.c_str());
260 return true;
261 }
262
263 for (const auto &fileName : fileNames) {
264 std::string patchFile = hqfFile + "/" + fileName;
265 HILOG_DEBUG("UnLoadRepairPatch, UnloadPatch, patchFile: %{private}s.", patchFile.c_str());
266 bool ret = panda::JSNApi::UnloadPatch(vm_, patchFile);
267 if (!ret) {
268 HILOG_ERROR("UnLoadRepairPatch, UnLoadPatch failed.");
269 return false;
270 }
271 HILOG_DEBUG("UnLoadRepairPatch, UnLoad patch %{private}s succeed.", patchFile.c_str());
272 }
273
274 return true;
275 }
276
NotifyHotReloadPage()277 bool NotifyHotReloadPage() override
278 {
279 HILOG_DEBUG("function called.");
280 Ace::HotReloader::HotReload();
281 return true;
282 }
283
UpdateModuleNameAndAssetPath(const std::string & moduleName)284 void UpdateModuleNameAndAssetPath(const std::string& moduleName) override
285 {
286 if (isBundle_) {
287 return;
288 }
289
290 if (!vm_ || moduleName.empty()) {
291 HILOG_ERROR("vm is nullptr or moduleName is empty");
292 return;
293 }
294
295 moduleName_ = moduleName;
296 std::string path = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_PATH;
297 panda::JSNApi::SetAssetPath(vm_, path);
298 panda::JSNApi::SetModuleName(vm_, moduleName_);
299 }
300
301 private:
PrintVmLog(int32_t,int32_t,const char *,const char *,const char * message)302 static int32_t PrintVmLog(int32_t, int32_t, const char*, const char*, const char* message)
303 {
304 HILOG_INFO("ArkLog: %{public}s", message);
305 return 0;
306 }
307
FinishPreload()308 void FinishPreload() override
309 {
310 panda::JSNApi::PreFork(vm_);
311 }
312
Initialize(const Runtime::Options & options)313 bool Initialize(const Runtime::Options& options) override
314 {
315 if (preloaded_) {
316 panda::RuntimeOption postOption;
317 postOption.SetBundleName(options.bundleName);
318 if (!options.arkNativeFilePath.empty()) {
319 std::string sandBoxAnFilePath = SANDBOX_ARK_CACHE_PATH + options.arkNativeFilePath;
320 postOption.SetAnDir(sandBoxAnFilePath);
321 }
322 bool profileEnabled = OHOS::system::GetBoolParameter("ark.profile", false);
323 postOption.SetEnableProfile(profileEnabled);
324 panda::JSNApi::PostFork(vm_, postOption);
325 nativeEngine_->ReinitUVLoop();
326 panda::JSNApi::SetLoop(vm_, nativeEngine_->GetUVLoop());
327 } else {
328 panda::RuntimeOption pandaOption;
329 int arkProperties = OHOS::system::GetIntParameter<int>("persist.ark.properties", -1);
330 std::string bundleName = OHOS::system::GetParameter("persist.ark.arkbundlename", "");
331 size_t gcThreadNum = OHOS::system::GetUintParameter<size_t>("persist.ark.gcthreads", 7);
332 size_t longPauseTime = OHOS::system::GetUintParameter<size_t>("persist.ark.longpausetime", 40);
333 pandaOption.SetArkProperties(arkProperties);
334 pandaOption.SetArkBundleName(bundleName);
335 pandaOption.SetGcThreadNum(gcThreadNum);
336 pandaOption.SetLongPauseTime(longPauseTime);
337 HILOG_INFO("ArkJSRuntime::Initialize ark properties = %{public}d bundlename = %{public}s",
338 arkProperties, bundleName.c_str());
339 pandaOption.SetGcType(panda::RuntimeOption::GC_TYPE::GEN_GC);
340 pandaOption.SetGcPoolSize(DEFAULT_GC_POOL_SIZE);
341 pandaOption.SetLogLevel(panda::RuntimeOption::LOG_LEVEL::INFO);
342 pandaOption.SetLogBufPrint(PrintVmLog);
343
344 bool asmInterpreterEnabled = OHOS::system::GetBoolParameter("persist.ark.asminterpreter", true);
345 std::string asmOpcodeDisableRange = OHOS::system::GetParameter("persist.ark.asmopcodedisablerange", "");
346 pandaOption.SetEnableAsmInterpreter(asmInterpreterEnabled);
347 pandaOption.SetAsmOpcodeDisableRange(asmOpcodeDisableRange);
348
349 // aot related
350 bool aotEnabled = OHOS::system::GetBoolParameter("persist.ark.aot", true);
351 pandaOption.SetEnableAOT(aotEnabled);
352 pandaOption.SetProfileDir(SANDBOX_ARK_PROIFILE_PATH);
353 HILOG_DEBUG("JSRuntime::Initialize ArkNative file path = %{public}s", options.arkNativeFilePath.c_str());
354 vm_ = panda::JSNApi::CreateJSVM(pandaOption);
355 if (vm_ == nullptr) {
356 return false;
357 }
358
359 nativeEngine_ = std::make_unique<ArkNativeEngine>(vm_, static_cast<JsRuntime*>(this));
360 }
361
362 if (!options.preload) {
363 bundleName_ = options.bundleName;
364 std::shared_ptr<RuntimeExtractor> runtimeExtractor = RuntimeExtractor::Create(options.hapPath);
365 if (runtimeExtractor == nullptr) {
366 return false;
367 }
368 runtimeExtractor->SetRuntimeFlag(true);
369 runtimeExtractorMap_.insert(make_pair(options.hapPath, runtimeExtractor));
370 panda::JSNApi::SetHostResolveBufferTracker(
371 vm_, JsModuleReader(options.bundleName, options.hapPath, runtimeExtractor));
372 panda::JSNApi::LoadAotFile(vm_, options.hapPath);
373 }
374 isBundle_ = options.isBundle;
375 panda::JSNApi::SetBundle(vm_, options.isBundle);
376 panda::JSNApi::SetBundleName(vm_, options.bundleName);
377 return JsRuntime::Initialize(options);
378 }
379
380 std::string bundleName_;
381 panda::ecmascript::EcmaVM* vm_ = nullptr;
382 uint32_t instanceId_ = 0;
383
384 static std::atomic<bool> hasInstance;
385 };
386
387 std::atomic<bool> ArkJsRuntime::hasInstance(false);
388
CanIUse(NativeEngine * engine,NativeCallbackInfo * info)389 NativeValue* CanIUse(NativeEngine* engine, NativeCallbackInfo* info)
390 {
391 if (engine == nullptr || info == nullptr) {
392 HILOG_ERROR("get syscap failed since engine or callback info is nullptr.");
393 return nullptr;
394 }
395
396 if (info->argc != 1 || info->argv[0]->TypeOf() != NATIVE_STRING) {
397 HILOG_ERROR("Get syscap failed with invalid parameter.");
398 return engine->CreateUndefined();
399 }
400
401 char syscap[SYSCAP_MAX_SIZE] = { 0 };
402
403 NativeString* str = ConvertNativeValueTo<NativeString>(info->argv[0]);
404 if (str == nullptr) {
405 HILOG_ERROR("Convert to NativeString failed.");
406 return engine->CreateUndefined();
407 }
408 size_t bufferLen = str->GetLength();
409 size_t strLen = 0;
410 str->GetCString(syscap, bufferLen + 1, &strLen);
411
412 bool ret = HasSystemCapability(syscap);
413 return engine->CreateBoolean(ret);
414 }
415
InitSyscapModule(NativeEngine & engine,NativeObject & globalObject)416 void InitSyscapModule(NativeEngine& engine, NativeObject& globalObject)
417 {
418 const char *moduleName = "JsRuntime";
419 BindNativeFunction(engine, globalObject, "canIUse", moduleName, CanIUse);
420 }
421
422 class UvLoopHandler : public AppExecFwk::FileDescriptorListener, public std::enable_shared_from_this<UvLoopHandler> {
423 public:
UvLoopHandler(uv_loop_t * uvLoop)424 explicit UvLoopHandler(uv_loop_t* uvLoop) : uvLoop_(uvLoop) {}
425
OnReadable(int32_t)426 void OnReadable(int32_t) override
427 {
428 HILOG_DEBUG("UvLoopHandler::OnReadable is triggered");
429 OnTriggered();
430 }
431
OnWritable(int32_t)432 void OnWritable(int32_t) override
433 {
434 HILOG_DEBUG("UvLoopHandler::OnWritable is triggered");
435 OnTriggered();
436 }
437
438 private:
OnTriggered()439 void OnTriggered()
440 {
441 HILOG_DEBUG("UvLoopHandler::OnTriggered is triggered");
442
443 auto fd = uv_backend_fd(uvLoop_);
444 struct epoll_event ev;
445 do {
446 uv_run(uvLoop_, UV_RUN_NOWAIT);
447 } while (epoll_wait(fd, &ev, 1, 0) > 0);
448
449 auto eventHandler = GetOwner();
450 if (!eventHandler) {
451 return;
452 }
453
454 int32_t timeout = uv_backend_timeout(uvLoop_);
455 if (timeout < 0) {
456 if (haveTimerTask_) {
457 eventHandler->RemoveTask(TIMER_TASK);
458 }
459 return;
460 }
461
462 int64_t timeStamp = static_cast<int64_t>(uv_now(uvLoop_)) + timeout;
463 if (timeStamp == lastTimeStamp_) {
464 return;
465 }
466
467 if (haveTimerTask_) {
468 eventHandler->RemoveTask(TIMER_TASK);
469 }
470
471 auto callback = [wp = weak_from_this()] {
472 auto sp = wp.lock();
473 if (sp) {
474 // Timer task is triggered, so there is no timer task now.
475 sp->haveTimerTask_ = false;
476 sp->OnTriggered();
477 }
478 };
479 eventHandler->PostTask(callback, TIMER_TASK, timeout);
480 lastTimeStamp_ = timeStamp;
481 haveTimerTask_ = true;
482 }
483
484 uv_loop_t* uvLoop_ = nullptr;
485 int64_t lastTimeStamp_ = 0;
486 bool haveTimerTask_ = false;
487 };
488 } // namespace
489
Create(const Runtime::Options & options)490 std::unique_ptr<Runtime> JsRuntime::Create(const Runtime::Options& options)
491 {
492 std::unique_ptr<JsRuntime> instance;
493
494 if (!options.preload) {
495 auto preloadedInstance = Runtime::GetPreloaded();
496 if (preloadedInstance && preloadedInstance->GetLanguage() == Runtime::Language::JS) {
497 instance.reset(static_cast<JsRuntime*>(preloadedInstance.release()));
498 } else {
499 instance = std::make_unique<ArkJsRuntime>();
500 }
501 } else {
502 instance = std::make_unique<ArkJsRuntime>();
503 }
504
505 if (!instance->Initialize(options)) {
506 return std::unique_ptr<Runtime>();
507 }
508 return instance;
509 }
510
LoadSystemModuleByEngine(NativeEngine * engine,const std::string & moduleName,NativeValue * const * argv,size_t argc)511 std::unique_ptr<NativeReference> JsRuntime::LoadSystemModuleByEngine(NativeEngine* engine,
512 const std::string& moduleName, NativeValue* const* argv, size_t argc)
513 {
514 HILOG_DEBUG("JsRuntime::LoadSystemModule(%{public}s)", moduleName.c_str());
515 if (engine == nullptr) {
516 HILOG_INFO("JsRuntime::LoadSystemModule: invalid engine.");
517 return std::unique_ptr<NativeReference>();
518 }
519
520 NativeObject* globalObj = ConvertNativeValueTo<NativeObject>(engine->GetGlobal());
521 std::unique_ptr<NativeReference> methodRequireNapiRef_;
522 methodRequireNapiRef_.reset(engine->CreateReference(globalObj->GetProperty("requireNapi"), 1));
523 if (!methodRequireNapiRef_) {
524 HILOG_ERROR("Failed to create reference for global.requireNapi");
525 return nullptr;
526 }
527 NativeValue* className = engine->CreateString(moduleName.c_str(), moduleName.length());
528 NativeValue* classValue =
529 engine->CallFunction(engine->GetGlobal(), methodRequireNapiRef_->Get(), &className, 1);
530 NativeValue* instanceValue = engine->CreateInstance(classValue, argv, argc);
531 if (instanceValue == nullptr) {
532 HILOG_ERROR("Failed to create object instance");
533 return std::unique_ptr<NativeReference>();
534 }
535
536 return std::unique_ptr<NativeReference>(engine->CreateReference(instanceValue, 1));
537 }
538
DetachCallbackFunc(NativeEngine * engine,void * value,void *)539 void *DetachCallbackFunc(NativeEngine *engine, void *value, void *)
540 {
541 return value;
542 }
543
Initialize(const Options & options)544 bool JsRuntime::Initialize(const Options& options)
545 {
546 HandleScope handleScope(*this);
547
548 NativeObject* globalObj = ConvertNativeValueTo<NativeObject>(nativeEngine_->GetGlobal());
549 if (globalObj == nullptr) {
550 HILOG_ERROR("Failed to get global object");
551 return false;
552 }
553
554 if (!preloaded_) {
555 InitConsoleLogModule(*nativeEngine_, *globalObj);
556 InitSyscapModule(*nativeEngine_, *globalObj);
557
558 // Simple hook function 'isSystemplugin'
559 const char *moduleName = "JsRuntime";
560 BindNativeFunction(*nativeEngine_, *globalObj, "isSystemplugin", moduleName,
561 [](NativeEngine* engine, NativeCallbackInfo* info) -> NativeValue* {
562 return engine->CreateUndefined();
563 });
564
565 methodRequireNapiRef_.reset(nativeEngine_->CreateReference(globalObj->GetProperty("requireNapi"), 1));
566 if (!methodRequireNapiRef_) {
567 HILOG_ERROR("Failed to create reference for global.requireNapi");
568 return false;
569 }
570 #ifdef SUPPORT_GRAPHICS
571 if (options.loadAce) {
572 // ArkTsCard start
573 if (options.isUnique) {
574 OHOS::Ace::DeclarativeModulePreloader::PreloadCard(*nativeEngine_);
575 } else {
576 OHOS::Ace::DeclarativeModulePreloader::Preload(*nativeEngine_);
577 }
578 // ArkTsCard end
579 }
580 #endif
581 }
582
583 if (!options.preload) {
584 // Create event handler for runtime
585 eventHandler_ = std::make_shared<AppExecFwk::EventHandler>(options.eventRunner);
586
587 auto uvLoop = nativeEngine_->GetUVLoop();
588 auto fd = uvLoop != nullptr ? uv_backend_fd(uvLoop) : -1;
589 if (fd < 0) {
590 HILOG_ERROR("Failed to get backend fd from uv loop");
591 return false;
592 }
593
594 // MUST run uv loop once before we listen its backend fd.
595 uv_run(uvLoop, UV_RUN_NOWAIT);
596
597 uint32_t events = AppExecFwk::FILE_DESCRIPTOR_INPUT_EVENT | AppExecFwk::FILE_DESCRIPTOR_OUTPUT_EVENT;
598 eventHandler_->AddFileDescriptorListener(fd, events, std::make_shared<UvLoopHandler>(uvLoop));
599
600 codePath_ = options.codePath;
601 }
602
603 auto moduleManager = NativeModuleManager::GetInstance();
604 if (moduleManager != nullptr) {
605 for (const auto &appLibPath : options.appLibPaths) {
606 moduleManager->SetAppLibPath(appLibPath.first, appLibPath.second);
607 }
608 }
609 bindSourceMaps_ = std::make_unique<ModSourceMap>(options.bundleCodeDir, options.isStageModel);
610 if (!options.preload) {
611 if (options.isUnique) {
612 HILOG_INFO("Not supported TimerModule when form render");
613 } else {
614 InitTimerModule(*nativeEngine_, *globalObj);
615 }
616
617 InitWorkerModule(*nativeEngine_, codePath_, options.isDebugVersion, options.isBundle);
618 }
619
620 preloaded_ = options.preload;
621 return true;
622 }
623
Deinitialize()624 void JsRuntime::Deinitialize()
625 {
626 for (auto it = modules_.begin(); it != modules_.end(); it = modules_.erase(it)) {
627 delete it->second;
628 it->second = nullptr;
629 }
630
631 methodRequireNapiRef_.reset();
632
633 if (nativeEngine_ == nullptr) {
634 return;
635 }
636 auto uvLoop = nativeEngine_->GetUVLoop();
637 auto fd = uvLoop != nullptr ? uv_backend_fd(uvLoop) : -1;
638 if (fd >= 0 && eventHandler_ != nullptr) {
639 eventHandler_->RemoveFileDescriptorListener(fd);
640 }
641 RemoveTask(TIMER_TASK);
642
643 nativeEngine_->DeleteEngine();
644 nativeEngine_.reset();
645 }
646
LoadJsBundle(const std::string & path,const std::string & hapPath,bool useCommonChunk)647 NativeValue* JsRuntime::LoadJsBundle(const std::string& path, const std::string& hapPath, bool useCommonChunk)
648 {
649 NativeObject* globalObj = ConvertNativeValueTo<NativeObject>(nativeEngine_->GetGlobal());
650 NativeValue* exports = nativeEngine_->CreateObject();
651 globalObj->SetProperty("exports", exports);
652
653 if (!RunScript(path, hapPath, useCommonChunk)) {
654 HILOG_ERROR("Failed to run script: %{private}s", path.c_str());
655 return nullptr;
656 }
657
658 NativeObject* exportsObj = ConvertNativeValueTo<NativeObject>(globalObj->GetProperty("exports"));
659 if (exportsObj == nullptr) {
660 HILOG_ERROR("Failed to get exports objcect: %{private}s", path.c_str());
661 return nullptr;
662 }
663
664 NativeValue* exportObj = exportsObj->GetProperty("default");
665 if (exportObj == nullptr) {
666 HILOG_ERROR("Failed to get default objcect: %{private}s", path.c_str());
667 return nullptr;
668 }
669
670 return exportObj;
671 }
672
LoadModule(const std::string & moduleName,const std::string & modulePath,const std::string & hapPath,bool esmodule,bool useCommonChunk)673 std::unique_ptr<NativeReference> JsRuntime::LoadModule(const std::string& moduleName, const std::string& modulePath,
674 const std::string& hapPath, bool esmodule, bool useCommonChunk)
675 {
676 HILOG_DEBUG("JsRuntime::LoadModule(%{public}s, %{private}s, %{private}s, %{public}s)",
677 moduleName.c_str(), modulePath.c_str(), hapPath.c_str(), esmodule ? "true" : "false");
678 HandleScope handleScope(*this);
679
680 std::string path = moduleName;
681 auto pos = path.find("::");
682 if (pos != std::string::npos) {
683 path.erase(pos, path.size() - pos);
684 moduleName_ = path;
685 }
686
687 NativeValue* classValue = nullptr;
688
689 auto it = modules_.find(modulePath);
690 if (it != modules_.end()) {
691 classValue = it->second->Get();
692 } else {
693 std::string fileName;
694 if (!hapPath.empty()) {
695 fileName.append(codePath_).append(Constants::FILE_SEPARATOR).append(modulePath);
696 std::regex pattern(std::string(Constants::FILE_DOT) + std::string(Constants::FILE_SEPARATOR));
697 fileName = std::regex_replace(fileName, pattern, "");
698 } else {
699 if (!MakeFilePath(codePath_, modulePath, fileName)) {
700 HILOG_ERROR("Failed to make module file path: %{private}s", modulePath.c_str());
701 return std::unique_ptr<NativeReference>();
702 }
703 }
704 HILOG_ERROR("Failed to make module file path: %{public}s", fileName.c_str());
705 classValue = esmodule ? LoadJsModule(fileName, hapPath) : LoadJsBundle(fileName, hapPath, useCommonChunk);
706 if (classValue == nullptr) {
707 return std::unique_ptr<NativeReference>();
708 }
709
710 modules_.emplace(modulePath, nativeEngine_->CreateReference(classValue, 1));
711 }
712
713 NativeValue* instanceValue = nativeEngine_->CreateInstance(classValue, nullptr, 0);
714 if (instanceValue == nullptr) {
715 HILOG_ERROR("Failed to create object instance");
716 return std::unique_ptr<NativeReference>();
717 }
718
719 return std::unique_ptr<NativeReference>(nativeEngine_->CreateReference(instanceValue, 1));
720 }
721
LoadSystemModule(const std::string & moduleName,NativeValue * const * argv,size_t argc)722 std::unique_ptr<NativeReference> JsRuntime::LoadSystemModule(
723 const std::string& moduleName, NativeValue* const* argv, size_t argc)
724 {
725 HILOG_INFO("JsRuntime::LoadSystemModule(%{public}s)", moduleName.c_str());
726
727 HandleScope handleScope(*this);
728
729 NativeValue* className = nativeEngine_->CreateString(moduleName.c_str(), moduleName.length());
730 NativeValue* classValue =
731 nativeEngine_->CallFunction(nativeEngine_->GetGlobal(), methodRequireNapiRef_->Get(), &className, 1);
732 NativeValue* instanceValue = nativeEngine_->CreateInstance(classValue, argv, argc);
733 if (instanceValue == nullptr) {
734 HILOG_ERROR("Failed to create object instance");
735 return std::unique_ptr<NativeReference>();
736 }
737
738 return std::unique_ptr<NativeReference>(nativeEngine_->CreateReference(instanceValue, 1));
739 }
740
RunScript(const std::string & srcPath,const std::string & hapPath,bool useCommonChunk)741 bool JsRuntime::RunScript(const std::string& srcPath, const std::string& hapPath, bool useCommonChunk)
742 {
743 bool result = false;
744 if (!hapPath.empty()) {
745 std::ostringstream outStream;
746 std::shared_ptr<RuntimeExtractor> runtimeExtractor;
747 if (runtimeExtractorMap_.find(hapPath) == runtimeExtractorMap_.end()) {
748 runtimeExtractor = RuntimeExtractor::Create(hapPath);
749 if (runtimeExtractor == nullptr) {
750 return result;
751 }
752 runtimeExtractor->SetRuntimeFlag(true);
753 runtimeExtractorMap_.insert(make_pair(hapPath, runtimeExtractor));
754 } else {
755 runtimeExtractor = runtimeExtractorMap_.at(hapPath);
756 }
757 if (isBundle_) {
758 if (!runtimeExtractor->GetFileBuffer(srcPath, outStream)) {
759 HILOG_ERROR("Get abc file failed");
760 return result;
761 }
762 } else {
763 std::string mergeAbcPath = BUNDLE_INSTALL_PATH + moduleName_ + MERGE_ABC_PATH;
764 if (!runtimeExtractor->GetFileBuffer(mergeAbcPath, outStream)) {
765 HILOG_ERROR("Get Module abc file failed");
766 return result;
767 }
768 }
769
770 const auto& outStr = outStream.str();
771 std::vector<uint8_t> buffer;
772 buffer.assign(outStr.begin(), outStr.end());
773
774 result = nativeEngine_->RunScriptBuffer(srcPath.c_str(), buffer, isBundle_) != nullptr;
775 } else {
776 result = nativeEngine_->RunScript(srcPath.c_str()) != nullptr;
777 }
778 return result;
779 }
780
RunSandboxScript(const std::string & path,const std::string & hapPath)781 bool JsRuntime::RunSandboxScript(const std::string& path, const std::string& hapPath)
782 {
783 std::string fileName;
784 if (!MakeFilePath(codePath_, path, fileName)) {
785 HILOG_ERROR("Failed to make module file path: %{private}s", path.c_str());
786 return false;
787 }
788
789 if (!RunScript(fileName, hapPath)) {
790 HILOG_ERROR("Failed to run script: %{public}s", fileName.c_str());
791 return false;
792 }
793 return true;
794 }
795
PostTask(const std::function<void ()> & task,const std::string & name,int64_t delayTime)796 void JsRuntime::PostTask(const std::function<void()>& task, const std::string& name, int64_t delayTime)
797 {
798 if (eventHandler_ != nullptr) {
799 eventHandler_->PostTask(task, name, delayTime);
800 }
801 }
802
RemoveTask(const std::string & name)803 void JsRuntime::RemoveTask(const std::string& name)
804 {
805 if (eventHandler_ != nullptr) {
806 eventHandler_->RemoveTask(name);
807 }
808 }
809
DumpHeapSnapshot(bool isPrivate)810 void JsRuntime::DumpHeapSnapshot(bool isPrivate)
811 {
812 nativeEngine_->DumpHeapSnapshot(true, DumpFormat::JSON, isPrivate);
813 }
814
BuildJsStackInfoList(uint32_t tid,std::vector<JsFrames> & jsFrames)815 bool JsRuntime::BuildJsStackInfoList(uint32_t tid, std::vector<JsFrames>& jsFrames)
816 {
817 std::vector<JsFrameInfo> jsFrameInfo;
818 bool ret = nativeEngine_->BuildJsStackInfoList(tid, jsFrameInfo);
819 if (!ret) {
820 return ret;
821 }
822 for (auto jf : jsFrameInfo) {
823 struct JsFrames jsFrame;
824 jsFrame.functionName = jf.functionName;
825 jsFrame.fileName = jf.fileName;
826 jsFrame.pos = jf.pos;
827 jsFrame.nativePointer = jf.nativePointer;
828 jsFrames.emplace_back(jsFrame);
829 }
830 return ret;
831 }
832
NotifyApplicationState(bool isBackground)833 void JsRuntime::NotifyApplicationState(bool isBackground)
834 {
835 if (nativeEngine_ == nullptr) {
836 HILOG_INFO("NotifyApplicationState, nativeEngine_ is nullptr");
837 return;
838 }
839 nativeEngine_->NotifyApplicationState(isBackground);
840 HILOG_INFO("NotifyApplicationState, isBackground %{public}d.", isBackground);
841 }
842
PreloadSystemModule(const std::string & moduleName)843 void JsRuntime::PreloadSystemModule(const std::string& moduleName)
844 {
845 HandleScope handleScope(*this);
846
847 NativeValue* className = nativeEngine_->CreateString(moduleName.c_str(), moduleName.length());
848 nativeEngine_->CallFunction(nativeEngine_->GetGlobal(), methodRequireNapiRef_->Get(), &className, 1);
849 }
850
UpdateExtensionType(int32_t extensionType)851 void JsRuntime::UpdateExtensionType(int32_t extensionType)
852 {
853 if (nativeEngine_ == nullptr) {
854 HILOG_ERROR("UpdateExtensionType error, nativeEngine_ is nullptr");
855 return;
856 }
857 NativeModuleManager* moduleManager = nativeEngine_->GetModuleManager();
858 if (moduleManager == nullptr) {
859 HILOG_ERROR("UpdateExtensionType error, moduleManager is nullptr");
860 return;
861 }
862 moduleManager->SetProcessExtensionType(extensionType);
863 }
864
FreeNativeReference(std::unique_ptr<NativeReference> reference)865 void JsRuntime::FreeNativeReference(std::unique_ptr<NativeReference> reference)
866 {
867 FreeNativeReference(std::move(reference), nullptr);
868 }
869
FreeNativeReference(std::shared_ptr<NativeReference> && reference)870 void JsRuntime::FreeNativeReference(std::shared_ptr<NativeReference>&& reference)
871 {
872 FreeNativeReference(nullptr, std::move(reference));
873 }
874
875 struct JsNativeReferenceDeleterObject {
876 std::unique_ptr<NativeReference> uniqueNativeRef_ = nullptr;
877 std::shared_ptr<NativeReference> sharedNativeRef_ = nullptr;
878 };
879
FreeNativeReference(std::unique_ptr<NativeReference> uniqueNativeRef,std::shared_ptr<NativeReference> && sharedNativeRef)880 void JsRuntime::FreeNativeReference(std::unique_ptr<NativeReference> uniqueNativeRef,
881 std::shared_ptr<NativeReference>&& sharedNativeRef)
882 {
883 if (uniqueNativeRef == nullptr && sharedNativeRef == nullptr) {
884 HILOG_WARN("native reference is invalid.");
885 return;
886 }
887
888 auto& nativeEngine = GetNativeEngine();
889 auto uvLoop = nativeEngine.GetUVLoop();
890 if (uvLoop == nullptr) {
891 HILOG_ERROR("uvloop is invalid.");
892 return;
893 }
894
895 auto work = new (std::nothrow) uv_work_t;
896 if (work == nullptr) {
897 HILOG_ERROR("new uv work failed.");
898 return;
899 }
900
901 auto cb = new (std::nothrow) JsNativeReferenceDeleterObject();
902 if (cb == nullptr) {
903 HILOG_ERROR("new deleter object failed.");
904 delete work;
905 work = nullptr;
906 return;
907 }
908
909 if (uniqueNativeRef != nullptr) {
910 cb->uniqueNativeRef_ = std::move(uniqueNativeRef);
911 }
912 if (sharedNativeRef != nullptr) {
913 cb->sharedNativeRef_ = std::move(sharedNativeRef);
914 }
915 work->data = reinterpret_cast<void*>(cb);
916 int ret = uv_queue_work(uvLoop, work, [](uv_work_t *work) {},
917 [](uv_work_t *work, int status) {
918 if (work != nullptr) {
919 if (work->data != nullptr) {
920 delete reinterpret_cast<JsNativeReferenceDeleterObject*>(work->data);
921 work->data = nullptr;
922 }
923 delete work;
924 work = nullptr;
925 }
926 });
927 if (ret != 0) {
928 delete reinterpret_cast<JsNativeReferenceDeleterObject*>(work->data);
929 work->data = nullptr;
930 delete work;
931 work = nullptr;
932 }
933 }
934 } // namespace AbilityRuntime
935 } // namespace OHOS
936