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