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