1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ark_native_engine.h"
17
18 #ifdef ENABLE_HITRACE
19 #include <sys/prctl.h>
20 #endif
21
22 #include <sstream>
23 #include "ark_crash_holder.h"
24 #include "ark_finalizers_pack.h"
25 #include "ark_native_deferred.h"
26 #include "ark_native_reference.h"
27 #include "native_engine/native_property.h"
28 #include "native_engine/native_utils.h"
29 #include "native_sendable.h"
30 #include "securec.h"
31 #include "utils/file.h"
32 #include "utils/log.h"
33 #if !defined(PREVIEW) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
34 #include "parameters.h"
35 #include <uv.h>
36 #endif
37 #ifdef OHOS_STANDARD_PLATFORM
38 #include "unwinder.h"
39 #endif
40 #ifdef ENABLE_CONTAINER_SCOPE
41 #include "core/common/container_scope.h"
42 #endif
43 #if defined(ENABLE_EVENT_HANDLER)
44 #include "event_handler.h"
45 #endif
46 #ifdef ENABLE_HITRACE
47 #include "hitrace/trace.h"
48 #include "hitrace_meter.h"
49 #include "parameter.h"
50 #include "musl_preinit_common.h"
51 #include "memory_trace.h"
52
53 // LCOV_EXCL_START
54 struct alignas(8) HookJsConfig { // 8 is 8 bit
55 int32_t jsStackReport = 0;
56 uint8_t maxJsStackDepth = 0;
57 bool jsFpUnwind = false;
58 char filterNapiName[64] = { "" };
59 };
60
61 class BlockHookScope {
62 public:
BlockHookScope()63 BlockHookScope()
64 {
65 previousState_ = __set_hook_flag(false);
66 }
~BlockHookScope()67 ~BlockHookScope()
68 {
69 __set_hook_flag(previousState_);
70 }
71 private:
72 bool previousState_ {true};
73 };
74
75 static HookJsConfig* g_hookJsConfig = nullptr;
76 static std::once_flag g_hookOnceFlag;
77 static std::string JS_CALL_STACK_DEPTH_SEP = ","; // ',' is js call stack depth separator
78 static std::string JS_SYMBOL_FILEPATH_SEP = "|"; // '|' is js symbol and filepath separator
79 static constexpr uint64_t BUF_SIZE = 128;
80 #endif
81
82 using panda::JsiRuntimeCallInfo;
83 using panda::BooleanRef;
84 using panda::ObjectRef;
85 using panda::StringRef;
86 using panda::Global;
87 using panda::JSNApi;
88 using panda::FunctionRef;
89 using panda::PrimitiveRef;
90 using panda::ArrayBufferRef;
91 using panda::TypedArrayRef;
92 using panda::PromiseCapabilityRef;
93 using panda::PropertyAttribute;
94 using panda::NativePointerRef;
95 using panda::SymbolRef;
96 using panda::IntegerRef;
97 using panda::DateRef;
98 using panda::BigIntRef;
99 static constexpr auto PANDA_MAIN_FUNCTION = "_GLOBAL::func_main_0";
100 static constexpr auto PANDA_MODULE_NAME = "_GLOBAL_MODULE_NAME";
101 static constexpr auto PANDA_MODULE_NAME_LEN = 32;
102 static std::unordered_set<std::string> NATIVE_MODULE = {"system.app", "ohos.app", "system.router",
103 "system.curves", "ohos.curves", "system.matrix4", "ohos.matrix4"};
104 static constexpr auto NATIVE_MODULE_PREFIX = "@native:";
105 static constexpr auto OHOS_MODULE_PREFIX = "@ohos:";
106 #ifdef ENABLE_HITRACE
107 constexpr auto NAPI_PROFILER_PARAM_SIZE = 10;
108 std::atomic<uint64_t> g_chainId = 0;
109 constexpr int NAPI_CALL_STACK = 2; // just for napi call stack
110 #endif
111
112 std::string ArkNativeEngine::tempModuleName_ {""};
113 bool ArkNativeEngine::napiProfilerEnabled {false};
114 bool ArkNativeEngine::napiProfilerParamReaded {false};
115 PermissionCheckCallback ArkNativeEngine::permissionCheckCallback_ {nullptr};
116
117 // This interface is using by ace_engine
LocalValueToLocalNapiValue(panda::Local<panda::JSValueRef> local)118 napi_value LocalValueToLocalNapiValue(panda::Local<panda::JSValueRef> local)
119 {
120 return JsValueFromLocalValue(local);
121 }
122
123 // This interface is using by ace_engine
NapiValueToLocalValue(napi_value v)124 panda::Local<panda::JSValueRef> NapiValueToLocalValue(napi_value v)
125 {
126 return LocalValueFromJsValue(v);
127 }
128
129 #ifdef ENABLE_CONTAINER_SCOPE
FunctionSetContainerId(const EcmaVM * vm,panda::Local<panda::JSValueRef> & value)130 void FunctionSetContainerId(const EcmaVM *vm, panda::Local<panda::JSValueRef> &value)
131 {
132 if (!value->IsFunction(vm)) {
133 return;
134 }
135 panda::Local<panda::FunctionRef> funcValue(value);
136 if (funcValue->IsNative(vm)) {
137 return;
138 }
139
140 auto extraInfo = funcValue->GetData(vm);
141 if (extraInfo != nullptr) {
142 return;
143 }
144
145 NapiFunctionInfo *funcInfo = NapiFunctionInfo::CreateNewInstance();
146 if (funcInfo == nullptr) {
147 HILOG_ERROR("funcInfo is nullptr");
148 return;
149 }
150 funcInfo->scopeId = OHOS::Ace::ContainerScope::CurrentId();
151 funcValue->SetData(vm, reinterpret_cast<void*>(funcInfo),
152 [](void* env, void *externalPointer, void *data) {
153 auto info = reinterpret_cast<NapiFunctionInfo*>(data);
154 if (info != nullptr) {
155 delete info;
156 info = nullptr;
157 }
158 }, true);
159 }
160 #endif
161
NapiDefineClass(napi_env env,const char * name,NapiNativeCallback callback,void * data,const NapiPropertyDescriptor * properties,size_t length)162 panda::Local<panda::JSValueRef> NapiDefineClass(napi_env env, const char* name, NapiNativeCallback callback,
163 void* data, const NapiPropertyDescriptor* properties, size_t length)
164 {
165 auto vm = const_cast<EcmaVM*>(reinterpret_cast<NativeEngine*>(env)->GetEcmaVm());
166 std::string className(name);
167 if (ArkNativeEngine::napiProfilerEnabled) {
168 className = ArkNativeEngine::tempModuleName_ + "." + name;
169 }
170
171 NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
172 if (funcInfo == nullptr) {
173 HILOG_ERROR("funcInfo is nullptr");
174 return panda::JSValueRef::Undefined(vm);
175 }
176 funcInfo->callback = callback;
177 funcInfo->data = data;
178 #ifdef ENABLE_CONTAINER_SCOPE
179 funcInfo->scopeId = OHOS::Ace::ContainerScope::CurrentId();
180 #endif
181
182 Local<panda::FunctionRef> fn = panda::FunctionRef::NewConcurrentClassFunction(vm, ArkNativeFunctionCallBack,
183 [](void* env, void* externalPointer, void* data) {
184 auto info = reinterpret_cast<NapiFunctionInfo*>(data);
185 if (info != nullptr) {
186 delete info;
187 }
188 },
189 reinterpret_cast<void*>(funcInfo), true);
190
191 Local<panda::StringRef> fnName = panda::StringRef::NewFromUtf8(vm, className.c_str());
192 fn->SetName(vm, fnName);
193
194 if (length == 0) {
195 return fn;
196 }
197 Local<panda::ObjectRef> classPrototype = fn->GetFunctionPrototype(vm);
198 Local<panda::ObjectRef> fnObj = fn->ToObject(vm);
199 for (size_t i = 0; i < length; i++) {
200 if (properties[i].attributes & NATIVE_STATIC) {
201 NapiDefineProperty(env, fnObj, properties[i]);
202 } else {
203 if (classPrototype->IsUndefined()) {
204 HILOG_ERROR("ArkNativeEngineImpl::Class's prototype is null");
205 continue;
206 }
207 reinterpret_cast<ArkNativeEngine*>(env)->SetModuleName(classPrototype, className);
208 NapiDefineProperty(env, classPrototype, properties[i]);
209 }
210 }
211
212 return fn;
213 }
214
NapiNativeCreateSendableFunction(napi_env env,const char * name,NapiNativeCallback cb,void * value)215 Local<panda::JSValueRef> NapiNativeCreateSendableFunction(napi_env env,
216 const char* name,
217 NapiNativeCallback cb,
218 void* value)
219 {
220 auto engine = reinterpret_cast<NativeEngine*>(env);
221 auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
222 NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
223 if (funcInfo == nullptr) {
224 HILOG_ERROR("funcInfo is nullptr");
225 return JSValueRef::Undefined(vm);
226 }
227 funcInfo->callback = cb;
228 funcInfo->data = value;
229
230 Local<panda::FunctionRef> fn = panda::FunctionRef::NewSendable(
231 vm, ArkNativeFunctionCallBack,
232 [](void* env, void* externalPointer, void* data) {
233 auto info = reinterpret_cast<NapiFunctionInfo*>(data);
234 if (info != nullptr) {
235 delete info;
236 }
237 },
238 reinterpret_cast<void*>(funcInfo), true);
239 return fn;
240 }
241
NapiDefineSendableClass(napi_env env,const char * name,NapiNativeCallback callback,void * data,const NapiPropertyDescriptor * properties,size_t propertiesLength,napi_value parent)242 panda::Local<panda::JSValueRef> NapiDefineSendableClass(napi_env env,
243 const char* name,
244 NapiNativeCallback callback,
245 void* data,
246 const NapiPropertyDescriptor* properties,
247 size_t propertiesLength,
248 napi_value parent)
249 {
250 const EcmaVM* vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
251 NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
252 if (funcInfo == nullptr) {
253 HILOG_FATAL("funcInfo is nullptr");
254 return JSValueRef::Undefined(vm);
255 }
256 funcInfo->callback = callback;
257 funcInfo->data = data;
258
259 std::string className(name);
260 if (ArkNativeEngine::napiProfilerEnabled) {
261 className = ArkNativeEngine::tempModuleName_ + "." + name;
262 }
263
264 Local<panda::StringRef> fnName = panda::StringRef::NewFromUtf8(vm, className.c_str());
265 Local<JSValueRef> localParent = JSValueRef::Null(vm);
266 if (parent != nullptr) {
267 localParent = LocalValueFromJsValue(parent);
268 }
269
270 auto infos = NativeSendable::CreateSendablePropertiesInfos(env, properties, propertiesLength);
271 Local<panda::FunctionRef> fn = panda::FunctionRef::NewSendableClassFunction(
272 vm, ArkNativeFunctionCallBack,
273 [](void* env, void* externalPointer, void* data) {
274 auto info = reinterpret_cast<NapiFunctionInfo*>(data);
275 if (info != nullptr) {
276 delete info;
277 }
278 },
279 reinterpret_cast<void*>(funcInfo), fnName, infos, localParent, true);
280
281 return fn;
282 }
283
284 struct MoudleNameLocker {
MoudleNameLockerMoudleNameLocker285 explicit MoudleNameLocker(std::string moduleName)
286 {
287 ArkNativeEngine::tempModuleName_ = moduleName;
288 }
~MoudleNameLockerMoudleNameLocker289 ~MoudleNameLocker()
290 {
291 ArkNativeEngine::tempModuleName_ = "";
292 }
293 };
294
GetNativePtrCallBack(void * data)295 void* ArkNativeEngine::GetNativePtrCallBack(void* data)
296 {
297 if (data == nullptr) {
298 HILOG_ERROR("data is nullptr");
299 return nullptr;
300 }
301 auto info = reinterpret_cast<NapiFunctionInfo*>(data);
302 auto cb = reinterpret_cast<void*>(info->callback);
303 return cb;
304 }
305
CheckArkApiAllowList(NativeModule * module,panda::ecmascript::ApiCheckContext context,panda::Local<panda::ObjectRef> & exportCopy)306 bool ArkNativeEngine::CheckArkApiAllowList(
307 NativeModule* module, panda::ecmascript::ApiCheckContext context, panda::Local<panda::ObjectRef>& exportCopy)
308 {
309 std::unique_ptr<ApiAllowListChecker>& apiAllowListChecker = module->apiAllowListChecker;
310 if (apiAllowListChecker != nullptr) {
311 const std::string apiPath = context.moduleName->ToString(context.ecmaVm);
312 if ((*apiAllowListChecker)(apiPath)) {
313 CopyPropertyApiFilter(apiAllowListChecker, context.ecmaVm, context.exportObj, exportCopy, apiPath);
314 }
315 return true;
316 }
317 return false;
318 }
319
CopyPropertyApiFilter(const std::unique_ptr<ApiAllowListChecker> & apiAllowListChecker,const EcmaVM * ecmaVm,const panda::Local<panda::ObjectRef> exportObj,panda::Local<panda::ObjectRef> & exportCopy,const std::string & apiPath)320 void ArkNativeEngine::CopyPropertyApiFilter(const std::unique_ptr<ApiAllowListChecker>& apiAllowListChecker,
321 const EcmaVM* ecmaVm, const panda::Local<panda::ObjectRef> exportObj, panda::Local<panda::ObjectRef>& exportCopy,
322 const std::string& apiPath)
323 {
324 panda::Local<panda::ArrayRef> namesArrayRef = exportObj->GetAllPropertyNames(ecmaVm, NATIVE_DEFAULT);
325 for (uint32_t i = 0; i < namesArrayRef->Length(ecmaVm); ++i) {
326 const panda::Local<panda::JSValueRef> nameValue = panda::ArrayRef::GetValueAt(ecmaVm, namesArrayRef, i);
327 const panda::Local<panda::JSValueRef> value = exportObj->Get(ecmaVm, nameValue);
328 const std::string curPath = apiPath + "." + nameValue->ToString(ecmaVm)->ToString(ecmaVm);
329 if ((*apiAllowListChecker)(curPath)) {
330 const std::string valueType = value->Typeof(ecmaVm)->ToString(ecmaVm);
331 if (valueType == "object") {
332 panda::Local<panda::ObjectRef> subObject = ObjectRef::New(ecmaVm);
333 CopyPropertyApiFilter(apiAllowListChecker, ecmaVm, value, subObject, curPath);
334 exportCopy->Set(ecmaVm, nameValue, subObject);
335 HILOG_DEBUG("Set the package '%{public}s' to the allow list", curPath.c_str());
336 } else if (valueType == "function") {
337 exportCopy->Set(ecmaVm, nameValue, value);
338 HILOG_DEBUG("Set the function '%{public}s' to the allow list", curPath.c_str());
339 } else {
340 exportCopy->Set(ecmaVm, nameValue, value);
341 HILOG_DEBUG("Set the element type is '%{public}s::%{public}s' to the allow list", valueType.c_str(),
342 curPath.c_str());
343 }
344 }
345 }
346 }
347
ArkNativeEngine(EcmaVM * vm,void * jsEngine,bool isLimitedWorker)348 ArkNativeEngine::ArkNativeEngine(EcmaVM* vm, void* jsEngine, bool isLimitedWorker) : NativeEngine(jsEngine),
349 vm_(vm),
350 topScope_(vm),
351 isLimitedWorker_(isLimitedWorker)
352 {
353 HILOG_DEBUG("ArkNativeEngine::ArkNativeEngine");
354 panda::JSNApi::SetEnv(vm, this);
355 #ifdef ENABLE_HITRACE
356 if (!ArkNativeEngine::napiProfilerParamReaded) {
357 char napiProfilerParam[NAPI_PROFILER_PARAM_SIZE] = {0};
358 int ret = GetParameter("persist.hiviewdfx.napiprofiler.enabled", "false",
359 napiProfilerParam, sizeof(napiProfilerParam));
360 if (ret > 0 && strcmp(napiProfilerParam, "true") == 0) {
361 ArkNativeEngine::napiProfilerEnabled = true;
362 }
363 ArkNativeEngine::napiProfilerParamReaded = true;
364 }
365 #endif
366 LocalScope scope(vm_);
367 Local<StringRef> requireInternalName = StringRef::NewFromUtf8(vm, "requireInternal");
368 void* requireData = static_cast<void*>(this);
369
370 options_ = new NapiOptions();
371 crossThreadCheck_ = JSNApi::IsMultiThreadCheckEnabled(vm);
372 #if defined(OHOS_PLATFORM) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
373 int napiProperties = OHOS::system::GetIntParameter<int>("persist.ark.napi.properties", -1);
374 if (options_ != nullptr) {
375 options_->SetProperties(napiProperties);
376 }
377 #endif
378 Local<FunctionRef> requireNapi =
379 FunctionRef::New(
380 vm,
381 [](JsiRuntimeCallInfo *info) -> Local<JSValueRef> {
382 EcmaVM *ecmaVm = info->GetVM();
383 panda::EscapeLocalScope scope(ecmaVm);
384 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
385 ArkNativeEngine* arkNativeEngine = static_cast<ArkNativeEngine*>(info->GetData());
386 Local<StringRef> moduleName(info->GetCallArgRef(0));
387 NativeModule* module = nullptr;
388 bool isAppModule = false;
389 std::string errInfo = "";
390 Local<JSValueRef> exports(JSValueRef::Undefined(ecmaVm));
391 #ifdef IOS_PLATFORM
392 if (arkNativeEngine->isLimitedWorker_) {
393 if (!moduleManager->CheckModuleRestricted(moduleName->ToString(ecmaVm).c_str())) {
394 HILOG_ERROR("module %{public}s does not found in whitelist",
395 moduleName->ToString(ecmaVm).c_str());
396 return scope.Escape(exports);
397 }
398 }
399 module = moduleManager->LoadNativeModule(
400 moduleName->ToString(ecmaVm).c_str(), nullptr, false, errInfo, false, "");
401 #else
402 const uint32_t lengthMax = 2;
403 if (info->GetArgsNumber() >= lengthMax) {
404 Local<BooleanRef> ret(info->GetCallArgRef(1));
405 isAppModule = ret->Value();
406 }
407 arkNativeEngine->isAppModule_ = isAppModule;
408 if (arkNativeEngine->isLimitedWorker_ && !isAppModule) {
409 if (!moduleManager->CheckModuleRestricted(moduleName->ToString(ecmaVm).c_str())) {
410 HILOG_ERROR("module %{public}s does not found in whitelist",
411 moduleName->ToString(ecmaVm).c_str());
412 return scope.Escape(exports);
413 }
414 }
415
416 if (info->GetArgsNumber() == 3) { // 3:Determine if the number of parameters is equal to 3
417 Local<StringRef> path(info->GetCallArgRef(2)); // 2:Take the second parameter
418 module = moduleManager->LoadNativeModule(moduleName->ToString(ecmaVm).c_str(),
419 path->ToString(ecmaVm).c_str(), isAppModule, errInfo, false, "");
420 } else if (info->GetArgsNumber() == 4) { // 4:Determine if the number of parameters is equal to 4
421 Local<StringRef> path(info->GetCallArgRef(2)); // 2:Take the second parameter
422 Local<StringRef> relativePath(info->GetCallArgRef(3)); // 3:Take the second parameter
423 module = moduleManager->LoadNativeModule(moduleName->ToString(ecmaVm).c_str(), nullptr, isAppModule,
424 errInfo, false, relativePath->ToString(ecmaVm).c_str());
425 } else {
426 module =
427 moduleManager->LoadNativeModule(moduleName->ToString(ecmaVm).c_str(),
428 nullptr, isAppModule, errInfo, false, "");
429 }
430 #endif
431 if (module != nullptr) {
432 auto it = arkNativeEngine->loadedModules_.find(module);
433 if (it != arkNativeEngine->loadedModules_.end()) {
434 return scope.Escape(it->second.ToLocal(ecmaVm));
435 }
436 std::string strModuleName = moduleName->ToString(ecmaVm);
437 moduleManager->SetNativeEngine(strModuleName, arkNativeEngine);
438 MoudleNameLocker nameLocker(strModuleName);
439
440 if (module->jsCode == nullptr && module->getABCCode != nullptr) {
441 module->getABCCode(&module->jsCode, &module->jsCodeLen);
442 }
443 if (module->jsABCCode != nullptr || module->jsCode != nullptr) {
444 char fileName[NAPI_PATH_MAX] = { 0 };
445 const char* name = module->name;
446 if (sprintf_s(fileName, sizeof(fileName), "lib%s.z.so/%s.js", name, name) == -1) {
447 HILOG_ERROR("sprintf_s file name failed");
448 return scope.Escape(exports);
449 }
450 HILOG_DEBUG("load js code from %{public}s", fileName);
451 const void *buffer = nullptr;
452 if (module->jsABCCode) {
453 buffer = static_cast<const void *>(module->jsABCCode);
454 } else {
455 buffer = static_cast<const void *>(module->jsCode);
456 }
457 auto exportObject = arkNativeEngine->LoadArkModule(buffer,
458 module->jsCodeLen, fileName);
459 if (exportObject->IsUndefined()) {
460 HILOG_ERROR("load module failed");
461 return scope.Escape(exports);
462 } else {
463 exports = exportObject;
464 arkNativeEngine->loadedModules_[module] = Global<JSValueRef>(ecmaVm, exports);
465 }
466 } else if (module->registerCallback != nullptr) {
467 Local<ObjectRef> exportObj = ObjectRef::New(ecmaVm);
468 #ifdef ENABLE_HITRACE
469 StartTrace(HITRACE_TAG_ACE, "NAPI module init, name = " + std::string(module->name));
470 #endif
471 arkNativeEngine->SetModuleName(exportObj, module->name);
472 module->registerCallback(reinterpret_cast<napi_env>(arkNativeEngine),
473 JsValueFromLocalValue(exportObj));
474 #ifdef ENABLE_HITRACE
475 FinishTrace(HITRACE_TAG_ACE);
476 #endif
477 panda::Local<panda::ObjectRef> exportCopy = panda::ObjectRef::New(ecmaVm);
478 panda::ecmascript::ApiCheckContext context{moduleManager, ecmaVm, moduleName, exportObj, scope};
479 if (CheckArkApiAllowList(module, context, exportCopy)) {
480 return scope.Escape(exportCopy);
481 }
482 exports = exportObj;
483 arkNativeEngine->loadedModules_[module] = Global<JSValueRef>(ecmaVm, exports);
484 } else {
485 HILOG_ERROR("init module failed");
486 return scope.Escape(exports);
487 }
488 }
489 if (module == nullptr) {
490 HILOG_INFO("%{public}s", errInfo.c_str());
491 exports = panda::ObjectRef::CreateNativeModuleFailureInfo(ecmaVm, errInfo);
492 }
493 return scope.Escape(exports);
494 },
495 nullptr,
496 requireData);
497
498 Local<FunctionRef> requireInternal =
499 FunctionRef::New(
500 vm,
501 [](JsiRuntimeCallInfo *info) -> Local<JSValueRef> {
502 EcmaVM *ecmaVm = info->GetVM();
503 panda::EscapeLocalScope scope(ecmaVm);
504 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
505 ArkNativeEngine* arkNativeEngine = static_cast<ArkNativeEngine*>(info->GetData());
506 Local<StringRef> moduleName(info->GetCallArgRef(0));
507 std::string errInfo = "";
508 Local<JSValueRef> exports(JSValueRef::Undefined(ecmaVm));
509 if (arkNativeEngine->isLimitedWorker_) {
510 if (!moduleManager->CheckModuleRestricted(moduleName->ToString(ecmaVm).c_str())) {
511 HILOG_ERROR("module %{public}s does not found in whitelist",
512 moduleName->ToString(ecmaVm).c_str());
513 return scope.Escape(exports);
514 }
515 }
516 NativeModule* module = moduleManager->LoadNativeModule(moduleName->ToString(ecmaVm).c_str(),
517 nullptr, false, errInfo, false, "");
518 MoudleNameLocker nameLocker(moduleName->ToString(ecmaVm).c_str());
519 if (module != nullptr && arkNativeEngine) {
520 auto it = arkNativeEngine->loadedModules_.find(module);
521 if (it != arkNativeEngine->loadedModules_.end()) {
522 return scope.Escape(it->second.ToLocal(ecmaVm));
523 }
524 std::string strModuleName = moduleName->ToString(ecmaVm);
525 moduleManager->SetNativeEngine(strModuleName, arkNativeEngine);
526 Local<ObjectRef> exportObj = ObjectRef::New(ecmaVm);
527 if (exportObj->IsObject(ecmaVm)) {
528 arkNativeEngine->SetModuleName(exportObj, module->name);
529 module->registerCallback(reinterpret_cast<napi_env>(arkNativeEngine),
530 JsValueFromLocalValue(exportObj));
531 exports = exportObj;
532 arkNativeEngine->loadedModules_[module] = Global<JSValueRef>(ecmaVm, exports);
533 } else {
534 HILOG_ERROR("exportObject is nullptr");
535 return scope.Escape(exports);
536 }
537 }
538 return scope.Escape(exports);
539 },
540 nullptr,
541 requireData);
542
543 Local<ObjectRef> global = panda::JSNApi::GetGlobalObject(vm);
544 #if !defined(PREVIEW)
545 Local<StringRef> requireName = StringRef::NewFromUtf8(vm, "requireNapi");
546 global->Set(vm, requireName, requireNapi);
547 #else
548 Local<StringRef> requireNapiPreview = StringRef::NewFromUtf8(vm, "requireNapiPreview");
549 global->Set(vm, requireNapiPreview, requireNapi);
550 #endif
551 global->Set(vm, requireInternalName, requireInternal);
552 JSNApi::SetNativePtrGetter(vm, reinterpret_cast<void*>(ArkNativeEngine::GetNativePtrCallBack));
553 // need to call init of base class.
554 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
555 std::function<bool(const std::string&)> func = [moduleManager](const std::string& moduleKey) -> bool {
556 return moduleManager->UnloadNativeModule(moduleKey);
557 };
558 JSNApi::SetUnloadNativeModuleCallback(vm, func);
559 Init();
560 panda::JSNApi::SetLoop(vm, loop_);
561 panda::JSNApi::SetWeakFinalizeTaskCallback(vm, [this] () -> void {
562 this->PostFinalizeTasks();
563 });
564 JSNApi::SetAsyncCleanTaskCallback(vm, [this] (AsyncNativeCallbacksPack *callbacksPack) {
565 this->PostAsyncTask(callbacksPack);
566 });
567 #if defined(ENABLE_EVENT_HANDLER)
568 if (JSNApi::IsJSMainThreadOfEcmaVM(vm)) {
569 arkIdleMonitor_ = std::make_shared<ArkIdleMonitor>(vm);
570 JSNApi::SetTriggerGCTaskCallback(vm, [this](TriggerGCData& data) {
571 this->PostTriggerGCTask(data);
572 });
573 arkIdleMonitor_->SetStartTimerCallback();
574 PostLooperTriggerIdleGCTask();
575 }
576 #endif
577 }
578
~ArkNativeEngine()579 ArkNativeEngine::~ArkNativeEngine()
580 {
581 HILOG_DEBUG("ArkNativeEngine::~ArkNativeEngine");
582 Deinit();
583 // Free cached objects
584 for (auto&& [module, exportObj] : loadedModules_) {
585 exportObj.FreeGlobalHandleAddr();
586 }
587 // Free callbackRef
588 if (promiseRejectCallbackRef_ != nullptr) {
589 delete promiseRejectCallbackRef_;
590 }
591 if (checkCallbackRef_ != nullptr) {
592 delete checkCallbackRef_;
593 }
594 if (options_ != nullptr) {
595 delete options_;
596 options_ = nullptr;
597 }
598 }
599
600 #ifdef ENABLE_HITRACE
CheckHookConfig(const std::string & nameRef)601 static inline bool CheckHookConfig(const std::string &nameRef)
602 {
603 if (g_hookJsConfig == nullptr || g_hookJsConfig->jsStackReport <= 0 ||
604 g_hookJsConfig->maxJsStackDepth == 0 || !g_hookJsConfig->jsFpUnwind) {
605 return false;
606 } else if (g_hookJsConfig->filterNapiName[0] != '\0' &&
607 nameRef.find(g_hookJsConfig->filterNapiName) != std::string::npos) {
608 return false;
609 }
610 return true;
611 }
612 #endif
613
StartNapiProfilerTrace(panda::JsiRuntimeCallInfo * runtimeInfo,void * cb)614 static inline uint64_t StartNapiProfilerTrace(panda::JsiRuntimeCallInfo* runtimeInfo, void* cb)
615 {
616 #ifdef ENABLE_HITRACE
617 if (ArkNativeEngine::napiProfilerEnabled) {
618 EcmaVM *vm = runtimeInfo->GetVM();
619 LocalScope scope(vm);
620 Local<panda::FunctionRef> fn = runtimeInfo->GetFunctionRef();
621 Local<panda::StringRef> nameRef = fn->GetName(vm);
622 char threadName[BUF_SIZE];
623 prctl(PR_GET_NAME, threadName);
624 StartTraceArgs(HITRACE_TAG_ACE, "Napi called:%s, tname:%s", nameRef->ToString(vm).c_str(), threadName);
625 }
626 bool hookFlag = __get_hook_flag() && __get_global_hook_flag();
627 if (!hookFlag) {
628 return 0;
629 }
630 EcmaVM* vm = runtimeInfo->GetVM();
631 LocalScope scope(vm);
632 Local<panda::FunctionRef> fn = runtimeInfo->GetFunctionRef();
633 Local<panda::StringRef> nameRef = fn->GetName(vm);
634 if (g_hookJsConfig == nullptr) {
635 std::call_once(g_hookOnceFlag, []() { g_hookJsConfig = (HookJsConfig*)__get_hook_config(); });
636 }
637 // add memtrace function
638 if (g_hookJsConfig != nullptr && g_hookJsConfig->jsStackReport == NAPI_CALL_STACK && !g_hookJsConfig->jsFpUnwind) {
639 OHOS::HiviewDFX::HiTraceChain::ClearId();
640 std::unique_ptr<OHOS::HiviewDFX::HiTraceId> arkCallBackTraceId = std::make_unique<OHOS::HiviewDFX::HiTraceId>(
641 OHOS::HiviewDFX::HiTraceChain::Begin("New ArkCallBackTrace", 0));
642 char buffer[256] = {0}; // 256 : buffer size of tag name
643 if (sprintf_s(buffer, sizeof(buffer), "napi:0x%x:%s", arkCallBackTraceId->GetChainId(),
644 nameRef->ToString(vm).c_str()) == -1) {
645 return 0;
646 }
647 uint64_t addr = reinterpret_cast<uint64_t>(cb);
648 ++g_chainId;
649 (void)memtrace(reinterpret_cast<void*>(addr + g_chainId), 8, buffer, true); // 8: the size of addr
650 return 0;
651 }
652 if (!CheckHookConfig(nameRef->ToString(vm))) {
653 return 0;
654 }
655 BlockHookScope blockHook; // block hook
656 std::string rawStack;
657 std::vector<JsFrameInfo> jsFrames;
658 uint64_t nestChainId = 0;
659 jsFrames.reserve(g_hookJsConfig->maxJsStackDepth);
660 auto env = reinterpret_cast<napi_env>(JSNApi::GetEnv(vm));
661 auto engine = reinterpret_cast<NativeEngine*>(env);
662 engine->BuildJsStackInfoListWithCustomDepth(jsFrames);
663 std::stringstream ssRawStack;
664 for (size_t i = 0; i < jsFrames.size() && i < g_hookJsConfig->maxJsStackDepth; i++) {
665 ssRawStack << jsFrames[i].functionName << JS_SYMBOL_FILEPATH_SEP << jsFrames[i].fileName << ":" <<
666 jsFrames[i].pos;
667 if (i < jsFrames.size() - 1) {
668 ssRawStack << JS_CALL_STACK_DEPTH_SEP;
669 }
670 }
671 rawStack = ssRawStack.str();
672 OHOS::HiviewDFX::HiTraceChain::Begin("ArkNativeFunctionCallBack", 0);
673 OHOS::HiviewDFX::HiTraceId hitraceId = OHOS::HiviewDFX::HiTraceChain::GetId();
674 // resolve nested calls to napi and ts
675 if (hitraceId.IsValid()) {
676 nestChainId = hitraceId.GetChainId();
677 }
678 uint64_t chainId = ++g_chainId;
679 hitraceId.SetChainId(chainId);
680 OHOS::HiviewDFX::HiTraceChain::SetId(hitraceId);
681 __send_hook_misc_data(chainId, rawStack.c_str(), rawStack.size() + 1, 1);
682 return nestChainId;
683
684 #endif
685 return 0;
686 }
687
FinishNapiProfilerTrace(uint64_t value)688 static inline void FinishNapiProfilerTrace(uint64_t value)
689 {
690 #ifdef ENABLE_HITRACE
691 if (ArkNativeEngine::napiProfilerEnabled) {
692 FinishTrace(HITRACE_TAG_ACE);
693 }
694 bool hookFlag = __get_hook_flag() && __get_global_hook_flag();
695 if (!hookFlag) {
696 return;
697 }
698 BlockHookScope blockHook; // block hook
699 OHOS::HiviewDFX::HiTraceId hitraceId = OHOS::HiviewDFX::HiTraceChain::GetId();
700 if (hitraceId.IsValid()) {
701 OHOS::HiviewDFX::HiTraceChain::End(hitraceId);
702 OHOS::HiviewDFX::HiTraceChain::ClearId();
703 }
704 // resolve nested calls to napi and ts
705 if (value) {
706 hitraceId.SetChainId(value);
707 OHOS::HiviewDFX::HiTraceChain::SetId(hitraceId);
708 }
709
710 #endif
711 }
712
713 template <bool changeState>
ArkNativeFunctionCallBack(JsiRuntimeCallInfo * runtimeInfo)714 panda::JSValueRef ArkNativeFunctionCallBack(JsiRuntimeCallInfo *runtimeInfo)
715 {
716 EcmaVM *vm = runtimeInfo->GetVM();
717 panda::LocalScope scope(vm);
718 bool getStackBeforeCallNapiSuccess = false;
719 JSNApi::GetStackBeforeCallNapiSuccess(vm, getStackBeforeCallNapiSuccess);
720 auto info = reinterpret_cast<NapiFunctionInfo*>(runtimeInfo->GetData());
721 auto env = reinterpret_cast<napi_env>(JSNApi::GetEnv(vm));
722 auto engine = reinterpret_cast<NativeEngine*>(env);
723 auto cb = info->callback;
724 if (engine == nullptr) {
725 HILOG_ERROR("native engine is null");
726 return **JSValueRef::Undefined(vm);
727 }
728 uint64_t nestChainId = StartNapiProfilerTrace(runtimeInfo, reinterpret_cast<void *>(cb));
729 if (JSNApi::IsMixedDebugEnabled(vm)) {
730 JSNApi::NotifyNativeCalling(vm, reinterpret_cast<void *>(cb));
731 }
732
733 napi_value result = nullptr;
734 if (cb != nullptr) {
735 if constexpr (changeState) {
736 panda::JsiNativeScope nativeScope(vm);
737 result = cb(env, runtimeInfo);
738 } else {
739 result = cb(env, runtimeInfo);
740 }
741 }
742
743 if (JSNApi::IsMixedDebugEnabled(vm)) {
744 JSNApi::NotifyNativeReturn(vm, reinterpret_cast<void *>(cb));
745 }
746
747 Local<panda::JSValueRef> localRet = panda::JSValueRef::Undefined(vm);
748 if (result != nullptr) {
749 localRet = LocalValueFromJsValue(result);
750 }
751
752 FinishNapiProfilerTrace(nestChainId);
753 // Fixme: Rethrow error to engine while clear lastException_
754 if (!engine->lastException_.IsEmpty()) {
755 engine->lastException_.Empty();
756 }
757
758 if (localRet.IsEmpty()) {
759 return **JSValueRef::Undefined(vm);
760 }
761 if (getStackBeforeCallNapiSuccess) {
762 JSNApi::GetStackAfterCallNapi(vm);
763 }
764 return **localRet;
765 }
766
NapiNativeCreateFunction(napi_env env,const char * name,NapiNativeCallback cb,void * value)767 static Local<panda::JSValueRef> NapiNativeCreateFunction(napi_env env, const char* name,
768 NapiNativeCallback cb, void* value)
769 {
770 auto engine = reinterpret_cast<NativeEngine*>(env);
771 auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
772 NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
773 if (funcInfo == nullptr) {
774 HILOG_ERROR("funcInfo is nullptr");
775 return JSValueRef::Undefined(vm);
776 }
777 funcInfo->callback = cb;
778 funcInfo->data = value;
779 #ifdef ENABLE_CONTAINER_SCOPE
780 funcInfo->scopeId = OHOS::Ace::ContainerScope::CurrentId();
781 #endif
782
783 Local<panda::FunctionRef> fn = panda::FunctionRef::NewConcurrent(
784 vm, ArkNativeFunctionCallBack,
785 [](void* env, void* externalPointer, void* data) {
786 auto info = reinterpret_cast<NapiFunctionInfo*>(data);
787 if (info != nullptr) {
788 delete info;
789 }
790 },
791 reinterpret_cast<void*>(funcInfo), true
792 );
793 Local<panda::StringRef> fnName = panda::StringRef::NewFromUtf8(vm, name);
794 fn->SetName(vm, fnName);
795 return fn;
796 }
797
GetProperty(EcmaVM * vm,Local<panda::ObjectRef> & obj,const char * name)798 static Local<JSValueRef> GetProperty(EcmaVM* vm, Local<panda::ObjectRef> &obj, const char* name)
799 {
800 Local<StringRef> key = StringRef::NewFromUtf8(vm, name);
801 Local<JSValueRef> val = obj->Get(vm, key);
802 return val;
803 }
804
GetCString(EcmaVM * vm,Local<StringRef> str,char * buffer,size_t size,size_t * length)805 void GetCString(EcmaVM* vm, Local<StringRef> str, char* buffer, size_t size, size_t* length)
806 {
807 if (length == nullptr) {
808 return;
809 }
810 if (buffer == nullptr) {
811 *length = str->Utf8Length(vm, true) - 1;
812 } else if (size != 0) {
813 int copied = str->WriteUtf8(vm, buffer, size - 1, true) - 1;
814 buffer[copied] = '\0';
815 *length = copied;
816 } else {
817 *length = 0;
818 }
819 }
820
NapiGetModuleName(napi_env env,Local<panda::ObjectRef> & obj)821 std::string NapiGetModuleName(napi_env env, Local<panda::ObjectRef> &obj)
822 {
823 auto engine = reinterpret_cast<NativeEngine*>(env);
824 auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
825 std::string moduleName("");
826 auto nativeModuleName = GetProperty(vm, obj, PANDA_MODULE_NAME);
827 if (nativeModuleName->IsString(vm)) {
828 char arrayName[PANDA_MODULE_NAME_LEN] = {0};
829 size_t len = 0;
830 GetCString(vm, nativeModuleName, arrayName, PANDA_MODULE_NAME_LEN, &len);
831 moduleName += arrayName;
832 moduleName += ".";
833 }
834 return moduleName;
835 }
836
NapiDefinePropertyInner(napi_env env,Local<panda::ObjectRef> & obj,NapiPropertyDescriptor & propertyDescriptor,Local<panda::JSValueRef> & propertyName,bool & result)837 void NapiDefinePropertyInner(napi_env env,
838 Local<panda::ObjectRef> &obj,
839 NapiPropertyDescriptor &propertyDescriptor,
840 Local<panda::JSValueRef> &propertyName,
841 bool &result)
842 {
843 auto engine = reinterpret_cast<NativeEngine*>(env);
844 auto vm = engine->GetEcmaVm();
845 bool writable = (propertyDescriptor.attributes & NATIVE_WRITABLE) != 0;
846 bool enumable = (propertyDescriptor.attributes & NATIVE_ENUMERABLE) != 0;
847 bool configable = (propertyDescriptor.attributes & NATIVE_CONFIGURABLE) != 0;
848 std::string fullName("");
849 if (propertyDescriptor.getter != nullptr || propertyDescriptor.setter != nullptr) {
850 #ifdef ENABLE_HITRACE
851 fullName += NapiGetModuleName(env, obj);
852 #endif
853 Local<panda::JSValueRef> localGetter = panda::JSValueRef::Undefined(vm);
854 Local<panda::JSValueRef> localSetter = panda::JSValueRef::Undefined(vm);
855
856 if (propertyDescriptor.getter != nullptr) {
857 fullName += "getter";
858 localGetter = NapiNativeCreateFunction(env, fullName.c_str(),
859 propertyDescriptor.getter, propertyDescriptor.data);
860 }
861 if (propertyDescriptor.setter != nullptr) {
862 fullName += "setter";
863 localSetter = NapiNativeCreateFunction(env, fullName.c_str(),
864 propertyDescriptor.setter, propertyDescriptor.data);
865 }
866
867 PropertyAttribute attr(panda::JSValueRef::Undefined(vm), false, enumable, configable);
868 result = obj->SetAccessorProperty(vm, propertyName, localGetter, localSetter, attr);
869 } else if (propertyDescriptor.method != nullptr) {
870 #ifdef ENABLE_HITRACE
871 fullName += NapiGetModuleName(env, obj);
872 #endif
873 if (propertyDescriptor.utf8name != nullptr) {
874 fullName += propertyDescriptor.utf8name;
875 } else {
876 fullName += propertyName->IsString(vm)
877 ? Local<panda::StringRef>(propertyName)->ToString(vm)
878 : Local<panda::SymbolRef>(propertyName)->GetDescription(vm)->ToString(vm);
879 }
880 Local<panda::JSValueRef> cbObj = NapiNativeCreateFunction(env, fullName.c_str(),
881 propertyDescriptor.method, propertyDescriptor.data);
882 PropertyAttribute attr(cbObj, writable, enumable, configable);
883 result = obj->DefineProperty(vm, propertyName, attr);
884 } else {
885 Local<panda::JSValueRef> val = LocalValueFromJsValue(propertyDescriptor.value);
886
887 PropertyAttribute attr(val, writable, enumable, configable);
888 result = obj->DefineProperty(vm, propertyName, attr);
889 }
890 }
891
NapiDefineProperty(napi_env env,Local<panda::ObjectRef> & obj,NapiPropertyDescriptor propertyDescriptor)892 bool NapiDefineProperty(napi_env env, Local<panda::ObjectRef> &obj, NapiPropertyDescriptor propertyDescriptor)
893 {
894 auto engine = reinterpret_cast<NativeEngine*>(env);
895 auto vm = engine->GetEcmaVm();
896 bool result = false;
897 Local<panda::JSValueRef> propertyName;
898 if (propertyDescriptor.utf8name != nullptr) {
899 propertyName = panda::StringRef::NewFromUtf8(vm, propertyDescriptor.utf8name);
900 } else {
901 propertyName = LocalValueFromJsValue(propertyDescriptor.name);
902 }
903 if (obj->IsJSShared(vm)) {
904 NativeSendable::NapiDefineSendabledProperty(env, obj, propertyDescriptor, propertyName, result);
905 } else {
906 NapiDefinePropertyInner(env, obj, propertyDescriptor, propertyName, result);
907 }
908 Local<panda::ObjectRef> excep = panda::JSNApi::GetUncaughtException(vm);
909 if (!excep.IsNull()) {
910 HILOG_DEBUG("ArkNativeObject::DefineProperty occur Exception");
911 panda::JSNApi::GetAndClearUncaughtException(vm);
912 }
913 return result;
914 }
915
NapiCreateObjectWithProperties(napi_env env,size_t propertyCount,const napi_property_descriptor * properties,Local<panda::JSValueRef> * keys,PropertyAttribute * attrs)916 panda::Local<panda::ObjectRef> NapiCreateObjectWithProperties(napi_env env, size_t propertyCount,
917 const napi_property_descriptor *properties,
918 Local<panda::JSValueRef> *keys,
919 PropertyAttribute *attrs)
920 {
921 auto vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
922 panda::EscapeLocalScope scope(vm);
923 for (size_t i = 0; i < propertyCount; ++i) {
924 const napi_property_descriptor &property = properties[i];
925
926 const char* utf8name = property.utf8name;
927 uint32_t attributes = property.attributes;
928 bool writable = (attributes & NATIVE_WRITABLE) != 0;
929 bool enumable = (attributes & NATIVE_ENUMERABLE) != 0;
930 bool configable = (attributes & NATIVE_CONFIGURABLE) != 0;
931 NapiNativeCallback method = reinterpret_cast<NapiNativeCallback>(property.method);
932 NapiNativeCallback getter = reinterpret_cast<NapiNativeCallback>(property.getter);
933 NapiNativeCallback setter = reinterpret_cast<NapiNativeCallback>(property.setter);
934 napi_value value = property.value;
935 void *data = property.data;
936
937 Local<panda::JSValueRef> val = panda::JSValueRef::Undefined(vm);
938
939 std::string fullName("");
940 if (getter != nullptr || setter != nullptr) {
941 Local<panda::JSValueRef> localGetter = panda::JSValueRef::Undefined(vm);
942 Local<panda::JSValueRef> localSetter = panda::JSValueRef::Undefined(vm);
943
944 if (getter != nullptr) {
945 fullName += "getter";
946 localGetter = NapiNativeCreateFunction(env, fullName.c_str(), getter, data);
947 }
948 if (setter != nullptr) {
949 fullName += "setter";
950 localSetter = NapiNativeCreateFunction(env, fullName.c_str(), setter, data);
951 }
952
953 val = panda::ObjectRef::CreateAccessorData(vm, localGetter, localSetter);
954 writable = false;
955 } else if (method != nullptr) {
956 fullName += utf8name;
957 val = NapiNativeCreateFunction(env, fullName.c_str(), method, data);
958 } else {
959 val = LocalValueFromJsValue(value);
960 }
961 new (reinterpret_cast<void *>(&attrs[i])) PropertyAttribute(val, writable, enumable, configable);
962 keys[i] = panda::StringRef::NewFromUtf8(vm, utf8name);
963 }
964 Local<panda::ObjectRef> object = panda::ObjectRef::NewWithProperties(vm, propertyCount, keys, attrs);
965 return scope.Escape(object);
966 }
967
NapiCreateSObjectWithProperties(napi_env env,size_t propertyCount,const NapiPropertyDescriptor * properties)968 panda::Local<panda::ObjectRef> NapiCreateSObjectWithProperties(napi_env env,
969 size_t propertyCount,
970 const NapiPropertyDescriptor* properties)
971 {
972 auto vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
973 panda::EscapeLocalScope scope(vm);
974 FunctionRef::SendablePropertiesInfo info;
975 for (size_t i = 0; i < propertyCount; ++i) {
976 NativeSendable::InitSendablePropertiesInfo(env, info, properties[i]);
977 }
978 Local<panda::ObjectRef> object = panda::ObjectRef::NewSWithProperties(vm, info);
979 return scope.Escape(object);
980 }
981
GetModuleFromName(const std::string & moduleName,bool isAppModule,const std::string & id,const std::string & param,const std::string & instanceName,void ** instance)982 panda::Local<panda::ObjectRef> ArkNativeEngine::GetModuleFromName(
983 const std::string& moduleName, bool isAppModule, const std::string& id, const std::string& param,
984 const std::string& instanceName, void** instance)
985 {
986 panda::EscapeLocalScope scope(vm_);
987 Local<ObjectRef> exports(JSValueRef::Undefined(vm_));
988 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
989 std::string errInfo = "";
990 NativeModule* module = moduleManager->LoadNativeModule(moduleName.c_str(), nullptr, isAppModule, errInfo);
991 if (module != nullptr) {
992 Local<StringRef> idStr = StringRef::NewFromUtf8(vm_, id.c_str(), id.size());
993 napi_value idValue = JsValueFromLocalValue(idStr);
994 Local<StringRef> paramStr = StringRef::NewFromUtf8(vm_, param.c_str(), param.size());
995 napi_value paramValue = JsValueFromLocalValue(paramStr);
996 Local<ObjectRef> exportObj = ObjectRef::New(vm_);
997 NapiPropertyDescriptor idProperty, paramProperty;
998 idProperty.utf8name = "id";
999 idProperty.value = idValue;
1000 paramProperty.utf8name = "param";
1001 paramProperty.value = paramValue;
1002 SetModuleName(exportObj, module->name);
1003 NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, idProperty);
1004 NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, paramProperty);
1005 MoudleNameLocker nameLocker(module->name);
1006 module->registerCallback(reinterpret_cast<napi_env>(this), JsValueFromLocalValue(exportObj));
1007 napi_value nExport = JsValueFromLocalValue(exportObj);
1008 napi_value exportInstance = nullptr;
1009 napi_status status = napi_get_named_property(
1010 reinterpret_cast<napi_env>(this), nExport, instanceName.c_str(), &exportInstance);
1011 if (status != napi_ok) {
1012 HILOG_ERROR("GetModuleFromName napi_get_named_property status != napi_ok");
1013 }
1014
1015 status = napi_unwrap(reinterpret_cast<napi_env>(this), exportInstance, reinterpret_cast<void**>(instance));
1016 if (status != napi_ok) {
1017 HILOG_ERROR("GetModuleFromName napi_unwrap status != napi_ok");
1018 }
1019 exports = exportObj;
1020 }
1021 return scope.Escape(exports);
1022 }
1023
CreatePromise(NativeDeferred ** deferred)1024 napi_value ArkNativeEngine::CreatePromise(NativeDeferred** deferred)
1025 {
1026 panda::EscapeLocalScope scope(vm_);
1027 Local<PromiseCapabilityRef> capability = PromiseCapabilityRef::New(vm_);
1028 *deferred = new ArkNativeDeferred(this, capability);
1029 Local<JSValueRef> promiseValue = capability->GetPromise(vm_);
1030 return JsValueFromLocalValue(scope.Escape(promiseValue));
1031 }
1032
LoadModuleByName(const std::string & moduleName,bool isAppModule,const std::string & param,const std::string & instanceName,void * instance,const std::string & path)1033 panda::Local<panda::ObjectRef> ArkNativeEngine::LoadModuleByName(const std::string& moduleName, bool isAppModule,
1034 const std::string& param, const std::string& instanceName, void* instance, const std::string& path)
1035 {
1036 panda::EscapeLocalScope scope(vm_);
1037 Local<ObjectRef> exports(JSValueRef::Undefined(vm_));
1038 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
1039 std::string errInfo = "";
1040 NativeModule* module = moduleManager->LoadNativeModule(moduleName.c_str(),
1041 path.empty() ? nullptr : path.c_str(), isAppModule, errInfo);
1042 if (module != nullptr) {
1043 Local<ObjectRef> exportObj = ObjectRef::New(vm_);
1044 NapiPropertyDescriptor paramProperty, instanceProperty;
1045 Local<StringRef> paramStr = StringRef::NewFromUtf8(vm_, param.c_str(), param.size());
1046 napi_value paramValue = JsValueFromLocalValue(paramStr);
1047 paramProperty.utf8name = "param";
1048 paramProperty.value = paramValue;
1049 Local<ObjectRef> instanceValue = ObjectRef::New(vm_);
1050 Local<StringRef> key = StringRef::GetNapiWrapperString(vm_);
1051 if (instance == nullptr && instanceValue->Has(vm_, key)) {
1052 Local<ObjectRef> wrapper = instanceValue->Get(vm_, key);
1053 auto ref = reinterpret_cast<NativeReference*>(wrapper->GetNativePointerField(vm_, 0));
1054 wrapper->SetNativePointerField(vm_, 0, nullptr, nullptr, nullptr, 0);
1055 instanceValue->Delete(vm_, key);
1056 delete ref;
1057 } else {
1058 Local<ObjectRef> object = ObjectRef::New(vm_);
1059 NativeReference* ref = nullptr;
1060 Local<JSValueRef> value(instanceValue);
1061 ref = new ArkNativeReference(this, value, 0, true, nullptr, instance, nullptr);
1062
1063 object->SetNativePointerFieldCount(vm_, 1);
1064 object->SetNativePointerField(vm_, 0, ref, nullptr, nullptr, 0);
1065 PropertyAttribute attr(object, true, false, true);
1066 instanceValue->DefineProperty(vm_, key, attr);
1067 }
1068 instanceProperty.utf8name = instanceName.c_str();
1069 instanceProperty.value = JsValueFromLocalValue(instanceValue);
1070 SetModuleName(exportObj, module->name);
1071 NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, paramProperty);
1072 NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, instanceProperty);
1073
1074 MoudleNameLocker nameLocker(module->name);
1075 module->registerCallback(reinterpret_cast<napi_env>(this), JsValueFromLocalValue(exportObj));
1076 exports = exportObj;
1077 }
1078 return scope.Escape(exports);
1079 }
1080
Loop(LoopMode mode,bool needSync)1081 void ArkNativeEngine::Loop(LoopMode mode, bool needSync)
1082 {
1083 LocalScope scope(vm_);
1084 NativeEngine::Loop(mode, needSync);
1085 panda::JSNApi::ExecutePendingJob(vm_);
1086 }
1087
SetModuleName(Local<ObjectRef> & nativeObj,std::string moduleName)1088 void ArkNativeEngine::SetModuleName(Local<ObjectRef> &nativeObj, std::string moduleName)
1089 {
1090 #ifdef ENABLE_HITRACE
1091 if (ArkNativeEngine::napiProfilerEnabled) {
1092 Local<StringRef> moduleNameStr = StringRef::NewFromUtf8(vm_, moduleName.c_str(), moduleName.size());
1093 Local<StringRef> key = StringRef::NewFromUtf8(vm_, PANDA_MODULE_NAME);
1094 nativeObj->Set(vm_, key, moduleNameStr);
1095 }
1096 #endif
1097 }
1098
ConcurrentCallbackFunc(Local<JSValueRef> result,bool success,void * taskInfo,void * data)1099 static void ConcurrentCallbackFunc(Local<JSValueRef> result, bool success, void *taskInfo, void *data)
1100 {
1101 if (data == nullptr) {
1102 return;
1103 }
1104 auto engine = static_cast<ArkNativeEngine *>(data);
1105 auto concurrentCallbackFunc = engine->GetConcurrentCallbackFunc();
1106 if (concurrentCallbackFunc == nullptr) {
1107 return;
1108 }
1109 napi_env env = reinterpret_cast<napi_env>(engine);
1110 concurrentCallbackFunc(env, ArkNativeEngine::ArkValueToNapiValue(env, result), success, taskInfo);
1111 }
1112
InitTaskPoolThread(NativeEngine * engine,NapiConcurrentCallback callback)1113 bool ArkNativeEngine::InitTaskPoolThread(NativeEngine* engine, NapiConcurrentCallback callback)
1114 {
1115 concurrentCallbackFunc_ = callback;
1116 return JSNApi::InitForConcurrentThread(vm_, ConcurrentCallbackFunc, static_cast<void *>(this));
1117 }
1118
InitTaskPoolThread(napi_env env,NapiConcurrentCallback callback)1119 bool ArkNativeEngine::InitTaskPoolThread(napi_env env, NapiConcurrentCallback callback)
1120 {
1121 concurrentCallbackFunc_ = callback;
1122 return JSNApi::InitForConcurrentThread(vm_, ConcurrentCallbackFunc, static_cast<void *>(this));
1123 }
1124
InitTaskPoolFunc(napi_env env,napi_value func,void * taskInfo)1125 bool ArkNativeEngine::InitTaskPoolFunc(napi_env env, napi_value func, void* taskInfo)
1126 {
1127 LocalScope scope(vm_);
1128 Local<JSValueRef> function = LocalValueFromJsValue(func);
1129 return JSNApi::InitForConcurrentFunction(vm_, function, taskInfo);
1130 }
1131
HasPendingJob() const1132 bool ArkNativeEngine::HasPendingJob() const
1133 {
1134 return JSNApi::HasPendingJob(vm_);
1135 }
1136
IsProfiling() const1137 bool ArkNativeEngine::IsProfiling() const
1138 {
1139 return JSNApi::IsProfiling(vm_);
1140 }
1141
IsExecutingPendingJob() const1142 bool ArkNativeEngine::IsExecutingPendingJob() const
1143 {
1144 return panda::JSNApi::IsExecutingPendingJob(vm_);
1145 }
1146
GetCurrentTaskInfo() const1147 void* ArkNativeEngine::GetCurrentTaskInfo() const
1148 {
1149 return JSNApi::GetCurrentTaskInfo(vm_);
1150 }
1151
ClearCurrentTaskInfo()1152 void ArkNativeEngine::ClearCurrentTaskInfo()
1153 {
1154 JSNApi::ClearCurrentTaskInfo(vm_);
1155 }
1156
TerminateExecution() const1157 void ArkNativeEngine::TerminateExecution() const
1158 {
1159 DFXJSNApi::TerminateExecution(vm_);
1160 }
1161
NotifyTaskBegin() const1162 void ArkNativeEngine::NotifyTaskBegin() const
1163 {
1164 JSNApi::NotifyTaskBegin(vm_);
1165 }
1166
NotifyTaskFinished() const1167 void ArkNativeEngine::NotifyTaskFinished() const
1168 {
1169 JSNApi::NotifyTaskFinished(vm_);
1170 }
1171
CallFunction(napi_value thisVar,napi_value function,napi_value const * argv,size_t argc)1172 napi_value ArkNativeEngine::CallFunction(
1173 napi_value thisVar, napi_value function, napi_value const* argv, size_t argc)
1174 {
1175 if (function == nullptr) {
1176 return nullptr;
1177 }
1178 panda::EscapeLocalScope scope(vm_);
1179 Local<JSValueRef> thisObj = JSValueRef::Undefined(vm_);
1180 if (thisVar != nullptr) {
1181 thisObj = LocalValueFromJsValue(thisVar);
1182 }
1183 Local<FunctionRef> funcObj = LocalValueFromJsValue(function);
1184 std::vector<Local<JSValueRef>> args;
1185 args.reserve(argc);
1186 for (size_t i = 0; i < argc; i++) {
1187 if (argv[i] != nullptr) {
1188 args.emplace_back(LocalValueFromJsValue(argv[i]));
1189 } else {
1190 args.emplace_back(JSValueRef::Undefined(vm_));
1191 }
1192 }
1193
1194 Local<JSValueRef> value = funcObj->Call(vm_, thisObj, args.data(), argc);
1195 if (panda::JSNApi::HasPendingException(vm_)) {
1196 HILOG_ERROR("pending exception when js function called");
1197 HILOG_ERROR("print exception info: ");
1198 panda::JSNApi::PrintExceptionInfo(vm_);
1199 return nullptr;
1200 }
1201
1202 return JsValueFromLocalValue(scope.Escape(value));
1203 }
1204
NapiNewTypedArray(const EcmaVM * vm,NativeTypedArrayType typedArrayType,Local<panda::ArrayBufferRef> arrayBuf,size_t byte_offset,size_t length,napi_value * result)1205 bool ArkNativeEngine::NapiNewTypedArray(const EcmaVM* vm, NativeTypedArrayType typedArrayType,
1206 Local<panda::ArrayBufferRef> arrayBuf,
1207 size_t byte_offset, size_t length, napi_value* result)
1208 {
1209 Local<panda::TypedArrayRef> typedArray;
1210 switch (typedArrayType) {
1211 case NATIVE_INT8_ARRAY:
1212 typedArray = panda::Int8ArrayRef::New(vm, arrayBuf, byte_offset, length);
1213 break;
1214 case NATIVE_UINT8_ARRAY:
1215 typedArray = panda::Uint8ArrayRef::New(vm, arrayBuf, byte_offset, length);
1216 break;
1217 case NATIVE_UINT8_CLAMPED_ARRAY:
1218 typedArray = panda::Uint8ClampedArrayRef::New(vm, arrayBuf, byte_offset, length);
1219 break;
1220 case NATIVE_INT16_ARRAY:
1221 typedArray = panda::Int16ArrayRef::New(vm, arrayBuf, byte_offset, length);
1222 break;
1223 case NATIVE_UINT16_ARRAY:
1224 typedArray = panda::Uint16ArrayRef::New(vm, arrayBuf, byte_offset, length);
1225 break;
1226 case NATIVE_INT32_ARRAY:
1227 typedArray = panda::Int32ArrayRef::New(vm, arrayBuf, byte_offset, length);
1228 break;
1229 case NATIVE_UINT32_ARRAY:
1230 typedArray = panda::Uint32ArrayRef::New(vm, arrayBuf, byte_offset, length);
1231 break;
1232 case NATIVE_FLOAT32_ARRAY:
1233 typedArray = panda::Float32ArrayRef::New(vm, arrayBuf, byte_offset, length);
1234 break;
1235 case NATIVE_FLOAT64_ARRAY:
1236 typedArray = panda::Float64ArrayRef::New(vm, arrayBuf, byte_offset, length);
1237 break;
1238 case NATIVE_BIGINT64_ARRAY:
1239 typedArray = panda::BigInt64ArrayRef::New(vm, arrayBuf, byte_offset, length);
1240 break;
1241 case NATIVE_BIGUINT64_ARRAY:
1242 typedArray = panda::BigUint64ArrayRef::New(vm, arrayBuf, byte_offset, length);
1243 break;
1244 default:
1245 *result = nullptr;
1246 return false;
1247 }
1248 *result = JsValueFromLocalValue(typedArray);
1249 return true;
1250 }
1251
NapiNewSendableTypedArray(const EcmaVM * vm,NativeTypedArrayType typedArrayType,Local<panda::SendableArrayBufferRef> arrayBuf,size_t byte_offset,size_t length,napi_value * result)1252 bool ArkNativeEngine::NapiNewSendableTypedArray(const EcmaVM* vm, NativeTypedArrayType typedArrayType,
1253 Local<panda::SendableArrayBufferRef> arrayBuf,
1254 size_t byte_offset, size_t length, napi_value* result)
1255 {
1256 Local<panda::SendableTypedArrayRef> typedArray;
1257 switch (typedArrayType) {
1258 case NATIVE_INT8_ARRAY:
1259 typedArray = panda::SharedInt8ArrayRef::New(vm, arrayBuf, byte_offset, length);
1260 break;
1261 case NATIVE_UINT8_ARRAY:
1262 typedArray = panda::SharedUint8ArrayRef::New(vm, arrayBuf, byte_offset, length);
1263 break;
1264 case NATIVE_INT16_ARRAY:
1265 typedArray = panda::SharedInt16ArrayRef::New(vm, arrayBuf, byte_offset, length);
1266 break;
1267 case NATIVE_UINT16_ARRAY:
1268 typedArray = panda::SharedUint16ArrayRef::New(vm, arrayBuf, byte_offset, length);
1269 break;
1270 case NATIVE_INT32_ARRAY:
1271 typedArray = panda::SharedInt32ArrayRef::New(vm, arrayBuf, byte_offset, length);
1272 break;
1273 case NATIVE_UINT32_ARRAY:
1274 typedArray = panda::SharedUint32ArrayRef::New(vm, arrayBuf, byte_offset, length);
1275 break;
1276 case NATIVE_FLOAT32_ARRAY:
1277 typedArray = panda::SharedFloat32ArrayRef::New(vm, arrayBuf, byte_offset, length);
1278 break;
1279 case NATIVE_UINT8_CLAMPED_ARRAY:
1280 typedArray = panda::SharedUint8ClampedArrayRef::New(vm, arrayBuf, byte_offset, length);
1281 break;
1282 default:
1283 *result = nullptr;
1284 return false;
1285 }
1286 *result = JsValueFromLocalValue(typedArray);
1287 return true;
1288 }
1289
GetTypedArrayType(panda::Local<panda::TypedArrayRef> typedArray)1290 NativeTypedArrayType ArkNativeEngine::GetTypedArrayType(panda::Local<panda::TypedArrayRef> typedArray)
1291 {
1292 NativeTypedArrayType thisType = NATIVE_INT8_ARRAY;
1293 if (typedArray->IsInt8Array(vm_)) {
1294 thisType = NATIVE_INT8_ARRAY;
1295 } else if (typedArray->IsUint8Array(vm_)) {
1296 thisType = NATIVE_UINT8_ARRAY;
1297 } else if (typedArray->IsUint8ClampedArray(vm_)) {
1298 thisType = NATIVE_UINT8_CLAMPED_ARRAY;
1299 } else if (typedArray->IsInt16Array(vm_)) {
1300 thisType = NATIVE_INT16_ARRAY;
1301 } else if (typedArray->IsUint16Array(vm_)) {
1302 thisType = NATIVE_UINT16_ARRAY;
1303 } else if (typedArray->IsInt32Array(vm_)) {
1304 thisType = NATIVE_INT32_ARRAY;
1305 } else if (typedArray->IsUint32Array(vm_)) {
1306 thisType = NATIVE_UINT32_ARRAY;
1307 } else if (typedArray->IsFloat32Array(vm_)) {
1308 thisType = NATIVE_FLOAT32_ARRAY;
1309 } else if (typedArray->IsFloat64Array(vm_)) {
1310 thisType = NATIVE_FLOAT64_ARRAY;
1311 } else if (typedArray->IsBigInt64Array(vm_)) {
1312 thisType = NATIVE_BIGINT64_ARRAY;
1313 } else if (typedArray->IsBigUint64Array(vm_)) {
1314 thisType = NATIVE_BIGUINT64_ARRAY;
1315 }
1316
1317 return thisType;
1318 }
1319
GetSendableTypedArrayType(panda::Local<panda::SendableTypedArrayRef> typedArray)1320 NativeTypedArrayType ArkNativeEngine::GetSendableTypedArrayType(panda::Local<panda::SendableTypedArrayRef> typedArray)
1321 {
1322 NativeTypedArrayType thisType = NATIVE_INT8_ARRAY;
1323 if (typedArray->IsJSSharedInt8Array(vm_)) {
1324 thisType = NATIVE_INT8_ARRAY;
1325 } else if (typedArray->IsJSSharedUint8Array(vm_)) {
1326 thisType = NATIVE_UINT8_ARRAY;
1327 } else if (typedArray->IsJSSharedInt16Array(vm_)) {
1328 thisType = NATIVE_INT16_ARRAY;
1329 } else if (typedArray->IsJSSharedUint16Array(vm_)) {
1330 thisType = NATIVE_UINT16_ARRAY;
1331 } else if (typedArray->IsJSSharedInt32Array(vm_)) {
1332 thisType = NATIVE_INT32_ARRAY;
1333 } else if (typedArray->IsJSSharedUint32Array(vm_)) {
1334 thisType = NATIVE_UINT32_ARRAY;
1335 } else if (typedArray->IsJSSharedFloat32Array(vm_)) {
1336 thisType = NATIVE_FLOAT32_ARRAY;
1337 } else if (typedArray->IsJSSharedUint8ClampedArray(vm_)) {
1338 thisType = NATIVE_UINT8_CLAMPED_ARRAY;
1339 }
1340
1341 return thisType;
1342 }
1343
1344 /*
1345 * Before: input: 1. @ohos.hilog
1346 2. @system.app (NATIVE_MODULE contains this name)
1347 * After: return: 1.@ohos:hilog
1348 * 2.@native:system.app
1349 */
GetOhmurl(std::string path)1350 std::string ArkNativeEngine::GetOhmurl(std::string path)
1351 {
1352 const std::regex reg("@(ohos|system)\\.(\\S+)");
1353 path.erase(0, path.find_first_not_of(" "));
1354 path.erase(path.find_last_not_of(" ") + 1);
1355 bool ret = std::regex_match(path, reg);
1356 if (!ret) {
1357 HILOG_ERROR("ArkNativeEngine:The module name doesn't comply with the naming rules");
1358 return "";
1359 }
1360 std::string systemModule = path.substr(1);
1361 if (NATIVE_MODULE.count(systemModule)) {
1362 return NATIVE_MODULE_PREFIX + systemModule;
1363 } else {
1364 int pos = static_cast<int>(path.find('.'));
1365 std::string systemKey = path.substr(pos + 1, systemModule.size());
1366 return OHOS_MODULE_PREFIX + systemKey;
1367 }
1368 }
1369
NapiLoadNativeModule(std::string path)1370 Local<JSValueRef> ArkNativeEngine::NapiLoadNativeModule(std::string path)
1371 {
1372 std::string key = GetOhmurl(path);
1373 if (key.size() == 0) {
1374 return JSValueRef::Undefined(vm_);
1375 }
1376 return panda::JSNApi::ExecuteNativeModule(vm_, key);
1377 }
1378
CheckLoadType(const std::string & path)1379 ModuleTypes ArkNativeEngine::CheckLoadType(const std::string &path)
1380 {
1381 if (path[0] == '@') {
1382 return ModuleTypes::NATIVE_MODULE;
1383 } else if (path.find("ets/") == 0) { // ets/xxx/xxx
1384 return ModuleTypes::MODULE_INNER_FILE;
1385 }
1386 return ModuleTypes::UNKNOWN;
1387 }
1388
NapiLoadModule(const char * path,const char * module_info)1389 napi_value ArkNativeEngine::NapiLoadModule(const char* path, const char* module_info)
1390 {
1391 if (path == nullptr) {
1392 HILOG_ERROR("ArkNativeEngine:The module name is empty");
1393 return nullptr;
1394 }
1395 panda::EscapeLocalScope scope(vm_);
1396 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
1397 Local<ObjectRef> exportObj(undefObj);
1398 std::string inputPath(path);
1399 std::string modulePath;
1400 if (module_info != nullptr) {
1401 modulePath = module_info;
1402 }
1403 switch (CheckLoadType(inputPath)) {
1404 case ModuleTypes::NATIVE_MODULE: {
1405 exportObj = NapiLoadNativeModule(inputPath);
1406 break;
1407 }
1408 case ModuleTypes::MODULE_INNER_FILE: {
1409 exportObj = panda::JSNApi::GetModuleNameSpaceFromFile(vm_, inputPath, modulePath);
1410 break;
1411 }
1412 default: {
1413 std::string msg = "ArkNativeEngine:NapiLoadModule input path:" + inputPath + " is invalid.";
1414 ThrowException(msg.c_str());
1415 }
1416 }
1417 if (!exportObj->IsObject(vm_)) {
1418 ThrowException("ArkNativeEngine:NapiLoadModule failed.");
1419 return JsValueFromLocalValue(scope.Escape(undefObj));
1420 }
1421 return JsValueFromLocalValue(scope.Escape(exportObj));
1422 }
1423
NapiLoadModuleWithInfo(const char * path,const char * module_info)1424 napi_value ArkNativeEngine::NapiLoadModuleWithInfo(const char* path, const char* module_info)
1425 {
1426 if (path == nullptr) {
1427 HILOG_ERROR("ArkNativeEngine:The module name is empty");
1428 return nullptr;
1429 }
1430 panda::EscapeLocalScope scope(vm_);
1431 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
1432 Local<ObjectRef> exportObj(undefObj);
1433 std::string inputPath(path);
1434 std::string modulePath;
1435 if (module_info != nullptr) {
1436 modulePath = module_info;
1437 exportObj = panda::JSNApi::GetModuleNameSpaceWithModuleInfo(vm_, inputPath, modulePath);
1438 } else {
1439 exportObj = NapiLoadNativeModule(inputPath);
1440 }
1441
1442 if (!exportObj->IsObject(vm_)) {
1443 ThrowException("ArkNativeEngine:NapiLoadModuleWithInfo failed.");
1444 return JsValueFromLocalValue(scope.Escape(undefObj));
1445 }
1446 return JsValueFromLocalValue(scope.Escape(exportObj));
1447 }
1448
SuspendVMById(uint32_t tid)1449 bool ArkNativeEngine::SuspendVMById(uint32_t tid)
1450 {
1451 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1452 return DFXJSNApi::SuspendVMById(vm_, tid);
1453 #else
1454 HILOG_WARN("ARK does not support dfx on windows");
1455 return false;
1456 #endif
1457 }
1458
ResumeVMById(uint32_t tid)1459 void ArkNativeEngine::ResumeVMById(uint32_t tid)
1460 {
1461 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1462 DFXJSNApi::ResumeVMById(vm_, tid);
1463 #else
1464 HILOG_WARN("ARK does not support dfx on windows");
1465 return;
1466 #endif
1467 }
1468
SetPackagePath(const std::string appLibPathKey,const std::vector<std::string> & packagePath)1469 void ArkNativeEngine::SetPackagePath(const std::string appLibPathKey, const std::vector<std::string>& packagePath)
1470 {
1471 auto moduleManager = NativeModuleManager::GetInstance();
1472 if (moduleManager && !packagePath.empty()) {
1473 moduleManager->SetAppLibPath(appLibPathKey, packagePath);
1474 }
1475 }
1476
CreateInstance(napi_value constructor,napi_value const * argv,size_t argc)1477 napi_value ArkNativeEngine::CreateInstance(napi_value constructor, napi_value const *argv, size_t argc)
1478 {
1479 if (constructor == nullptr) {
1480 return nullptr;
1481 }
1482 panda::EscapeLocalScope scope(vm_);
1483 Local<FunctionRef> value = LocalValueFromJsValue(constructor);
1484 std::vector<Local<JSValueRef>> args;
1485 args.reserve(argc);
1486 for (size_t i = 0; i < argc; i++) {
1487 if (argv[i] != nullptr) {
1488 args.emplace_back(LocalValueFromJsValue(argv[i]));
1489 } else {
1490 args.emplace_back(JSValueRef::Undefined(vm_));
1491 }
1492 }
1493 Local<JSValueRef> instance = value->Constructor(vm_, args.data(), argc);
1494 Local<ObjectRef> excep = panda::JSNApi::GetUncaughtException(vm_);
1495 if (!excep.IsNull()) {
1496 HILOG_ERROR("ArkNativeEngineImpl::CreateInstance occur Exception");
1497 return nullptr;
1498 }
1499 return JsValueFromLocalValue(scope.Escape(instance));
1500 }
1501
CreateReference(napi_value value,uint32_t initialRefcount,bool flag,NapiNativeFinalize callback,void * data,void * hint,size_t nativeBindingSize)1502 NativeReference* ArkNativeEngine::CreateReference(napi_value value, uint32_t initialRefcount,
1503 bool flag, NapiNativeFinalize callback, void* data, void* hint, size_t nativeBindingSize)
1504 {
1505 return new ArkNativeReference(this, value, initialRefcount, flag, callback, data, hint, false, nativeBindingSize);
1506 }
1507
CreateAsyncReference(napi_value value,uint32_t initialRefcount,bool flag,NapiNativeFinalize callback,void * data,void * hint)1508 NativeReference* ArkNativeEngine::CreateAsyncReference(napi_value value, uint32_t initialRefcount,
1509 bool flag, NapiNativeFinalize callback, void* data, void* hint)
1510 {
1511 return new ArkNativeReference(this, value, initialRefcount, flag, callback, data, hint, true);
1512 }
1513
RunCallbacks(TriggerGCData * triggerGCData)1514 __attribute__((optnone)) void ArkNativeEngine::RunCallbacks(TriggerGCData *triggerGCData)
1515 {
1516 #ifdef ENABLE_HITRACE
1517 StartTrace(HITRACE_TAG_ACE, "RunTriggerGCTaskCallback");
1518 #endif
1519 std::pair<void *, uint8_t> ¶m = *triggerGCData;
1520 JSNApi::TriggerIdleGC(reinterpret_cast<panda::ecmascript::EcmaVM *>(param.first),
1521 static_cast<panda::JSNApi::TRIGGER_IDLE_GC_TYPE>(param.second));
1522 #ifdef ENABLE_HITRACE
1523 FinishTrace(HITRACE_TAG_ACE);
1524 #endif
1525 }
1526
RunCallbacks(ArkFinalizersPack * finalizersPack)1527 __attribute__((optnone)) void ArkNativeEngine::RunCallbacks(ArkFinalizersPack *finalizersPack)
1528 {
1529 #ifdef ENABLE_HITRACE
1530 StartTrace(HITRACE_TAG_ACE, "RunFinalizeCallbacks:" + std::to_string(finalizersPack->GetNumFinalizers()));
1531 #endif
1532 finalizersPack->ProcessAll();
1533 #ifdef ENABLE_HITRACE
1534 FinishTrace(HITRACE_TAG_ACE);
1535 #endif
1536 }
1537
RunAsyncCallbacks(std::vector<RefFinalizer> * finalizers)1538 __attribute__((optnone)) void ArkNativeEngine::RunAsyncCallbacks(std::vector<RefFinalizer> *finalizers)
1539 {
1540 #ifdef ENABLE_HITRACE
1541 StartTrace(HITRACE_TAG_ACE, "RunFinalizeCallbacks:" + std::to_string(finalizers->size()));
1542 #endif
1543 INIT_CRASH_HOLDER(holder);
1544 for (auto iter : (*finalizers)) {
1545 NapiNativeFinalize callback = iter.first;
1546 std::tuple<NativeEngine*, void*, void*> ¶m = iter.second;
1547 holder.UpdateCallbackPtr(reinterpret_cast<uintptr_t>(callback));
1548 callback(reinterpret_cast<napi_env>(std::get<0>(param)),
1549 std::get<1>(param), std::get<2>(param)); // 2 is the param.
1550 }
1551 #ifdef ENABLE_HITRACE
1552 FinishTrace(HITRACE_TAG_ACE);
1553 #endif
1554 }
1555
PostFinalizeTasks()1556 void ArkNativeEngine::PostFinalizeTasks()
1557 {
1558 if (IsInDestructor()) {
1559 return;
1560 }
1561 if (!pendingAsyncFinalizers_.empty()) {
1562 uv_work_t *asynWork = new uv_work_t;
1563 std::vector<RefFinalizer> *asyncFinalizers = new std::vector<RefFinalizer>();
1564 asyncFinalizers->swap(pendingAsyncFinalizers_);
1565 asynWork->data = reinterpret_cast<void *>(asyncFinalizers);
1566
1567 int ret = uv_queue_work_with_qos(GetUVLoop(), asynWork, [](uv_work_t *asynWork) {
1568 std::vector<RefFinalizer> *finalizers = reinterpret_cast<std::vector<RefFinalizer> *>(asynWork->data);
1569 RunAsyncCallbacks(finalizers);
1570 HILOG_DEBUG("uv_queue_work async running ");
1571 delete finalizers;
1572 }, [](uv_work_t *asynWork, int32_t) {
1573 delete asynWork;
1574 }, uv_qos_t(napi_qos_background));
1575 if (ret != 0) {
1576 HILOG_ERROR("uv_queue_work fail ret '%{public}d'", ret);
1577 RunAsyncCallbacks(asyncFinalizers);
1578 delete asynWork;
1579 delete asyncFinalizers;
1580 }
1581 }
1582 if (arkFinalizersPack_.Empty()) {
1583 return;
1584 }
1585 ArkFinalizersPack *finalizersPack = new ArkFinalizersPack();
1586 std::swap(arkFinalizersPack_, *finalizersPack);
1587 if (!IsMainThread()) {
1588 panda::JsiNativeScope nativeScope(vm_);
1589 RunCallbacks(finalizersPack);
1590 delete finalizersPack;
1591 return;
1592 }
1593 size_t bindingSize = finalizersPack->GetTotalNativeBindingSize();
1594 if (pendingFinalizersPackNativeBindingSize_ > FINALIZERS_PACK_PENDING_NATIVE_BINDING_SIZE_THRESHOLD &&
1595 bindingSize > 0) {
1596 HILOG_DEBUG("Pending Finalizers NativeBindingSize '%{public}zu' large than '%{public}zu', process sync.",
1597 pendingFinalizersPackNativeBindingSize_, FINALIZERS_PACK_PENDING_NATIVE_BINDING_SIZE_THRESHOLD);
1598 panda::JsiNativeScope nativeScope(vm_);
1599 RunCallbacks(finalizersPack);
1600 delete finalizersPack;
1601 return;
1602 }
1603 uv_work_t *syncWork = new uv_work_t;
1604 finalizersPack->RegisterFinishNotify([this] (size_t totalNativeBindingSize) {
1605 this->DecreasePendingFinalizersPackNativeBindingSize(totalNativeBindingSize);
1606 });
1607 IncreasePendingFinalizersPackNativeBindingSize(bindingSize);
1608
1609 syncWork->data = reinterpret_cast<void *>(finalizersPack);
1610 int ret = uv_queue_work_with_qos(GetUVLoop(), syncWork, [](uv_work_t *) {}, [](uv_work_t *syncWork, int32_t) {
1611 ArkFinalizersPack *finalizersPack = reinterpret_cast<ArkFinalizersPack*>(syncWork->data);
1612 RunCallbacks(finalizersPack);
1613 HILOG_DEBUG("uv_queue_work running");
1614 delete syncWork;
1615 delete finalizersPack;
1616 }, uv_qos_t(napi_qos_background));
1617 if (ret != 0) {
1618 HILOG_ERROR("uv_queue_work fail ret '%{public}d'", ret);
1619 panda::JsiNativeScope nativeScope(vm_);
1620 RunCallbacks(finalizersPack);
1621 delete syncWork;
1622 delete finalizersPack;
1623 }
1624 }
1625
RunCallbacks(AsyncNativeCallbacksPack * callbacksPack)1626 __attribute__((optnone)) void ArkNativeEngine::RunCallbacks(AsyncNativeCallbacksPack *callbacksPack)
1627 {
1628 #ifdef ENABLE_HITRACE
1629 StartTrace(HITRACE_TAG_ACE, "RunNativeCallbacks:" + std::to_string(callbacksPack->GetNumCallBacks()));
1630 #endif
1631 callbacksPack->ProcessAll();
1632 #ifdef ENABLE_HITRACE
1633 FinishTrace(HITRACE_TAG_ACE);
1634 #endif
1635 }
1636
PostAsyncTask(AsyncNativeCallbacksPack * callBacksPack)1637 void ArkNativeEngine::PostAsyncTask(AsyncNativeCallbacksPack *callBacksPack)
1638 {
1639 if (IsInDestructor()) {
1640 delete callBacksPack;
1641 return;
1642 }
1643 uv_work_t *syncWork = new uv_work_t;
1644 syncWork->data = reinterpret_cast<void *>(callBacksPack);
1645
1646 int ret = uv_queue_work_with_qos(GetUVLoop(), syncWork, [](uv_work_t *) {}, [](uv_work_t *syncWork, int32_t) {
1647 AsyncNativeCallbacksPack *finalizers = reinterpret_cast<AsyncNativeCallbacksPack*>(syncWork->data);
1648 RunCallbacks(finalizers);
1649 HILOG_DEBUG("uv_queue_work running");
1650 delete syncWork;
1651 delete finalizers;
1652 }, uv_qos_t(napi_qos_background));
1653 if (ret != 0) {
1654 HILOG_ERROR("uv_queue_work fail ret '%{public}d'", ret);
1655 panda::JsiNativeScope nativeScope(vm_);
1656 RunCallbacks(callBacksPack);
1657 delete callBacksPack;
1658 delete syncWork;
1659 }
1660 }
1661
PostTriggerGCTask(TriggerGCData & data)1662 void ArkNativeEngine::PostTriggerGCTask(TriggerGCData& data)
1663 {
1664 TriggerGCData *triggerGCData = new TriggerGCData(data);
1665 uv_work_t *syncWork = new uv_work_t;
1666 syncWork->data = reinterpret_cast<void *>(triggerGCData);
1667 int ret = uv_queue_work_with_qos(GetUVLoop(), syncWork, [](uv_work_t *) {}, [](uv_work_t *syncWork, int32_t) {
1668 auto triggerGCData = reinterpret_cast<TriggerGCData *>(syncWork->data);
1669 RunCallbacks(triggerGCData);
1670 delete syncWork;
1671 delete triggerGCData;
1672 }, uv_qos_t(napi_qos_user_initiated));
1673 if (ret != 0) {
1674 HILOG_ERROR("uv_queue_work fail ret '%{public}d'", ret);
1675 RunCallbacks(triggerGCData);
1676 delete syncWork;
1677 delete triggerGCData;
1678 }
1679 }
1680
1681 #if defined(OHOS_PLATFORM) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
SetAttribute(bool isLimitedWorker,panda::RuntimeOption & option)1682 void ArkNativeEngine::SetAttribute(bool isLimitedWorker, panda::RuntimeOption &option)
1683 {
1684 int arkProperties = OHOS::system::GetIntParameter<int>("persist.ark.properties", -1);
1685 std::string bundleName = OHOS::system::GetParameter("persist.ark.arkbundlename", "");
1686 std::string memConfigProperty = OHOS::system::GetParameter("persist.ark.mem_config_property", "");
1687 size_t gcThreadNum = OHOS::system::GetUintParameter<size_t>("persist.ark.gcthreads", 7);
1688 size_t longPauseTime = OHOS::system::GetUintParameter<size_t>("persist.ark.longpausetime", 40);
1689 bool asmInterpreterEnabled = OHOS::system::GetBoolParameter("persist.ark.asminterpreter", true);
1690 std::string asmOpcodeDisableRange = OHOS::system::GetParameter("persist.ark.asmopcodedisablerange", "");
1691 bool builtinsLazyEnabled = OHOS::system::GetBoolParameter("persist.ark.enablebuiltinslazy", true);
1692 option.SetEnableBuiltinsLazy(builtinsLazyEnabled);
1693 option.SetArkProperties(arkProperties);
1694 option.SetArkBundleName(bundleName);
1695 option.SetMemConfigProperty(memConfigProperty);
1696 option.SetGcThreadNum(gcThreadNum);
1697 option.SetLongPauseTime(longPauseTime);
1698 option.SetEnableAsmInterpreter(asmInterpreterEnabled);
1699 option.SetAsmOpcodeDisableRange(asmOpcodeDisableRange);
1700 option.SetIsWorker();
1701 option.SetIsRestrictedWorker(isLimitedWorker);
1702 HILOG_DEBUG("ArkNativeEngineImpl::CreateRuntimeFunc ark properties = %{public}d, bundlename = %{public}s",
1703 arkProperties, bundleName.c_str());
1704 }
1705 #endif
1706
CreateRuntimeFunc(NativeEngine * engine,void * jsEngine,bool isLimitedWorker)1707 NativeEngine* ArkNativeEngine::CreateRuntimeFunc(NativeEngine* engine, void* jsEngine, bool isLimitedWorker)
1708 {
1709 panda::RuntimeOption option;
1710 #if defined(OHOS_PLATFORM) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
1711 SetAttribute(isLimitedWorker, option);
1712 #endif
1713 option.SetGcType(panda::RuntimeOption::GC_TYPE::GEN_GC);
1714 const int64_t poolSize = 0x1000000;
1715 option.SetGcPoolSize(poolSize);
1716 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1717 option.SetLogLevel(panda::RuntimeOption::LOG_LEVEL::INFO);
1718 #endif
1719 option.SetDebuggerLibraryPath("");
1720 EcmaVM* vm = panda::JSNApi::CreateJSVM(option);
1721 if (vm == nullptr) {
1722 return nullptr;
1723 }
1724 // worker adaptation mergeabc
1725 const panda::ecmascript::EcmaVM* hostVM = reinterpret_cast<ArkNativeEngine*>(engine)->GetEcmaVm();
1726 panda::JSNApi::SynchronizVMInfo(vm, hostVM);
1727 ArkNativeEngine* arkEngine = new ArkNativeEngine(vm, jsEngine, isLimitedWorker);
1728 // init callback
1729 arkEngine->RegisterWorkerFunction(engine);
1730 arkEngine->SetHostEngine(engine);
1731 // sync apiVersion
1732 arkEngine->SetApiVersion(engine->GetApiVersion());
1733
1734 auto cleanEnv = [vm]() {
1735 if (vm != nullptr) {
1736 HILOG_DEBUG("cleanEnv is called");
1737 panda::JSNApi::DestroyJSVM(vm);
1738 }
1739 };
1740 arkEngine->SetCleanEnv(cleanEnv);
1741 if (hostVM != nullptr) {
1742 panda::JSNApi::AddWorker(const_cast<EcmaVM*>(hostVM), vm);
1743 }
1744 return arkEngine;
1745 }
1746
CreateRuntime(bool isLimitedWorker)1747 void* ArkNativeEngine::CreateRuntime(bool isLimitedWorker)
1748 {
1749 return ArkNativeEngine::CreateRuntimeFunc(this, jsEngine_, isLimitedWorker);
1750 }
1751
SetJsDumpThresholds(size_t thresholds)1752 void ArkNativeEngine::SetJsDumpThresholds(size_t thresholds)
1753 {
1754 DFXJSNApi::SetJsDumpThresholds(vm_, thresholds);
1755 }
1756
SetAppFreezeFilterCallback(AppFreezeFilterCallback callback)1757 void ArkNativeEngine::SetAppFreezeFilterCallback(AppFreezeFilterCallback callback)
1758 {
1759 DFXJSNApi::SetAppFreezeFilterCallback(vm_, callback);
1760 }
1761
StartCpuProfiler(const std::string & fileName)1762 void ArkNativeEngine::StartCpuProfiler(const std::string& fileName)
1763 {
1764 JSNApi::SetNativePtrGetter(vm_, reinterpret_cast<void*>(ArkNativeEngine::GetNativePtrCallBack));
1765 DFXJSNApi::StartCpuProfilerForFile(vm_, fileName);
1766 }
1767
StopCpuProfiler()1768 void ArkNativeEngine::StopCpuProfiler()
1769 {
1770 DFXJSNApi::StopCpuProfilerForFile(vm_);
1771 JSNApi::SetNativePtrGetter(vm_, nullptr);
1772 }
1773
ResumeVM()1774 void ArkNativeEngine::ResumeVM()
1775 {
1776 DFXJSNApi::ResumeVM(vm_);
1777 }
1778
SuspendVM()1779 bool ArkNativeEngine::SuspendVM()
1780 {
1781 return DFXJSNApi::SuspendVM(vm_);
1782 }
1783
IsSuspended()1784 bool ArkNativeEngine::IsSuspended()
1785 {
1786 return DFXJSNApi::IsSuspended(vm_);
1787 }
1788
CheckSafepoint()1789 bool ArkNativeEngine::CheckSafepoint()
1790 {
1791 return DFXJSNApi::CheckSafepoint(vm_);
1792 }
1793
GetCurrentModuleInfo(std::string & moduleName,std::string & fileName,bool needRecordName)1794 void ArkNativeEngine::GetCurrentModuleInfo(std::string& moduleName, std::string& fileName, bool needRecordName)
1795 {
1796 LocalScope scope(vm_);
1797 std::pair<std::string, std::string> moduleInfo = panda::JSNApi::GetCurrentModuleInfo(vm_, needRecordName);
1798 moduleName = moduleInfo.first; // if needRecordName is true, then moduleName is recordName.
1799 fileName = moduleInfo.second;
1800 }
1801
GetIsBundle()1802 bool ArkNativeEngine::GetIsBundle()
1803 {
1804 LocalScope scope(vm_);
1805 return panda::JSNApi::IsBundle(vm_);
1806 }
1807
GetIsNormalizedOhmUrlPack()1808 bool ArkNativeEngine::GetIsNormalizedOhmUrlPack()
1809 {
1810 LocalScope scope(vm_);
1811 return panda::JSNApi::IsNormalizedOhmUrlPack(vm_);
1812 }
1813
GetIsDebugModeEnabled()1814 bool ArkNativeEngine::GetIsDebugModeEnabled()
1815 {
1816 LocalScope scope(vm_);
1817 return panda::JSNApi::IsDebugModeEnabled(vm_);
1818 }
1819
GetBundleName()1820 std::string ArkNativeEngine::GetBundleName()
1821 {
1822 LocalScope scope(vm_);
1823 return panda::JSNApi::GetBundleName(vm_);
1824 }
1825
GetPkgName(const std::string & moduleName)1826 std::string ArkNativeEngine::GetPkgName(const std::string &moduleName)
1827 {
1828 LocalScope scope(vm_);
1829 return panda::JSNApi::GetPkgName(vm_, moduleName);
1830 }
1831
GetProcessStartRealTime()1832 int ArkNativeEngine::GetProcessStartRealTime()
1833 {
1834 LocalScope scope(vm_);
1835 return panda::JSNApi::GetStartRealTime(vm_);
1836 }
1837
IsExecuteModuleInAbcFile(std::string bundleName,std::string moduleName,std::string ohmurl)1838 bool ArkNativeEngine::IsExecuteModuleInAbcFile(std::string bundleName, std::string moduleName, std::string ohmurl)
1839 {
1840 LocalScope scope(vm_);
1841 return panda::JSNApi::IsExecuteModuleInAbcFile(vm_, bundleName, moduleName, ohmurl);
1842 }
1843
ValueToNapiValue(JSValueWrapper & value)1844 napi_value ArkNativeEngine::ValueToNapiValue(JSValueWrapper& value)
1845 {
1846 Global<JSValueRef> arkValue = value;
1847 return JsValueFromLocalValue(arkValue.ToLocal(vm_));
1848 }
1849
ArkValueToNapiValue(napi_env env,Local<JSValueRef> value)1850 napi_value ArkNativeEngine::ArkValueToNapiValue(napi_env env, Local<JSValueRef> value)
1851 {
1852 return JsValueFromLocalValue(value);
1853 }
1854
GetSourceCodeInfo(napi_value value,ErrorPos pos)1855 std::string ArkNativeEngine::GetSourceCodeInfo(napi_value value, ErrorPos pos)
1856 {
1857 if (value == nullptr || pos.first == 0) {
1858 return "";
1859 }
1860
1861 LocalScope scope(vm_);
1862 Local<panda::FunctionRef> func = LocalValueFromJsValue(value);
1863 uint32_t line = pos.first;
1864 uint32_t column = pos.second;
1865 Local<panda::StringRef> sourceCode = func->GetSourceCode(vm_, line);
1866 std::string sourceCodeStr = sourceCode->ToString(vm_);
1867 if (sourceCodeStr.empty()) {
1868 return "";
1869 }
1870 std::string sourceCodeInfo = "SourceCode:\n";
1871 sourceCodeInfo.append(sourceCodeStr).append("\n");
1872 for (uint32_t k = 1; k < column; k++) {
1873 sourceCodeInfo.push_back(' ');
1874 }
1875 sourceCodeInfo.append("^\n");
1876 return sourceCodeInfo;
1877 }
1878
TriggerFatalException(panda::Local<panda::JSValueRef> exceptionValue)1879 void ArkNativeEngine::TriggerFatalException(panda::Local<panda::JSValueRef> exceptionValue)
1880 {
1881 panda::JSNApi::ThrowException(GetEcmaVm(), exceptionValue);
1882 HandleUncaughtException();
1883 }
1884
AdjustExternalMemory(int64_t ChangeInBytes,int64_t * AdjustedValue)1885 bool ArkNativeEngine::AdjustExternalMemory(int64_t ChangeInBytes, int64_t* AdjustedValue)
1886 {
1887 return true;
1888 }
1889
SetPromiseRejectCallback(NativeReference * rejectCallbackRef,NativeReference * checkCallbackRef)1890 void ArkNativeEngine::SetPromiseRejectCallback(NativeReference* rejectCallbackRef, NativeReference* checkCallbackRef)
1891 {
1892 if (rejectCallbackRef == nullptr || checkCallbackRef == nullptr) {
1893 HILOG_ERROR("rejectCallbackRef or checkCallbackRef is nullptr");
1894 return;
1895 }
1896 promiseRejectCallbackRef_ = rejectCallbackRef;
1897 checkCallbackRef_ = checkCallbackRef;
1898 JSNApi::SetHostPromiseRejectionTracker(vm_, reinterpret_cast<void*>(PromiseRejectCallback),
1899 reinterpret_cast<void*>(this));
1900 }
1901
PromiseRejectCallback(void * info)1902 void ArkNativeEngine::PromiseRejectCallback(void* info)
1903 {
1904 panda::PromiseRejectInfo* promiseRejectInfo = reinterpret_cast<panda::PromiseRejectInfo*>(info);
1905 ArkNativeEngine* env = reinterpret_cast<ArkNativeEngine*>(promiseRejectInfo->GetData());
1906
1907 if (env == nullptr) {
1908 HILOG_ERROR("engine is nullptr");
1909 return;
1910 }
1911
1912 if (env->promiseRejectCallbackRef_ == nullptr || env->checkCallbackRef_ == nullptr) {
1913 HILOG_ERROR("promiseRejectCallbackRef or checkCallbackRef is nullptr");
1914 return;
1915 }
1916 panda::ecmascript::EcmaVM* vm = const_cast<EcmaVM*>(env->GetEcmaVm());
1917 LocalScope scope(vm);
1918 Local<JSValueRef> promise = promiseRejectInfo->GetPromise();
1919 Local<JSValueRef> reason = promiseRejectInfo->GetReason();
1920 panda::PromiseRejectInfo::PROMISE_REJECTION_EVENT operation = promiseRejectInfo->GetOperation();
1921
1922 Local<JSValueRef> type(IntegerRef::New(vm, static_cast<int32_t>(operation)));
1923
1924 Local<JSValueRef> args[] = {type, promise, reason};
1925
1926 napi_value promiseNapiRejectCallback = env->promiseRejectCallbackRef_->Get(env);
1927 Local<FunctionRef> promiseRejectCallback = LocalValueFromJsValue(promiseNapiRejectCallback);
1928 if (!promiseRejectCallback.IsEmpty()) {
1929 promiseRejectCallback->Call(vm, JSValueRef::Undefined(vm), args, 3); // 3 args size
1930 }
1931
1932 if (operation == panda::PromiseRejectInfo::PROMISE_REJECTION_EVENT::REJECT) {
1933 Local<JSValueRef> checkCallback = LocalValueFromJsValue(env->checkCallbackRef_->Get(env));
1934 if (!checkCallback.IsEmpty()) {
1935 JSNApi::SetHostEnqueueJob(vm, checkCallback, panda::QueueType::QUEUE_SCRIPT);
1936 }
1937 }
1938 }
1939
DumpHeapSnapshot(const std::string & path,bool isVmMode,DumpFormat dumpFormat,bool isPrivate,bool captureNumericValue)1940 void ArkNativeEngine::DumpHeapSnapshot(const std::string& path, bool isVmMode, DumpFormat dumpFormat,
1941 bool isPrivate, bool captureNumericValue)
1942 {
1943 panda::ecmascript::DumpSnapShotOption dumpOption;
1944 dumpOption.isVmMode = isVmMode;
1945 dumpOption.isSync = true;
1946 if (dumpFormat == DumpFormat::JSON) {
1947 dumpOption.dumpFormat = panda::ecmascript::DumpFormat::JSON;
1948 dumpOption.isPrivate = isPrivate;
1949 dumpOption.captureNumericValue = captureNumericValue;
1950 DFXJSNApi::DumpHeapSnapshot(vm_, path, dumpOption);
1951 }
1952 if (dumpFormat == DumpFormat::BINARY) {
1953 dumpOption.dumpFormat = panda::ecmascript::DumpFormat::BINARY;
1954 DFXJSNApi::DumpHeapSnapshot(vm_, path, dumpOption);
1955 }
1956 if (dumpFormat == DumpFormat::OTHER) {
1957 dumpOption.dumpFormat = panda::ecmascript::DumpFormat::OTHER;
1958 DFXJSNApi::DumpHeapSnapshot(vm_, path, dumpOption); // 2:enum is 2
1959 }
1960 }
1961
DumpCpuProfile()1962 void ArkNativeEngine::DumpCpuProfile()
1963 {
1964 DFXJSNApi::DumpCpuProfile(vm_);
1965 }
1966
DumpHeapSnapshot(bool isVmMode,DumpFormat dumpFormat,bool isPrivate,bool isFullGC)1967 void ArkNativeEngine::DumpHeapSnapshot(bool isVmMode, DumpFormat dumpFormat, bool isPrivate, bool isFullGC)
1968 {
1969 panda::ecmascript::DumpSnapShotOption dumpOption;
1970 dumpOption.isVmMode = isVmMode;
1971 dumpOption.isPrivate = isPrivate;
1972 dumpOption.isFullGC = isFullGC;
1973 dumpOption.isSync = false;
1974 if (dumpFormat == DumpFormat::JSON) {
1975 dumpOption.dumpFormat = panda::ecmascript::DumpFormat::JSON;
1976 DFXJSNApi::DumpHeapSnapshot(vm_, dumpOption);
1977 }
1978 if (dumpFormat == DumpFormat::BINARY) {
1979 dumpOption.dumpFormat = panda::ecmascript::DumpFormat::BINARY;
1980 DFXJSNApi::DumpHeapSnapshot(vm_, dumpOption);
1981 }
1982 if (dumpFormat == DumpFormat::OTHER) {
1983 dumpOption.dumpFormat = panda::ecmascript::DumpFormat::OTHER;
1984 DFXJSNApi::DumpHeapSnapshot(vm_, dumpOption);
1985 }
1986 }
1987
BuildNativeAndJsStackTrace(std::string & stackTraceStr)1988 bool ArkNativeEngine::BuildNativeAndJsStackTrace(std::string& stackTraceStr)
1989 {
1990 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1991 return DFXJSNApi::BuildNativeAndJsStackTrace(vm_, stackTraceStr);
1992 #else
1993 HILOG_WARN("ARK does not support dfx on windows");
1994 return false;
1995 #endif
1996 }
1997
BuildJsStackTrace(std::string & stackTraceStr)1998 bool ArkNativeEngine::BuildJsStackTrace(std::string& stackTraceStr)
1999 {
2000 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
2001 return DFXJSNApi::BuildJsStackTrace(vm_, stackTraceStr);
2002 #else
2003 HILOG_WARN("ARK does not support dfx on windows");
2004 return false;
2005 #endif
2006 }
2007
BuildJsStackInfoListWithCustomDepth(std::vector<JsFrameInfo> & jsFrames)2008 bool ArkNativeEngine::BuildJsStackInfoListWithCustomDepth(std::vector<JsFrameInfo>& jsFrames)
2009 {
2010 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
2011 bool sign = DFXJSNApi::BuildJsStackInfoList(vm_, gettid(), jsFrames);
2012 return sign;
2013 #else
2014 HILOG_WARN("ARK does not support dfx on windows");
2015 return false;
2016 #endif
2017 }
2018
DeleteWorker(NativeEngine * workerEngine)2019 bool ArkNativeEngine::DeleteWorker(NativeEngine* workerEngine)
2020 {
2021 if (workerEngine != nullptr) {
2022 #if !defined(PREVIEW)
2023 const panda::ecmascript::EcmaVM* workerVM = reinterpret_cast<ArkNativeEngine*>(workerEngine)->GetEcmaVm();
2024 if (workerVM != nullptr) {
2025 return panda::JSNApi::DeleteWorker(vm_, const_cast<EcmaVM*>(workerVM));
2026 }
2027 #else
2028 HILOG_WARN("ARK does not support dfx on windows");
2029 #endif
2030 return false;
2031 }
2032 return false;
2033 }
2034
StartHeapTracking(double timeInterval,bool isVmMode)2035 bool ArkNativeEngine::StartHeapTracking(double timeInterval, bool isVmMode)
2036 {
2037 return DFXJSNApi::StartHeapTracking(vm_, timeInterval, isVmMode);
2038 }
2039
StopHeapTracking(const std::string & filePath)2040 bool ArkNativeEngine::StopHeapTracking(const std::string &filePath)
2041 {
2042 return DFXJSNApi::StopHeapTracking(vm_, filePath);
2043 }
2044
2045 #if !defined(PREVIEW)
PrintStatisticResult()2046 void ArkNativeEngine::PrintStatisticResult()
2047 {
2048 DFXJSNApi::PrintStatisticResult(vm_);
2049 }
2050
StartRuntimeStat()2051 void ArkNativeEngine::StartRuntimeStat()
2052 {
2053 DFXJSNApi::StartRuntimeStat(vm_);
2054 }
2055
StopRuntimeStat()2056 void ArkNativeEngine::StopRuntimeStat()
2057 {
2058 DFXJSNApi::StopRuntimeStat(vm_);
2059 }
2060
GetArrayBufferSize()2061 size_t ArkNativeEngine::GetArrayBufferSize()
2062 {
2063 return DFXJSNApi::GetArrayBufferSize(vm_);
2064 }
2065
GetHeapTotalSize()2066 size_t ArkNativeEngine::GetHeapTotalSize()
2067 {
2068 return DFXJSNApi::GetHeapTotalSize(vm_);
2069 }
2070
GetHeapUsedSize()2071 size_t ArkNativeEngine::GetHeapUsedSize()
2072 {
2073 return DFXJSNApi::GetHeapUsedSize(vm_);
2074 }
2075
GetHeapObjectSize()2076 size_t ArkNativeEngine::GetHeapObjectSize()
2077 {
2078 return DFXJSNApi::GetHeapObjectSize(vm_);
2079 }
2080
GetHeapLimitSize()2081 size_t ArkNativeEngine::GetHeapLimitSize()
2082 {
2083 return DFXJSNApi::GetHeapLimitSize(vm_);
2084 }
2085
GetProcessHeapLimitSize()2086 size_t ArkNativeEngine::GetProcessHeapLimitSize()
2087 {
2088 return DFXJSNApi::GetProcessHeapLimitSize();
2089 }
2090
GetGCCount()2091 size_t ArkNativeEngine::GetGCCount()
2092 {
2093 return DFXJSNApi::GetGCCount(vm_);
2094 }
2095
GetGCDuration()2096 size_t ArkNativeEngine::GetGCDuration()
2097 {
2098 return DFXJSNApi::GetGCDuration(vm_);
2099 }
2100
GetAccumulatedAllocateSize()2101 size_t ArkNativeEngine::GetAccumulatedAllocateSize()
2102 {
2103 return DFXJSNApi::GetAccumulatedAllocateSize(vm_);
2104 }
2105
GetAccumulatedFreeSize()2106 size_t ArkNativeEngine::GetAccumulatedFreeSize()
2107 {
2108 return DFXJSNApi::GetAccumulatedFreeSize(vm_);
2109 }
2110
GetFullGCLongTimeCount()2111 size_t ArkNativeEngine::GetFullGCLongTimeCount()
2112 {
2113 return DFXJSNApi::GetFullGCLongTimeCount(vm_);
2114 }
2115
NotifyApplicationState(bool inBackground)2116 void ArkNativeEngine::NotifyApplicationState(bool inBackground)
2117 {
2118 DFXJSNApi::NotifyApplicationState(vm_, inBackground);
2119 arkIdleMonitor_->NotifyChangeBackgroundState(inBackground);
2120 }
2121
NotifyIdleStatusControl(std::function<void (bool)> callback)2122 void ArkNativeEngine::NotifyIdleStatusControl(std::function<void(bool)> callback)
2123 {
2124 DFXJSNApi::NotifyIdleStatusControl(vm_, callback);
2125 }
2126
NotifyIdleTime(int idleMicroSec)2127 void ArkNativeEngine::NotifyIdleTime(int idleMicroSec)
2128 {
2129 DFXJSNApi::NotifyIdleTime(vm_, idleMicroSec);
2130 }
2131
NotifyMemoryPressure(bool inHighMemoryPressure)2132 void ArkNativeEngine::NotifyMemoryPressure(bool inHighMemoryPressure)
2133 {
2134 DFXJSNApi::NotifyMemoryPressure(vm_, inHighMemoryPressure);
2135 }
2136
NotifyForceExpandState(int32_t value)2137 void ArkNativeEngine::NotifyForceExpandState(int32_t value)
2138 {
2139 switch (ForceExpandState(value)) {
2140 case ForceExpandState::FINISH_COLD_START:
2141 DFXJSNApi::NotifyFinishColdStart(vm_, true);
2142 break;
2143 case ForceExpandState::START_HIGH_SENSITIVE:
2144 DFXJSNApi::NotifyHighSensitive(vm_, true);
2145 break;
2146 case ForceExpandState::FINISH_HIGH_SENSITIVE:
2147 DFXJSNApi::NotifyHighSensitive(vm_, false);
2148 break;
2149 default:
2150 HILOG_ERROR("Invalid Force Expand State: %{public}d.", value);
2151 break;
2152 }
2153 }
2154 #else
PrintStatisticResult()2155 void ArkNativeEngine::PrintStatisticResult()
2156 {
2157 HILOG_WARN("ARK does not support dfx on windows");
2158 }
2159
StartRuntimeStat()2160 void ArkNativeEngine::StartRuntimeStat()
2161 {
2162 HILOG_WARN("ARK does not support dfx on windows");
2163 }
2164
StopRuntimeStat()2165 void ArkNativeEngine::StopRuntimeStat()
2166 {
2167 HILOG_WARN("ARK does not support dfx on windows");
2168 }
2169
GetArrayBufferSize()2170 size_t ArkNativeEngine::GetArrayBufferSize()
2171 {
2172 HILOG_WARN("ARK does not support dfx on windows");
2173 return 0;
2174 }
2175
GetHeapTotalSize()2176 size_t ArkNativeEngine::GetHeapTotalSize()
2177 {
2178 HILOG_WARN("ARK does not support dfx on windows");
2179 return 0;
2180 }
2181
GetHeapUsedSize()2182 size_t ArkNativeEngine::GetHeapUsedSize()
2183 {
2184 HILOG_WARN("ARK does not support dfx on windows");
2185 return 0;
2186 }
2187
GetHeapObjectSize()2188 size_t ArkNativeEngine::GetHeapObjectSize()
2189 {
2190 HILOG_WARN("ARK does not support dfx on windows");
2191 return 0;
2192 }
2193
GetHeapLimitSize()2194 size_t ArkNativeEngine::GetHeapLimitSize()
2195 {
2196 HILOG_WARN("ARK does not support dfx on windows");
2197 return 0;
2198 }
2199
GetProcessHeapLimitSize()2200 size_t ArkNativeEngine::GetProcessHeapLimitSize()
2201 {
2202 HILOG_WARN("ARK does not support dfx on windows");
2203 return 0;
2204 }
2205
GetGCCount()2206 size_t ArkNativeEngine::GetGCCount()
2207 {
2208 HILOG_WARN("ARK does not support dfx on windows");
2209 return 0;
2210 }
2211
GetGCDuration()2212 size_t ArkNativeEngine::GetGCDuration()
2213 {
2214 HILOG_WARN("ARK does not support dfx on windows");
2215 return 0;
2216 }
2217
GetAccumulatedAllocateSize()2218 size_t ArkNativeEngine::GetAccumulatedAllocateSize()
2219 {
2220 HILOG_WARN("ARK does not support dfx on windows");
2221 return 0;
2222 }
2223
GetAccumulatedFreeSize()2224 size_t ArkNativeEngine::GetAccumulatedFreeSize()
2225 {
2226 HILOG_WARN("ARK does not support dfx on windows");
2227 return 0;
2228 }
2229
GetFullGCLongTimeCount()2230 size_t ArkNativeEngine::GetFullGCLongTimeCount()
2231 {
2232 HILOG_WARN("ARK does not support dfx on windows");
2233 return 0;
2234 }
2235
NotifyApplicationState(bool inBackground)2236 void ArkNativeEngine::NotifyApplicationState([[maybe_unused]] bool inBackground)
2237 {
2238 HILOG_WARN("ARK does not support dfx on windows");
2239 }
2240
NotifyIdleStatusControl(std::function<void (bool)> callback)2241 void ArkNativeEngine::NotifyIdleStatusControl([[maybe_unused]] std::function<void(bool)> callback)
2242 {
2243 HILOG_WARN("ARK does not support dfx on windows");
2244 }
2245
NotifyIdleTime(int idleMicroSec)2246 void ArkNativeEngine::NotifyIdleTime([[maybe_unused]] int idleMicroSec)
2247 {
2248 HILOG_WARN("ARK does not support dfx on windows");
2249 }
2250
NotifyMemoryPressure(bool inHighMemoryPressure)2251 void ArkNativeEngine::NotifyMemoryPressure([[maybe_unused]] bool inHighMemoryPressure)
2252 {
2253 HILOG_WARN("ARK does not support dfx on windows");
2254 }
2255
NotifyForceExpandState(int32_t value)2256 void ArkNativeEngine::NotifyForceExpandState([[maybe_unused]] int32_t value)
2257 {
2258 HILOG_WARN("ARK does not support dfx on windows");
2259 }
2260 #endif
2261
SetMockModuleList(const std::map<std::string,std::string> & list)2262 void ArkNativeEngine::SetMockModuleList(const std::map<std::string, std::string> &list)
2263 {
2264 JSNApi::SetMockModuleList(vm_, list);
2265 }
2266
RegisterNapiUncaughtExceptionHandler(NapiUncaughtExceptionCallback callback)2267 void ArkNativeEngine::RegisterNapiUncaughtExceptionHandler(NapiUncaughtExceptionCallback callback)
2268 {
2269 JSNApi::EnableUserUncaughtErrorHandler(vm_);
2270 napiUncaughtExceptionCallback_ = callback;
2271 }
2272
HandleUncaughtException()2273 void ArkNativeEngine::HandleUncaughtException()
2274 {
2275 if (napiUncaughtExceptionCallback_ == nullptr) {
2276 return;
2277 }
2278 LocalScope scope(vm_);
2279 lastException_.Empty();
2280 Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(vm_);
2281 if (!exception.IsEmpty() && !exception->IsHole()) {
2282 if (napiUncaughtExceptionCallback_ != nullptr) {
2283 napiUncaughtExceptionCallback_(ArkValueToNapiValue(reinterpret_cast<napi_env>(this), exception));
2284 }
2285 }
2286 }
2287
HasPendingException()2288 bool ArkNativeEngine::HasPendingException()
2289 {
2290 return panda::JSNApi::HasPendingException(vm_);
2291 }
2292
RegisterPermissionCheck(PermissionCheckCallback callback)2293 void ArkNativeEngine::RegisterPermissionCheck(PermissionCheckCallback callback)
2294 {
2295 if (permissionCheckCallback_ == nullptr) {
2296 permissionCheckCallback_ = callback;
2297 }
2298 }
2299
ExecutePermissionCheck()2300 bool ArkNativeEngine::ExecutePermissionCheck()
2301 {
2302 if (permissionCheckCallback_ != nullptr) {
2303 return permissionCheckCallback_();
2304 } else {
2305 HILOG_INFO("permissionCheckCallback_ is still nullptr when executing permission check!");
2306 return true;
2307 }
2308 }
2309
RegisterTranslateBySourceMap(SourceMapCallback callback)2310 void ArkNativeEngine::RegisterTranslateBySourceMap(SourceMapCallback callback)
2311 {
2312 if (SourceMapCallback_ == nullptr) {
2313 SourceMapCallback_ = callback;
2314 }
2315 // regedit SourceMapCallback to ark_js_runtime
2316 panda::JSNApi::SetSourceMapCallback(vm_, callback);
2317 }
2318
RegisterSourceMapTranslateCallback(SourceMapTranslateCallback callback)2319 void ArkNativeEngine::RegisterSourceMapTranslateCallback(SourceMapTranslateCallback callback)
2320 {
2321 panda::JSNApi::SetSourceMapTranslateCallback(vm_, callback);
2322 }
2323
ExecuteTranslateBySourceMap(const std::string & rawStack)2324 std::string ArkNativeEngine::ExecuteTranslateBySourceMap(const std::string& rawStack)
2325 {
2326 if (SourceMapCallback_ != nullptr) {
2327 return SourceMapCallback_(rawStack);
2328 } else {
2329 HILOG_WARN("SourceMapCallback_ is nullptr.");
2330 return rawStack;
2331 }
2332 }
2333
IsMixedDebugEnabled()2334 bool ArkNativeEngine::IsMixedDebugEnabled()
2335 {
2336 return JSNApi::IsMixedDebugEnabled(vm_);
2337 }
2338
NotifyNativeCalling(const void * nativeAddress)2339 void ArkNativeEngine::NotifyNativeCalling(const void *nativeAddress)
2340 {
2341 JSNApi::NotifyNativeCalling(vm_, nativeAddress);
2342 }
2343
AllowCrossThreadExecution() const2344 void ArkNativeEngine::AllowCrossThreadExecution() const
2345 {
2346 JSNApi::AllowCrossThreadExecution(vm_);
2347 }
2348
2349 #if !defined(is_arkui_x) && defined(OHOS_PLATFORM)
DumpHybridStack(const EcmaVM * vm)2350 std::string DumpHybridStack(const EcmaVM* vm)
2351 {
2352 constexpr size_t skipframes = 5;
2353 auto unwinder = std::make_shared<OHOS::HiviewDFX::Unwinder>();
2354 std::vector<OHOS::HiviewDFX::DfxFrame> frames;
2355 unwinder->EnableMethodIdLocal(true);
2356 if (unwinder->UnwindLocal(false, false, DEFAULT_MAX_FRAME_NUM, skipframes)) {
2357 frames = unwinder->GetFrames();
2358 } else {
2359 HILOG_ERROR("Failed to unwind local");
2360 }
2361
2362 for (auto &frame : frames) {
2363 if (frame.isJsFrame) {
2364 DFXJSNApi::TranslateJSStackInfo(vm, frame.mapName, frame.line, frame.column);
2365 }
2366 }
2367
2368 return OHOS::HiviewDFX::Unwinder::GetFramesStr(frames);
2369 }
2370 #endif
2371
PostLooperTriggerIdleGCTask()2372 void ArkNativeEngine::PostLooperTriggerIdleGCTask()
2373 {
2374 #if defined(ENABLE_EVENT_HANDLER)
2375 std::shared_ptr<OHOS::AppExecFwk::EventRunner> mainThreadRunner =
2376 OHOS::AppExecFwk::EventRunner::GetMainEventRunner();
2377 if (mainThreadRunner.get() == nullptr) {
2378 HILOG_FATAL("ArkNativeEngine:: the mainEventRunner is nullptr");
2379 return;
2380 }
2381 std::weak_ptr<ArkIdleMonitor> weakArkIdleMonitor = arkIdleMonitor_;
2382 auto callback = [weakArkIdleMonitor](OHOS::AppExecFwk::EventRunnerStage stage,
2383 const OHOS::AppExecFwk::StageInfo* info) -> int {
2384 auto arkIdleMonitor = weakArkIdleMonitor.lock();
2385 if (nullptr == arkIdleMonitor) {
2386 HILOG_ERROR("ArkIdleMonitor has been destructed.");
2387 return 0;
2388 }
2389 switch (stage) {
2390 case OHOS::AppExecFwk::EventRunnerStage::STAGE_BEFORE_WAITING:
2391 arkIdleMonitor->NotifyLooperIdleStart(info->timestamp, info->sleepTime);
2392 break;
2393 case OHOS::AppExecFwk::EventRunnerStage::STAGE_AFTER_WAITING:
2394 arkIdleMonitor->NotifyLooperIdleEnd(info->timestamp);
2395 break;
2396 default:
2397 HILOG_ERROR("this branch is unreachable");
2398 }
2399 return 0;
2400 };
2401 uint32_t stage = (static_cast<uint32_t>(OHOS::AppExecFwk::EventRunnerStage::STAGE_BEFORE_WAITING) |
2402 static_cast<uint32_t>(OHOS::AppExecFwk::EventRunnerStage::STAGE_AFTER_WAITING));
2403 mainThreadRunner->GetEventQueue()->AddObserver(OHOS::AppExecFwk::Observer::ARKTS_GC, stage, callback);
2404 #endif
2405 }
2406
GetObjectHash(napi_env env,napi_value src)2407 int32_t ArkNativeEngine::GetObjectHash(napi_env env, napi_value src)
2408 {
2409 auto engine = reinterpret_cast<NativeEngine*>(env);
2410 auto vm = engine->GetEcmaVm();
2411 auto nativeValue = LocalValueFromJsValue(src);
2412 return DFXJSNApi::GetObjectHash(vm, nativeValue);
2413 }
2414 // LCOV_EXCL_STOP
2415
RunScriptPath(const char * path,bool checkPath)2416 bool ArkNativeEngine::RunScriptPath(const char* path, bool checkPath)
2417 {
2418 if (checkPath && !IsValidPandaFile(path)) {
2419 HILOG_ERROR("file is not exist or format is invalid");
2420 return false;
2421 }
2422 // LCOV_EXCL_START
2423 panda::JSExecutionScope executionScope(vm_);
2424 LocalScope scope(vm_);
2425 [[maybe_unused]] bool ret = panda::JSNApi::Execute(vm_, path, PANDA_MAIN_FUNCTION);
2426 if (panda::JSNApi::HasPendingException(vm_)) {
2427 HandleUncaughtException();
2428 return false;
2429 }
2430 // LCOV_EXCL_STOP
2431 return true;
2432 }
2433
IsValidPandaFile(const char * path)2434 bool ArkNativeEngine::IsValidPandaFile(const char* path)
2435 {
2436 if (path == nullptr) {
2437 HILOG_ERROR("file path is nullptr");
2438 return false;
2439 }
2440
2441 char filePath[PATH_MAX + 1] = { 0 };
2442 if (!RealPath(path, filePath, PATH_MAX + 1)) {
2443 HILOG_ERROR("failed to format path");
2444 return false;
2445 }
2446 struct stat fileStat;
2447 int ret = stat(filePath, &fileStat);
2448 if (ret != 0) {
2449 HILOG_ERROR("script file \"%{public}s\" is not exist", filePath);
2450 return false;
2451 }
2452
2453 if (!(fileStat.st_mode & S_IFREG)) {
2454 HILOG_ERROR("script path \"%{public}s\" is a directory", filePath);
2455 return false;
2456 }
2457 std::ifstream abcStream(filePath, std::ios::in | std::ios::binary);
2458
2459 constexpr size_t fileHeaderLength = sizeof(uint64_t);
2460 uint8_t fileHeader[fileHeaderLength] = { 0 };
2461 if (abcStream.is_open()) {
2462 size_t fileSize = fileStat.st_size;
2463 if (fileSize < fileHeaderLength) {
2464 HILOG_ERROR("faild to read file header, invalid format \"%{public}s\"", filePath);
2465 abcStream.close();
2466 return false;
2467 }
2468 abcStream.read(reinterpret_cast<char*>(fileHeader), fileHeaderLength);
2469 abcStream.close();
2470 return IsValidScriptBuffer(fileHeader, fileHeaderLength);
2471 }
2472 return false;
2473 }
2474
IsValidScriptBuffer(uint8_t * scriptBuffer,size_t bufferSize)2475 bool ArkNativeEngine::IsValidScriptBuffer(uint8_t* scriptBuffer, size_t bufferSize)
2476 {
2477 if (scriptBuffer == nullptr) {
2478 HILOG_ERROR("buffer is nullptr");
2479 return false;
2480 }
2481 constexpr size_t headerLen = sizeof(uint64_t);
2482 if (bufferSize < headerLen) {
2483 HILOG_ERROR("invalid buffer");
2484 return false;
2485 }
2486 constexpr char pandaFileHeader[headerLen] = "PANDA";
2487 const uint64_t bytePandaHeader = *reinterpret_cast<const uint64_t*>(pandaFileHeader);
2488 char fileHeader[headerLen] = { 0 };
2489 // Ensure destMax paramter is set correctly to avoid buffer overflows
2490 if (memcpy_s(fileHeader, sizeof(fileHeader), scriptBuffer, sizeof(fileHeader)) != 0) {
2491 HILOG_ERROR("faild to read file header of buffer");
2492 return false;
2493 }
2494
2495 uint64_t byteFileHeader = *reinterpret_cast<uint64_t*>(fileHeader);
2496 if (byteFileHeader != bytePandaHeader) {
2497 HILOG_ERROR("invalid format of file buffer");
2498 return false;
2499 }
2500 return true;
2501 }
2502
2503 // The security interface needs to be modified accordingly.
RunScriptBuffer(const char * path,std::vector<uint8_t> & buffer,bool isBundle)2504 napi_value ArkNativeEngine::RunScriptBuffer(const char* path, std::vector<uint8_t>& buffer, bool isBundle)
2505 {
2506 if (!IsValidScriptBuffer(buffer.data(), buffer.size())) {
2507 HILOG_ERROR("invalid script buffer");
2508 return nullptr;
2509 }
2510
2511 // LCOV_EXCL_START
2512 panda::EscapeLocalScope scope(vm_);
2513 [[maybe_unused]] bool ret = false;
2514 if (isBundle) {
2515 ret = panda::JSNApi::Execute(vm_, buffer.data(), buffer.size(), PANDA_MAIN_FUNCTION, path);
2516 } else {
2517 ret = panda::JSNApi::ExecuteModuleBuffer(vm_, buffer.data(), buffer.size(), path);
2518 }
2519
2520 if (panda::JSNApi::HasPendingException(vm_)) {
2521 HandleUncaughtException();
2522 return nullptr;
2523 }
2524 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
2525 // LCOV_EXCL_STOP
2526 return JsValueFromLocalValue(scope.Escape(undefObj));
2527 }
2528
RunScriptBuffer(const std::string & path,uint8_t * buffer,size_t size,bool isBundle)2529 bool ArkNativeEngine::RunScriptBuffer(const std::string& path, uint8_t* buffer, size_t size, bool isBundle)
2530 {
2531 if (!IsValidScriptBuffer(buffer, size)) {
2532 HILOG_ERROR("invalid script buffer");
2533 return false;
2534 }
2535
2536 // LCOV_EXCL_START
2537 panda::JSExecutionScope executionScope(vm_);
2538 LocalScope scope(vm_);
2539 bool ret = false;
2540 if (isBundle) {
2541 ret = panda::JSNApi::ExecuteSecure(vm_, buffer, size, PANDA_MAIN_FUNCTION, path);
2542 } else {
2543 ret = panda::JSNApi::ExecuteModuleBufferSecure(vm_, buffer, size, path);
2544 }
2545
2546 if (panda::JSNApi::HasPendingException(vm_)) {
2547 HandleUncaughtException();
2548 return false;
2549 }
2550 return ret;
2551 // LCOV_EXCL_STOP
2552 }
2553
RunBufferScript(std::vector<uint8_t> & buffer)2554 napi_value ArkNativeEngine::RunBufferScript(std::vector<uint8_t>& buffer)
2555 {
2556 if (!IsValidScriptBuffer(buffer.data(), buffer.size())) {
2557 HILOG_ERROR("invalid script buffer");
2558 return nullptr;
2559 }
2560
2561 // LCOV_EXCL_START
2562 panda::EscapeLocalScope scope(vm_);
2563 [[maybe_unused]] bool ret = panda::JSNApi::Execute(vm_, buffer.data(), buffer.size(), PANDA_MAIN_FUNCTION);
2564
2565 if (panda::JSNApi::HasPendingException(vm_)) {
2566 HandleUncaughtException();
2567 return nullptr;
2568 }
2569 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
2570 return JsValueFromLocalValue(scope.Escape(undefObj));
2571 // LCOV_EXCL_STOP
2572 }
2573
2574 #define EXECUTE_BUFFER(functionName) \
2575 if (panda::JSNApi::IsBundle(vm_)) { \
2576 /* FA doesn't enable securemem */ \
2577 ret = panda::JSNApi::Execute(vm_, buffer, bufferSize, PANDA_MAIN_FUNCTION, desc); \
2578 } else if (bufferSize != 0) { \
2579 if (entryPoint == nullptr) { \
2580 HILOG_DEBUG("Input entryPoint is nullptr, please input entryPoint for merged ESModule"); \
2581 /* this path for bundle and abc compiled by single module js */ \
2582 ret = panda::JSNApi::functionName(vm_, buffer, bufferSize, PANDA_MAIN_FUNCTION, desc); \
2583 } else { \
2584 /* this path for mergeabc with specific entryPoint */ \
2585 ret = panda::JSNApi::functionName(vm_, buffer, bufferSize, entryPoint, desc); \
2586 } \
2587 } else { \
2588 /* this path for worker */ \
2589 ret = panda::JSNApi::Execute(vm_, desc, PANDA_MAIN_FUNCTION); \
2590 }
2591
RunActor(uint8_t * buffer,size_t bufferSize,const char * descriptor,char * entryPoint,bool checkPath)2592 napi_value ArkNativeEngine::RunActor(uint8_t* buffer, size_t bufferSize,
2593 const char* descriptor, char* entryPoint, bool checkPath)
2594 {
2595 if (buffer == nullptr && descriptor == nullptr) {
2596 HILOG_ERROR("invalid param, both buffer and descriptor are nullptr");
2597 return nullptr;
2598 }
2599
2600 if ((buffer != nullptr && !IsValidScriptBuffer(buffer, bufferSize)) &&
2601 (checkPath && descriptor != nullptr && !IsValidPandaFile(descriptor))) {
2602 HILOG_ERROR("invalid param");
2603 return nullptr;
2604 }
2605
2606 // LCOV_EXCL_START
2607 panda::EscapeLocalScope scope(vm_);
2608 std::string desc(descriptor);
2609 [[maybe_unused]] bool ret = false;
2610 // if apiVersion > API11, use secure path.
2611 if (IsApplicationApiVersionAPI11Plus()) {
2612 EXECUTE_BUFFER(ExecuteSecure);
2613 } else {
2614 EXECUTE_BUFFER(Execute);
2615 }
2616 if (panda::JSNApi::HasPendingException(vm_)) {
2617 HandleUncaughtException();
2618 return nullptr;
2619 }
2620 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
2621 return JsValueFromLocalValue(scope.Escape(undefObj));
2622 // LCOV_EXCL_STOP
2623 }
2624
LoadArkModule(const void * buffer,int32_t len,const std::string & fileName)2625 panda::Local<panda::ObjectRef> ArkNativeEngine::LoadArkModule(const void* buffer,
2626 int32_t len, const std::string& fileName)
2627 {
2628 panda::EscapeLocalScope scope(vm_);
2629 Local<ObjectRef> undefObj(JSValueRef::Undefined(vm_));
2630 if (buffer == nullptr || len <= 0 || fileName.empty()) {
2631 HILOG_ERROR("fileName is nullptr or source code is nullptr");
2632 return scope.Escape(undefObj);
2633 }
2634 if (!IsValidScriptBuffer(reinterpret_cast<uint8_t*>(const_cast<void*>(buffer)), len)) {
2635 HILOG_ERROR("invalid script buffer");
2636 return scope.Escape(undefObj);
2637 }
2638
2639 // LCOV_EXCL_START
2640 bool res = JSNApi::ExecuteModuleFromBuffer(vm_, buffer, len, fileName);
2641 if (!res) {
2642 HILOG_ERROR("Execute module failed");
2643 return scope.Escape(undefObj);
2644 }
2645
2646 Local<ObjectRef> exportObj = JSNApi::GetExportObjectFromBuffer(vm_, fileName, "default");
2647 if (exportObj->IsNull()) {
2648 HILOG_ERROR("Get export object failed");
2649 return scope.Escape(undefObj);
2650 }
2651
2652 HILOG_DEBUG("ArkNativeEngineImpl::LoadModule end");
2653 return scope.Escape(exportObj);
2654 // LCOV_EXCL_STOP
2655 }
2656
ExecuteJsBin(const std::string & fileName,bool checkPath)2657 bool ArkNativeEngine::ExecuteJsBin(const std::string& fileName, bool checkPath)
2658 {
2659 if (checkPath && !IsValidPandaFile(fileName.c_str())) {
2660 HILOG_ERROR("faild to execute js bin, file is not exist or format is invalid");
2661 return false;
2662 }
2663 // LCOV_EXCL_START
2664 panda::JSExecutionScope executionScope(vm_);
2665 LocalScope scope(vm_);
2666 bool ret = JSNApi::Execute(vm_, fileName, PANDA_MAIN_FUNCTION);
2667 return ret;
2668 // LCOV_EXCL_STOP
2669 }
2670