1/*
2 * Copyright (c) 2021-2024 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 <fstream>
22#include <mutex>
23#include <regex>
24
25#include <atomic>
26#include <sys/epoll.h>
27#include <unistd.h>
28
29#include "file_ex.h"
30#include "accesstoken_kit.h"
31#include "config_policy_utils.h"
32#include "constants.h"
33#include "connect_server_manager.h"
34#include "ecmascript/napi/include/jsnapi.h"
35#include "extract_resource_manager.h"
36#include "file_mapper.h"
37#include "file_path_utils.h"
38#include "hdc_register.h"
39#include "hilog_tag_wrapper.h"
40#include "hitrace_meter.h"
41#include "ipc_skeleton.h"
42#include "iservice_registry.h"
43#include "js_environment.h"
44#include "js_module_reader.h"
45#include "js_module_searcher.h"
46#include "js_quickfix_callback.h"
47#include "js_runtime_utils.h"
48#include "js_utils.h"
49#include "js_worker.h"
50#include "module_checker_delegate.h"
51#include "napi/native_api.h"
52#include "native_engine/impl/ark/ark_native_engine.h"
53#include "native_engine/native_create_env.h"
54#include "native_engine/native_engine.h"
55#include "js_runtime_lite.h"
56#include "ohos_js_env_logger.h"
57#include "ohos_js_environment_impl.h"
58#include "parameters.h"
59#include "extractor.h"
60#include "system_ability_definition.h"
61#include "source_map.h"
62#include "source_map_operator.h"
63
64#ifdef SUPPORT_SCREEN
65#include "hot_reloader.h"
66#include "ace_forward_compatibility.h"
67#include "declarative_module_preloader.h"
68#endif //SUPPORT_SCREEN
69
70#include "syscap_ts.h"
71
72using namespace OHOS::AbilityBase;
73using Extractor = OHOS::AbilityBase::Extractor;
74
75namespace OHOS {
76namespace AbilityRuntime {
77namespace {
78constexpr size_t PARAM_TWO = 2;
79constexpr uint8_t SYSCAP_MAX_SIZE = 100;
80constexpr int64_t DEFAULT_GC_POOL_SIZE = 0x10000000; // 256MB
81constexpr int32_t DEFAULT_INTER_VAL = 500;
82constexpr int32_t API8 = 8;
83const std::string SANDBOX_ARK_CACHE_PATH = "/data/storage/ark-cache/";
84const std::string SANDBOX_ARK_PROIFILE_PATH = "/data/storage/ark-profile";
85const std::string DEBUGGER = "@Debugger";
86
87constexpr char MERGE_ABC_PATH[] = "/ets/modules.abc";
88constexpr char BUNDLE_INSTALL_PATH[] = "/data/storage/el1/bundle/";
89constexpr const char* PERMISSION_RUN_ANY_CODE = "ohos.permission.RUN_ANY_CODE";
90
91const std::string CONFIG_PATH = "/etc/system_kits_config.json";
92const std::string SYSTEM_KITS_CONFIG_PATH = "/system/etc/system_kits_config.json";
93
94const std::string SYSTEM_KITS = "systemkits";
95const std::string NAMESPACE = "namespace";
96const std::string TARGET_OHM = "targetohm";
97const std::string SINCE_VERSION = "sinceVersion";
98
99constexpr char DEVELOPER_MODE_STATE[] = "const.security.developermode.state";
100static auto PermissionCheckFunc = []() {
101    Security::AccessToken::AccessTokenID callerToken = IPCSkeleton::GetCallingTokenID();
102
103    int result = Security::AccessToken::AccessTokenKit::VerifyAccessToken(callerToken, PERMISSION_RUN_ANY_CODE);
104    if (result == Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
105        return true;
106    } else {
107        return false;
108    }
109};
110
111int32_t PrintVmLog(int32_t, int32_t, const char*, const char*, const char* message)
112{
113    TAG_LOGI(AAFwkTag::JSRUNTIME, "ArkLog: %{public}s", message);
114    return 0;
115}
116} // namespace
117
118std::atomic<bool> JsRuntime::hasInstance(false);
119JsRuntime::JsRuntime()
120{
121    TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
122}
123
124JsRuntime::~JsRuntime()
125{
126    TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
127    Deinitialize();
128    StopDebugMode();
129}
130
131std::unique_ptr<JsRuntime> JsRuntime::Create(const Options& options)
132{
133    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
134    std::unique_ptr<JsRuntime> instance;
135    JsRuntimeLite::InitJsRuntimeLite(options);
136    if (!options.preload && options.isStageModel) {
137        auto preloadedInstance = Runtime::GetPreloaded();
138#ifdef SUPPORT_SCREEN
139        // reload ace if compatible mode changes
140        if (Ace::AceForwardCompatibility::PipelineChanged() && preloadedInstance) {
141            preloadedInstance.reset();
142        }
143#endif
144        if (preloadedInstance && preloadedInstance->GetLanguage() == Runtime::Language::JS) {
145            instance.reset(static_cast<JsRuntime*>(preloadedInstance.release()));
146        } else {
147            instance = std::make_unique<JsRuntime>();
148        }
149    } else {
150        instance = std::make_unique<JsRuntime>();
151    }
152
153    if (!instance->Initialize(options)) {
154        return std::unique_ptr<JsRuntime>();
155    }
156    return instance;
157}
158
159void JsRuntime::StartDebugMode(const DebugOption dOption)
160{
161    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
162    if (!system::GetBoolParameter(DEVELOPER_MODE_STATE, false)) {
163        TAG_LOGE(AAFwkTag::JSRUNTIME, "Developer Mode is false.");
164        return;
165    }
166    CHECK_POINTER(jsEnv_);
167    if (jsEnv_->GetDebugMode()) {
168        TAG_LOGI(AAFwkTag::JSRUNTIME, "debugMode");
169        return;
170    }
171    // Set instance id to tid after the first instance.
172    if (JsRuntime::hasInstance.exchange(true, std::memory_order_relaxed)) {
173        instanceId_ = static_cast<uint32_t>(getproctid());
174    }
175
176    bool isStartWithDebug = dOption.isStartWithDebug;
177    bool isDebugApp = dOption.isDebugApp;
178    TAG_LOGD(AAFwkTag::JSRUNTIME, "Ark VM is starting debug mode [%{public}s]", isStartWithDebug ? "break" : "normal");
179    StartDebuggerInWorkerModule(isDebugApp, dOption.isStartWithNative);
180    const std::string bundleName = bundleName_;
181    uint32_t instanceId = instanceId_;
182    auto weak = jsEnv_;
183    std::string inputProcessName = bundleName_ != dOption.processName ? dOption.processName : "";
184    HdcRegister::Get().StartHdcRegister(bundleName_, inputProcessName, isDebugApp, [bundleName,
185            isStartWithDebug, instanceId, weak, isDebugApp] (int socketFd, std::string option) {
186            TAG_LOGI(AAFwkTag::JSRUNTIME, "HdcRegister msg, fd= %{public}d, option= %{public}s",
187                socketFd, option.c_str());
188        if (weak == nullptr) {
189                TAG_LOGE(AAFwkTag::JSRUNTIME, "null weak");
190            return;
191        }
192        if (option.find(DEBUGGER) == std::string::npos) {
193            if (isDebugApp) {
194                ConnectServerManager::Get().StopConnectServer(false);
195            }
196            ConnectServerManager::Get().SendDebuggerInfo(isStartWithDebug, isDebugApp);
197            ConnectServerManager::Get().StartConnectServer(bundleName, socketFd, false);
198        } else {
199            if (isDebugApp) {
200                weak->StopDebugger(option);
201            }
202            weak->StartDebugger(option, socketFd, isDebugApp);
203        }
204    });
205    if (isDebugApp) {
206        ConnectServerManager::Get().StartConnectServer(bundleName_, -1, true);
207    }
208
209    DebuggerConnectionHandler(isDebugApp, isStartWithDebug);
210}
211
212void JsRuntime::DebuggerConnectionHandler(bool isDebugApp, bool isStartWithDebug)
213{
214    ConnectServerManager::Get().StoreInstanceMessage(getproctid(), instanceId_);
215    EcmaVM* vm = GetEcmaVm();
216    auto dTask = jsEnv_->GetDebuggerPostTask();
217    panda::JSNApi::DebugOption option = {ARK_DEBUGGER_LIB_PATH, isDebugApp ? isStartWithDebug : false};
218    ConnectServerManager::Get().StoreDebuggerInfo(getproctid(), reinterpret_cast<void*>(vm), option, dTask, isDebugApp);
219    jsEnv_->NotifyDebugMode(getproctid(), ARK_DEBUGGER_LIB_PATH, instanceId_, isDebugApp, isStartWithDebug);
220}
221
222void JsRuntime::StopDebugMode()
223{
224    CHECK_POINTER(jsEnv_);
225    if (jsEnv_->GetDebugMode()) {
226        ConnectServerManager::Get().RemoveInstance(instanceId_);
227        StopDebugger();
228    }
229}
230
231void JsRuntime::InitConsoleModule()
232{
233    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
234    CHECK_POINTER(jsEnv_);
235    jsEnv_->InitConsoleModule();
236}
237
238bool JsRuntime::StartDebugger(bool needBreakPoint, uint32_t instanceId)
239{
240    TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
241    return true;
242}
243
244void JsRuntime::StopDebugger()
245{
246    CHECK_POINTER(jsEnv_);
247    jsEnv_->StopDebugger();
248}
249
250int32_t JsRuntime::JsperfProfilerCommandParse(const std::string &command, int32_t defaultValue)
251{
252    TAG_LOGD(AAFwkTag::JSRUNTIME, "profiler command parse %{public}s", command.c_str());
253    auto findPos = command.find("jsperf");
254    if (findPos == std::string::npos) {
255        // jsperf command not found, so not to do, return zero.
256        TAG_LOGD(AAFwkTag::JSRUNTIME, "jsperf command not found");
257        return 0;
258    }
259
260    // match jsperf command
261    auto jsPerfStr = command.substr(findPos, command.length() - findPos);
262    const std::regex regexJsperf(R"(^jsperf($|\s+($|\d*\s*($|nativeperf.*))))");
263    std::match_results<std::string::const_iterator> matchResults;
264    if (!std::regex_match(jsPerfStr, matchResults, regexJsperf)) {
265        TAG_LOGD(AAFwkTag::JSRUNTIME, "the order not match");
266        return defaultValue;
267    }
268
269    // get match resuflt
270    std::string jsperfResuflt;
271    constexpr size_t matchResultIndex = 1;
272    if (matchResults.size() < PARAM_TWO) {
273        TAG_LOGE(AAFwkTag::JSRUNTIME, "no results need to be matched");
274        return defaultValue;
275    }
276
277    jsperfResuflt = matchResults[matchResultIndex].str();
278    // match number result
279    const std::regex regexJsperfNum(R"(^\s*(\d+).*)");
280    std::match_results<std::string::const_iterator> jsperfMatchResults;
281    if (!std::regex_match(jsperfResuflt, jsperfMatchResults, regexJsperfNum)) {
282        TAG_LOGD(AAFwkTag::JSRUNTIME, "the jsperf results not match");
283        return defaultValue;
284    }
285
286    // get match result
287    std::string interval;
288    constexpr size_t matchNumResultIndex = 1;
289    if (jsperfMatchResults.size() < PARAM_TWO) {
290        TAG_LOGE(AAFwkTag::JSRUNTIME, "jsperfMatchResults not match");
291        return defaultValue;
292    }
293
294    interval = jsperfMatchResults[matchNumResultIndex].str();
295    if (interval.empty()) {
296        TAG_LOGD(AAFwkTag::JSRUNTIME, "empty interval");
297        return defaultValue;
298    }
299
300    return std::stoi(interval);
301}
302
303void JsRuntime::StartProfiler(const DebugOption dOption)
304{
305    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
306    if (!system::GetBoolParameter(DEVELOPER_MODE_STATE, false)) {
307        TAG_LOGE(AAFwkTag::JSRUNTIME, "Developer Mode is false.");
308        return;
309    }
310    CHECK_POINTER(jsEnv_);
311    if (JsRuntime::hasInstance.exchange(true, std::memory_order_relaxed)) {
312        instanceId_ = static_cast<uint32_t>(getproctid());
313    }
314
315    bool isStartWithDebug = dOption.isStartWithDebug;
316    bool isDebugApp = dOption.isDebugApp;
317    StartDebuggerInWorkerModule(isDebugApp, dOption.isStartWithNative);
318    const std::string bundleName = bundleName_;
319    auto weak = jsEnv_;
320    uint32_t instanceId = instanceId_;
321    std::string inputProcessName = bundleName_ != dOption.processName ? dOption.processName : "";
322    HdcRegister::Get().StartHdcRegister(bundleName_, inputProcessName, isDebugApp,
323        [bundleName, isStartWithDebug, instanceId, weak, isDebugApp](int socketFd, std::string option) {
324        TAG_LOGI(AAFwkTag::JSRUNTIME, "HdcRegister msg, fd= %{public}d, option= %{public}s", socketFd, option.c_str());
325        if (weak == nullptr) {
326            TAG_LOGE(AAFwkTag::JSRUNTIME, "null jsEnv");
327            return;
328        }
329        if (option.find(DEBUGGER) == std::string::npos) {
330            if (isDebugApp) {
331                ConnectServerManager::Get().StopConnectServer(false);
332            }
333            ConnectServerManager::Get().SendDebuggerInfo(isStartWithDebug, isDebugApp);
334            ConnectServerManager::Get().StartConnectServer(bundleName, socketFd, false);
335        } else {
336            if (isDebugApp) {
337                weak->StopDebugger(option);
338            }
339            weak->StartDebugger(option, socketFd, isDebugApp);
340        }
341    });
342
343    DebuggerConnectionManager(isDebugApp, isStartWithDebug, dOption);
344}
345
346void JsRuntime::DebuggerConnectionManager(bool isDebugApp, bool isStartWithDebug, const DebugOption dOption)
347{
348    if (isDebugApp) {
349        ConnectServerManager::Get().StartConnectServer(bundleName_, 0, true);
350    }
351    ConnectServerManager::Get().StoreInstanceMessage(getproctid(), instanceId_);
352    JsEnv::JsEnvironment::PROFILERTYPE profiler = JsEnv::JsEnvironment::PROFILERTYPE::PROFILERTYPE_HEAP;
353    int32_t interval = 0;
354    const std::string profilerCommand("profile");
355    if (dOption.perfCmd.find(profilerCommand) != std::string::npos) {
356        profiler = JsEnv::JsEnvironment::PROFILERTYPE::PROFILERTYPE_CPU;
357        interval = JsperfProfilerCommandParse(dOption.perfCmd, DEFAULT_INTER_VAL);
358    }
359    EcmaVM* vm = GetEcmaVm();
360    auto dTask = jsEnv_->GetDebuggerPostTask();
361    panda::JSNApi::DebugOption option = {ARK_DEBUGGER_LIB_PATH, isDebugApp ? isStartWithDebug : false};
362    ConnectServerManager::Get().StoreDebuggerInfo(getproctid(), reinterpret_cast<void*>(vm), option, dTask, isDebugApp);
363    TAG_LOGD(AAFwkTag::JSRUNTIME, "profiler:%{public}d interval:%{public}d", profiler, interval);
364    jsEnv_->StartProfiler(ARK_DEBUGGER_LIB_PATH, instanceId_, profiler, interval, getproctid(), isDebugApp);
365}
366
367bool JsRuntime::GetFileBuffer(const std::string& filePath, std::string& fileFullName, std::vector<uint8_t>& buffer,
368                              bool isABC)
369{
370    Extractor extractor(filePath);
371    if (!extractor.Init()) {
372        TAG_LOGE(AAFwkTag::JSRUNTIME, "Extractor of %{private}s init failed", filePath.c_str());
373        return false;
374    }
375
376    std::vector<std::string> fileNames;
377    if (isABC) {
378        extractor.GetSpecifiedTypeFiles(fileNames, ".abc");
379    } else {
380        extractor.GetSpecifiedTypeFiles(fileNames, ".map");
381    }
382    if (fileNames.empty()) {
383        TAG_LOGW(
384            AAFwkTag::JSRUNTIME, "no .abc in hap/hqf %{private}s", filePath.c_str());
385        return true;
386    }
387
388    std::string fileName = fileNames.front();
389    fileFullName = filePath + "/" + fileName;
390    std::unique_ptr<uint8_t[]> data;
391    size_t dataLen = 0;
392    if (!extractor.ExtractToBufByName(fileName, data, dataLen)) {
393        TAG_LOGE(AAFwkTag::JSRUNTIME, "Extract %{public}s failed", fileFullName.c_str());
394        return false;
395    }
396
397    buffer.assign(data.get(), data.get() + dataLen);
398    return true;
399}
400
401std::shared_ptr<AbilityBase::FileMapper> JsRuntime::GetSafeData(const std::string& path, std::string& fileFullName)
402{
403    bool newCreate = false;
404    auto extractor = ExtractorUtil::GetExtractor(path, newCreate, true);
405    if (extractor == nullptr) {
406        TAG_LOGE(AAFwkTag::JSRUNTIME, "Get extractor failed. path: %{private}s", path.c_str());
407        return nullptr;
408    }
409
410    std::vector<std::string> fileNames;
411    extractor->GetSpecifiedTypeFiles(fileNames, ".abc");
412    if (fileNames.empty()) {
413        TAG_LOGI(AAFwkTag::JSRUNTIME, "There's no abc file in hap or hqf: %{private}s", path.c_str());
414        return nullptr;
415    }
416    std::string fileName = fileNames.front();
417    fileFullName = path + "/" + fileName;
418
419    auto safeData = extractor->GetSafeData(fileName);
420    if (safeData == nullptr) {
421        TAG_LOGE(AAFwkTag::JSRUNTIME, "Get safe data failed. path: %{private}s", path.c_str());
422        return nullptr;
423    }
424
425    return safeData;
426}
427
428bool JsRuntime::LoadRepairPatch(const std::string& hqfFile, const std::string& hapPath)
429{
430    TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
431    auto vm = GetEcmaVm();
432    CHECK_POINTER_AND_RETURN(vm, false);
433
434    InitSourceMap(hqfFile);
435
436    std::string patchFile;
437    auto hqfSafeData = GetSafeData(hqfFile, patchFile);
438    if (hqfSafeData == nullptr) {
439        if (patchFile.empty()) {
440            TAG_LOGI(AAFwkTag::JSRUNTIME, "No need to load patch cause no ets. path: %{private}s", hqfFile.c_str());
441            return true;
442        }
443        return false;
444    }
445
446    std::string baseFile;
447    auto hapSafeData = GetSafeData(hapPath, baseFile);
448    if (hapSafeData == nullptr) {
449        return false;
450    }
451
452    std::string resolvedHapPath;
453    auto position = hapPath.find(".hap");
454    if (position != std::string::npos) {
455        resolvedHapPath = hapPath.substr(0, position) + MERGE_ABC_PATH;
456    }
457
458    auto hspPosition = hapPath.find(".hsp");
459    if (hspPosition != std::string::npos) {
460        resolvedHapPath = hapPath.substr(0, hspPosition) + MERGE_ABC_PATH;
461    }
462
463    TAG_LOGD(AAFwkTag::JSRUNTIME, "LoadPatch, patchFile: %{private}s, baseFile: %{private}s",
464        patchFile.c_str(), resolvedHapPath.c_str());
465    auto ret = panda::JSNApi::LoadPatch(vm, patchFile, hqfSafeData->GetDataPtr(), hqfSafeData->GetDataLen(),
466        resolvedHapPath, hapSafeData->GetDataPtr(), hapSafeData->GetDataLen());
467    if (ret != panda::JSNApi::PatchErrorCode::SUCCESS) {
468        TAG_LOGE(AAFwkTag::JSRUNTIME, "LoadPatch failed:%{public}d", static_cast<int32_t>(ret));
469        return false;
470    }
471
472    TAG_LOGD(AAFwkTag::JSRUNTIME, "Load patch %{private}s succeed", patchFile.c_str());
473    return true;
474}
475
476bool JsRuntime::UnLoadRepairPatch(const std::string& hqfFile)
477{
478    TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
479    auto vm = GetEcmaVm();
480    CHECK_POINTER_AND_RETURN(vm, false);
481
482    Extractor extractor(hqfFile);
483    if (!extractor.Init()) {
484        TAG_LOGE(AAFwkTag::JSRUNTIME, "Extractor of %{private}s init failed", hqfFile.c_str());
485        return false;
486    }
487
488    std::vector<std::string> fileNames;
489    extractor.GetSpecifiedTypeFiles(fileNames, ".abc");
490    if (fileNames.empty()) {
491        TAG_LOGW(AAFwkTag::JSRUNTIME, "no .abc in hqf %{private}s", hqfFile.c_str());
492        return true;
493    }
494
495    for (const auto &fileName : fileNames) {
496        std::string patchFile = hqfFile + "/" + fileName;
497        TAG_LOGD(AAFwkTag::JSRUNTIME, "UnloadPatch, patchFile: %{private}s", patchFile.c_str());
498        auto ret = panda::JSNApi::UnloadPatch(vm, patchFile);
499        if (ret != panda::JSNApi::PatchErrorCode::SUCCESS) {
500            TAG_LOGW(AAFwkTag::JSRUNTIME, "UnLoadPatch failed with %{public}d", static_cast<int32_t>(ret));
501        }
502        TAG_LOGD(AAFwkTag::JSRUNTIME, "UnLoad patch %{private}s succeed", patchFile.c_str());
503    }
504
505    return true;
506}
507
508bool JsRuntime::NotifyHotReloadPage()
509{
510    TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
511#ifdef SUPPORT_SCREEN
512    Ace::HotReloader::HotReload();
513#endif // SUPPORT_SCREEN
514    return true;
515}
516
517bool JsRuntime::LoadScript(const std::string& path, std::vector<uint8_t>* buffer, bool isBundle)
518{
519    TAG_LOGD(AAFwkTag::JSRUNTIME, "path: %{private}s", path.c_str());
520    CHECK_POINTER_AND_RETURN(jsEnv_, false);
521    return jsEnv_->LoadScript(path, buffer, isBundle);
522}
523
524bool JsRuntime::LoadScript(const std::string& path, uint8_t* buffer, size_t len, bool isBundle,
525    const std::string& srcEntrance)
526{
527    TAG_LOGD(AAFwkTag::JSRUNTIME, "path: %{private}s", path.c_str());
528    CHECK_POINTER_AND_RETURN(jsEnv_, false);
529    if (isOhmUrl_ && !moduleName_.empty()) {
530        auto vm = GetEcmaVm();
531        CHECK_POINTER_AND_RETURN(vm, false);
532        std::string srcFilename = "";
533        srcFilename = BUNDLE_INSTALL_PATH + moduleName_ + MERGE_ABC_PATH;
534        return panda::JSNApi::ExecuteSecureWithOhmUrl(vm, buffer, len, srcFilename, srcEntrance);
535    }
536    return jsEnv_->LoadScript(path, buffer, len, isBundle);
537}
538
539std::unique_ptr<NativeReference> JsRuntime::LoadSystemModuleByEngine(
540    napi_env env, const std::string& moduleName, const napi_value* argv, size_t argc)
541{
542    TAG_LOGD(AAFwkTag::JSRUNTIME, "ModuleName %{public}s", moduleName.c_str());
543    if (env == nullptr) {
544        TAG_LOGI(AAFwkTag::JSRUNTIME, "invalid engine");
545        return nullptr;
546    }
547
548    napi_value globalObj = nullptr;
549    napi_get_global(env, &globalObj);
550    napi_value propertyValue = nullptr;
551    napi_get_named_property(env, globalObj, "requireNapi", &propertyValue);
552
553    std::unique_ptr<NativeReference> methodRequireNapiRef_;
554    napi_ref tmpRef = nullptr;
555    napi_create_reference(env, propertyValue, 1, &tmpRef);
556    methodRequireNapiRef_.reset(reinterpret_cast<NativeReference*>(tmpRef));
557    if (!methodRequireNapiRef_) {
558        TAG_LOGE(AAFwkTag::JSRUNTIME, "Failed to create reference for global.requireNapi");
559        return nullptr;
560    }
561
562    napi_value className = nullptr;
563    napi_create_string_utf8(env, moduleName.c_str(), moduleName.length(), &className);
564    auto refValue = methodRequireNapiRef_->GetNapiValue();
565    napi_value args[1] = { className };
566    napi_value classValue = nullptr;
567    napi_call_function(env, globalObj, refValue, 1, args, &classValue);
568    napi_value instanceValue = nullptr;
569    napi_new_instance(env, classValue, argc, argv, &instanceValue);
570    if (instanceValue == nullptr) {
571        TAG_LOGE(AAFwkTag::JSRUNTIME, "Failed to create object instance");
572        return nullptr;
573    }
574
575    napi_ref resultRef = nullptr;
576    napi_create_reference(env, instanceValue, 1, &resultRef);
577    return std::unique_ptr<NativeReference>(reinterpret_cast<NativeReference*>(resultRef));
578}
579
580void JsRuntime::FinishPreload()
581{
582    auto vm = GetEcmaVm();
583    CHECK_POINTER(vm);
584    panda::JSNApi::PreFork(vm);
585}
586
587void JsRuntime::PostPreload(const Options& options)
588{
589    auto vm = GetEcmaVm();
590    CHECK_POINTER(vm);
591    auto env = GetNapiEnv();
592    CHECK_POINTER(env);
593    panda::RuntimeOption postOption;
594    postOption.SetBundleName(options.bundleName);
595    if (!options.arkNativeFilePath.empty()) {
596        std::string sandBoxAnFilePath = SANDBOX_ARK_CACHE_PATH + options.arkNativeFilePath;
597        postOption.SetAnDir(sandBoxAnFilePath);
598    }
599    if (options.isMultiThread) {
600        TAG_LOGD(AAFwkTag::JSRUNTIME, "Multi-Thread Mode: %{public}d", options.isMultiThread);
601        panda::JSNApi::SetMultiThreadCheck();
602    }
603    if (options.isErrorInfoEnhance) {
604        TAG_LOGD(AAFwkTag::JSRUNTIME, "Start Error-Info-Enhance Mode: %{public}d.", options.isErrorInfoEnhance);
605        panda::JSNApi::SetErrorInfoEnhance();
606    }
607    bool profileEnabled = OHOS::system::GetBoolParameter("ark.profile", false);
608    postOption.SetEnableProfile(profileEnabled);
609    TAG_LOGD(AAFwkTag::JSRUNTIME, "ASMM JIT Verify PostFork, jitEnabled: %{public}d", options.jitEnabled);
610    postOption.SetEnableJIT(options.jitEnabled);
611    postOption.SetAOTCompileStatusMap(options.aotCompileStatusMap);
612    {
613        HITRACE_METER_NAME(HITRACE_TAG_APP, "panda::JSNApi::PostFork");
614        panda::JSNApi::PostFork(vm, postOption);
615    }
616    reinterpret_cast<NativeEngine*>(env)->ReinitUVLoop();
617    uv_loop_s* loop = nullptr;
618    napi_get_uv_event_loop(env, &loop);
619    panda::JSNApi::SetLoop(vm, loop);
620}
621
622void JsRuntime::LoadAotFile(const Options& options)
623{
624    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
625    auto vm = GetEcmaVm();
626    CHECK_POINTER(vm);
627    if (options.hapPath.empty()) {
628        return;
629    }
630
631    bool newCreate = false;
632    std::string loadPath = ExtractorUtil::GetLoadFilePath(options.hapPath);
633    std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(loadPath, newCreate, true);
634    if (extractor != nullptr && newCreate) {
635        panda::JSNApi::LoadAotFile(vm, options.moduleName);
636    }
637}
638
639bool JsRuntime::Initialize(const Options& options)
640{
641    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
642#ifdef SUPPORT_SCREEN
643    if (Ace::AceForwardCompatibility::PipelineChanged()) {
644        preloaded_ = false;
645    }
646#endif
647    if (!preloaded_) {
648        if (!CreateJsEnv(options)) {
649            TAG_LOGE(AAFwkTag::JSRUNTIME, "Create jsEnv failed");
650            return false;
651        }
652    }
653    apiTargetVersion_ = options.apiTargetVersion;
654    TAG_LOGD(AAFwkTag::JSRUNTIME, "Initialize: %{public}d", apiTargetVersion_);
655    bool isModular = false;
656    if (IsUseAbilityRuntime(options)) {
657        auto env = GetNapiEnv();
658        auto nativeEngine = reinterpret_cast<NativeEngine*>(env);
659        CHECK_POINTER_AND_RETURN(nativeEngine, false);
660
661        auto vm = GetEcmaVm();
662        CHECK_POINTER_AND_RETURN(vm, false);
663
664        if (preloaded_) {
665            PostPreload(options);
666        }
667        HandleScope handleScope(*this);
668        napi_value globalObj = nullptr;
669        napi_get_global(env, &globalObj);
670        CHECK_POINTER_AND_RETURN(globalObj, false);
671
672        if (!preloaded_) {
673            InitSyscapModule(env);
674
675            // Simple hook function 'isSystemplugin'
676            const char* moduleName = "JsRuntime";
677            BindNativeFunction(env, globalObj, "isSystemplugin", moduleName,
678                [](napi_env env, napi_callback_info cbinfo) -> napi_value {
679                    return CreateJsUndefined(env);
680                });
681
682            napi_value propertyValue = nullptr;
683            napi_get_named_property(env, globalObj, "requireNapi", &propertyValue);
684            napi_ref tmpRef = nullptr;
685            napi_create_reference(env, propertyValue, 1, &tmpRef);
686            methodRequireNapiRef_.reset(reinterpret_cast<NativeReference*>(tmpRef));
687            if (!methodRequireNapiRef_) {
688                TAG_LOGE(AAFwkTag::JSRUNTIME, "Failed to create reference for global.requireNapi");
689                return false;
690            }
691            TAG_LOGD(AAFwkTag::JSRUNTIME, "PreloadAce start");
692            PreloadAce(options);
693            TAG_LOGD(AAFwkTag::JSRUNTIME, "PreloadAce end");
694            nativeEngine->RegisterPermissionCheck(PermissionCheckFunc);
695        }
696
697        if (!options.preload) {
698            isBundle_ = options.isBundle;
699            bundleName_ = options.bundleName;
700            codePath_ = options.codePath;
701            panda::JSNApi::SetSearchHapPathTracker(
702                vm, [options](const std::string moduleName, std::string &hapPath) -> bool {
703                    if (options.hapModulePath.find(moduleName) == options.hapModulePath.end()) {
704                        return false;
705                    }
706                    hapPath = options.hapModulePath.find(moduleName)->second;
707                    return true;
708                });
709            ReInitJsEnvImpl(options);
710            LoadAotFile(options);
711            panda::JSNApi::SetBundle(vm, options.isBundle);
712            panda::JSNApi::SetBundleName(vm, options.bundleName);
713            panda::JSNApi::SetHostResolveBufferTracker(
714                vm, JsModuleReader(options.bundleName, options.hapPath, options.isUnique));
715            isModular = !panda::JSNApi::IsBundle(vm);
716            std::vector<panda::HmsMap> systemKitsMap = GetSystemKitsMap(apiTargetVersion_);
717            panda::JSNApi::SetHmsModuleList(vm, systemKitsMap);
718            std::map<std::string, std::vector<std::vector<std::string>>> pkgContextInfoMap;
719            std::map<std::string, std::string> pkgAliasMap;
720            pkgContextInfoJsonStringMap_ = options.pkgContextInfoJsonStringMap;
721            packageNameList_ = options.packageNameList;
722            JsRuntimeLite::GetInstance().GetPkgContextInfoListMap(
723                options.pkgContextInfoJsonStringMap, pkgContextInfoMap, pkgAliasMap);
724            panda::JSNApi::SetpkgContextInfoList(vm, pkgContextInfoMap);
725            panda::JSNApi::SetPkgAliasList(vm, pkgAliasMap);
726            panda::JSNApi::SetPkgNameList(vm, options.packageNameList);
727        }
728    }
729
730    if (!preloaded_) {
731        InitConsoleModule();
732    }
733
734    if (!options.preload) {
735        auto operatorObj = std::make_shared<JsEnv::SourceMapOperator>(options.bundleName, isModular,
736                                                                      options.isDebugVersion);
737        InitSourceMap(operatorObj);
738
739        if (options.isUnique) {
740            TAG_LOGD(AAFwkTag::JSRUNTIME, "Not supported TimerModule when form render");
741        } else {
742            InitTimerModule();
743        }
744
745        InitWorkerModule(options);
746        SetModuleLoadChecker(options.moduleCheckerDelegate);
747        SetRequestAotCallback();
748
749        if (!InitLoop(options.isStageModel)) {
750            TAG_LOGE(AAFwkTag::JSRUNTIME, "Init loop failed");
751            return false;
752        }
753    }
754
755    preloaded_ = options.preload;
756    return true;
757}
758
759bool JsRuntime::CreateJsEnv(const Options& options)
760{
761    panda::RuntimeOption pandaOption;
762    int arkProperties = OHOS::system::GetIntParameter<int>("persist.ark.properties", -1);
763    std::string bundleName = OHOS::system::GetParameter("persist.ark.arkbundlename", "");
764    std::string memConfigProperty = OHOS::system::GetParameter("persist.ark.mem_config_property", "");
765    size_t gcThreadNum = OHOS::system::GetUintParameter<size_t>("persist.ark.gcthreads", 7);
766    size_t longPauseTime = OHOS::system::GetUintParameter<size_t>("persist.ark.longpausetime", 40);
767    pandaOption.SetArkProperties(arkProperties);
768    pandaOption.SetArkBundleName(bundleName);
769    pandaOption.SetMemConfigProperty(memConfigProperty);
770    pandaOption.SetGcThreadNum(gcThreadNum);
771    pandaOption.SetLongPauseTime(longPauseTime);
772    TAG_LOGD(AAFwkTag::JSRUNTIME, "ark properties=%{public}d bundlename=%{public}s",
773        arkProperties, bundleName.c_str());
774    pandaOption.SetGcType(panda::RuntimeOption::GC_TYPE::GEN_GC);
775    pandaOption.SetGcPoolSize(DEFAULT_GC_POOL_SIZE);
776    pandaOption.SetLogLevel(panda::RuntimeOption::LOG_LEVEL::FOLLOW);
777    pandaOption.SetLogBufPrint(PrintVmLog);
778
779    bool asmInterpreterEnabled = OHOS::system::GetBoolParameter("persist.ark.asminterpreter", true);
780    std::string asmOpcodeDisableRange = OHOS::system::GetParameter("persist.ark.asmopcodedisablerange", "");
781    pandaOption.SetEnableAsmInterpreter(asmInterpreterEnabled);
782    pandaOption.SetAsmOpcodeDisableRange(asmOpcodeDisableRange);
783    TAG_LOGD(AAFwkTag::JSRUNTIME, "ASMM JIT Verify CreateJsEnv, jitEnabled: %{public}d", options.jitEnabled);
784    pandaOption.SetEnableJIT(options.jitEnabled);
785
786    if (options.isMultiThread) {
787        TAG_LOGD(AAFwkTag::JSRUNTIME, "Start Multi Thread Mode: %{public}d", options.isMultiThread);
788        panda::JSNApi::SetMultiThreadCheck();
789    }
790
791    if (options.isErrorInfoEnhance) {
792        TAG_LOGD(AAFwkTag::JSRUNTIME, "Start Error Info Enhance Mode: %{public}d.", options.isErrorInfoEnhance);
793        panda::JSNApi::SetErrorInfoEnhance();
794    }
795
796    if (IsUseAbilityRuntime(options)) {
797        // aot related
798        bool aotEnabled = OHOS::system::GetBoolParameter("persist.ark.aot", true);
799        pandaOption.SetEnableAOT(aotEnabled);
800        pandaOption.SetProfileDir(SANDBOX_ARK_PROIFILE_PATH);
801    }
802
803    OHOSJsEnvLogger::RegisterJsEnvLogger();
804    jsEnv_ = std::make_shared<JsEnv::JsEnvironment>(std::make_unique<OHOSJsEnvironmentImpl>(options.eventRunner));
805    if (jsEnv_ == nullptr || !jsEnv_->Initialize(pandaOption, static_cast<void*>(this))) {
806        TAG_LOGE(AAFwkTag::JSRUNTIME, "Init jsEnv failed");
807        return false;
808    }
809
810    return true;
811}
812
813void JsRuntime::PreloadAce(const Options& options)
814{
815    auto nativeEngine = GetNativeEnginePointer();
816    CHECK_POINTER(nativeEngine);
817#ifdef SUPPORT_SCREEN
818    if (options.loadAce) {
819        // ArkTsCard start
820        if (options.isUnique) {
821            OHOS::Ace::DeclarativeModulePreloader::PreloadCard(
822                *nativeEngine, options.bundleName, options.pkgContextInfoJsonStringMap);
823        } else {
824            OHOS::Ace::DeclarativeModulePreloader::Preload(*nativeEngine);
825        }
826        // ArkTsCard end
827    }
828#endif
829}
830
831void JsRuntime::ReloadFormComponent()
832{
833    TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
834    auto nativeEngine = GetNativeEnginePointer();
835    CHECK_POINTER(nativeEngine);
836    // ArkTsCard update condition, need to reload new component
837#ifdef SUPPORT_SCREEN
838    OHOS::Ace::DeclarativeModulePreloader::ReloadCard(*nativeEngine, bundleName_, pkgContextInfoJsonStringMap_);
839#endif
840}
841
842bool JsRuntime::InitLoop(bool isStage)
843{
844    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
845    CHECK_POINTER_AND_RETURN(jsEnv_, false);
846    return jsEnv_->InitLoop(isStage);
847}
848
849void JsRuntime::SetAppLibPath(const AppLibPathMap& appLibPaths, const bool& isSystemApp)
850{
851    TAG_LOGD(AAFwkTag::JSRUNTIME, "Set library path");
852
853    if (appLibPaths.size() == 0) {
854        TAG_LOGW(AAFwkTag::JSRUNTIME, "no lib path to set");
855        return;
856    }
857
858    auto moduleManager = NativeModuleManager::GetInstance();
859    if (moduleManager == nullptr) {
860        TAG_LOGE(AAFwkTag::JSRUNTIME, "null moduleManager");
861        return;
862    }
863
864    for (const auto &appLibPath : appLibPaths) {
865        moduleManager->SetAppLibPath(appLibPath.first, appLibPath.second, isSystemApp);
866    }
867}
868
869void JsRuntime::InitSourceMap(const std::shared_ptr<JsEnv::SourceMapOperator> operatorObj)
870{
871    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
872    CHECK_POINTER(jsEnv_);
873    jsEnv_->InitSourceMap(operatorObj);
874    JsEnv::SourceMap::RegisterReadSourceMapCallback(JsRuntime::ReadSourceMapData);
875    JsEnv::SourceMap::RegisterGetHapPathCallback(JsModuleReader::GetHapPathList);
876}
877
878void JsRuntime::InitSourceMap(const std::string hqfFilePath)
879{
880    std::string patchSoureMapFile;
881    std::vector<uint8_t> soureMapBuffer;
882    if (!GetFileBuffer(hqfFilePath, patchSoureMapFile, soureMapBuffer, false)) {
883        TAG_LOGE(AAFwkTag::JSRUNTIME, "get patchSoureMap file buffer failed");
884        return;
885    }
886    std::string str(soureMapBuffer.begin(), soureMapBuffer.end());
887    auto sourceMapOperator = jsEnv_->GetSourceMapOperator();
888    if (sourceMapOperator != nullptr) {
889        auto sourceMapObj = sourceMapOperator->GetSourceMapObj();
890        if (sourceMapObj != nullptr) {
891            sourceMapObj->SplitSourceMap(str);
892        }
893    }
894}
895
896void JsRuntime::Deinitialize()
897{
898    TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
899    for (auto it = modules_.begin(); it != modules_.end(); it = modules_.erase(it)) {
900        delete it->second;
901        it->second = nullptr;
902    }
903
904    methodRequireNapiRef_.reset();
905
906    CHECK_POINTER(jsEnv_);
907    jsEnv_->DeInitLoop();
908}
909
910napi_value JsRuntime::LoadJsBundle(const std::string& path, const std::string& hapPath, bool useCommonChunk)
911{
912    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
913    auto env = GetNapiEnv();
914    CHECK_POINTER_AND_RETURN(env, nullptr);
915    napi_value globalObj = nullptr;
916    napi_get_global(env, &globalObj);
917    napi_value exports = nullptr;
918    napi_create_object(env, &exports);
919    napi_set_named_property(env, globalObj, "exports", exports);
920
921    if (!RunScript(path, hapPath, useCommonChunk)) {
922        TAG_LOGE(AAFwkTag::JSRUNTIME, "Failed to run script: %{private}s", path.c_str());
923        return nullptr;
924    }
925
926    napi_value exportsObj = nullptr;
927    napi_get_named_property(env, globalObj, "exports", &exportsObj);
928    if (exportsObj == nullptr) {
929        TAG_LOGE(AAFwkTag::JSRUNTIME, "Failed to get exports objcect: %{private}s", path.c_str());
930        return nullptr;
931    }
932
933    napi_value exportObj = nullptr;
934    napi_get_named_property(env, exportsObj, "default", &exportObj);
935    if (exportObj == nullptr) {
936        TAG_LOGE(AAFwkTag::JSRUNTIME, "Failed to get default objcect: %{private}s", path.c_str());
937        return nullptr;
938    }
939
940    return exportObj;
941}
942
943napi_value JsRuntime::LoadJsModule(const std::string& path, const std::string& hapPath, const std::string& srcEntrance)
944{
945    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
946    if (!RunScript(path, hapPath, false, srcEntrance)) {
947        TAG_LOGE(AAFwkTag::JSRUNTIME, "Failed to run script: %{private}s", path.c_str());
948        return nullptr;
949    }
950
951    auto vm = GetEcmaVm();
952    CHECK_POINTER_AND_RETURN(vm, nullptr);
953    panda::Local<panda::ObjectRef> exportObj;
954    if (isOhmUrl_) {
955        exportObj = panda::JSNApi::GetExportObjectFromOhmUrl(vm, srcEntrance, "default");
956    } else {
957        exportObj = panda::JSNApi::GetExportObject(vm, path, "default");
958    }
959
960    if (exportObj->IsNull()) {
961        TAG_LOGE(AAFwkTag::JSRUNTIME, "Get export object failed");
962        return nullptr;
963    }
964
965    auto env = GetNapiEnv();
966    CHECK_POINTER_AND_RETURN(env, nullptr);
967    return ArkNativeEngine::ArkValueToNapiValue(env, exportObj);
968}
969
970std::unique_ptr<NativeReference> JsRuntime::LoadModule(const std::string& moduleName, const std::string& modulePath,
971    const std::string& hapPath, bool esmodule, bool useCommonChunk, const std::string& srcEntrance)
972{
973    HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
974    TAG_LOGD(AAFwkTag::JSRUNTIME, "Load module(%{public}s, %{private}s, %{private}s, %{public}s)",
975        moduleName.c_str(), modulePath.c_str(), hapPath.c_str(), esmodule ? "true" : "false");
976    auto vm = GetEcmaVm();
977    CHECK_POINTER_AND_RETURN(vm, std::unique_ptr<NativeReference>());
978    // use for debugger, js engine need to know load module to handle debug event
979    panda::JSNApi::NotifyLoadModule(vm);
980    auto env = GetNapiEnv();
981    CHECK_POINTER_AND_RETURN(env, std::unique_ptr<NativeReference>());
982    isOhmUrl_ = panda::JSNApi::IsOhmUrl(srcEntrance);
983
984    HandleScope handleScope(*this);
985
986    std::string path = moduleName;
987    auto pos = path.find("::");
988    if (pos != std::string::npos) {
989        path.erase(pos, path.size() - pos);
990        moduleName_ = path;
991    }
992
993    napi_value classValue = nullptr;
994
995    auto it = modules_.find(modulePath);
996    if (it != modules_.end()) {
997        classValue = it->second->GetNapiValue();
998    } else {
999        std::string fileName;
1000        if (!hapPath.empty()) {
1001            fileName.append(codePath_).append(Constants::FILE_SEPARATOR).append(modulePath);
1002            std::regex pattern(std::string(Constants::FILE_DOT) + std::string(Constants::FILE_SEPARATOR));
1003            fileName = std::regex_replace(fileName, pattern, "");
1004        } else {
1005            if (!MakeFilePath(codePath_, modulePath, fileName)) {
1006                TAG_LOGE(AAFwkTag::JSRUNTIME, "Failed to make module file path: %{private}s", modulePath.c_str());
1007                return std::unique_ptr<NativeReference>();
1008            }
1009        }
1010        classValue = esmodule ? LoadJsModule(fileName, hapPath, srcEntrance)
1011            : LoadJsBundle(fileName, hapPath, useCommonChunk);
1012        if (classValue == nullptr) {
1013            return std::unique_ptr<NativeReference>();
1014        }
1015
1016        napi_ref tmpRef = nullptr;
1017        napi_create_reference(env, classValue, 1, &tmpRef);
1018        modules_.emplace(modulePath, reinterpret_cast<NativeReference*>(tmpRef));
1019    }
1020
1021    napi_value instanceValue = nullptr;
1022    napi_new_instance(env, classValue, 0, nullptr, &instanceValue);
1023    if (instanceValue == nullptr) {
1024        TAG_LOGE(AAFwkTag::JSRUNTIME, "Failed to create object instance");
1025        return std::unique_ptr<NativeReference>();
1026    }
1027
1028    napi_ref resultRef = nullptr;
1029    napi_create_reference(env, instanceValue, 1, &resultRef);
1030    return std::unique_ptr<NativeReference>(reinterpret_cast<NativeReference*>(resultRef));
1031}
1032
1033std::unique_ptr<NativeReference> JsRuntime::LoadSystemModule(
1034    const std::string& moduleName, const napi_value* argv, size_t argc)
1035{
1036    TAG_LOGD(AAFwkTag::JSRUNTIME, "SystemModule %{public}s", moduleName.c_str());
1037    napi_env env = GetNapiEnv();
1038    CHECK_POINTER_AND_RETURN(env, std::unique_ptr<NativeReference>());
1039
1040    HandleScope handleScope(*this);
1041
1042    napi_value className = nullptr;
1043    napi_create_string_utf8(env, moduleName.c_str(), moduleName.length(), &className);
1044    napi_value globalObj = nullptr;
1045    napi_get_global(env, &globalObj);
1046    napi_value refValue = methodRequireNapiRef_->GetNapiValue();
1047    napi_value args[1] = { className };
1048    napi_value classValue = nullptr;
1049    napi_call_function(env, globalObj, refValue, 1, args, &classValue);
1050    napi_value instanceValue = nullptr;
1051    napi_new_instance(env, classValue, argc, argv, &instanceValue);
1052    if (instanceValue == nullptr) {
1053        TAG_LOGE(AAFwkTag::JSRUNTIME, "Failed to create object instance");
1054        return std::unique_ptr<NativeReference>();
1055    }
1056
1057    napi_ref resultRef = nullptr;
1058    napi_create_reference(env, instanceValue, 1, &resultRef);
1059    return std::unique_ptr<NativeReference>(reinterpret_cast<NativeReference*>(resultRef));
1060}
1061
1062bool JsRuntime::RunScript(const std::string& srcPath, const std::string& hapPath, bool useCommonChunk,
1063    const std::string& srcEntrance)
1064{
1065    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
1066    auto vm = GetEcmaVm();
1067    CHECK_POINTER_AND_RETURN(vm, false);
1068    std::string commonsPath = std::string(Constants::LOCAL_CODE_PATH) + "/" + moduleName_ + "/ets/commons.abc";
1069    std::string vendorsPath = std::string(Constants::LOCAL_CODE_PATH) + "/" + moduleName_ + "/ets/vendors.abc";
1070    if (hapPath.empty()) {
1071        if (useCommonChunk) {
1072            (void)LoadScript(commonsPath);
1073            (void)LoadScript(vendorsPath);
1074        }
1075        return LoadScript(srcPath);
1076    }
1077
1078    bool newCreate = false;
1079    std::string loadPath = ExtractorUtil::GetLoadFilePath(hapPath);
1080    std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(loadPath, newCreate, true);
1081    if (!extractor) {
1082        TAG_LOGE(AAFwkTag::JSRUNTIME, "Get extractor failed. hapPath[%{private}s]", hapPath.c_str());
1083        return false;
1084    }
1085    if (newCreate) {
1086        panda::JSNApi::LoadAotFile(vm, moduleName_);
1087        auto resourceManager = AbilityBase::ExtractResourceManager::GetExtractResourceManager().GetGlobalObject();
1088        if (resourceManager) {
1089            resourceManager->AddResource(loadPath.c_str());
1090        }
1091    }
1092
1093    auto func = [&](std::string modulePath, const std::string abcPath) {
1094        bool useSafeMempry = apiTargetVersion_ == 0 || apiTargetVersion_ > API8;
1095        if (!extractor->IsHapCompress(modulePath) && useSafeMempry) {
1096            auto safeData = extractor->GetSafeData(modulePath);
1097            if (!safeData) {
1098                TAG_LOGE(AAFwkTag::JSRUNTIME, "Get safeData abc file failed");
1099                return false;
1100            }
1101            return LoadScript(abcPath, safeData->GetDataPtr(), safeData->GetDataLen(), isBundle_, srcEntrance);
1102        } else {
1103            std::unique_ptr<uint8_t[]> data;
1104            size_t dataLen = 0;
1105            if (!extractor->ExtractToBufByName(modulePath, data, dataLen)) {
1106                TAG_LOGE(AAFwkTag::JSRUNTIME, "Get File  Buffer abc file failed");
1107                return false;
1108            }
1109            std::vector<uint8_t> buffer;
1110            buffer.assign(data.get(), data.get() + dataLen);
1111
1112            return LoadScript(abcPath, &buffer, isBundle_);
1113        }
1114    };
1115
1116    if (useCommonChunk) {
1117        (void)func(commonsPath, commonsPath);
1118        (void)func(vendorsPath, vendorsPath);
1119    }
1120
1121    std::string path = srcPath;
1122    if (!isBundle_) {
1123        if (moduleName_.empty()) {
1124            TAG_LOGE(AAFwkTag::JSRUNTIME, "moduleName is hole");
1125            return false;
1126        }
1127        path = BUNDLE_INSTALL_PATH + moduleName_ + MERGE_ABC_PATH;
1128        panda::JSNApi::SetAssetPath(vm, path);
1129        panda::JSNApi::SetModuleName(vm, moduleName_);
1130    }
1131    return func(path, srcPath);
1132}
1133
1134bool JsRuntime::RunSandboxScript(const std::string& path, const std::string& hapPath)
1135{
1136    std::string fileName;
1137    if (!hapPath.empty()) {
1138        fileName.append(codePath_).append(Constants::FILE_SEPARATOR).append(path);
1139        std::regex pattern(std::string(Constants::FILE_DOT) + std::string(Constants::FILE_SEPARATOR));
1140        fileName = std::regex_replace(fileName, pattern, "");
1141    } else {
1142        if (!MakeFilePath(codePath_, path, fileName)) {
1143            TAG_LOGE(AAFwkTag::JSRUNTIME, "Failed to make module file path: %{private}s", path.c_str());
1144            return false;
1145        }
1146    }
1147
1148    if (!RunScript(fileName, hapPath)) {
1149        TAG_LOGE(AAFwkTag::JSRUNTIME, "Failed to run script: %{public}s", fileName.c_str());
1150        return false;
1151    }
1152    return true;
1153}
1154
1155void JsRuntime::PostTask(const std::function<void()>& task, const std::string& name, int64_t delayTime)
1156{
1157    CHECK_POINTER(jsEnv_);
1158    jsEnv_->PostTask(task, name, delayTime);
1159}
1160
1161void JsRuntime::PostSyncTask(const std::function<void()>& task, const std::string& name)
1162{
1163    CHECK_POINTER(jsEnv_);
1164    jsEnv_->PostSyncTask(task, name);
1165}
1166
1167void JsRuntime::RemoveTask(const std::string& name)
1168{
1169    CHECK_POINTER(jsEnv_);
1170    jsEnv_->RemoveTask(name);
1171}
1172
1173void JsRuntime::DumpCpuProfile()
1174{
1175    auto nativeEngine = GetNativeEnginePointer();
1176    CHECK_POINTER(nativeEngine);
1177    nativeEngine->DumpCpuProfile();
1178}
1179
1180void JsRuntime::DumpHeapSnapshot(bool isPrivate)
1181{
1182    auto nativeEngine = GetNativeEnginePointer();
1183    CHECK_POINTER(nativeEngine);
1184    nativeEngine->DumpHeapSnapshot(true, DumpFormat::JSON, isPrivate, false);
1185}
1186
1187void JsRuntime::DumpHeapSnapshot(uint32_t tid, bool isFullGC)
1188{
1189    auto vm = GetEcmaVm();
1190    CHECK_POINTER(vm);
1191    panda::ecmascript::DumpSnapShotOption dumpOption;
1192    dumpOption.dumpFormat = panda::ecmascript::DumpFormat::JSON;
1193    dumpOption.isVmMode = true;
1194    dumpOption.isPrivate = false;
1195    dumpOption.captureNumericValue = true;
1196    dumpOption.isFullGC = isFullGC;
1197    dumpOption.isSync = false;
1198    DFXJSNApi::DumpHeapSnapshot(vm, dumpOption, tid);
1199}
1200
1201void JsRuntime::ForceFullGC(uint32_t tid)
1202{
1203    auto vm = GetEcmaVm();
1204    CHECK_POINTER(vm);
1205    DFXJSNApi::TriggerGC(vm, tid);
1206}
1207
1208void JsRuntime::DestroyHeapProfiler()
1209{
1210    CHECK_POINTER(jsEnv_);
1211    jsEnv_->DestroyHeapProfiler();
1212}
1213
1214void JsRuntime::ForceFullGC()
1215{
1216    auto vm = GetEcmaVm();
1217    CHECK_POINTER(vm);
1218    panda::JSNApi::TriggerGC(vm, panda::ecmascript::GCReason::TRIGGER_BY_ABILITY,
1219        panda::JSNApi::TRIGGER_GC_TYPE::FULL_GC);
1220}
1221
1222void JsRuntime::AllowCrossThreadExecution()
1223{
1224    auto vm = GetEcmaVm();
1225    CHECK_POINTER(vm);
1226    panda::JSNApi::AllowCrossThreadExecution(vm);
1227}
1228
1229void JsRuntime::GetHeapPrepare()
1230{
1231    CHECK_POINTER(jsEnv_);
1232    jsEnv_->GetHeapPrepare();
1233}
1234
1235void JsRuntime::NotifyApplicationState(bool isBackground)
1236{
1237    auto nativeEngine = GetNativeEnginePointer();
1238    CHECK_POINTER(nativeEngine);
1239    nativeEngine->NotifyApplicationState(isBackground);
1240    TAG_LOGD(AAFwkTag::JSRUNTIME, "isBackground %{public}d", isBackground);
1241}
1242
1243bool JsRuntime::SuspendVM(uint32_t tid)
1244{
1245    auto nativeEngine = GetNativeEnginePointer();
1246    CHECK_POINTER_AND_RETURN(nativeEngine, false);
1247    return nativeEngine->SuspendVMById(tid);
1248}
1249
1250void JsRuntime::ResumeVM(uint32_t tid)
1251{
1252    auto nativeEngine = GetNativeEnginePointer();
1253    CHECK_POINTER(nativeEngine);
1254    nativeEngine->ResumeVMById(tid);
1255}
1256
1257void JsRuntime::PreloadSystemModule(const std::string& moduleName)
1258{
1259    HandleScope handleScope(*this);
1260    auto env = GetNapiEnv();
1261    CHECK_POINTER(env);
1262    napi_value className = nullptr;
1263    napi_create_string_utf8(env, moduleName.c_str(), moduleName.length(), &className);
1264    napi_value globalObj = nullptr;
1265    napi_get_global(env, &globalObj);
1266    napi_value refValue = methodRequireNapiRef_->GetNapiValue();
1267    napi_value args[1] = { className };
1268    napi_call_function(env, globalObj, refValue, 1, args, nullptr);
1269}
1270
1271NativeEngine& JsRuntime::GetNativeEngine() const
1272{
1273    return *GetNativeEnginePointer();
1274}
1275
1276napi_env JsRuntime::GetNapiEnv() const
1277{
1278    return reinterpret_cast<napi_env>(GetNativeEnginePointer());
1279}
1280
1281NativeEngine* JsRuntime::GetNativeEnginePointer() const
1282{
1283    CHECK_POINTER_AND_RETURN(jsEnv_, nullptr);
1284    return jsEnv_->GetNativeEngine();
1285}
1286
1287panda::ecmascript::EcmaVM* JsRuntime::GetEcmaVm() const
1288{
1289    CHECK_POINTER_AND_RETURN(jsEnv_, nullptr);
1290    return jsEnv_->GetVM();
1291}
1292
1293bool JsRuntime::IsUseAbilityRuntime(const Options& options) const
1294{
1295    return (options.isStageModel) || (options.isTestFramework);
1296}
1297
1298void JsRuntime::UpdateModuleNameAndAssetPath(const std::string& moduleName)
1299{
1300    if (isBundle_) {
1301        return;
1302    }
1303
1304    auto vm = GetEcmaVm();
1305    if (!vm || moduleName.empty()) {
1306        TAG_LOGE(AAFwkTag::JSRUNTIME, "vm is nullptr or moduleName is empty");
1307        return;
1308    }
1309
1310    moduleName_ = moduleName;
1311    std::string path = BUNDLE_INSTALL_PATH + moduleName_ + MERGE_ABC_PATH;
1312    panda::JSNApi::SetAssetPath(vm, path);
1313    panda::JSNApi::SetModuleName(vm, moduleName_);
1314}
1315
1316void JsRuntime::RegisterUncaughtExceptionHandler(const JsEnv::UncaughtExceptionInfo& uncaughtExceptionInfo)
1317{
1318    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
1319    CHECK_POINTER(jsEnv_);
1320    jsEnv_->RegisterUncaughtExceptionHandler(uncaughtExceptionInfo);
1321}
1322
1323void JsRuntime::RegisterQuickFixQueryFunc(const std::map<std::string, std::string>& moduleAndPath)
1324{
1325    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
1326    auto vm = GetEcmaVm();
1327    CHECK_POINTER(vm);
1328    for (auto it = moduleAndPath.begin(); it != moduleAndPath.end(); it++) {
1329        std::string hqfFile(AbilityBase::GetLoadPath(it->second));
1330        InitSourceMap(hqfFile);
1331    }
1332    panda::JSNApi::RegisterQuickFixQueryFunc(vm, JsQuickfixCallback(moduleAndPath));
1333}
1334
1335bool JsRuntime::ReadSourceMapData(const std::string& hapPath, const std::string& sourceMapPath, std::string& content)
1336{
1337    // Source map relative path, FA: "/assets/js", Stage: "/ets"
1338    if (hapPath.empty()) {
1339        TAG_LOGE(AAFwkTag::JSRUNTIME, "empty hapPath");
1340        return false;
1341    }
1342    bool newCreate = false;
1343    std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(
1344        ExtractorUtil::GetLoadFilePath(hapPath), newCreate);
1345    if (extractor == nullptr) {
1346        TAG_LOGE(AAFwkTag::JSRUNTIME, "hap's path: %{public}s, get extractor failed", hapPath.c_str());
1347        return false;
1348    }
1349    std::unique_ptr<uint8_t[]> dataPtr = nullptr;
1350    size_t len = 0;
1351    if (!extractor->ExtractToBufByName(sourceMapPath, dataPtr, len)) {
1352        TAG_LOGD(AAFwkTag::JSRUNTIME, "can't find source map, and switch to stage model");
1353        std::string tempPath = std::regex_replace(sourceMapPath, std::regex("ets"), "assets/js");
1354        if (!extractor->ExtractToBufByName(tempPath, dataPtr, len)) {
1355            TAG_LOGD(AAFwkTag::JSRUNTIME, "get mergeSourceMapData fileBuffer failed, map path: %{private}s",
1356                tempPath.c_str());
1357            return false;
1358        }
1359    }
1360    content.assign(dataPtr.get(), dataPtr.get() + len);
1361    return true;
1362}
1363
1364void JsRuntime::FreeNativeReference(std::unique_ptr<NativeReference> reference)
1365{
1366    FreeNativeReference(std::move(reference), nullptr);
1367}
1368
1369void JsRuntime::FreeNativeReference(std::shared_ptr<NativeReference>&& reference)
1370{
1371    FreeNativeReference(nullptr, std::move(reference));
1372}
1373
1374struct JsNativeReferenceDeleterObject {
1375    std::unique_ptr<NativeReference> uniqueNativeRef_ = nullptr;
1376    std::shared_ptr<NativeReference> sharedNativeRef_ = nullptr;
1377};
1378
1379void JsRuntime::FreeNativeReference(std::unique_ptr<NativeReference> uniqueNativeRef,
1380    std::shared_ptr<NativeReference>&& sharedNativeRef)
1381{
1382    if (uniqueNativeRef == nullptr && sharedNativeRef == nullptr) {
1383        TAG_LOGW(AAFwkTag::JSRUNTIME, "invalid nativeRef");
1384        return;
1385    }
1386
1387    auto nativeEngine = GetNativeEnginePointer();
1388    CHECK_POINTER(nativeEngine);
1389    auto uvLoop = nativeEngine->GetUVLoop();
1390    CHECK_POINTER(uvLoop);
1391
1392    auto work = new (std::nothrow) uv_work_t;
1393    if (work == nullptr) {
1394        TAG_LOGE(AAFwkTag::JSRUNTIME, "null work");
1395        return;
1396    }
1397
1398    auto cb = new (std::nothrow) JsNativeReferenceDeleterObject();
1399    if (cb == nullptr) {
1400        TAG_LOGE(AAFwkTag::JSRUNTIME, "null cb");
1401        delete work;
1402        work = nullptr;
1403        return;
1404    }
1405
1406    if (uniqueNativeRef != nullptr) {
1407        cb->uniqueNativeRef_ = std::move(uniqueNativeRef);
1408    }
1409    if (sharedNativeRef != nullptr) {
1410        cb->sharedNativeRef_ = std::move(sharedNativeRef);
1411    }
1412    work->data = reinterpret_cast<void*>(cb);
1413    int ret = uv_queue_work(uvLoop, work, [](uv_work_t *work) {},
1414    [](uv_work_t *work, int status) {
1415        if (work != nullptr) {
1416            if (work->data != nullptr) {
1417                delete reinterpret_cast<JsNativeReferenceDeleterObject*>(work->data);
1418                work->data = nullptr;
1419            }
1420            delete work;
1421            work = nullptr;
1422        }
1423    });
1424    if (ret != 0) {
1425        delete reinterpret_cast<JsNativeReferenceDeleterObject*>(work->data);
1426        work->data = nullptr;
1427        delete work;
1428        work = nullptr;
1429    }
1430}
1431
1432void JsRuntime::InitTimerModule()
1433{
1434    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
1435    CHECK_POINTER(jsEnv_);
1436    jsEnv_->InitTimerModule();
1437}
1438
1439void JsRuntime::InitWorkerModule(const Options& options)
1440{
1441    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
1442    CHECK_POINTER(jsEnv_);
1443    std::shared_ptr<JsEnv::WorkerInfo> workerInfo = std::make_shared<JsEnv::WorkerInfo>();
1444    workerInfo->codePath = panda::panda_file::StringPacProtect(options.codePath);
1445    workerInfo->isDebugVersion = options.isDebugVersion;
1446    workerInfo->isBundle = options.isBundle;
1447    workerInfo->packagePathStr = options.packagePathStr;
1448    workerInfo->assetBasePathStr = options.assetBasePathStr;
1449    workerInfo->hapPath = panda::panda_file::StringPacProtect(options.hapPath);
1450    workerInfo->isStageModel = panda::panda_file::BoolPacProtect(options.isStageModel);
1451    workerInfo->moduleName = options.moduleName;
1452    workerInfo->apiTargetVersion = panda::panda_file::DataProtect(static_cast<uintptr_t>(options.apiTargetVersion));
1453    if (options.isJsFramework) {
1454        SetJsFramework();
1455    }
1456    jsEnv_->InitWorkerModule(workerInfo);
1457}
1458
1459void JsRuntime::ReInitJsEnvImpl(const Options& options)
1460{
1461    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
1462    CHECK_POINTER(jsEnv_);
1463    jsEnv_->ReInitJsEnvImpl(std::make_unique<OHOSJsEnvironmentImpl>(options.eventRunner));
1464}
1465
1466void JsRuntime::SetModuleLoadChecker(const std::shared_ptr<ModuleCheckerDelegate> moduleCheckerDelegate) const
1467{
1468    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
1469    CHECK_POINTER(jsEnv_);
1470    jsEnv_->SetModuleLoadChecker(moduleCheckerDelegate);
1471}
1472
1473void JsRuntime::SetRequestAotCallback()
1474{
1475    HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
1476    CHECK_POINTER(jsEnv_);
1477    auto callback = [](const std::string& bundleName, const std::string& moduleName, int32_t triggerMode) -> int32_t {
1478        auto systemAbilityMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
1479        if (systemAbilityMgr == nullptr) {
1480            TAG_LOGE(AAFwkTag::JSRUNTIME, "get SaMgr failed");
1481            return ERR_INVALID_VALUE;
1482        }
1483
1484        auto remoteObj = systemAbilityMgr->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
1485        if (remoteObj == nullptr) {
1486            TAG_LOGE(AAFwkTag::JSRUNTIME, "null remoteObject");
1487            return ERR_INVALID_VALUE;
1488        }
1489
1490        auto bundleMgr = iface_cast<AppExecFwk::IBundleMgr>(remoteObj);
1491        if (bundleMgr == nullptr) {
1492            TAG_LOGE(AAFwkTag::JSRUNTIME, "get bms failed");
1493            return ERR_INVALID_VALUE;
1494        }
1495
1496        TAG_LOGD(AAFwkTag::JSRUNTIME,
1497            "Reset compile status, bundleName: %{public}s, moduleName: %{public}s, triggerMode: %{public}d",
1498            bundleName.c_str(), moduleName.c_str(), triggerMode);
1499        return bundleMgr->ResetAOTCompileStatus(bundleName, moduleName, triggerMode);
1500    };
1501
1502    jsEnv_->SetRequestAotCallback(callback);
1503}
1504
1505void JsRuntime::SetDeviceDisconnectCallback(const std::function<bool()> &cb)
1506{
1507    TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
1508    CHECK_POINTER(jsEnv_);
1509    jsEnv_->SetDeviceDisconnectCallback(cb);
1510}
1511
1512std::string JsRuntime::GetSystemKitPath()
1513{
1514    char buf[MAX_PATH_LEN] = { 0 };
1515    char *configPath = GetOneCfgFile(CONFIG_PATH.c_str(), buf, MAX_PATH_LEN);
1516    if (configPath == nullptr || configPath[0] == '\0' || strlen(configPath) > MAX_PATH_LEN) {
1517        return SYSTEM_KITS_CONFIG_PATH;
1518    }
1519    return configPath;
1520}
1521
1522std::vector<panda::HmsMap> JsRuntime::GetSystemKitsMap(uint32_t version)
1523{
1524    std::vector<panda::HmsMap> systemKitsMap;
1525    nlohmann::json jsonBuf;
1526    std::string configPath = GetSystemKitPath();
1527    if (configPath == "" || access(configPath.c_str(), F_OK) != 0) {
1528        return systemKitsMap;
1529    }
1530
1531    std::fstream in;
1532    char errBuf[256];
1533    errBuf[0] = '\0';
1534    in.open(configPath, std::ios_base::in);
1535    if (!in.is_open()) {
1536        strerror_r(errno, errBuf, sizeof(errBuf));
1537        return systemKitsMap;
1538    }
1539
1540    in.seekg(0, std::ios::end);
1541    int64_t size = in.tellg();
1542    if (size <= 0) {
1543        in.close();
1544        return systemKitsMap;
1545    }
1546
1547    in.seekg(0, std::ios::beg);
1548    jsonBuf = nlohmann::json::parse(in, nullptr, false);
1549    in.close();
1550    if (jsonBuf.is_discarded()) {
1551        return systemKitsMap;
1552    }
1553
1554    if (!jsonBuf.contains(SYSTEM_KITS)) {
1555        return systemKitsMap;
1556    }
1557    for (auto &item : jsonBuf.at(SYSTEM_KITS).items()) {
1558        nlohmann::json& jsonObject = item.value();
1559        if (!jsonObject.contains(NAMESPACE) || !jsonObject.at(NAMESPACE).is_string() ||
1560            !jsonObject.contains(TARGET_OHM) || !jsonObject.at(TARGET_OHM).is_string() ||
1561            !jsonObject.contains(SINCE_VERSION) || !jsonObject.at(SINCE_VERSION).is_number()) {
1562            continue;
1563        }
1564        uint32_t sinceVersion = jsonObject.at(SINCE_VERSION).get<uint32_t>();
1565        if (version >= sinceVersion) {
1566            panda::HmsMap hmsMap = {
1567                .originalPath = jsonObject.at(NAMESPACE).get<std::string>(),
1568                .targetPath = jsonObject.at(TARGET_OHM).get<std::string>(),
1569                .sinceVersion = sinceVersion
1570            };
1571            systemKitsMap.emplace_back(hmsMap);
1572        }
1573    }
1574    TAG_LOGD(AAFwkTag::JSRUNTIME, "The size of the map is %{public}zu", systemKitsMap.size());
1575    return systemKitsMap;
1576}
1577
1578void JsRuntime::UpdatePkgContextInfoJson(std::string moduleName, std::string hapPath, std::string packageName)
1579{
1580    auto iterator = pkgContextInfoJsonStringMap_.find(moduleName);
1581    if (iterator == pkgContextInfoJsonStringMap_.end()) {
1582        pkgContextInfoJsonStringMap_[moduleName] = hapPath;
1583        packageNameList_[moduleName] = packageName;
1584        auto vm = GetEcmaVm();
1585        std::map<std::string, std::vector<std::vector<std::string>>> pkgContextInfoMap;
1586        std::map<std::string, std::string> pkgAliasMap;
1587        JsRuntimeLite::GetInstance().GetPkgContextInfoListMap(
1588            pkgContextInfoJsonStringMap_, pkgContextInfoMap, pkgAliasMap);
1589        panda::JSNApi::SetpkgContextInfoList(vm, pkgContextInfoMap);
1590        panda::JSNApi::SetPkgAliasList(vm, pkgAliasMap);
1591        panda::JSNApi::SetPkgNameList(vm, packageNameList_);
1592    }
1593}
1594} // namespace AbilityRuntime
1595} // namespace OHOS
1596