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