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