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 #include "ecmascript/napi/include/jsnapi_expo.h"
18
19 #ifdef ENABLE_HITRACE
20 #include <sys/prctl.h>
21 #endif
22
23 #include "ark_hybrid_native_reference.h"
24 #include "ark_native_deferred.h"
25 #include "ark_native_reference.h"
26 #include "ark_native_timer.h"
27 #include "native_engine/native_utils.h"
28 #include "native_sendable.h"
29 #include "cj_support.h"
30 #include "securec.h"
31 #include "utils/file.h"
32 #include <cinttypes>
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
47 #ifdef ENABLE_HITRACE
48 #include "hitrace_meter.h"
49 #include "parameter.h"
50 #include "musl_preinit_common.h"
51 #include "memory_trace.h"
52 #include "ecmascript/base/config.h"
53
54 // LCOV_EXCL_START
55 struct alignas(8) HookJsConfig { // 8 is 8 bit
56 int32_t jsStackReport = 0;
57 uint8_t maxJsStackDepth = 0;
58 bool jsFpUnwind = false;
59 char filterNapiName[64] = { "" };
60 };
61
62 class BlockHookScope {
63 public:
BlockHookScope()64 BlockHookScope()
65 {
66 previousState_ = __set_hook_flag(false);
67 }
~BlockHookScope()68 ~BlockHookScope()
69 {
70 __set_hook_flag(previousState_);
71 }
72 private:
73 bool previousState_ {true};
74 };
75
76 static HookJsConfig* g_hookJsConfig = nullptr;
77 static std::once_flag g_hookOnceFlag;
78 static std::string JS_CALL_STACK_DEPTH_SEP = ","; // ',' is js call stack depth separator
79 static std::string JS_SYMBOL_FILEPATH_SEP = "|"; // '|' is js symbol and filepath separator
80 static constexpr uint64_t BUF_SIZE = 128;
81 #endif // ENABLE_HITRACE
82
83 using panda::JsiRuntimeCallInfo;
84 using panda::BooleanRef;
85 using panda::ObjectRef;
86 using panda::StringRef;
87 using panda::Global;
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 using ArkCrashHolder = panda::ArkCrashHolder;
100 using ArkIdleMonitor = panda::ecmascript::ArkIdleMonitor;
101 using AsyncNativeCallbacksPack = panda::AsyncNativeCallbacksPack;
102 using EcmaVM = panda::ecmascript::EcmaVM;
103 using TriggerGCData = panda::TriggerGCData;
104
105 static constexpr auto PANDA_MAIN_FUNCTION = "_GLOBAL::func_main_0";
106 static constexpr auto PANDA_MODULE_NAME = "_GLOBAL_MODULE_NAME";
107 static constexpr auto PANDA_MODULE_NAME_LEN = 32;
108 static std::unordered_set<std::string> NATIVE_MODULE = {"system.app", "ohos.app", "system.router",
109 "system.curves", "ohos.curves", "system.matrix4", "ohos.matrix4"};
110 static constexpr auto NATIVE_MODULE_PREFIX = "@native:";
111 static constexpr auto OHOS_MODULE_PREFIX = "@ohos:";
112 static constexpr int ARGC_THREE = 3;
113
114 // See `ArkNativeEngine::RequireNapi` for more information.
115 #ifndef PREVIEW
116 static constexpr const char* REQUIRE_NAPI_FUNCTION_NAME = "requireNapi";
117 #else
118 static constexpr const char* REQUIRE_NAPI_FUNCTION_NAME = "requireNapiPreview";
119 #endif
120 // See `ArkNativeEngine::RequireInternal` for more information.
121 static constexpr const char* REQUIRE_NAPI_INTERNAL_NAME = "requireInternal";
122
123 #ifdef ENABLE_HITRACE
124 constexpr auto NAPI_PROFILER_PARAM_SIZE = 10;
125 std::atomic<uint64_t> g_chainId = 0;
126 constexpr int NAPI_CALL_STACK = 2; // just for napi call stack
127 #endif
128
129 std::string ArkNativeEngine::tempModuleName_ {""};
130 bool ArkNativeEngine::napiProfilerEnabled {false};
131 bool ArkNativeEngine::napiProfilerParamReaded {false};
132 PermissionCheckCallback ArkNativeEngine::permissionCheckCallback_ {nullptr};
133 std::atomic<NapiModuleValidateCallback> ArkNativeEngine::moduleValidateCallback_ {nullptr};
134 #if defined(PREVIEW)
135 bool ArkNativeEngine::enableFileOperation_ {false};
136 #endif
137
138 // This interface is using by ace_engine
LocalValueToLocalNapiValue(panda::Local<panda::JSValueRef> local)139 napi_value LocalValueToLocalNapiValue(panda::Local<panda::JSValueRef> local)
140 {
141 return JsValueFromLocalValue(local);
142 }
143
144 // This interface is using by ace_engine
NapiValueToLocalValue(napi_value v)145 panda::Local<panda::JSValueRef> NapiValueToLocalValue(napi_value v)
146 {
147 return LocalValueFromJsValue(v);
148 }
149
150 #ifdef ENABLE_CONTAINER_SCOPE
FunctionSetContainerId(napi_env env,panda::Local<panda::JSValueRef> & value)151 void FunctionSetContainerId(napi_env env, panda::Local<panda::JSValueRef> &value)
152 {
153 NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
154 if (!engine->IsContainerScopeEnabled()) {
155 return;
156 }
157 auto vm = engine->GetEcmaVm();
158 if (!value->IsFunction(vm)) {
159 return;
160 }
161 panda::Local<panda::FunctionRef> funcValue(value);
162 if (funcValue->IsNative(vm)) {
163 return;
164 }
165
166 auto extraInfo = funcValue->GetData(vm);
167 if (extraInfo != nullptr) {
168 return;
169 }
170
171 NapiFunctionInfo *funcInfo = NapiFunctionInfo::CreateNewInstance();
172 if (funcInfo == nullptr) {
173 HILOG_ERROR("funcInfo is nullptr");
174 return;
175 }
176 funcInfo->scopeId = OHOS::Ace::ContainerScope::CurrentId();
177 funcValue->SetData(vm, reinterpret_cast<void*>(funcInfo),
178 [](void* env, void *externalPointer, void *data) {
179 auto info = reinterpret_cast<NapiFunctionInfo*>(data);
180 if (info != nullptr) {
181 delete info;
182 info = nullptr;
183 }
184 }, true);
185 }
186 #endif
187
NapiNativeCreateFunction(napi_env env,const char * name,NapiNativeCallback cb,void * value)188 static Local<panda::JSValueRef> NapiNativeCreateFunction(napi_env env, const char* name,
189 NapiNativeCallback cb, void* value)
190 {
191 auto engine = reinterpret_cast<NativeEngine*>(env);
192 auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
193 NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
194 if (funcInfo == nullptr) {
195 HILOG_ERROR("funcInfo is nullptr");
196 return JSValueRef::Undefined(vm);
197 }
198 funcInfo->callback = cb;
199 funcInfo->data = value;
200 funcInfo->env = env;
201 #ifdef ENABLE_CONTAINER_SCOPE
202 if (engine->IsContainerScopeEnabled()) {
203 funcInfo->scopeId = OHOS::Ace::ContainerScope::CurrentId();
204 }
205 #endif
206
207 Local<JSValueRef> context = engine->GetContext();
208 Local<panda::FunctionRef> fn = panda::FunctionRef::NewConcurrentWithName(vm, context, ArkNativeFunctionCallBack,
209 CommonDeleter, name,
210 reinterpret_cast<void*>(funcInfo), true);
211 return fn;
212 }
213
NapiInitAttrValFromProp(napi_env env,const NapiPropertyDescriptor & property,bool & writable,Local<panda::JSValueRef> * curKey)214 static Local<panda::JSValueRef> NapiInitAttrValFromProp(napi_env env, const NapiPropertyDescriptor &property,
215 bool &writable, Local<panda::JSValueRef> *curKey)
216 {
217 const EcmaVM *vm = reinterpret_cast<NativeEngine *>(env)->GetEcmaVm();
218 Local<panda::JSValueRef> val = panda::JSValueRef::Undefined(vm);
219 std::string fullName("");
220 if (property.getter != nullptr || property.setter != nullptr) {
221 Local<panda::JSValueRef> localGetter = panda::JSValueRef::Undefined(vm);
222 Local<panda::JSValueRef> localSetter = panda::JSValueRef::Undefined(vm);
223 if (property.getter != nullptr) {
224 fullName += "getter";
225 localGetter = NapiNativeCreateFunction(env, fullName.c_str(), property.getter, property.data);
226 }
227 if (property.setter != nullptr) {
228 fullName += "setter";
229 localSetter = NapiNativeCreateFunction(env, fullName.c_str(), property.setter, property.data);
230 }
231 val = panda::ObjectRef::CreateAccessorData(vm, localGetter, localSetter);
232 writable = false; // the default writable of getter and setter is 'false'
233 } else if (property.method != nullptr) {
234 if (property.utf8name != nullptr) {
235 fullName += property.utf8name;
236 } else {
237 fullName += (*curKey)->IsString(vm) ?
238 Local<panda::StringRef>(*curKey)->ToString(vm) :
239 Local<panda::SymbolRef>(*curKey)->GetDescription(vm)->ToString(vm);
240 }
241 val = NapiNativeCreateFunction(env, fullName.c_str(), property.method, property.data);
242 } else {
243 val = LocalValueFromJsValue(property.value);
244 }
245 return val;
246 }
247
NapiGetKeysAndAttrsFromProps(napi_env env,size_t propertyCount,const NapiPropertyDescriptor * properties,Local<panda::JSValueRef> * keys,PropertyAttribute * attrs)248 static size_t NapiGetKeysAndAttrsFromProps(napi_env env, size_t propertyCount, const NapiPropertyDescriptor *properties,
249 Local<panda::JSValueRef> *keys, PropertyAttribute *attrs)
250 {
251 auto vm = reinterpret_cast<NativeEngine *>(env)->GetEcmaVm();
252 size_t curNonStaticPropIdx = propertyCount - 1; // 1: last index of array is 'lenght - 1'.
253 size_t curStaticPropIdx = 0;
254 for (size_t i = 0; i < propertyCount; ++i) {
255 const NapiPropertyDescriptor &property = properties[i];
256 Local<panda::JSValueRef> *curKey;
257 PropertyAttribute *curAttr;
258 // Properties in keys and attrs are stored in the following way:
259 // +------------------+ ... + -------------------------------------+ ... +---------------------+
260 // | first staticProp | ... | last staticProp | last nonStaticProp | ... | first nonStaticProp |
261 // +------------------+ ... + -------------------------------------+ ... +---------------------+
262 if (properties[i].attributes & NATIVE_STATIC) {
263 curKey = &keys[curStaticPropIdx];
264 curAttr = &attrs[curStaticPropIdx];
265 ++curStaticPropIdx;
266 } else {
267 curKey = &keys[curNonStaticPropIdx];
268 curAttr = &attrs[curNonStaticPropIdx];
269 --curNonStaticPropIdx;
270 }
271 if (property.utf8name != nullptr) {
272 *curKey = panda::StringRef::NewFromUtf8(vm, property.utf8name);
273 } else {
274 *curKey = LocalValueFromJsValue(property.name);
275 }
276 bool writable = (property.attributes & NATIVE_WRITABLE) != 0;
277 bool enumable = (property.attributes & NATIVE_ENUMERABLE) != 0;
278 bool configable = (property.attributes & NATIVE_CONFIGURABLE) != 0;
279 Local<panda::JSValueRef> val = NapiInitAttrValFromProp(env, property, writable, curKey);
280 // ~PropertyAttribute() was called in NewConcurrentClassFunctionWithName
281 new (curAttr) PropertyAttribute(val, writable, enumable, configable);
282 }
283 return curStaticPropIdx;
284 }
285
NapiCreateClassFunction(napi_env env,std::string & className,NapiFunctionInfo * funcInfo,size_t propCount,const NapiPropertyDescriptor * properties)286 static Local<panda::FunctionRef> NapiCreateClassFunction(napi_env env, std::string &className,
287 NapiFunctionInfo* funcInfo, size_t propCount,
288 const NapiPropertyDescriptor* properties)
289 {
290 const EcmaVM *vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
291 NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
292 Local<JSValueRef> context = engine->GetContext();
293 Local<panda::FunctionRef> fn;
294 if (propCount == 0) {
295 fn = panda::FunctionRef::NewConcurrentClassFunctionWithName(vm, context, ArkNativeFunctionCallBack,
296 CommonDeleter, className.c_str(),
297 reinterpret_cast<void*>(funcInfo), true);
298 } else if (propCount <= panda::ObjectRef::MAX_PROPERTIES_ON_STACK) {
299 Local<panda::JSValueRef> keys[panda::ObjectRef::MAX_PROPERTIES_ON_STACK];
300 PropertyAttribute attrs[panda::ObjectRef::MAX_PROPERTIES_ON_STACK];
301 size_t staticPropCount = NapiGetKeysAndAttrsFromProps(env, propCount, properties, &keys[0], &attrs[0]);
302 fn = panda::FunctionRef::NewConcurrentClassFunctionWithName(vm, context, ArkNativeFunctionCallBack,
303 CommonDeleter, className.c_str(),
304 reinterpret_cast<void*>(funcInfo), true, propCount,
305 staticPropCount, &keys[0], &attrs[0]);
306 } else {
307 Local<panda::JSValueRef> *keys =
308 reinterpret_cast<Local<panda::JSValueRef> *>(malloc(sizeof(Local<panda::JSValueRef>) * propCount));
309 PropertyAttribute *attrs = reinterpret_cast<PropertyAttribute *>(malloc(sizeof(PropertyAttribute) * propCount));
310 if (attrs != nullptr && keys != nullptr) {
311 size_t staticPropCount = NapiGetKeysAndAttrsFromProps(env, propCount, properties, keys, attrs);
312 fn = panda::FunctionRef::NewConcurrentClassFunctionWithName(vm, context, ArkNativeFunctionCallBack,
313 CommonDeleter, className.c_str(),
314 reinterpret_cast<void*>(funcInfo), true,
315 propCount, staticPropCount, keys, attrs);
316 } else {
317 fn = panda::JSValueRef::Undefined(vm);
318 napi_throw_error(env, nullptr, "malloc failed in napi_define_class");
319 }
320
321 if (keys != nullptr) {
322 free(keys);
323 }
324 if (attrs != nullptr) {
325 free(attrs);
326 }
327 }
328 return fn;
329 }
330
NapiDefineClass(napi_env env,const char * name,NapiNativeCallback callback,void * data,const NapiPropertyDescriptor * properties,size_t length)331 panda::Local<panda::JSValueRef> NapiDefineClass(napi_env env, const char* name, NapiNativeCallback callback,
332 void* data, const NapiPropertyDescriptor* properties, size_t length)
333 {
334 auto vm = const_cast<EcmaVM*>(reinterpret_cast<NativeEngine*>(env)->GetEcmaVm());
335 std::string className(name);
336 if (ArkNativeEngine::napiProfilerEnabled) {
337 className = ArkNativeEngine::tempModuleName_ + "." + name;
338 }
339
340 NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
341 if (funcInfo == nullptr) {
342 HILOG_ERROR("funcInfo is nullptr");
343 return panda::JSValueRef::Undefined(vm);
344 }
345 funcInfo->callback = callback;
346 funcInfo->data = data;
347 funcInfo->env = env;
348 #ifdef ENABLE_CONTAINER_SCOPE
349 NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
350 if (engine->IsContainerScopeEnabled()) {
351 funcInfo->scopeId = OHOS::Ace::ContainerScope::CurrentId();
352 }
353 #endif
354 Local<panda::FunctionRef> fn = NapiCreateClassFunction(env, className, funcInfo, length, properties);
355
356 Local<panda::ObjectRef> excep = JSNApi::GetUncaughtException(vm);
357 if (!excep.IsNull()) {
358 HILOG_DEBUG("ArkNativeObject::NapiDefineClass occur Exception");
359 JSNApi::GetAndClearUncaughtException(vm);
360 }
361 #ifdef ENABLE_HITRACE
362 Local<panda::ObjectRef> classPrototype = fn->GetFunctionPrototype(vm);
363 reinterpret_cast<ArkNativeEngine*>(env)->SetModuleName(classPrototype, className);
364 #endif
365 return fn;
366 }
367
NapiDefineSendableClass(napi_env env,const char * name,NapiNativeCallback callback,void * data,const NapiPropertyDescriptor * properties,size_t propertiesLength,napi_value parent)368 panda::Local<panda::JSValueRef> NapiDefineSendableClass(napi_env env,
369 const char* name,
370 NapiNativeCallback callback,
371 void* data,
372 const NapiPropertyDescriptor* properties,
373 size_t propertiesLength,
374 napi_value parent)
375 {
376 const EcmaVM* vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
377 NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
378 if (funcInfo == nullptr) {
379 HILOG_FATAL("funcInfo is nullptr");
380 return JSValueRef::Undefined(vm);
381 }
382 funcInfo->callback = callback;
383 funcInfo->data = data;
384 funcInfo->isSendable = true;
385 std::string className(name);
386 if (ArkNativeEngine::napiProfilerEnabled) {
387 className = ArkNativeEngine::tempModuleName_ + "." + name;
388 }
389
390 Local<panda::StringRef> fnName = panda::StringRef::NewFromUtf8(vm, className.c_str());
391 Local<JSValueRef> localParent = JSValueRef::Hole(vm);
392 if (parent != nullptr) {
393 localParent = LocalValueFromJsValue(parent);
394 }
395
396 auto infos = NativeSendable::CreateSendablePropertiesInfos(env, properties, propertiesLength);
397 Local<panda::FunctionRef> fn = panda::FunctionRef::NewSendableClassFunction(vm, ArkNativeFunctionCallBack,
398 CommonDeleter, reinterpret_cast<void*>(funcInfo), fnName, infos, localParent, true);
399
400 return fn;
401 }
402
403 struct MoudleNameLocker {
MoudleNameLockerMoudleNameLocker404 explicit MoudleNameLocker(std::string moduleName)
405 {
406 ArkNativeEngine::tempModuleName_ = moduleName;
407 }
~MoudleNameLockerMoudleNameLocker408 ~MoudleNameLocker()
409 {
410 ArkNativeEngine::tempModuleName_ = "";
411 }
412 };
413
GetNativePtrCallBack(void * data)414 void* ArkNativeEngine::GetNativePtrCallBack(void* data)
415 {
416 if (data == nullptr) {
417 HILOG_ERROR("data is nullptr");
418 return nullptr;
419 }
420 auto info = reinterpret_cast<NapiFunctionInfo*>(data);
421 auto cb = reinterpret_cast<void*>(info->callback);
422 return cb;
423 }
424
SetModuleValidateCallback(NapiModuleValidateCallback validateCallback)425 bool ArkNativeEngine::SetModuleValidateCallback(NapiModuleValidateCallback validateCallback)
426 {
427 if (validateCallback == nullptr) {
428 HILOG_WARN("Module Validate Callback nullptr. Please check input.");
429 return false;
430 }
431 if (moduleValidateCallback_.load()) {
432 HILOG_ERROR("Module Validate Callback is already set by another module or thread.");
433 return false;
434 }
435 moduleValidateCallback_ = validateCallback;
436 return true;
437 }
438
CheckArkApiAllowList(NativeModule * module,panda::ecmascript::ApiCheckContext context,panda::Local<panda::ObjectRef> & exportCopy)439 bool ArkNativeEngine::CheckArkApiAllowList(
440 NativeModule* module, panda::ecmascript::ApiCheckContext context, panda::Local<panda::ObjectRef>& exportCopy)
441 {
442 std::unique_ptr<ApiAllowListChecker>& apiAllowListChecker = module->apiAllowListChecker;
443 if (apiAllowListChecker != nullptr) {
444 const std::string apiPath = context.moduleName->ToString(context.ecmaVm);
445 if ((*apiAllowListChecker)(apiPath)) {
446 CopyPropertyApiFilter(apiAllowListChecker, context.ecmaVm, context.exportObj, exportCopy, apiPath);
447 }
448 return true;
449 }
450 return false;
451 }
452
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)453 void ArkNativeEngine::CopyPropertyApiFilter(const std::unique_ptr<ApiAllowListChecker>& apiAllowListChecker,
454 const EcmaVM* ecmaVm, const panda::Local<panda::ObjectRef> exportObj, panda::Local<panda::ObjectRef>& exportCopy,
455 const std::string& apiPath)
456 {
457 panda::Local<panda::ArrayRef> namesArrayRef = exportObj->GetAllPropertyNames(ecmaVm, NATIVE_DEFAULT);
458 for (uint32_t i = 0; i < namesArrayRef->Length(ecmaVm); ++i) {
459 const panda::Local<panda::JSValueRef> nameValue = panda::ArrayRef::GetValueAt(ecmaVm, namesArrayRef, i);
460 const panda::Local<panda::JSValueRef> value = exportObj->Get(ecmaVm, nameValue);
461 const std::string curPath = apiPath + "." + nameValue->ToString(ecmaVm)->ToString(ecmaVm);
462 if ((*apiAllowListChecker)(curPath)) {
463 const std::string valueType = value->Typeof(ecmaVm)->ToString(ecmaVm);
464 if (valueType == "object") {
465 panda::Local<panda::ObjectRef> subObject = ObjectRef::New(ecmaVm);
466 CopyPropertyApiFilter(apiAllowListChecker, ecmaVm, value, subObject, curPath);
467 exportCopy->Set(ecmaVm, nameValue, subObject);
468 HILOG_DEBUG("Set the package '%{public}s' to the allow list", curPath.c_str());
469 } else if (valueType == "function") {
470 exportCopy->Set(ecmaVm, nameValue, value);
471 HILOG_DEBUG("Set the function '%{public}s' to the allow list", curPath.c_str());
472 } else {
473 exportCopy->Set(ecmaVm, nameValue, value);
474 HILOG_DEBUG("Set the element type is '%{public}s::%{public}s' to the allow list", valueType.c_str(),
475 curPath.c_str());
476 }
477 }
478 }
479 }
480
ArkNativeEngine(EcmaVM * vm,void * jsEngine,bool isLimitedWorker)481 ArkNativeEngine::ArkNativeEngine(EcmaVM* vm, void* jsEngine, bool isLimitedWorker) : NativeEngine(jsEngine),
482 vm_(vm),
483 topScope_(vm),
484 isLimitedWorker_(isLimitedWorker),
485 isMainEnvContext_(true)
486 {
487 HILOG_INFO("ArkNativeEngine is created, id %{public}" PRIu64, GetId());
488
489 JSNApi::SetEnv(vm, this);
490 // enable napi profiler
491 EnableNapiProfiler();
492 LocalScope scope(vm_);
493
494 options_ = new NapiOptions();
495 // Update cache of ark runtime cross thread check option.
496 UpdateCrossThreadCheckStatus();
497 #ifdef ENABLE_CONTAINER_SCOPE
498 containerScopeEnable_ = OHOS::system::GetBoolParameter("persist.ace.napiContainerScope.enabled", true);
499 #endif
500 #if defined(OHOS_PLATFORM) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
501 int napiProperties = OHOS::system::GetIntParameter<int>("persist.ark.napi.properties", -1);
502 if (options_ != nullptr) {
503 options_->SetProperties(napiProperties);
504 }
505 #endif
506
507 // init common requireNapi and requireInternal
508 void* requireData = static_cast<void*>(this);
509 Local<ObjectRef> global = JSNApi::GetGlobalObject(vm);
510 global->Set(vm, StringRef::NewFromUtf8(vm, REQUIRE_NAPI_FUNCTION_NAME),
511 FunctionRef::New(vm, RequireNapi, nullptr, requireData));
512
513 global->Set(vm, StringRef::NewFromUtf8(vm, REQUIRE_NAPI_INTERNAL_NAME),
514 FunctionRef::New(vm, RequireInternal, nullptr, requireData));
515
516 JSNApi::SetNativePtrGetter(vm, reinterpret_cast<void*>(ArkNativeEngine::GetNativePtrCallBack));
517 // need to call init of base class.
518 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
519 std::function<bool(const std::string&)> func = [moduleManager](const std::string& moduleKey) -> bool {
520 return moduleManager->UnloadNativeModule(moduleKey);
521 };
522 JSNApi::SetUnloadNativeModuleCallback(vm, func);
523 Init();
524 JSNApi::SetLoop(vm, loop_);
525 DFXJSNApi::RegisterAsyncDetectCallBack(vm);
526 JSNApi::SetWeakFinalizeTaskCallback(vm, [this] () -> void {
527 this->PostFinalizeTasks();
528 });
529 JSNApi::SetAsyncCleanTaskCallback(vm, [this] (AsyncNativeCallbacksPack *callbacksPack) {
530 this->PostAsyncTask(callbacksPack);
531 });
532 JSNApi::SetHostPromiseRejectionTracker(vm_, reinterpret_cast<void*>(PromiseRejectCallback),
533 reinterpret_cast<void*>(this));
534 JSNApi::SetTimerTaskCallback(vm, NativeTimerCallbackInfo::TimerTaskCallback);
535 JSNApi::SetCancelTimerCallback(vm, NativeTimerCallbackInfo::CancelTimerCallback);
536 JSNApi::NotifyEnvInitialized(vm);
537 if (IsMainThread()) {
538 RegisterAllPromiseCallback([this] (napi_value* args) -> void {
539 if (!NativeEngine::IsAlive(this)) {
540 HILOG_WARN("napi_env has been destoryed!");
541 return;
542 }
543 NapiErrorManager::GetInstance()->NotifyUnhandledRejection(reinterpret_cast<napi_env>(this), args, "", 0);
544 });
545 }
546
547 // enable idle gc
548 ArkIdleMonitor::GetInstance()->EnableIdleGC(this);
549
550 // save the first context
551 context_ = Global<JSValueRef>(vm, JSNApi::GetCurrentContext(vm));
552 }
553
554 /**
555 * Constructor for Ark Context Engine
556 * 1. Must be created from the root engine.
557 * 2. Does not directly provide UV capabilities (i.e., libuv-related functionality).
558 * 3. Async capabilities are provided by the parent engine.
559 */
ArkNativeEngine(NativeEngine * parent,EcmaVM * vm,const Local<JSValueRef> & context)560 ArkNativeEngine::ArkNativeEngine(NativeEngine* parent, EcmaVM* vm, const Local<JSValueRef>& context)
561 : NativeEngine(parent),
562 vm_(vm),
563 topScope_(vm),
564 context_(vm, context),
565 parentEngine_(reinterpret_cast<ArkNativeEngine*>(parent)),
566 containerScopeEnable_(parent->IsContainerScopeEnabled()),
567 isMainEnvContext_(false),
568 isMultiContextEnabled_(true)
569 {
570 HILOG_INFO("ArkContextEngine is created, id %{public}" PRIu64, GetId());
571
572 // The sub-context environment must be deleted before the uv_loop is destroyed.
573 // In this case, we cannot delay the destruction of the context environment
574 // until all napi_ref callbacks are completed.
575 parent->AddCleanupHook(EnvironmentCleanup, this);
576
577 parent->SetMultiContextEnabled(true);
578
579 LocalScope scope(vm);
580
581 // enable napi profiler
582 EnableNapiProfiler();
583
584 // Update cache of ark runtime cross thread check option.
585 UpdateCrossThreadCheckStatus();
586
587 options_ = new NapiOptions();
588 #if defined(OHOS_PLATFORM) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
589 int napiProperties = OHOS::system::GetIntParameter<int>("persist.ark.napi.properties", -1);
590 if (options_ != nullptr) {
591 options_->SetProperties(napiProperties);
592 }
593 #endif
594
595 // init common requireNapi and requireInternal
596 void* requireData = static_cast<void*>(this);
597 Local<ObjectRef> global = JSNApi::GetGlobalObject(vm, context);
598 global->Set(vm, StringRef::NewFromUtf8(vm, REQUIRE_NAPI_FUNCTION_NAME),
599 FunctionRef::New(vm, context, RequireNapiForCtxEnv, nullptr, requireData));
600 global->Set(vm, StringRef::NewFromUtf8(vm, REQUIRE_NAPI_INTERNAL_NAME),
601 FunctionRef::New(vm, context, RequireInternal, nullptr, requireData));
602
603 InitWithoutUV();
604 // The VM scope callback is initialized during the construction of the root engine and is ignored in this context.
605 }
606
~ArkNativeEngine()607 ArkNativeEngine::~ArkNativeEngine()
608 {
609 HILOG_INFO("%{public}s %{public}" PRIu64 " is deconstructed",
610 isMainEnvContext_ ? "ArkNativeEngine" : "ArkContextEngine", GetId());
611
612 engineState_ = ArkNativeEngineState::RELEASING;
613
614 if (isMainEnvContext_) {
615 // unregister worker env for idle GC
616 ArkIdleMonitor::GetInstance()->UnregisterEnv(this);
617 JSNApi::SetTimerTaskCallback(vm_, nullptr);
618 JSNApi::SetCancelTimerCallback(vm_, nullptr);
619 NativeTimerCallbackInfo::ReleaseTimerList(this);
620 // destroy looper resource on the ark native engine
621 Deinit();
622 if (JSNApi::IsJSMainThreadOfEcmaVM(vm_)) {
623 ArkIdleMonitor::GetInstance()->SetMainThreadEcmaVM(nullptr);
624 }
625 } else {
626 DeconstructCtxEnv();
627 }
628 // Free cached module objects
629 for (auto&& [module, exportObj] : loadedModules_) {
630 exportObj.FreeGlobalHandleAddr();
631 }
632 // Free callbackRef
633 if (promiseRejectCallbackRef_ != nullptr) {
634 delete promiseRejectCallbackRef_;
635 }
636 if (checkCallbackRef_ != nullptr) {
637 delete checkCallbackRef_;
638 }
639 if (options_ != nullptr) {
640 delete options_;
641 options_ = nullptr;
642 }
643 }
644
New(NativeEngine * engine,EcmaVM * vm,const Local<JSValueRef> & context)645 ArkNativeEngine *ArkNativeEngine::New(NativeEngine* engine, EcmaVM* vm, const Local<JSValueRef>& context)
646 {
647 if (engine == nullptr) {
648 HILOG_FATAL("Invalid arguments, parameter engine cannot be nullptr");
649 }
650 if (vm == nullptr) {
651 HILOG_FATAL("Invalid arguments, parameter vm cannot be nullptr");
652 }
653 if (!engine->IsMainEnvContext()) {
654 HILOG_FATAL("Invalid arguments, parameter engine cannot be Ark Context Engine");
655 }
656 if (!context->IsJsGlobalEnv(vm)) {
657 HILOG_FATAL("Invalid arguments, parameter context must be JsGlobalEnv");
658 }
659 return new ArkNativeEngine(engine, vm, context);
660 }
661
IsReadyToDelete()662 bool ArkNativeEngine::IsReadyToDelete()
663 {
664 // Fast-path optimization: main contexts are not deletable and common case.
665 // Also ensure the environment is only deleted once (not during destruction).
666 return !isMainEnvContext_ && // Check whether current engine is context engine.
667 engineState_ == ArkNativeEngineState::STOPPED && // Check whether `DestroyContext` is invoked,
668 // and engine is not deconstructing.
669 !HasRuntimeOwnedRef(); // Check whether runtime owned ref is released.
670 }
671
Delete()672 void ArkNativeEngine::Delete()
673 {
674 context_.FreeGlobalHandleAddr();
675 delete this;
676 }
677
678
679 /**
680 * Replacement of NativeEngine::Deinit
681 * The Ark Context Engine does not maintain its own uv_loop.
682 * Any related resource lists will be checked and cleaned up when the context is destroyed.
683 *
684 * Cleanup Steps:
685 * 1. Cleanup hooks will be invoked to handle any necessary cleanup logic.
686 * 2. Owned napi_async_work and napi_threadsafe_function must either
687 * complete execution or be released before the context is destroyed.
688 * - ERROR: uv_run is not supported when loop is running.
689 * - Check `tsfn` and incomplete `async_work` counts, abort if not equal to 0.
690 * 3. Trigger all managed reference finalize callbacks.
691 * 4. Mark the engine as dead (this is particularly important for preventing conflicts
692 * with any future engine instances that may be created at the same memory address).
693 * 5. Recheck async work and tsfn counts to ensure no task leaks after finalize callbacks.
694 */
DeconstructCtxEnv()695 void ArkNativeEngine::DeconstructCtxEnv()
696 {
697 // To avoid blocking the thread, do not wait for any incomplete asynchronous tasks here.
698 RunCleanupHooks(false);
699 DeinitWithoutUV();
700
701 parentEngine_->RemoveCleanupHook(EnvironmentCleanup, this);
702
703 if (HasWaitingRequest()) {
704 HILOG_FATAL("Do not release Ark Context Engine until all async work done");
705 }
706
707 // An active TSFN blocks uv_run, indirectly keeping the engine alive in Node.js (unless unrefed).
708 // Context doesn't have its own uv_loop, so abort if still exists.
709 if (HasActiveTsfn()) {
710 HILOG_FATAL("Failed to release Ark Context Engine: active napi_threadsafe_function still exists.");
711 }
712 SetDead();
713 // twice check after wrap/finalizer callbacks
714 if (HasWaitingRequest()) {
715 HILOG_FATAL("Do not release Ark Context Engine env until all async work done");
716 }
717 if (HasActiveTsfn()) {
718 HILOG_FATAL("Failed to release Ark Context Engine: active napi_threadsafe_function still exists.");
719 }
720
721 if (HasNonCallbackRef()) {
722 HILOG_ERROR("Non-callback napi_ref is leak after context env teardown, counts: %{public}" PRIu64,
723 GetNonCallbackRefCount());
724 }
725 if (HasCallbackbleRef()) {
726 HILOG_ERROR("Callbackble napi_ref is leak after context env teardown, counts: %{public}" PRIu64,
727 GetCallbackbleRefCount());
728 }
729 parentEngine_ = nullptr;
730 }
731
NotifyVMIgnoreFinalizeCallback() const732 void ArkNativeEngine::NotifyVMIgnoreFinalizeCallback() const
733 {
734 JSNApi::IgnoreFinalizeCallback(vm_);
735 }
736
EnvironmentCleanup(void * arg)737 void ArkNativeEngine::EnvironmentCleanup(void* arg)
738 {
739 reinterpret_cast<ArkNativeEngine*>(arg)->Delete();
740 }
741
GetContext() const742 Local<JSValueRef> ArkNativeEngine::GetContext() const
743 {
744 return context_.ToLocal();
745 }
746
GetParent() const747 const ArkNativeEngine* ArkNativeEngine::GetParent() const
748 {
749 return parentEngine_;
750 }
751
CheckAndGetModule(JsiRuntimeCallInfo * info,NativeModuleManager * moduleManager,bool isAppModule,Local<panda::StringRef> & moduleName,NativeModule * & module,Local<JSValueRef> & exports,std::string & errInfo)752 int ArkNativeEngine::CheckAndGetModule(
753 JsiRuntimeCallInfo *info,
754 NativeModuleManager* moduleManager,
755 bool isAppModule,
756 Local<panda::StringRef> &moduleName,
757 NativeModule *&module,
758 Local<JSValueRef> &exports,
759 std::string &errInfo)
760 {
761 #ifdef IOS_PLATFORM
762 if (isLimitedWorker_) {
763 if (!moduleManager->CheckModuleRestricted(moduleName->ToString(vm_).c_str())) {
764 HILOG_ERROR("module %{public}s does not found in whitelist",
765 moduleName->ToString(vm_).c_str());
766 return -1;
767 }
768 }
769 module = moduleManager->LoadNativeModule(
770 moduleName->ToString(vm_).c_str(), nullptr, false, errInfo, false, "");
771 return 0;
772 #else
773 isAppModule_ = isAppModule;
774 if (isLimitedWorker_ && !isAppModule) {
775 if (!moduleManager->CheckModuleRestricted(moduleName->ToString(vm_).c_str())) {
776 HILOG_ERROR("module %{public}s does not found in whitelist",
777 moduleName->ToString(vm_).c_str());
778 return -1;
779 }
780 }
781
782 if (info->GetArgsNumber() == 3) { // 3:Determine if the number of parameters is equal to 3
783 Local<StringRef> path(info->GetCallArgRef(2)); // 2:Take the second parameter
784 if (UNLIKELY(IsCJModule(moduleName->ToString(vm_).c_str()))) {
785 exports = NapiValueToLocalValue(
786 LoadCJModule((napi_env)this, moduleName->ToString(vm_).c_str()));
787 return 1;
788 }
789 module = moduleManager->LoadNativeModule(moduleName->ToString(vm_).c_str(),
790 path->ToString(vm_).c_str(), isAppModule, errInfo, false, "");
791 } else if (info->GetArgsNumber() == 4) { // 4:Determine if the number of parameters is equal to 4
792 Local<StringRef> path(info->GetCallArgRef(2)); // 2:Take the second parameter
793 Local<StringRef> relativePath(info->GetCallArgRef(3)); // 3:Take the second parameter
794 module = moduleManager->LoadNativeModule(moduleName->ToString(vm_).c_str(), nullptr, isAppModule,
795 errInfo, false, relativePath->ToString(vm_).c_str());
796 } else {
797 module = moduleManager->LoadNativeModule(moduleName->ToString(vm_).c_str(),
798 nullptr, isAppModule, errInfo, false, "");
799 }
800 return 0;
801 #endif
802 }
803
LoadNativeModule(NativeModuleManager * moduleManager,Local<StringRef> & moduleName,NativeModule * module,Local<JSValueRef> exports,std::string & errInfo)804 Local<JSValueRef> ArkNativeEngine::LoadNativeModule(
805 NativeModuleManager* moduleManager,
806 Local<StringRef> &moduleName,
807 NativeModule* module,
808 Local<JSValueRef> exports,
809 std::string &errInfo)
810 {
811 if (module == nullptr) {
812 return exports;
813 }
814 panda::EscapeLocalScope scope(vm_);
815 auto it = loadedModules_.find(module);
816 if (it != loadedModules_.end()) {
817 return scope.Escape(it->second.ToLocal(vm_));
818 }
819 std::string strModuleName = moduleName->ToString(vm_);
820 moduleManager->SetNativeEngine(strModuleName, this);
821 MoudleNameLocker nameLocker(strModuleName);
822
823 if (module->jsCode == nullptr && module->getABCCode != nullptr) {
824 module->getABCCode(&module->jsCode, &module->jsCodeLen);
825 }
826 if (module->jsABCCode != nullptr || module->jsCode != nullptr) {
827 char fileName[NAPI_PATH_MAX] = { 0 };
828 const char* name = module->name;
829 if (sprintf_s(fileName, sizeof(fileName), "lib%s.z.so/%s.js", name, name) == -1) {
830 HILOG_ERROR("sprintf_s file name failed, name:%{public}s", name ? name : "nullptr");
831 return scope.Escape(exports);
832 }
833 HILOG_DEBUG("load js code from %{public}s", fileName);
834 const void *buffer = nullptr;
835 if (module->jsABCCode) {
836 buffer = static_cast<const void *>(module->jsABCCode);
837 } else {
838 buffer = static_cast<const void *>(module->jsCode);
839 }
840 auto exportObject = LoadArkModule(buffer,
841 module->jsCodeLen, fileName);
842 if (exportObject->IsUndefined()) {
843 HILOG_ERROR("load module failed, fileName:%{public}s", fileName);
844 return scope.Escape(exports);
845 } else {
846 exports = exportObject;
847 loadedModules_[module] = Global<JSValueRef>(vm_, exports);
848 }
849 } else if (module->registerCallback != nullptr) {
850 Local<ObjectRef> exportObj = ObjectRef::New(vm_);
851 #ifdef ENABLE_HITRACE
852 StartTrace(HITRACE_TAG_ACE, "NAPI module init, name = " + std::string(module->name));
853 #endif
854 SetModuleName(exportObj, module->name);
855 module->registerCallback(reinterpret_cast<napi_env>(this),
856 JsValueFromLocalValue(exportObj));
857 #ifdef ENABLE_HITRACE
858 FinishTrace(HITRACE_TAG_ACE);
859 #endif
860 panda::Local<panda::ObjectRef> exportCopy = panda::ObjectRef::New(vm_);
861 panda::ecmascript::ApiCheckContext context{moduleManager, vm_, moduleName, exportObj, scope};
862 if (CheckArkApiAllowList(module, context, exportCopy)) {
863 return scope.Escape(exportCopy);
864 }
865 exports = exportObj;
866 loadedModules_[module] = Global<JSValueRef>(vm_, exports);
867 } else {
868 HILOG_ERROR("init module failed, moduleName:%{public}s", strModuleName.c_str());
869 return scope.Escape(exports);
870 }
871
872 return scope.Escape(exports);
873 }
874
875 #if defined(PREVIEW)
SetCurrentPreviewenv(bool enableFileOperation)876 void ArkNativeEngine::SetCurrentPreviewenv(bool enableFileOperation)
877 {
878 enableFileOperation_ = enableFileOperation;
879 }
880 #endif
881
882 /** require napi module for Ark Native Engine (standard napi_env).
883 *
884 * TypeScript declaration
885 * - for iOS
886 * function requireNapi(name: string): any;
887 * - other Platform
888 * function requireNapi(
889 * name: string,
890 * appModule: boolean = false,
891 * path?: string,
892 * relativePath?: string): any;
893 */
RequireNapi(JsiRuntimeCallInfo * info)894 Local<JSValueRef> ArkNativeEngine::RequireNapi(JsiRuntimeCallInfo *info)
895 {
896 EcmaVM *ecmaVm = info->GetVM();
897 panda::EscapeLocalScope scope(ecmaVm);
898 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
899 ArkNativeEngine* arkNativeEngine = static_cast<ArkNativeEngine*>(info->GetData());
900 std::string errInfo = "";
901 Local<JSValueRef> exports(JSValueRef::Undefined(ecmaVm));
902 if (info->GetArgsNumber() == 0) {
903 return scope.Escape(exports);
904 }
905 Local<StringRef> moduleName(info->GetCallArgRef(0));
906 #if defined(PREVIEW)
907 if (!enableFileOperation_ && (moduleName->ToString(ecmaVm) == "file.fs")) {
908 return scope.Escape(JSValueRef::Undefined(ecmaVm));
909 }
910 #endif
911 bool isAppModule = false;
912 if (info->GetArgsNumber() > 1) { // 1: index of arguments, isAppModule
913 Local<BooleanRef> ret(info->GetCallArgRef(1));
914 isAppModule = ret->Value();
915 }
916
917 NativeModule* module = nullptr;
918 // Returns the module exports or undefined
919 // if the module is fully loaded (code 1)
920 // or has failed to load (code -1).
921 if (arkNativeEngine->CheckAndGetModule(info, moduleManager, isAppModule,
922 moduleName, module, exports, errInfo) != 0) {
923 return scope.Escape(exports);
924 }
925 // process loaded module
926 if (module) {
927 return scope.Escape(arkNativeEngine->LoadNativeModule(moduleManager, moduleName, module, exports, errInfo));
928 } else {
929 HILOG_INFO("%{public}s", errInfo.c_str());
930 return scope.Escape(panda::ObjectRef::CreateNativeModuleFailureInfo(ecmaVm, errInfo));
931 }
932 }
933
934 /** require napi module for Ark Context Engine.
935 * 1. The app module is not supported.
936 * 2. Whitelist verification will be performed during the callback provided by ArkUI.
937 *
938 * TypeScript declaration
939 * - for iOS
940 * function requireNapi(name: string): any;
941 * - other Platform
942 * function requireNapi(
943 * name: string,
944 * appModule: boolean = false,
945 * path?: string,
946 * relativePath?: string): any;
947 */
RequireNapiForCtxEnv(JsiRuntimeCallInfo * info)948 Local<JSValueRef> ArkNativeEngine::RequireNapiForCtxEnv(JsiRuntimeCallInfo *info)
949 {
950 EcmaVM *ecmaVm = info->GetVM();
951 panda::EscapeLocalScope scope(ecmaVm);
952 Local<JSValueRef> exports(JSValueRef::Undefined(ecmaVm));
953 if (info->GetArgsNumber() == 0) {
954 return scope.Escape(exports);
955 }
956 Local<StringRef> moduleName(info->GetCallArgRef(0));
957
958 bool isAppModule = false;
959 if (info->GetArgsNumber() > 1) { // 1: index of arguments, isAppModule
960 Local<BooleanRef> ret(info->GetCallArgRef(1));
961 isAppModule = ret->Value();
962 }
963 if (isAppModule) {
964 HILOG_FATAL("AppModule is not supported in Context Engine.");
965 }
966
967 std::string modNameCstr = moduleName->ToString(ecmaVm);
968 NapiModuleValidateCallback modCheckCb = moduleValidateCallback_.load();
969 if (modCheckCb == nullptr) {
970 HILOG_ERROR("Cannot load native modules: module validation callback is null.");
971 return scope.Escape(exports);
972 }
973 if (!modCheckCb(modNameCstr.c_str())) {
974 HILOG_ERROR("Module \"%{public}s\" is rejected by the module validation callback.", modNameCstr.c_str());
975 return scope.Escape(exports);
976 }
977
978 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
979 ArkNativeEngine* arkNativeEngine = static_cast<ArkNativeEngine*>(info->GetData());
980 std::string errInfo = "";
981 NativeModule* module = nullptr;
982 // Returns the module exports or undefined
983 // if the module is fully loaded (code 1)
984 // or has failed to load (code -1).
985 if (arkNativeEngine->CheckAndGetModule(info, moduleManager, isAppModule,
986 moduleName, module, exports, errInfo) != 0) {
987 return scope.Escape(exports);
988 }
989 // process loaded module
990 if (module) {
991 return scope.Escape(arkNativeEngine->LoadNativeModule(moduleManager, moduleName, module, exports, errInfo));
992 } else {
993 HILOG_INFO("%{public}s", errInfo.c_str());
994 return scope.Escape(panda::ObjectRef::CreateNativeModuleFailureInfo(ecmaVm, errInfo));
995 }
996 }
997
998 /** Require native part for mixed module
999 *
1000 * Only support in system mixed module, app module would not have AtkTS part.
1001 *
1002 * TypeScript declaration
1003 * function requireInternal(moduleName: string, relativePath?: string): any;
1004 */
RequireInternal(JsiRuntimeCallInfo * info)1005 Local<JSValueRef> ArkNativeEngine::RequireInternal(JsiRuntimeCallInfo *info)
1006 {
1007 EcmaVM *ecmaVm = info->GetVM();
1008 panda::EscapeLocalScope scope(ecmaVm);
1009 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
1010 ArkNativeEngine* arkNativeEngine = static_cast<ArkNativeEngine*>(info->GetData());
1011 Local<StringRef> moduleName(info->GetCallArgRef(0));
1012 std::string errInfo = "";
1013 Local<JSValueRef> exports(JSValueRef::Undefined(ecmaVm));
1014 if (arkNativeEngine->isLimitedWorker_) {
1015 if (!moduleManager->CheckModuleRestricted(moduleName->ToString(ecmaVm).c_str())) {
1016 HILOG_ERROR("module %{public}s does not found in whitelist",
1017 moduleName->ToString(ecmaVm).c_str());
1018 return scope.Escape(exports);
1019 }
1020 }
1021 NativeModule* module = moduleManager->LoadNativeModule(moduleName->ToString(ecmaVm).c_str(),
1022 nullptr, false, errInfo, false, "");
1023 MoudleNameLocker nameLocker(moduleName->ToString(ecmaVm).c_str());
1024 if (module != nullptr && arkNativeEngine) {
1025 if (module->registerCallback == nullptr) {
1026 if (module->name != nullptr) {
1027 HILOG_ERROR("requireInternal Init function is nullptr. module name: %{public}s",
1028 module->name);
1029 } else {
1030 HILOG_ERROR("requireInternal Init function is nullptr.");
1031 }
1032 return scope.Escape(exports);
1033 }
1034
1035 auto it = arkNativeEngine->loadedModules_.find(module);
1036 if (it != arkNativeEngine->loadedModules_.end()) {
1037 return scope.Escape(it->second.ToLocal(ecmaVm));
1038 }
1039 std::string strModuleName = moduleName->ToString(ecmaVm);
1040 moduleManager->SetNativeEngine(strModuleName, arkNativeEngine);
1041 Local<ObjectRef> exportObj = ObjectRef::New(ecmaVm);
1042 if (exportObj->IsObject(ecmaVm)) {
1043 arkNativeEngine->SetModuleName(exportObj, module->name);
1044 module->registerCallback(reinterpret_cast<napi_env>(arkNativeEngine),
1045 JsValueFromLocalValue(exportObj));
1046 panda::Local<panda::ObjectRef> exportCopy = panda::ObjectRef::New(ecmaVm);
1047 panda::ecmascript::ApiCheckContext context{moduleManager, ecmaVm, moduleName, exportObj, scope};
1048 if (CheckArkApiAllowList(module, context, exportCopy)) {
1049 return scope.Escape(exportCopy);
1050 }
1051 exports = exportObj;
1052 arkNativeEngine->loadedModules_[module] = Global<JSValueRef>(ecmaVm, exports);
1053 } else {
1054 HILOG_ERROR("exportObject is nullptr");
1055 return scope.Escape(exports);
1056 }
1057 }
1058 return scope.Escape(exports);
1059 }
1060
1061 #ifdef ENABLE_HITRACE
CheckHookConfig(const std::string & nameRef)1062 static inline bool CheckHookConfig(const std::string &nameRef)
1063 {
1064 if (g_hookJsConfig == nullptr || g_hookJsConfig->jsStackReport <= 0 ||
1065 g_hookJsConfig->maxJsStackDepth == 0 || !g_hookJsConfig->jsFpUnwind) {
1066 return false;
1067 } else if (g_hookJsConfig->filterNapiName[0] != '\0' &&
1068 nameRef.find(g_hookJsConfig->filterNapiName) != std::string::npos) {
1069 return false;
1070 }
1071 return true;
1072 }
1073 #endif
1074
StartNapiProfilerTrace(panda::JsiRuntimeCallInfo * runtimeInfo,NativeEngine * engine,void * cb)1075 static inline uint64_t StartNapiProfilerTrace(panda::JsiRuntimeCallInfo* runtimeInfo, NativeEngine* engine, void* cb)
1076 {
1077 #ifdef ENABLE_HITRACE
1078 if (ArkNativeEngine::napiProfilerEnabled) {
1079 EcmaVM *vm = runtimeInfo->GetVM();
1080 LocalScope scope(vm);
1081 Local<panda::FunctionRef> fn = runtimeInfo->GetFunctionRef();
1082 Local<panda::StringRef> nameRef = fn->GetName(vm);
1083 char threadName[BUF_SIZE];
1084 prctl(PR_GET_NAME, threadName);
1085 StartTraceArgs(HITRACE_TAG_ACE, "Napi called:%s, tname:%s", nameRef->ToString(vm).c_str(), threadName);
1086 }
1087 bool hookFlag = __get_hook_flag() && __get_global_hook_flag();
1088 if (!hookFlag) {
1089 return 0;
1090 }
1091 EcmaVM* vm = runtimeInfo->GetVM();
1092 LocalScope scope(vm);
1093 Local<panda::FunctionRef> fn = runtimeInfo->GetFunctionRef();
1094 Local<panda::StringRef> nameRef = fn->GetName(vm);
1095 if (g_hookJsConfig == nullptr) {
1096 std::call_once(g_hookOnceFlag, []() { g_hookJsConfig = (HookJsConfig*)__get_hook_config(); });
1097 }
1098 // add memtrace function
1099 if (g_hookJsConfig != nullptr && g_hookJsConfig->jsStackReport == NAPI_CALL_STACK && !g_hookJsConfig->jsFpUnwind) {
1100 OHOS::HiviewDFX::HiTraceChain::ClearId();
1101 std::unique_ptr<OHOS::HiviewDFX::HiTraceId> arkCallBackTraceId = std::make_unique<OHOS::HiviewDFX::HiTraceId>(
1102 OHOS::HiviewDFX::HiTraceChain::Begin("New ArkCallBackTrace", 0));
1103 char buffer[256] = {0}; // 256 : buffer size of tag name
1104 if (sprintf_s(buffer, sizeof(buffer), "napi:0x%x:%s", arkCallBackTraceId->GetChainId(),
1105 nameRef->ToString(vm).c_str()) == -1) {
1106 return 0;
1107 }
1108 uint64_t addr = reinterpret_cast<uint64_t>(cb);
1109 ++g_chainId;
1110 (void)memtrace(reinterpret_cast<void*>(addr + g_chainId), 8, buffer, true); // 8: the size of addr
1111 return 0;
1112 }
1113 if (!CheckHookConfig(nameRef->ToString(vm))) {
1114 return 0;
1115 }
1116 BlockHookScope blockHook; // block hook
1117 std::string rawStack;
1118 std::vector<JsFrameInfo> jsFrames;
1119 uint64_t nestChainId = 0;
1120 jsFrames.reserve(g_hookJsConfig->maxJsStackDepth);
1121 engine->BuildJsStackInfoListWithCustomDepth(jsFrames);
1122 std::stringstream ssRawStack;
1123 for (size_t i = 0; i < jsFrames.size() && i < g_hookJsConfig->maxJsStackDepth; i++) {
1124 ssRawStack << jsFrames[i].functionName << JS_SYMBOL_FILEPATH_SEP << jsFrames[i].fileName << ":" <<
1125 jsFrames[i].pos;
1126 if (i < jsFrames.size() - 1) {
1127 ssRawStack << JS_CALL_STACK_DEPTH_SEP;
1128 }
1129 }
1130 rawStack = ssRawStack.str();
1131 OHOS::HiviewDFX::HiTraceChain::Begin("ArkNativeFunctionCallBack", HITRACE_FLAG_NO_BE_INFO);
1132 OHOS::HiviewDFX::HiTraceId hitraceId = OHOS::HiviewDFX::HiTraceChain::GetId();
1133 // resolve nested calls to napi and ts
1134 if (hitraceId.IsValid()) {
1135 nestChainId = hitraceId.GetChainId();
1136 }
1137 uint64_t chainId = ++g_chainId;
1138 hitraceId.SetChainId(chainId);
1139 OHOS::HiviewDFX::HiTraceChain::SetId(hitraceId);
1140 __send_hook_misc_data(chainId, rawStack.c_str(), rawStack.size() + 1, 1);
1141 return nestChainId;
1142
1143 #endif
1144 return 0;
1145 }
1146
FinishNapiProfilerTrace(uint64_t value)1147 static inline void FinishNapiProfilerTrace(uint64_t value)
1148 {
1149 #ifdef ENABLE_HITRACE
1150 if (ArkNativeEngine::napiProfilerEnabled) {
1151 FinishTrace(HITRACE_TAG_ACE);
1152 }
1153 bool hookFlag = __get_hook_flag() && __get_global_hook_flag();
1154 if (!hookFlag) {
1155 return;
1156 }
1157 BlockHookScope blockHook; // block hook
1158 OHOS::HiviewDFX::HiTraceId hitraceId = OHOS::HiviewDFX::HiTraceChain::GetId();
1159 if (hitraceId.IsValid()) {
1160 OHOS::HiviewDFX::HiTraceChain::ClearId();
1161 }
1162 // resolve nested calls to napi and ts
1163 if (value) {
1164 hitraceId.SetChainId(value);
1165 OHOS::HiviewDFX::HiTraceChain::SetId(hitraceId);
1166 }
1167
1168 #endif
1169 }
1170
1171 template <bool changeState>
ArkNativeFunctionCallBack(JsiRuntimeCallInfo * runtimeInfo)1172 panda::JSValueRef ArkNativeFunctionCallBack(JsiRuntimeCallInfo *runtimeInfo)
1173 {
1174 EcmaVM *vm = runtimeInfo->GetVM();
1175 panda::LocalScope scope(vm);
1176 bool getStackBeforeCallNapiSuccess = false;
1177 JSNApi::GetStackBeforeCallNapiSuccess(vm, getStackBeforeCallNapiSuccess);
1178 auto info = reinterpret_cast<NapiFunctionInfo*>(runtimeInfo->GetData());
1179 napi_env env = nullptr;
1180 if (info->isSendable) {
1181 env = reinterpret_cast<napi_env>(JSNApi::GetEnv(vm));
1182 } else {
1183 env = info->env;
1184 }
1185 auto engine = reinterpret_cast<NativeEngine*>(env);
1186 auto cb = info->callback;
1187 if (engine == nullptr) {
1188 HILOG_ERROR("native engine is null");
1189 return **JSValueRef::Undefined(vm);
1190 }
1191
1192 uint64_t nestChainId = StartNapiProfilerTrace(runtimeInfo, engine, reinterpret_cast<void *>(cb));
1193
1194 if (JSNApi::IsMixedDebugEnabled(vm)) {
1195 JSNApi::NotifyNativeCalling(vm, reinterpret_cast<void *>(cb));
1196 }
1197
1198 napi_value result = nullptr;
1199 if (cb != nullptr) {
1200 if constexpr (changeState) {
1201 panda::JsiNativeScope nativeScope(vm);
1202 #if ECMASCRIPT_ENABLE_INTERPRETER_ARKUINAITVE_TRACE
1203 #ifdef ENABLE_HITRACE
1204 StartTrace(HITRACE_TAG_ACE, "Developer::NativeCallBack::One");
1205 #endif
1206 #endif
1207 result = cb(env, runtimeInfo);
1208 #if ECMASCRIPT_ENABLE_INTERPRETER_ARKUINAITVE_TRACE
1209 #ifdef ENABLE_HITRACE
1210 FinishTrace(HITRACE_TAG_ACE);
1211 #endif
1212 #endif
1213 } else {
1214 #if ECMASCRIPT_ENABLE_INTERPRETER_ARKUINAITVE_TRACE
1215 #ifdef ENABLE_HITRACE
1216 StartTrace(HITRACE_TAG_ACE, "Developer::NativeCallBack::Two");
1217 #endif
1218 #endif
1219 result = cb(env, runtimeInfo);
1220 #if ECMASCRIPT_ENABLE_INTERPRETER_ARKUINAITVE_TRACE
1221 #ifdef ENABLE_HITRACE
1222 FinishTrace(HITRACE_TAG_ACE);
1223 #endif
1224 #endif
1225 }
1226 }
1227
1228 if (JSNApi::IsMixedDebugEnabled(vm)) {
1229 JSNApi::NotifyNativeReturn(vm, reinterpret_cast<void *>(cb));
1230 }
1231
1232 Local<panda::JSValueRef> localRet = panda::JSValueRef::Undefined(vm);
1233 if (result != nullptr) {
1234 localRet = LocalValueFromJsValue(result);
1235 }
1236
1237 FinishNapiProfilerTrace(nestChainId);
1238 // Fixme: Rethrow error to engine while clear lastException_
1239 if (!engine->lastException_.IsEmpty()) {
1240 engine->lastException_.Empty();
1241 }
1242
1243 if (localRet.IsEmpty()) {
1244 return **JSValueRef::Undefined(vm);
1245 }
1246 if (getStackBeforeCallNapiSuccess) {
1247 JSNApi::GetStackAfterCallNapi(vm);
1248 }
1249 return **localRet;
1250 }
1251
GetProperty(EcmaVM * vm,Local<panda::ObjectRef> & obj,const char * name)1252 static Local<JSValueRef> GetProperty(EcmaVM* vm, Local<panda::ObjectRef> &obj, const char* name)
1253 {
1254 Local<StringRef> key = StringRef::NewFromUtf8(vm, name);
1255 Local<JSValueRef> val = obj->Get(vm, key);
1256 return val;
1257 }
1258
GetCString(EcmaVM * vm,Local<StringRef> str,char * buffer,size_t size,size_t * length)1259 void GetCString(EcmaVM* vm, Local<StringRef> str, char* buffer, size_t size, size_t* length)
1260 {
1261 if (length == nullptr) {
1262 return;
1263 }
1264 if (buffer == nullptr) {
1265 *length = str->Utf8Length(vm, true) - 1;
1266 } else if (size != 0) {
1267 uint32_t copied = str->WriteUtf8(vm, buffer, size - 1, true) - 1;
1268 buffer[copied] = '\0';
1269 *length = copied;
1270 } else {
1271 *length = 0;
1272 }
1273 }
1274
NapiGetModuleName(napi_env env,Local<panda::ObjectRef> & obj)1275 std::string NapiGetModuleName(napi_env env, Local<panda::ObjectRef> &obj)
1276 {
1277 auto engine = reinterpret_cast<NativeEngine*>(env);
1278 auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
1279 std::string moduleName("");
1280 auto nativeModuleName = GetProperty(vm, obj, PANDA_MODULE_NAME);
1281 if (nativeModuleName->IsString(vm)) {
1282 char arrayName[PANDA_MODULE_NAME_LEN] = {0};
1283 size_t len = 0;
1284 GetCString(vm, nativeModuleName, arrayName, PANDA_MODULE_NAME_LEN, &len);
1285 moduleName += arrayName;
1286 moduleName += ".";
1287 }
1288 return moduleName;
1289 }
1290
NapiDefinePropertyInner(napi_env env,Local<panda::ObjectRef> & obj,NapiPropertyDescriptor & propertyDescriptor,Local<panda::JSValueRef> & propertyName,bool & result)1291 void NapiDefinePropertyInner(napi_env env,
1292 Local<panda::ObjectRef> &obj,
1293 NapiPropertyDescriptor &propertyDescriptor,
1294 Local<panda::JSValueRef> &propertyName,
1295 bool &result)
1296 {
1297 auto engine = reinterpret_cast<NativeEngine*>(env);
1298 auto vm = engine->GetEcmaVm();
1299 bool writable = (propertyDescriptor.attributes & NATIVE_WRITABLE) != 0;
1300 bool enumable = (propertyDescriptor.attributes & NATIVE_ENUMERABLE) != 0;
1301 bool configable = (propertyDescriptor.attributes & NATIVE_CONFIGURABLE) != 0;
1302 std::string fullName("");
1303 if (propertyDescriptor.getter != nullptr || propertyDescriptor.setter != nullptr) {
1304 #ifdef ENABLE_HITRACE
1305 fullName += NapiGetModuleName(env, obj);
1306 #endif
1307 Local<panda::JSValueRef> localGetter = panda::JSValueRef::Undefined(vm);
1308 Local<panda::JSValueRef> localSetter = panda::JSValueRef::Undefined(vm);
1309
1310 if (propertyDescriptor.getter != nullptr) {
1311 fullName += "getter";
1312 localGetter = NapiNativeCreateFunction(env, fullName.c_str(),
1313 propertyDescriptor.getter, propertyDescriptor.data);
1314 }
1315 if (propertyDescriptor.setter != nullptr) {
1316 fullName += "setter";
1317 localSetter = NapiNativeCreateFunction(env, fullName.c_str(),
1318 propertyDescriptor.setter, propertyDescriptor.data);
1319 }
1320
1321 PropertyAttribute attr(panda::JSValueRef::Undefined(vm), false, enumable, configable);
1322 result = obj->SetAccessorProperty(vm, propertyName, localGetter, localSetter, attr);
1323 } else if (propertyDescriptor.method != nullptr) {
1324 #ifdef ENABLE_HITRACE
1325 fullName += NapiGetModuleName(env, obj);
1326 #endif
1327 if (propertyDescriptor.utf8name != nullptr) {
1328 fullName += propertyDescriptor.utf8name;
1329 } else {
1330 fullName += propertyName->IsString(vm)
1331 ? Local<panda::StringRef>(propertyName)->ToString(vm)
1332 : Local<panda::SymbolRef>(propertyName)->GetDescription(vm)->ToString(vm);
1333 }
1334 Local<panda::JSValueRef> cbObj = NapiNativeCreateFunction(env, fullName.c_str(),
1335 propertyDescriptor.method, propertyDescriptor.data);
1336 PropertyAttribute attr(cbObj, writable, enumable, configable);
1337 result = obj->DefineProperty(vm, propertyName, attr);
1338 } else {
1339 Local<panda::JSValueRef> val = LocalValueFromJsValue(propertyDescriptor.value);
1340
1341 PropertyAttribute attr(val, writable, enumable, configable);
1342 result = obj->DefineProperty(vm, propertyName, attr);
1343 }
1344 }
1345
NapiDefineProperty(napi_env env,Local<panda::ObjectRef> & obj,NapiPropertyDescriptor propertyDescriptor)1346 bool NapiDefineProperty(napi_env env, Local<panda::ObjectRef> &obj, NapiPropertyDescriptor propertyDescriptor)
1347 {
1348 auto engine = reinterpret_cast<NativeEngine*>(env);
1349 auto vm = engine->GetEcmaVm();
1350 bool result = false;
1351 Local<panda::JSValueRef> propertyName;
1352 if (propertyDescriptor.utf8name != nullptr) {
1353 propertyName = panda::StringRef::NewFromUtf8(vm, propertyDescriptor.utf8name);
1354 } else {
1355 propertyName = LocalValueFromJsValue(propertyDescriptor.name);
1356 }
1357 if (obj->IsJSShared(vm)) {
1358 NativeSendable::NapiDefineSendabledProperty(env, obj, propertyDescriptor, propertyName, result);
1359 } else {
1360 NapiDefinePropertyInner(env, obj, propertyDescriptor, propertyName, result);
1361 }
1362 Local<panda::ObjectRef> excep = JSNApi::GetUncaughtException(vm);
1363 if (!excep.IsNull()) {
1364 HILOG_DEBUG("ArkNativeObject::DefineProperty occur Exception");
1365 JSNApi::GetAndClearUncaughtException(vm);
1366 }
1367 return result;
1368 }
1369
NapiCreateObjectWithProperties(napi_env env,size_t propertyCount,const napi_property_descriptor * properties,Local<panda::JSValueRef> * keys,PropertyAttribute * attrs)1370 panda::Local<panda::ObjectRef> NapiCreateObjectWithProperties(napi_env env, size_t propertyCount,
1371 const napi_property_descriptor *properties,
1372 Local<panda::JSValueRef> *keys,
1373 PropertyAttribute *attrs)
1374 {
1375 auto vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
1376 panda::EscapeLocalScope scope(vm);
1377 for (size_t i = 0; i < propertyCount; ++i) {
1378 const napi_property_descriptor &property = properties[i];
1379
1380 const char* utf8name = property.utf8name;
1381 uint32_t attributes = property.attributes;
1382 bool writable = (attributes & NATIVE_WRITABLE) != 0;
1383 bool enumable = (attributes & NATIVE_ENUMERABLE) != 0;
1384 bool configable = (attributes & NATIVE_CONFIGURABLE) != 0;
1385 NapiNativeCallback method = reinterpret_cast<NapiNativeCallback>(property.method);
1386 NapiNativeCallback getter = reinterpret_cast<NapiNativeCallback>(property.getter);
1387 NapiNativeCallback setter = reinterpret_cast<NapiNativeCallback>(property.setter);
1388 napi_value value = property.value;
1389 void *data = property.data;
1390
1391 Local<panda::JSValueRef> val = panda::JSValueRef::Undefined(vm);
1392
1393 std::string fullName("");
1394 if (getter != nullptr || setter != nullptr) {
1395 Local<panda::JSValueRef> localGetter = panda::JSValueRef::Undefined(vm);
1396 Local<panda::JSValueRef> localSetter = panda::JSValueRef::Undefined(vm);
1397
1398 if (getter != nullptr) {
1399 fullName += "getter";
1400 localGetter = NapiNativeCreateFunction(env, fullName.c_str(), getter, data);
1401 }
1402 if (setter != nullptr) {
1403 fullName += "setter";
1404 localSetter = NapiNativeCreateFunction(env, fullName.c_str(), setter, data);
1405 }
1406
1407 val = panda::ObjectRef::CreateAccessorData(vm, localGetter, localSetter);
1408 writable = false;
1409 } else if (method != nullptr) {
1410 fullName += utf8name;
1411 val = NapiNativeCreateFunction(env, fullName.c_str(), method, data);
1412 } else {
1413 val = LocalValueFromJsValue(value);
1414 }
1415 new (reinterpret_cast<void *>(&attrs[i])) PropertyAttribute(val, writable, enumable, configable);
1416 keys[i] = panda::StringRef::NewFromUtf8(vm, utf8name);
1417 }
1418 Local<panda::ObjectRef> object = panda::ObjectRef::NewWithProperties(vm, propertyCount, keys, attrs);
1419 return scope.Escape(object);
1420 }
1421
NapiCreateSObjectWithProperties(napi_env env,size_t propertyCount,const NapiPropertyDescriptor * properties)1422 panda::Local<panda::ObjectRef> NapiCreateSObjectWithProperties(napi_env env,
1423 size_t propertyCount,
1424 const NapiPropertyDescriptor* properties)
1425 {
1426 auto vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
1427 panda::EscapeLocalScope scope(vm);
1428 FunctionRef::SendablePropertiesInfo info;
1429 for (size_t i = 0; i < propertyCount; ++i) {
1430 NativeSendable::InitSendablePropertiesInfo(env, info, properties[i]);
1431 }
1432 Local<panda::ObjectRef> object = panda::ObjectRef::NewSWithProperties(vm, info);
1433 return scope.Escape(object);
1434 }
1435
CommonDeleter(void * env,void * externalPointer,void * data)1436 void CommonDeleter(void *env, void *externalPointer, void *data)
1437 {
1438 auto info = reinterpret_cast<NapiFunctionInfo *>(data);
1439 if (info != nullptr) {
1440 delete info;
1441 }
1442 }
1443
GetModuleFromName(const std::string & moduleName,bool isAppModule,const std::string & id,const std::string & param,const std::string & instanceName,void ** instance)1444 panda::Local<panda::ObjectRef> ArkNativeEngine::GetModuleFromName(
1445 const std::string& moduleName, bool isAppModule, const std::string& id, const std::string& param,
1446 const std::string& instanceName, void** instance)
1447 {
1448 panda::EscapeLocalScope scope(vm_);
1449 Local<ObjectRef> exports(JSValueRef::Undefined(vm_));
1450 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
1451 std::string errInfo = "";
1452 NativeModule* module = moduleManager->LoadNativeModule(moduleName.c_str(), nullptr, isAppModule, errInfo);
1453 if (module != nullptr) {
1454 Local<StringRef> idStr = StringRef::NewFromUtf8(vm_, id.c_str(), id.size());
1455 napi_value idValue = JsValueFromLocalValue(idStr);
1456 Local<StringRef> paramStr = StringRef::NewFromUtf8(vm_, param.c_str(), param.size());
1457 napi_value paramValue = JsValueFromLocalValue(paramStr);
1458 Local<ObjectRef> exportObj = ObjectRef::New(vm_);
1459 NapiPropertyDescriptor idProperty;
1460 NapiPropertyDescriptor paramProperty;
1461 idProperty.utf8name = "id";
1462 idProperty.value = idValue;
1463 paramProperty.utf8name = "param";
1464 paramProperty.value = paramValue;
1465 SetModuleName(exportObj, module->name);
1466 NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, idProperty);
1467 NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, paramProperty);
1468 MoudleNameLocker nameLocker(module->name);
1469 module->registerCallback(reinterpret_cast<napi_env>(this), JsValueFromLocalValue(exportObj));
1470 napi_value nExport = JsValueFromLocalValue(exportObj);
1471 napi_value exportInstance = nullptr;
1472 napi_status status = napi_get_named_property(
1473 reinterpret_cast<napi_env>(this), nExport, instanceName.c_str(), &exportInstance);
1474 if (status != napi_ok) {
1475 HILOG_ERROR("GetModuleFromName napi_get_named_property status != napi_ok");
1476 }
1477
1478 status = napi_unwrap(reinterpret_cast<napi_env>(this), exportInstance, reinterpret_cast<void**>(instance));
1479 if (status != napi_ok) {
1480 HILOG_ERROR("GetModuleFromName napi_unwrap status != napi_ok");
1481 }
1482 exports = exportObj;
1483 }
1484 return scope.Escape(exports);
1485 }
1486
CreatePromise(NativeDeferred ** deferred)1487 napi_value ArkNativeEngine::CreatePromise(NativeDeferred** deferred)
1488 {
1489 panda::EscapeLocalScope scope(vm_);
1490 Local<PromiseCapabilityRef> capability = PromiseCapabilityRef::New(vm_);
1491 if (capability->IsUndefined()) {
1492 return JsValueFromLocalValue(scope.Escape(JSValueRef::Undefined(vm_)));
1493 }
1494 *deferred = new ArkNativeDeferred(this, capability);
1495 Local<JSValueRef> promiseValue = capability->GetPromise(vm_);
1496 return JsValueFromLocalValue(scope.Escape(promiseValue));
1497 }
1498
LoadModuleByName(const std::string & moduleName,bool isAppModule,const std::string & param,const std::string & instanceName,void * instance,const std::string & path)1499 panda::Local<panda::ObjectRef> ArkNativeEngine::LoadModuleByName(const std::string& moduleName, bool isAppModule,
1500 const std::string& param, const std::string& instanceName, void* instance, const std::string& path)
1501 {
1502 panda::EscapeLocalScope scope(vm_);
1503 Local<ObjectRef> exports(JSValueRef::Undefined(vm_));
1504 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
1505 std::string errInfo = "";
1506 NativeModule* module = moduleManager->LoadNativeModule(moduleName.c_str(),
1507 path.empty() ? nullptr : path.c_str(), isAppModule, errInfo);
1508 if (module != nullptr) {
1509 Local<ObjectRef> exportObj = ObjectRef::New(vm_);
1510 NapiPropertyDescriptor instanceProperty;
1511 NapiPropertyDescriptor paramProperty;
1512 Local<StringRef> paramStr = StringRef::NewFromUtf8(vm_, param.c_str(), param.size());
1513 napi_value paramValue = JsValueFromLocalValue(paramStr);
1514 paramProperty.utf8name = "param";
1515 paramProperty.value = paramValue;
1516 Local<ObjectRef> instanceValue = ObjectRef::New(vm_);
1517 Local<StringRef> key = StringRef::GetNapiWrapperString(vm_);
1518 if (instance == nullptr && instanceValue->Has(vm_, key)) {
1519 Local<ObjectRef> wrapper = instanceValue->Get(vm_, key);
1520 auto ref = reinterpret_cast<NativeReference*>(wrapper->GetNativePointerField(vm_, 0));
1521 wrapper->SetNativePointerField(vm_, 0, nullptr, nullptr, nullptr, 0);
1522 instanceValue->Delete(vm_, key);
1523 delete ref;
1524 } else {
1525 Local<ObjectRef> object = ObjectRef::New(vm_);
1526 NativeReference* ref = nullptr;
1527 Local<JSValueRef> value(instanceValue);
1528 ref = new ArkNativeReference(this, value, 0, true, nullptr, instance, nullptr);
1529
1530 object->SetNativePointerFieldCount(vm_, 1);
1531 object->SetNativePointerField(vm_, 0, ref, nullptr, nullptr, 0);
1532 PropertyAttribute attr(object, true, false, true);
1533 instanceValue->DefineProperty(vm_, key, attr);
1534 }
1535 instanceProperty.utf8name = instanceName.c_str();
1536 instanceProperty.value = JsValueFromLocalValue(instanceValue);
1537 SetModuleName(exportObj, module->name);
1538 NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, paramProperty);
1539 NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, instanceProperty);
1540
1541 MoudleNameLocker nameLocker(module->name);
1542 module->registerCallback(reinterpret_cast<napi_env>(this), JsValueFromLocalValue(exportObj));
1543 exports = exportObj;
1544 }
1545 return scope.Escape(exports);
1546 }
1547
Loop(LoopMode mode,bool needSync)1548 void ArkNativeEngine::Loop(LoopMode mode, bool needSync)
1549 {
1550 LocalScope scope(vm_);
1551 NativeEngine::Loop(mode, needSync);
1552 JSNApi::ExecutePendingJob(vm_);
1553 }
1554
SetModuleName(Local<ObjectRef> & nativeObj,std::string moduleName)1555 void ArkNativeEngine::SetModuleName(Local<ObjectRef> &nativeObj, std::string moduleName)
1556 {
1557 #ifdef ENABLE_HITRACE
1558 if (ArkNativeEngine::napiProfilerEnabled) {
1559 Local<StringRef> moduleNameStr = StringRef::NewFromUtf8(vm_, moduleName.c_str(), moduleName.size());
1560 Local<StringRef> key = StringRef::NewFromUtf8(vm_, PANDA_MODULE_NAME);
1561 nativeObj->Set(vm_, key, moduleNameStr);
1562 }
1563 #endif
1564 }
1565
ConcurrentCallbackFunc(Local<JSValueRef> result,bool success,void * taskInfo,void * data)1566 static void ConcurrentCallbackFunc(Local<JSValueRef> result, bool success, void *taskInfo, void *data)
1567 {
1568 if (data == nullptr) {
1569 return;
1570 }
1571 auto engine = static_cast<ArkNativeEngine *>(data);
1572 auto concurrentCallbackFunc = engine->GetConcurrentCallbackFunc();
1573 if (concurrentCallbackFunc == nullptr) {
1574 return;
1575 }
1576 napi_env env = reinterpret_cast<napi_env>(engine);
1577 concurrentCallbackFunc(env, ArkNativeEngine::ArkValueToNapiValue(env, result), success, taskInfo);
1578 }
1579
InitTaskPoolThread(NativeEngine * engine,NapiConcurrentCallback callback)1580 bool ArkNativeEngine::InitTaskPoolThread(NativeEngine* engine, NapiConcurrentCallback callback)
1581 {
1582 concurrentCallbackFunc_ = callback;
1583 return JSNApi::InitForConcurrentThread(vm_, ConcurrentCallbackFunc, static_cast<void *>(this));
1584 }
1585
InitTaskPoolThread(napi_env env,NapiConcurrentCallback callback)1586 bool ArkNativeEngine::InitTaskPoolThread(napi_env env, NapiConcurrentCallback callback)
1587 {
1588 concurrentCallbackFunc_ = callback;
1589 return JSNApi::InitForConcurrentThread(vm_, ConcurrentCallbackFunc, static_cast<void *>(this));
1590 }
1591
InitTaskPoolFunc(napi_env env,napi_value func,void * taskInfo)1592 bool ArkNativeEngine::InitTaskPoolFunc(napi_env env, napi_value func, void* taskInfo)
1593 {
1594 LocalScope scope(vm_);
1595 Local<JSValueRef> function = LocalValueFromJsValue(func);
1596 return JSNApi::InitForConcurrentFunction(vm_, function, taskInfo);
1597 }
1598
HasPendingJob() const1599 bool ArkNativeEngine::HasPendingJob() const
1600 {
1601 return JSNApi::HasPendingJob(vm_);
1602 }
1603
IsProfiling() const1604 bool ArkNativeEngine::IsProfiling() const
1605 {
1606 return JSNApi::IsProfiling(vm_);
1607 }
1608
IsExecutingPendingJob() const1609 bool ArkNativeEngine::IsExecutingPendingJob() const
1610 {
1611 return JSNApi::IsExecutingPendingJob(vm_);
1612 }
1613
GetCurrentTaskInfo() const1614 void* ArkNativeEngine::GetCurrentTaskInfo() const
1615 {
1616 return JSNApi::GetCurrentTaskInfo(vm_);
1617 }
1618
ClearCurrentTaskInfo()1619 void ArkNativeEngine::ClearCurrentTaskInfo()
1620 {
1621 JSNApi::ClearCurrentTaskInfo(vm_);
1622 }
1623
TerminateExecution() const1624 void ArkNativeEngine::TerminateExecution() const
1625 {
1626 DFXJSNApi::TerminateExecution(vm_);
1627 }
1628
NotifyTaskBegin() const1629 void ArkNativeEngine::NotifyTaskBegin() const
1630 {
1631 JSNApi::NotifyTaskBegin(vm_);
1632 }
1633
NotifyTaskFinished() const1634 void ArkNativeEngine::NotifyTaskFinished() const
1635 {
1636 JSNApi::NotifyTaskFinished(vm_);
1637 }
1638
CallFunction(napi_value thisVar,napi_value function,napi_value const * argv,size_t argc)1639 napi_value ArkNativeEngine::CallFunction(
1640 napi_value thisVar, napi_value function, napi_value const* argv, size_t argc)
1641 {
1642 if (function == nullptr) {
1643 return nullptr;
1644 }
1645 panda::EscapeLocalScope scope(vm_);
1646 Local<JSValueRef> thisObj = JSValueRef::Undefined(vm_);
1647 if (thisVar != nullptr) {
1648 thisObj = LocalValueFromJsValue(thisVar);
1649 }
1650 Local<FunctionRef> funcObj = LocalValueFromJsValue(function);
1651 std::vector<Local<JSValueRef>> args;
1652 args.reserve(argc);
1653 for (size_t i = 0; i < argc; i++) {
1654 if (argv[i] != nullptr) {
1655 args.emplace_back(LocalValueFromJsValue(argv[i]));
1656 } else {
1657 args.emplace_back(JSValueRef::Undefined(vm_));
1658 }
1659 }
1660
1661 Local<JSValueRef> value = funcObj->Call(vm_, thisObj, args.data(), argc);
1662 if (JSNApi::HasPendingException(vm_)) {
1663 HILOG_ERROR("pending exception when js function called");
1664 HILOG_ERROR("print exception info: ");
1665 JSNApi::PrintExceptionInfo(vm_);
1666 return nullptr;
1667 }
1668
1669 return JsValueFromLocalValue(scope.Escape(value));
1670 }
1671
NapiNewTypedArray(NativeTypedArrayType typedArrayType,Local<panda::ArrayBufferRef> arrayBuf,size_t byte_offset,size_t length,napi_value * result)1672 bool ArkNativeEngine::NapiNewTypedArray(NativeTypedArrayType typedArrayType,
1673 Local<panda::ArrayBufferRef> arrayBuf,
1674 size_t byte_offset, size_t length, napi_value* result)
1675 {
1676 Local<panda::TypedArrayRef> typedArray;
1677 switch (typedArrayType) {
1678 case NATIVE_INT8_ARRAY:
1679 typedArray = panda::Int8ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1680 break;
1681 case NATIVE_UINT8_ARRAY:
1682 typedArray = panda::Uint8ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1683 break;
1684 case NATIVE_UINT8_CLAMPED_ARRAY:
1685 typedArray = panda::Uint8ClampedArrayRef::New(vm_, arrayBuf, byte_offset, length);
1686 break;
1687 case NATIVE_INT16_ARRAY:
1688 typedArray = panda::Int16ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1689 break;
1690 case NATIVE_UINT16_ARRAY:
1691 typedArray = panda::Uint16ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1692 break;
1693 case NATIVE_INT32_ARRAY:
1694 typedArray = panda::Int32ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1695 break;
1696 case NATIVE_UINT32_ARRAY:
1697 typedArray = panda::Uint32ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1698 break;
1699 case NATIVE_FLOAT32_ARRAY:
1700 typedArray = panda::Float32ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1701 break;
1702 case NATIVE_FLOAT64_ARRAY:
1703 typedArray = panda::Float64ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1704 break;
1705 case NATIVE_BIGINT64_ARRAY:
1706 typedArray = panda::BigInt64ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1707 break;
1708 case NATIVE_BIGUINT64_ARRAY:
1709 typedArray = panda::BigUint64ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1710 break;
1711 default:
1712 *result = nullptr;
1713 return false;
1714 }
1715 *result = JsValueFromLocalValue(typedArray);
1716 return true;
1717 }
1718
NapiNewSendableTypedArray(NativeTypedArrayType typedArrayType,Local<panda::SendableArrayBufferRef> arrayBuf,size_t byte_offset,size_t length,napi_value * result)1719 bool ArkNativeEngine::NapiNewSendableTypedArray(NativeTypedArrayType typedArrayType,
1720 Local<panda::SendableArrayBufferRef> arrayBuf,
1721 size_t byte_offset, size_t length, napi_value* result)
1722 {
1723 Local<panda::SendableTypedArrayRef> typedArray;
1724 switch (typedArrayType) {
1725 case NATIVE_INT8_ARRAY:
1726 typedArray = panda::SharedInt8ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1727 break;
1728 case NATIVE_UINT8_ARRAY:
1729 typedArray = panda::SharedUint8ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1730 break;
1731 case NATIVE_INT16_ARRAY:
1732 typedArray = panda::SharedInt16ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1733 break;
1734 case NATIVE_UINT16_ARRAY:
1735 typedArray = panda::SharedUint16ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1736 break;
1737 case NATIVE_INT32_ARRAY:
1738 typedArray = panda::SharedInt32ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1739 break;
1740 case NATIVE_UINT32_ARRAY:
1741 typedArray = panda::SharedUint32ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1742 break;
1743 case NATIVE_FLOAT32_ARRAY:
1744 typedArray = panda::SharedFloat32ArrayRef::New(vm_, arrayBuf, byte_offset, length);
1745 break;
1746 case NATIVE_UINT8_CLAMPED_ARRAY:
1747 typedArray = panda::SharedUint8ClampedArrayRef::New(vm_, arrayBuf, byte_offset, length);
1748 break;
1749 default:
1750 *result = nullptr;
1751 return false;
1752 }
1753 *result = JsValueFromLocalValue(typedArray);
1754 return true;
1755 }
1756
GetTypedArrayType(panda::Local<panda::TypedArrayRef> typedArray)1757 NativeTypedArrayType ArkNativeEngine::GetTypedArrayType(panda::Local<panda::TypedArrayRef> typedArray)
1758 {
1759 NativeTypedArrayType thisType = NATIVE_INT8_ARRAY;
1760 if (typedArray->IsInt32Array(vm_)) {
1761 thisType = NATIVE_INT32_ARRAY;
1762 } else if (typedArray->IsInt8Array(vm_)) {
1763 thisType = NATIVE_INT8_ARRAY;
1764 } else if (typedArray->IsUint8Array(vm_)) {
1765 thisType = NATIVE_UINT8_ARRAY;
1766 } else if (typedArray->IsUint8ClampedArray(vm_)) {
1767 thisType = NATIVE_UINT8_CLAMPED_ARRAY;
1768 } else if (typedArray->IsInt16Array(vm_)) {
1769 thisType = NATIVE_INT16_ARRAY;
1770 } else if (typedArray->IsUint16Array(vm_)) {
1771 thisType = NATIVE_UINT16_ARRAY;
1772 } else if (typedArray->IsUint32Array(vm_)) {
1773 thisType = NATIVE_UINT32_ARRAY;
1774 } else if (typedArray->IsFloat32Array(vm_)) {
1775 thisType = NATIVE_FLOAT32_ARRAY;
1776 } else if (typedArray->IsFloat64Array(vm_)) {
1777 thisType = NATIVE_FLOAT64_ARRAY;
1778 } else if (typedArray->IsBigInt64Array(vm_)) {
1779 thisType = NATIVE_BIGINT64_ARRAY;
1780 } else if (typedArray->IsBigUint64Array(vm_)) {
1781 thisType = NATIVE_BIGUINT64_ARRAY;
1782 }
1783
1784 return thisType;
1785 }
1786
GetSendableTypedArrayType(panda::Local<panda::SendableTypedArrayRef> typedArray)1787 NativeTypedArrayType ArkNativeEngine::GetSendableTypedArrayType(panda::Local<panda::SendableTypedArrayRef> typedArray)
1788 {
1789 NativeTypedArrayType thisType = NATIVE_INT8_ARRAY;
1790 if (typedArray->IsJSSharedInt8Array(vm_)) {
1791 thisType = NATIVE_INT8_ARRAY;
1792 } else if (typedArray->IsJSSharedUint8Array(vm_)) {
1793 thisType = NATIVE_UINT8_ARRAY;
1794 } else if (typedArray->IsJSSharedInt16Array(vm_)) {
1795 thisType = NATIVE_INT16_ARRAY;
1796 } else if (typedArray->IsJSSharedUint16Array(vm_)) {
1797 thisType = NATIVE_UINT16_ARRAY;
1798 } else if (typedArray->IsJSSharedInt32Array(vm_)) {
1799 thisType = NATIVE_INT32_ARRAY;
1800 } else if (typedArray->IsJSSharedUint32Array(vm_)) {
1801 thisType = NATIVE_UINT32_ARRAY;
1802 } else if (typedArray->IsJSSharedFloat32Array(vm_)) {
1803 thisType = NATIVE_FLOAT32_ARRAY;
1804 } else if (typedArray->IsJSSharedUint8ClampedArray(vm_)) {
1805 thisType = NATIVE_UINT8_CLAMPED_ARRAY;
1806 }
1807
1808 return thisType;
1809 }
1810
1811 /*
1812 * Before: input: 1. @ohos.hilog
1813 2. @system.app (NATIVE_MODULE contains this name)
1814 * After: return: 1.@ohos:hilog
1815 * 2.@native:system.app
1816 */
GetOhmurl(std::string path)1817 std::string ArkNativeEngine::GetOhmurl(std::string path)
1818 {
1819 const std::regex reg("@(ohos|system)\\.(\\S+)");
1820 path.erase(0, path.find_first_not_of(" "));
1821 path.erase(path.find_last_not_of(" ") + 1);
1822 bool ret = std::regex_match(path, reg);
1823 if (!ret) {
1824 HILOG_ERROR("ArkNativeEngine:The module name doesn't comply with the naming rules");
1825 return "";
1826 }
1827 std::string systemModule = path.substr(1);
1828 if (NATIVE_MODULE.count(systemModule)) {
1829 return NATIVE_MODULE_PREFIX + systemModule;
1830 } else {
1831 int pos = static_cast<int>(path.find('.'));
1832 std::string systemKey = path.substr(pos + 1, systemModule.size());
1833 return OHOS_MODULE_PREFIX + systemKey;
1834 }
1835 }
1836
NapiLoadNativeModule(std::string path)1837 Local<JSValueRef> ArkNativeEngine::NapiLoadNativeModule(std::string path)
1838 {
1839 std::string key = GetOhmurl(path);
1840 if (key.size() == 0) {
1841 return JSValueRef::Undefined(vm_);
1842 }
1843 return JSNApi::ExecuteNativeModule(vm_, key);
1844 }
1845
NapiLoadModule(const char * path)1846 napi_value ArkNativeEngine::NapiLoadModule(const char* path)
1847 {
1848 if (path == nullptr) {
1849 HILOG_ERROR("ArkNativeEngine:The module name is empty");
1850 return nullptr;
1851 }
1852 HILOG_INFO("ArkNativeEngine::NapiLoadModule path:%{public}s", path);
1853 panda::EscapeLocalScope scope(vm_);
1854 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
1855 Local exportObj(undefObj);
1856 std::string inputPath(path);
1857 std::string ohmurl = GetOhmurl(inputPath);
1858 if (!ohmurl.empty()) {
1859 exportObj = JSNApi::ExecuteNativeModule(vm_, ohmurl);
1860 } else {
1861 exportObj = JSNApi::GetModuleNameSpaceFromFile(vm_, inputPath);
1862 }
1863 if (!exportObj->IsObject(vm_)) {
1864 ThrowException("ArkNativeEngine:NapiLoadModule failed.");
1865 return JsValueFromLocalValue(scope.Escape(undefObj));
1866 }
1867 return JsValueFromLocalValue(scope.Escape(exportObj));
1868 }
1869
NapiLoadModuleWithInfo(const char * path,const char * module_info)1870 napi_value ArkNativeEngine::NapiLoadModuleWithInfo(const char* path, const char* module_info)
1871 {
1872 if (path == nullptr) {
1873 HILOG_ERROR("ArkNativeEngine:The module name is empty");
1874 return nullptr;
1875 }
1876 panda::EscapeLocalScope scope(vm_);
1877 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
1878 Local<ObjectRef> exportObj(undefObj);
1879 std::string inputPath(path);
1880 std::string modulePath;
1881 if (module_info != nullptr) {
1882 modulePath = module_info;
1883 exportObj = panda::JSNApi::GetModuleNameSpaceWithModuleInfoForNormalApp(vm_, inputPath, modulePath);
1884 } else {
1885 exportObj = NapiLoadNativeModule(inputPath);
1886 }
1887
1888 if (panda::JSNApi::HasPendingException(vm_)) {
1889 HILOG_WARN("ArkNativeEngine:NapiLoadModuleWithInfo failed.");
1890 panda::JSNApi::PrintExceptionInfo(vm_);
1891 panda::JSNApi::GetAndClearUncaughtException(vm_); // clear exception here
1892 return JsValueFromLocalValue(scope.Escape(undefObj));
1893 }
1894 return JsValueFromLocalValue(scope.Escape(exportObj));
1895 }
1896
NapiLoadModuleWithInfoForHybridApp(const char * path,const char * module_info)1897 napi_value ArkNativeEngine::NapiLoadModuleWithInfoForHybridApp(const char* path, const char* module_info)
1898 {
1899 if (path == nullptr) {
1900 HILOG_ERROR("ArkNativeEngine:The module name is empty");
1901 return nullptr;
1902 }
1903 panda::EscapeLocalScope scope(vm_);
1904 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
1905 Local<ObjectRef> exportObj(undefObj);
1906 std::string inputPath(path);
1907 std::string modulePath;
1908 if (module_info != nullptr) {
1909 modulePath = module_info;
1910 exportObj = panda::JSNApi::GetModuleNameSpaceWithModuleInfoForHybridApp(vm_, inputPath, modulePath);
1911 } else {
1912 exportObj = NapiLoadNativeModule(inputPath);
1913 }
1914
1915 if (JSNApi::HasPendingException(vm_)) {
1916 HILOG_WARN("ArkNativeEngine:NapiLoadModuleWithInfo failed.");
1917 JSNApi::PrintExceptionInfo(vm_);
1918 JSNApi::GetAndClearUncaughtException(vm_); // clear exception here
1919 return JsValueFromLocalValue(scope.Escape(undefObj));
1920 }
1921 return JsValueFromLocalValue(scope.Escape(exportObj));
1922 }
1923
SuspendVMById(uint32_t tid)1924 bool ArkNativeEngine::SuspendVMById(uint32_t tid)
1925 {
1926 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1927 return DFXJSNApi::SuspendVMById(vm_, tid);
1928 #else
1929 HILOG_WARN("ARK does not support dfx on windows");
1930 return false;
1931 #endif
1932 }
1933
ResumeVMById(uint32_t tid)1934 void ArkNativeEngine::ResumeVMById(uint32_t tid)
1935 {
1936 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1937 DFXJSNApi::ResumeVMById(vm_, tid);
1938 #else
1939 HILOG_WARN("ARK does not support dfx on windows");
1940 return;
1941 #endif
1942 }
1943
SetPackagePath(const std::string appLibPathKey,const std::vector<std::string> & packagePath)1944 void ArkNativeEngine::SetPackagePath(const std::string appLibPathKey, const std::vector<std::string>& packagePath)
1945 {
1946 auto moduleManager = NativeModuleManager::GetInstance();
1947 if (moduleManager && !packagePath.empty()) {
1948 moduleManager->SetAppLibPath(appLibPathKey, packagePath);
1949 }
1950 }
1951
CreateInstance(napi_value constructor,napi_value const * argv,size_t argc)1952 napi_value ArkNativeEngine::CreateInstance(napi_value constructor, napi_value const *argv, size_t argc)
1953 {
1954 if (constructor == nullptr) {
1955 return nullptr;
1956 }
1957 panda::EscapeLocalScope scope(vm_);
1958 Local<FunctionRef> value = LocalValueFromJsValue(constructor);
1959 std::vector<Local<JSValueRef>> args;
1960 args.reserve(argc);
1961 for (size_t i = 0; i < argc; i++) {
1962 if (argv[i] != nullptr) {
1963 args.emplace_back(LocalValueFromJsValue(argv[i]));
1964 } else {
1965 args.emplace_back(JSValueRef::Undefined(vm_));
1966 }
1967 }
1968 Local<JSValueRef> instance = value->Constructor(vm_, args.data(), argc);
1969 Local<ObjectRef> excep = JSNApi::GetUncaughtException(vm_);
1970 if (!excep.IsNull()) {
1971 HILOG_ERROR("ArkNativeEngineImpl::CreateInstance occur Exception");
1972 return nullptr;
1973 }
1974 return JsValueFromLocalValue(scope.Escape(instance));
1975 }
1976
CreateReference(napi_value value,uint32_t initialRefcount,bool flag,NapiNativeFinalize callback,void * data,void * hint,size_t nativeBindingSize)1977 NativeReference* ArkNativeEngine::CreateReference(napi_value value, uint32_t initialRefcount,
1978 bool flag, NapiNativeFinalize callback, void* data, void* hint, size_t nativeBindingSize)
1979 {
1980 return new ArkNativeReference(this, value, initialRefcount, flag, callback, data, hint, false, nativeBindingSize);
1981 }
1982
CreateXRefReference(napi_value value,uint32_t initialRefcount,bool flag,NapiNativeFinalize callback,void * data)1983 NativeReference* ArkNativeEngine::CreateXRefReference(napi_value value, uint32_t initialRefcount,
1984 bool flag, NapiNativeFinalize callback, void* data)
1985 {
1986 ArkNativeReferenceConfig config(initialRefcount, flag, callback, data);
1987 return new ArkXRefNativeReference(this, value, config);
1988 }
1989
CreateAsyncReference(napi_value value,uint32_t initialRefcount,bool flag,NapiNativeFinalize callback,void * data,void * hint)1990 NativeReference* ArkNativeEngine::CreateAsyncReference(napi_value value, uint32_t initialRefcount,
1991 bool flag, NapiNativeFinalize callback, void* data, void* hint)
1992 {
1993 return new ArkNativeReference(this, value, initialRefcount, flag, callback, data, hint, true);
1994 }
1995
RunCallbacks(TriggerGCData * triggerGCData)1996 __attribute__((optnone)) void ArkNativeEngine::RunCallbacks(TriggerGCData *triggerGCData)
1997 {
1998 #ifdef ENABLE_HITRACE
1999 StartTrace(HITRACE_TAG_ACE, "RunTriggerGCTaskCallback");
2000 #endif
2001 std::pair<void *, uint8_t> ¶m = *triggerGCData;
2002 JSNApi::TriggerIdleGC(reinterpret_cast<EcmaVM *>(param.first),
2003 static_cast<JSNApi::TRIGGER_IDLE_GC_TYPE>(param.second));
2004 #ifdef ENABLE_HITRACE
2005 FinishTrace(HITRACE_TAG_ACE);
2006 #endif
2007 }
2008
RunCallbacks(ArkFinalizersPack * finalizersPack)2009 __attribute__((optnone)) void ArkNativeEngine::RunCallbacks(ArkFinalizersPack *finalizersPack)
2010 {
2011 #ifdef ENABLE_HITRACE
2012 StartTrace(HITRACE_TAG_ACE, "RunFinalizeCallbacks:" + std::to_string(finalizersPack->GetNumFinalizers()));
2013 #endif
2014 finalizersPack->ProcessAll();
2015 #ifdef ENABLE_HITRACE
2016 FinishTrace(HITRACE_TAG_ACE);
2017 #endif
2018 }
2019
RunAsyncCallbacks(std::vector<RefAsyncFinalizer> * finalizers)2020 __attribute__((optnone)) void ArkNativeEngine::RunAsyncCallbacks(std::vector<RefAsyncFinalizer> *finalizers)
2021 {
2022 #ifdef ENABLE_HITRACE
2023 StartTrace(HITRACE_TAG_ACE, "RunFinalizeCallbacks:" + std::to_string(finalizers->size()));
2024 #endif
2025 INIT_CRASH_HOLDER(holder, "NAPI");
2026 for (auto iter : (*finalizers)) {
2027 NapiNativeFinalize callback = iter.first;
2028 std::pair<void*, void*> ¶m = iter.second;
2029 holder.UpdateCallbackPtr(reinterpret_cast<uintptr_t>(callback));
2030 callback(nullptr, std::get<0>(param), std::get<1>(param)); // 1 is the param.
2031 }
2032 #ifdef ENABLE_HITRACE
2033 FinishTrace(HITRACE_TAG_ACE);
2034 #endif
2035 }
2036
PostFinalizeTasks()2037 void ArkNativeEngine::PostFinalizeTasks()
2038 {
2039 if (IsInDestructor()) {
2040 return;
2041 }
2042 if (!pendingAsyncFinalizers_.empty()) {
2043 uv_work_t *asynWork = new uv_work_t;
2044 std::vector<RefAsyncFinalizer> *asyncFinalizers = new std::vector<RefAsyncFinalizer>();
2045 asyncFinalizers->swap(pendingAsyncFinalizers_);
2046 asynWork->data = reinterpret_cast<void *>(asyncFinalizers);
2047
2048 int ret = uv_queue_work_with_qos(GetUVLoop(), asynWork, [](uv_work_t *asynWork) {
2049 std::vector<RefAsyncFinalizer> *finalizers =
2050 reinterpret_cast<std::vector<RefAsyncFinalizer> *>(asynWork->data);
2051 RunAsyncCallbacks(finalizers);
2052 HILOG_DEBUG("uv_queue_work async running ");
2053 delete finalizers;
2054 }, [](uv_work_t *asynWork, int32_t) {
2055 delete asynWork;
2056 }, uv_qos_t(napi_qos_background));
2057 if (ret != 0) {
2058 HILOG_ERROR("uv_queue_work fail ret '%{public}d'", ret);
2059 RunAsyncCallbacks(asyncFinalizers);
2060 delete asynWork;
2061 delete asyncFinalizers;
2062 }
2063 }
2064 if (arkFinalizersPack_.Empty()) {
2065 return;
2066 }
2067 ArkFinalizersPack *finalizersPack = new ArkFinalizersPack();
2068 std::swap(arkFinalizersPack_, *finalizersPack);
2069 if (!IsMainThread()) {
2070 panda::JsiNativeScope nativeScope(vm_);
2071 RunCallbacks(finalizersPack);
2072 delete finalizersPack;
2073 return;
2074 }
2075 size_t bindingSize = finalizersPack->GetTotalNativeBindingSize();
2076 if (pendingFinalizersPackNativeBindingSize_ > FINALIZERS_PACK_PENDING_NATIVE_BINDING_SIZE_THRESHOLD &&
2077 bindingSize > 0) {
2078 HILOG_DEBUG("Pending Finalizers NativeBindingSize '%{public}zu' large than '%{public}zu', process sync.",
2079 pendingFinalizersPackNativeBindingSize_, FINALIZERS_PACK_PENDING_NATIVE_BINDING_SIZE_THRESHOLD);
2080 panda::JsiNativeScope nativeScope(vm_);
2081 RunCallbacks(finalizersPack);
2082 delete finalizersPack;
2083 return;
2084 }
2085 uv_work_t *syncWork = new uv_work_t;
2086 finalizersPack->RegisterFinishNotify([this] (size_t totalNativeBindingSize) {
2087 this->DecreasePendingFinalizersPackNativeBindingSize(totalNativeBindingSize);
2088 });
2089 IncreasePendingFinalizersPackNativeBindingSize(bindingSize);
2090
2091 syncWork->data = reinterpret_cast<void *>(finalizersPack);
2092 int ret = uv_queue_work_with_qos(GetUVLoop(), syncWork, [](uv_work_t *) {}, [](uv_work_t *syncWork, int32_t) {
2093 ArkFinalizersPack *finalizersPack = reinterpret_cast<ArkFinalizersPack*>(syncWork->data);
2094 RunCallbacks(finalizersPack);
2095 delete syncWork;
2096 delete finalizersPack;
2097 }, uv_qos_t(napi_qos_background));
2098 if (ret != 0) {
2099 HILOG_ERROR("uv_queue_work fail ret '%{public}d'", ret);
2100 panda::JsiNativeScope nativeScope(vm_);
2101 RunCallbacks(finalizersPack);
2102 delete syncWork;
2103 delete finalizersPack;
2104 }
2105 }
2106
RunCallbacks(AsyncNativeCallbacksPack * callbacksPack)2107 __attribute__((optnone)) void ArkNativeEngine::RunCallbacks(AsyncNativeCallbacksPack *callbacksPack)
2108 {
2109 #ifdef ENABLE_HITRACE
2110 StartTrace(HITRACE_TAG_ACE, "RunNativeCallbacks:" + std::to_string(callbacksPack->GetNumCallBacks()));
2111 #endif
2112 callbacksPack->ProcessAll("NAPI");
2113 #ifdef ENABLE_HITRACE
2114 FinishTrace(HITRACE_TAG_ACE);
2115 #endif
2116 }
2117
PostAsyncTask(AsyncNativeCallbacksPack * callBacksPack)2118 void ArkNativeEngine::PostAsyncTask(AsyncNativeCallbacksPack *callBacksPack)
2119 {
2120 if (IsInDestructor()) {
2121 delete callBacksPack;
2122 return;
2123 }
2124 uv_work_t *syncWork = new uv_work_t;
2125 syncWork->data = reinterpret_cast<void *>(callBacksPack);
2126
2127 int ret = uv_queue_work_with_qos(GetUVLoop(), syncWork, [](uv_work_t *) {}, [](uv_work_t *syncWork, int32_t) {
2128 AsyncNativeCallbacksPack *finalizers = reinterpret_cast<AsyncNativeCallbacksPack*>(syncWork->data);
2129 RunCallbacks(finalizers);
2130 HILOG_DEBUG("uv_queue_work running");
2131 delete syncWork;
2132 delete finalizers;
2133 }, uv_qos_t(napi_qos_background));
2134 if (ret != 0) {
2135 HILOG_ERROR("uv_queue_work fail ret '%{public}d'", ret);
2136 panda::JsiNativeScope nativeScope(vm_);
2137 RunCallbacks(callBacksPack);
2138 delete callBacksPack;
2139 delete syncWork;
2140 }
2141 }
2142
PostTriggerGCTask(TriggerGCData & data)2143 void ArkNativeEngine::PostTriggerGCTask(TriggerGCData& data)
2144 {
2145 TriggerGCData *triggerGCData = new TriggerGCData(data);
2146 uv_work_t *syncWork = new uv_work_t;
2147 syncWork->data = reinterpret_cast<void *>(triggerGCData);
2148 int ret = uv_queue_work_with_qos(GetUVLoop(), syncWork, [](uv_work_t *) {}, [](uv_work_t *syncWork, int32_t) {
2149 auto triggerGCData = reinterpret_cast<TriggerGCData *>(syncWork->data);
2150 RunCallbacks(triggerGCData);
2151 delete syncWork;
2152 delete triggerGCData;
2153 }, uv_qos_t(napi_qos_user_initiated));
2154 if (ret != 0) {
2155 HILOG_ERROR("uv_queue_work fail ret '%{public}d'", ret);
2156 RunCallbacks(triggerGCData);
2157 delete syncWork;
2158 delete triggerGCData;
2159 }
2160 }
2161
2162 #if defined(OHOS_PLATFORM) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
SetAttribute(bool isLimitedWorker,panda::RuntimeOption & option)2163 void ArkNativeEngine::SetAttribute(bool isLimitedWorker, panda::RuntimeOption &option)
2164 {
2165 int arkProperties = OHOS::system::GetIntParameter<int>("persist.ark.properties", -1);
2166 std::string bundleName = OHOS::system::GetParameter("persist.ark.arkbundlename", "");
2167 std::string memConfigProperty = OHOS::system::GetParameter("persist.ark.mem_config_property", "");
2168 size_t gcThreadNum = OHOS::system::GetUintParameter<size_t>("persist.ark.gcthreads", 7);
2169 size_t longPauseTime = OHOS::system::GetUintParameter<size_t>("persist.ark.longpausetime", 40);
2170 bool asmInterpreterEnabled = OHOS::system::GetBoolParameter("persist.ark.asminterpreter", true);
2171 std::string asmOpcodeDisableRange = OHOS::system::GetParameter("persist.ark.asmopcodedisablerange", "");
2172 bool builtinsLazyEnabled = OHOS::system::GetBoolParameter("persist.ark.enablebuiltinslazy", true);
2173 option.SetEnableBuiltinsLazy(builtinsLazyEnabled);
2174 option.SetArkProperties(arkProperties);
2175 option.SetArkBundleName(bundleName);
2176 option.SetMemConfigProperty(memConfigProperty);
2177 option.SetGcThreadNum(gcThreadNum);
2178 option.SetLongPauseTime(longPauseTime);
2179 option.SetEnableAsmInterpreter(asmInterpreterEnabled);
2180 option.SetAsmOpcodeDisableRange(asmOpcodeDisableRange);
2181 option.SetIsWorker();
2182 option.SetIsRestrictedWorker(isLimitedWorker);
2183 HILOG_DEBUG("ArkNativeEngineImpl::CreateRuntimeFunc ark properties = %{public}d, bundlename = %{public}s",
2184 arkProperties, bundleName.c_str());
2185 }
2186 #endif
2187
CreateRuntimeFunc(NativeEngine * engine,void * jsEngine,bool isLimitedWorker)2188 NativeEngine* ArkNativeEngine::CreateRuntimeFunc(NativeEngine* engine, void* jsEngine, bool isLimitedWorker)
2189 {
2190 panda::RuntimeOption option;
2191 #if defined(OHOS_PLATFORM) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
2192 SetAttribute(isLimitedWorker, option);
2193 #endif
2194 option.SetGcType(panda::RuntimeOption::GC_TYPE::GEN_GC);
2195 const int64_t poolSize = 0x1000000;
2196 option.SetGcPoolSize(poolSize);
2197 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
2198 option.SetLogLevel(panda::RuntimeOption::LOG_LEVEL::INFO);
2199 #endif
2200 option.SetDebuggerLibraryPath("");
2201 EcmaVM* vm = JSNApi::CreateJSVM(option);
2202 if (vm == nullptr) {
2203 return nullptr;
2204 }
2205 // worker adaptation mergeabc
2206 const EcmaVM* hostVM = reinterpret_cast<ArkNativeEngine*>(engine)->GetEcmaVm();
2207 JSNApi::SynchronizVMInfo(vm, hostVM);
2208 ArkNativeEngine* arkEngine = new ArkNativeEngine(vm, jsEngine, isLimitedWorker);
2209 // init callback
2210 arkEngine->RegisterWorkerFunction(engine);
2211 arkEngine->SetHostEngine(engine);
2212 // sync apiVersion
2213 arkEngine->SetApiVersion(engine->GetApiVersion());
2214
2215 auto cleanEnv = [vm]() {
2216 if (vm != nullptr) {
2217 HILOG_DEBUG("cleanEnv is called");
2218 JSNApi::DestroyJSVM(vm);
2219 }
2220 };
2221 arkEngine->SetCleanEnv(cleanEnv);
2222 if (hostVM != nullptr) {
2223 JSNApi::AddWorker(const_cast<EcmaVM*>(hostVM), vm);
2224 }
2225 return arkEngine;
2226 }
2227
CreateRuntime(bool isLimitedWorker)2228 void* ArkNativeEngine::CreateRuntime(bool isLimitedWorker)
2229 {
2230 return ArkNativeEngine::CreateRuntimeFunc(this, jsEngine_, isLimitedWorker);
2231 }
2232
SetJsDumpThresholds(size_t thresholds)2233 void ArkNativeEngine::SetJsDumpThresholds(size_t thresholds)
2234 {
2235 DFXJSNApi::SetJsDumpThresholds(vm_, thresholds);
2236 }
2237
SetAppFreezeFilterCallback(AppFreezeFilterCallback callback)2238 void ArkNativeEngine::SetAppFreezeFilterCallback(AppFreezeFilterCallback callback)
2239 {
2240 DFXJSNApi::SetAppFreezeFilterCallback(vm_, callback);
2241 }
2242
SetRawHeapTrimLevel(uint32_t level)2243 void ArkNativeEngine::SetRawHeapTrimLevel(uint32_t level)
2244 {
2245 DFXJSNApi::SetJsRawHeapCropLevel(static_cast<panda::CropLevel>(level));
2246 }
2247
StartCpuProfiler(const std::string & fileName)2248 void ArkNativeEngine::StartCpuProfiler(const std::string& fileName)
2249 {
2250 JSNApi::SetNativePtrGetter(vm_, reinterpret_cast<void*>(ArkNativeEngine::GetNativePtrCallBack));
2251 DFXJSNApi::StartCpuProfilerForFile(vm_, fileName);
2252 }
2253
StopCpuProfiler()2254 void ArkNativeEngine::StopCpuProfiler()
2255 {
2256 DFXJSNApi::StopCpuProfilerForFile(vm_);
2257 JSNApi::SetNativePtrGetter(vm_, nullptr);
2258 }
2259
ResumeVM()2260 void ArkNativeEngine::ResumeVM()
2261 {
2262 DFXJSNApi::ResumeVM(vm_);
2263 }
2264
SuspendVM()2265 bool ArkNativeEngine::SuspendVM()
2266 {
2267 return DFXJSNApi::SuspendVM(vm_);
2268 }
2269
IsSuspended()2270 bool ArkNativeEngine::IsSuspended()
2271 {
2272 return DFXJSNApi::IsSuspended(vm_);
2273 }
2274
CheckSafepoint()2275 bool ArkNativeEngine::CheckSafepoint()
2276 {
2277 return DFXJSNApi::CheckSafepoint(vm_);
2278 }
2279
GetCurrentModuleInfo(std::string & moduleName,std::string & fileName,bool needRecordName)2280 void ArkNativeEngine::GetCurrentModuleInfo(std::string& moduleName, std::string& fileName, bool needRecordName)
2281 {
2282 LocalScope scope(vm_);
2283 std::pair<std::string, std::string> moduleInfo = JSNApi::GetCurrentModuleInfo(vm_, needRecordName);
2284 moduleName = moduleInfo.first; // if needRecordName is true, then moduleName is recordName.
2285 fileName = moduleInfo.second;
2286 }
2287
GetIsBundle()2288 bool ArkNativeEngine::GetIsBundle()
2289 {
2290 LocalScope scope(vm_);
2291 return JSNApi::IsBundle(vm_);
2292 }
2293
GetIsNormalizedOhmUrlPack()2294 bool ArkNativeEngine::GetIsNormalizedOhmUrlPack()
2295 {
2296 LocalScope scope(vm_);
2297 return JSNApi::IsNormalizedOhmUrlPack(vm_);
2298 }
2299
GetIsDebugModeEnabled()2300 bool ArkNativeEngine::GetIsDebugModeEnabled()
2301 {
2302 LocalScope scope(vm_);
2303 return JSNApi::IsDebugModeEnabled(vm_);
2304 }
2305
GetBundleName()2306 std::string ArkNativeEngine::GetBundleName()
2307 {
2308 LocalScope scope(vm_);
2309 return JSNApi::GetBundleName(vm_);
2310 }
2311
GetPkgName(const std::string & moduleName)2312 std::string ArkNativeEngine::GetPkgName(const std::string &moduleName)
2313 {
2314 LocalScope scope(vm_);
2315 return JSNApi::GetPkgName(vm_, moduleName);
2316 }
2317
GetProcessStartRealTime()2318 int ArkNativeEngine::GetProcessStartRealTime()
2319 {
2320 LocalScope scope(vm_);
2321 return JSNApi::GetStartRealTime(vm_);
2322 }
2323
IsExecuteModuleInAbcFile(std::string bundleName,std::string moduleName,std::string ohmurl)2324 bool ArkNativeEngine::IsExecuteModuleInAbcFile(std::string bundleName, std::string moduleName, std::string ohmurl)
2325 {
2326 LocalScope scope(vm_);
2327 return JSNApi::IsExecuteModuleInAbcFile(vm_, bundleName, moduleName, ohmurl);
2328 }
2329
ValueToNapiValue(JSValueWrapper & value)2330 napi_value ArkNativeEngine::ValueToNapiValue(JSValueWrapper& value)
2331 {
2332 Global<JSValueRef> arkValue = value;
2333 return JsValueFromLocalValue(arkValue.ToLocal(vm_));
2334 }
2335
ArkValueToNapiValue(napi_env env,Local<JSValueRef> value)2336 napi_value ArkNativeEngine::ArkValueToNapiValue(napi_env env, Local<JSValueRef> value)
2337 {
2338 return JsValueFromLocalValue(value);
2339 }
2340
GetSourceCodeInfo(napi_value value,ErrorPos pos)2341 std::string ArkNativeEngine::GetSourceCodeInfo(napi_value value, ErrorPos pos)
2342 {
2343 if (value == nullptr || pos.first == 0) {
2344 return "";
2345 }
2346
2347 LocalScope scope(vm_);
2348 Local<panda::FunctionRef> func = LocalValueFromJsValue(value);
2349 uint32_t line = pos.first;
2350 uint32_t column = pos.second;
2351 Local<panda::StringRef> sourceCode = func->GetSourceCode(vm_, line);
2352 std::string sourceCodeStr = sourceCode->ToString(vm_);
2353 if (sourceCodeStr.empty()) {
2354 return "";
2355 }
2356 std::string sourceCodeInfo = "SourceCode:\n";
2357 sourceCodeInfo.append(sourceCodeStr).append("\n");
2358 for (uint32_t k = 1; k < column; k++) {
2359 sourceCodeInfo.push_back(' ');
2360 }
2361 sourceCodeInfo.append("^\n");
2362 return sourceCodeInfo;
2363 }
2364
TriggerFatalException(panda::Local<panda::JSValueRef> exceptionValue)2365 void ArkNativeEngine::TriggerFatalException(panda::Local<panda::JSValueRef> exceptionValue)
2366 {
2367 JSNApi::ThrowException(GetEcmaVm(), exceptionValue);
2368 HandleUncaughtException();
2369 }
2370
AdjustExternalMemory(int64_t ChangeInBytes,int64_t * AdjustedValue)2371 bool ArkNativeEngine::AdjustExternalMemory(int64_t ChangeInBytes, int64_t* AdjustedValue)
2372 {
2373 return true;
2374 }
2375
SetPromiseRejectCallback(NativeReference * rejectCallbackRef,NativeReference * checkCallbackRef)2376 void ArkNativeEngine::SetPromiseRejectCallback(NativeReference* rejectCallbackRef, NativeReference* checkCallbackRef)
2377 {
2378 if (rejectCallbackRef == nullptr || checkCallbackRef == nullptr) {
2379 HILOG_ERROR("rejectCallbackRef or checkCallbackRef is nullptr");
2380 return;
2381 }
2382 promiseRejectCallbackRef_ = rejectCallbackRef;
2383 checkCallbackRef_ = checkCallbackRef;
2384 }
2385
PromiseRejectCallback(void * info)2386 void ArkNativeEngine::PromiseRejectCallback(void* info)
2387 {
2388 panda::PromiseRejectInfo* promiseRejectInfo = reinterpret_cast<panda::PromiseRejectInfo*>(info);
2389 ArkNativeEngine* env = reinterpret_cast<ArkNativeEngine*>(promiseRejectInfo->GetData());
2390
2391 if (env == nullptr) {
2392 HILOG_ERROR("engine is nullptr");
2393 return;
2394 }
2395 bool hasRef = env->promiseRejectCallbackRef_ != nullptr;
2396 auto hasCallback = NapiErrorManager::GetInstance()->GetHasAllUnhandledRejectionCallback();
2397 if (!hasRef && !hasCallback) {
2398 return;
2399 }
2400
2401 EcmaVM* vm = const_cast<EcmaVM*>(env->GetEcmaVm());
2402 LocalScope scope(vm);
2403 Local<JSValueRef> promise = promiseRejectInfo->GetPromise();
2404 Local<JSValueRef> reason = promiseRejectInfo->GetReason();
2405 panda::PromiseRejectInfo::PROMISE_REJECTION_EVENT operation = promiseRejectInfo->GetOperation();
2406
2407 Local<JSValueRef> type(IntegerRef::New(vm, static_cast<int32_t>(operation)));
2408
2409 Local<JSValueRef> args[] = {type, promise, reason};
2410 if (env->allPromiseRejectCallback_) {
2411 if (hasCallback && hasCallback()) {
2412 napi_value *callErrorArgs = new napi_value[ARGC_THREE];
2413 for (int i = 0; i < ARGC_THREE; i++) {
2414 callErrorArgs[i] = JsValueFromLocalValue(args[i]);
2415 }
2416 env->allPromiseRejectCallback_(callErrorArgs);
2417 delete[] callErrorArgs;
2418 }
2419 }
2420 if (env->promiseRejectCallbackRef_ == nullptr || env->checkCallbackRef_ == nullptr) {
2421 HILOG_ERROR("promiseRejectCallbackRef or checkCallbackRef is nullptr");
2422 return;
2423 }
2424 napi_value promiseNapiRejectCallback = env->promiseRejectCallbackRef_->Get(env);
2425 Local<FunctionRef> promiseRejectCallback = LocalValueFromJsValue(promiseNapiRejectCallback);
2426 if (!promiseRejectCallback.IsEmpty()) {
2427 promiseRejectCallback->Call(vm, JSValueRef::Undefined(vm), args, 3); // 3 args size
2428 }
2429
2430 if (operation == panda::PromiseRejectInfo::PROMISE_REJECTION_EVENT::REJECT) {
2431 Local<JSValueRef> checkCallback = LocalValueFromJsValue(env->checkCallbackRef_->Get(env));
2432 if (!checkCallback.IsEmpty()) {
2433 JSNApi::SetHostEnqueueJob(vm, checkCallback, panda::QueueType::QUEUE_SCRIPT);
2434 }
2435 }
2436 }
2437
DumpHeapSnapshot(const std::string & path,bool isVmMode,DumpFormat dumpFormat,bool isPrivate,bool captureNumericValue,bool isJSLeakWatcher)2438 void ArkNativeEngine::DumpHeapSnapshot(const std::string &path, bool isVmMode, DumpFormat dumpFormat,
2439 bool isPrivate, bool captureNumericValue, bool isJSLeakWatcher)
2440 {
2441 panda::ecmascript::DumpSnapShotOption dumpOption;
2442 dumpOption.isVmMode = isVmMode;
2443 dumpOption.isSync = true;
2444 if (dumpFormat == DumpFormat::JSON) {
2445 dumpOption.dumpFormat = panda::ecmascript::DumpFormat::JSON;
2446 dumpOption.isPrivate = isPrivate;
2447 dumpOption.captureNumericValue = captureNumericValue;
2448 DFXJSNApi::DumpHeapSnapshot(vm_, path, dumpOption);
2449 return;
2450 }
2451 if (dumpFormat == DumpFormat::BINARY) {
2452 dumpOption.dumpFormat = panda::ecmascript::DumpFormat::BINARY;
2453 dumpOption.isJSLeakWatcher = isJSLeakWatcher;
2454 DFXJSNApi::DumpHeapSnapshot(vm_, path, dumpOption);
2455 return;
2456 }
2457 if (dumpFormat == DumpFormat::OTHER) {
2458 dumpOption.dumpFormat = panda::ecmascript::DumpFormat::OTHER;
2459 DFXJSNApi::DumpHeapSnapshot(vm_, path, dumpOption); // 2:enum is 2
2460 }
2461 }
2462
DumpHeapSnapshot(bool isFullGC,const std::string & path,const std::function<void (uint8_t)> & callback)2463 void ArkNativeEngine::DumpHeapSnapshot(bool isFullGC, const std::string &path,
2464 const std::function<void(uint8_t)> &callback)
2465 {
2466 panda::ecmascript::DumpSnapShotOption dumpOption;
2467 dumpOption.isVmMode = true;
2468 dumpOption.isPrivate = false;
2469 dumpOption.isFullGC = isFullGC;
2470 dumpOption.isSync = false;
2471 dumpOption.dumpFormat = panda::ecmascript::DumpFormat::BINARY;
2472 DFXJSNApi::DumpHeapSnapshot(vm_, path, dumpOption, callback);
2473 }
2474
DumpCpuProfile()2475 void ArkNativeEngine::DumpCpuProfile()
2476 {
2477 DFXJSNApi::DumpCpuProfile(vm_);
2478 }
2479
DumpHeapSnapshot(bool isVmMode,DumpFormat dumpFormat,bool isPrivate,bool isFullGC)2480 void ArkNativeEngine::DumpHeapSnapshot(bool isVmMode, DumpFormat dumpFormat, bool isPrivate, bool isFullGC)
2481 {
2482 panda::ecmascript::DumpSnapShotOption dumpOption;
2483 dumpOption.isVmMode = isVmMode;
2484 dumpOption.isPrivate = isPrivate;
2485 dumpOption.isFullGC = isFullGC;
2486 dumpOption.isSync = false;
2487 if (dumpFormat == DumpFormat::JSON) {
2488 dumpOption.dumpFormat = panda::ecmascript::DumpFormat::JSON;
2489 DFXJSNApi::DumpHeapSnapshot(vm_, dumpOption);
2490 return;
2491 }
2492 if (dumpFormat == DumpFormat::BINARY) {
2493 dumpOption.dumpFormat = panda::ecmascript::DumpFormat::BINARY;
2494 DFXJSNApi::DumpHeapSnapshot(vm_, dumpOption);
2495 return;
2496 }
2497 if (dumpFormat == DumpFormat::OTHER) {
2498 dumpOption.dumpFormat = panda::ecmascript::DumpFormat::OTHER;
2499 DFXJSNApi::DumpHeapSnapshot(vm_, dumpOption);
2500 }
2501 }
2502
BuildNativeAndJsStackTrace(std::string & stackTraceStr)2503 bool ArkNativeEngine::BuildNativeAndJsStackTrace(std::string& stackTraceStr)
2504 {
2505 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
2506 return DFXJSNApi::BuildNativeAndJsStackTrace(vm_, stackTraceStr);
2507 #else
2508 HILOG_WARN("ARK does not support dfx on windows");
2509 return false;
2510 #endif
2511 }
2512
BuildJsStackTrace(std::string & stackTraceStr)2513 bool ArkNativeEngine::BuildJsStackTrace(std::string& stackTraceStr)
2514 {
2515 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
2516 return DFXJSNApi::BuildJsStackTrace(vm_, stackTraceStr);
2517 #else
2518 HILOG_WARN("ARK does not support dfx on windows");
2519 return false;
2520 #endif
2521 }
2522
BuildJsStackInfoListWithCustomDepth(std::vector<JsFrameInfo> & jsFrames)2523 bool ArkNativeEngine::BuildJsStackInfoListWithCustomDepth(std::vector<JsFrameInfo>& jsFrames)
2524 {
2525 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
2526 return DFXJSNApi::BuildJsStackInfoList(vm_, gettid(), jsFrames);
2527 #else
2528 HILOG_WARN("ARK does not support dfx on windows");
2529 return false;
2530 #endif
2531 }
2532
GetMainThreadStackTrace(napi_env env,std::string & stackTraceStr)2533 void ArkNativeEngine::GetMainThreadStackTrace(napi_env env, std::string &stackTraceStr)
2534 {
2535 auto vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
2536 DFXJSNApi::GetMainThreadStackTrace(vm, stackTraceStr);
2537 }
2538
DeleteWorker(NativeEngine * workerEngine)2539 bool ArkNativeEngine::DeleteWorker(NativeEngine* workerEngine)
2540 {
2541 if (workerEngine != nullptr) {
2542 #if !defined(PREVIEW)
2543 auto workerVM = const_cast<EcmaVM *>(workerEngine->GetEcmaVm());
2544 if (workerVM != nullptr) {
2545 return JSNApi::DeleteWorker(vm_, workerVM);
2546 }
2547 #else
2548 HILOG_WARN("ARK does not support dfx on windows");
2549 #endif
2550 }
2551 return false;
2552 }
2553
StartHeapTracking(double timeInterval,bool isVmMode)2554 bool ArkNativeEngine::StartHeapTracking(double timeInterval, bool isVmMode)
2555 {
2556 return DFXJSNApi::StartHeapTracking(vm_, timeInterval, isVmMode);
2557 }
2558
StopHeapTracking(const std::string & filePath)2559 bool ArkNativeEngine::StopHeapTracking(const std::string &filePath)
2560 {
2561 return DFXJSNApi::StopHeapTracking(vm_, filePath);
2562 }
2563
2564 #if !defined(PREVIEW)
PrintStatisticResult()2565 void ArkNativeEngine::PrintStatisticResult()
2566 {
2567 DFXJSNApi::PrintStatisticResult(vm_);
2568 }
2569
StartRuntimeStat()2570 void ArkNativeEngine::StartRuntimeStat()
2571 {
2572 DFXJSNApi::StartRuntimeStat(vm_);
2573 }
2574
StopRuntimeStat()2575 void ArkNativeEngine::StopRuntimeStat()
2576 {
2577 DFXJSNApi::StopRuntimeStat(vm_);
2578 }
2579
GetArrayBufferSize()2580 size_t ArkNativeEngine::GetArrayBufferSize()
2581 {
2582 return DFXJSNApi::GetArrayBufferSize(vm_);
2583 }
2584
GetHeapTotalSize()2585 size_t ArkNativeEngine::GetHeapTotalSize()
2586 {
2587 return DFXJSNApi::GetHeapTotalSize(vm_);
2588 }
2589
GetHeapUsedSize()2590 size_t ArkNativeEngine::GetHeapUsedSize()
2591 {
2592 return DFXJSNApi::GetHeapUsedSize(vm_);
2593 }
2594
GetHeapObjectSize()2595 size_t ArkNativeEngine::GetHeapObjectSize()
2596 {
2597 return DFXJSNApi::GetHeapObjectSize(vm_);
2598 }
2599
GetHeapLimitSize()2600 size_t ArkNativeEngine::GetHeapLimitSize()
2601 {
2602 return DFXJSNApi::GetHeapLimitSize(vm_);
2603 }
2604
GetProcessHeapLimitSize()2605 size_t ArkNativeEngine::GetProcessHeapLimitSize()
2606 {
2607 return DFXJSNApi::GetProcessHeapLimitSize();
2608 }
2609
GetGCCount()2610 size_t ArkNativeEngine::GetGCCount()
2611 {
2612 return DFXJSNApi::GetGCCount(vm_);
2613 }
2614
GetGCDuration()2615 size_t ArkNativeEngine::GetGCDuration()
2616 {
2617 return DFXJSNApi::GetGCDuration(vm_);
2618 }
2619
GetAccumulatedAllocateSize()2620 size_t ArkNativeEngine::GetAccumulatedAllocateSize()
2621 {
2622 return DFXJSNApi::GetAccumulatedAllocateSize(vm_);
2623 }
2624
GetAccumulatedFreeSize()2625 size_t ArkNativeEngine::GetAccumulatedFreeSize()
2626 {
2627 return DFXJSNApi::GetAccumulatedFreeSize(vm_);
2628 }
2629
GetFullGCLongTimeCount()2630 size_t ArkNativeEngine::GetFullGCLongTimeCount()
2631 {
2632 return DFXJSNApi::GetFullGCLongTimeCount(vm_);
2633 }
2634
NotifyApplicationState(bool inBackground)2635 void ArkNativeEngine::NotifyApplicationState(bool inBackground)
2636 {
2637 DFXJSNApi::NotifyApplicationState(vm_, inBackground);
2638 ArkIdleMonitor::GetInstance()->NotifyChangeBackgroundState(inBackground);
2639 interopAppState_.Notify(inBackground ? NAPI_APP_STATE_BACKGROUND : NAPI_APP_STATE_FOREGROUND);
2640 }
2641
NotifyIdleStatusControl(std::function<void (bool)> callback)2642 void ArkNativeEngine::NotifyIdleStatusControl(std::function<void(bool)> callback)
2643 {
2644 DFXJSNApi::NotifyIdleStatusControl(vm_, callback);
2645 }
2646
NotifyIdleTime(int idleMicroSec)2647 void ArkNativeEngine::NotifyIdleTime(int idleMicroSec)
2648 {
2649 DFXJSNApi::NotifyIdleTime(vm_, idleMicroSec);
2650 }
2651
NotifyMemoryPressure(bool inHighMemoryPressure)2652 void ArkNativeEngine::NotifyMemoryPressure(bool inHighMemoryPressure)
2653 {
2654 DFXJSNApi::NotifyMemoryPressure(vm_, inHighMemoryPressure);
2655 }
2656
GetArkNativeEngineByID(uint64_t tid)2657 NativeEngine* ArkNativeEngine::GetArkNativeEngineByID(uint64_t tid)
2658 {
2659 #if defined(OHOS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(IOS_PLATFORM)
2660 for (auto engine : g_alivedEngine_) {
2661 if (static_cast<uint64_t>(engine->GetTid()) == tid ||
2662 static_cast<uint64_t>(engine->GetSysTid()) == tid) {
2663 return engine;
2664 }
2665 }
2666 return nullptr;
2667 #else
2668 return nullptr;
2669 #endif
2670 }
2671
NotifyForceExpandState(int32_t value)2672 void ArkNativeEngine::NotifyForceExpandState(int32_t value)
2673 {
2674 switch (ForceExpandState(value)) {
2675 case ForceExpandState::FINISH_COLD_START:
2676 DFXJSNApi::NotifyFinishColdStart(vm_, true);
2677 interopAppState_.Notify(NAPI_APP_STATE_COLD_START_FINISHED);
2678 break;
2679 case ForceExpandState::START_HIGH_SENSITIVE:
2680 DFXJSNApi::NotifyHighSensitive(vm_, true);
2681 interopAppState_.Notify(NAPI_APP_STATE_SENSITIVE_START);
2682 break;
2683 case ForceExpandState::FINISH_HIGH_SENSITIVE:
2684 DFXJSNApi::NotifyHighSensitive(vm_, false);
2685 interopAppState_.Notify(NAPI_APP_STATE_SENSITIVE_END);
2686 break;
2687 case ForceExpandState::WARM_START:
2688 DFXJSNApi::NotifyWarmStart(vm_);
2689 interopAppState_.Notify(NAPI_APP_STATE_WARM_START);
2690 break;
2691 default:
2692 HILOG_ERROR("Invalid Force Expand State: %{public}d.", value);
2693 break;
2694 }
2695 }
2696
NotifyForceExpandState(uint64_t tid,int32_t value)2697 void ArkNativeEngine::NotifyForceExpandState(uint64_t tid, int32_t value)
2698 {
2699 std::lock_guard<std::mutex> alivedEngLock(GetAliveEngineMutex());
2700 NativeEngine *nativeEngine = GetArkNativeEngineByID(tid);
2701 if (nativeEngine == nullptr) {
2702 return;
2703 }
2704 nativeEngine->NotifyForceExpandState(value);
2705 }
2706 #else
PrintStatisticResult()2707 void ArkNativeEngine::PrintStatisticResult()
2708 {
2709 HILOG_WARN("ARK does not support dfx on windows");
2710 }
2711
StartRuntimeStat()2712 void ArkNativeEngine::StartRuntimeStat()
2713 {
2714 HILOG_WARN("ARK does not support dfx on windows");
2715 }
2716
StopRuntimeStat()2717 void ArkNativeEngine::StopRuntimeStat()
2718 {
2719 HILOG_WARN("ARK does not support dfx on windows");
2720 }
2721
GetArrayBufferSize()2722 size_t ArkNativeEngine::GetArrayBufferSize()
2723 {
2724 HILOG_WARN("ARK does not support dfx on windows");
2725 return 0;
2726 }
2727
GetHeapTotalSize()2728 size_t ArkNativeEngine::GetHeapTotalSize()
2729 {
2730 HILOG_WARN("ARK does not support dfx on windows");
2731 return 0;
2732 }
2733
GetHeapUsedSize()2734 size_t ArkNativeEngine::GetHeapUsedSize()
2735 {
2736 HILOG_WARN("ARK does not support dfx on windows");
2737 return 0;
2738 }
2739
GetHeapObjectSize()2740 size_t ArkNativeEngine::GetHeapObjectSize()
2741 {
2742 HILOG_WARN("ARK does not support dfx on windows");
2743 return 0;
2744 }
2745
GetHeapLimitSize()2746 size_t ArkNativeEngine::GetHeapLimitSize()
2747 {
2748 HILOG_WARN("ARK does not support dfx on windows");
2749 return 0;
2750 }
2751
GetProcessHeapLimitSize()2752 size_t ArkNativeEngine::GetProcessHeapLimitSize()
2753 {
2754 HILOG_WARN("ARK does not support dfx on windows");
2755 return 0;
2756 }
2757
GetGCCount()2758 size_t ArkNativeEngine::GetGCCount()
2759 {
2760 HILOG_WARN("ARK does not support dfx on windows");
2761 return 0;
2762 }
2763
GetGCDuration()2764 size_t ArkNativeEngine::GetGCDuration()
2765 {
2766 HILOG_WARN("ARK does not support dfx on windows");
2767 return 0;
2768 }
2769
GetAccumulatedAllocateSize()2770 size_t ArkNativeEngine::GetAccumulatedAllocateSize()
2771 {
2772 HILOG_WARN("ARK does not support dfx on windows");
2773 return 0;
2774 }
2775
GetAccumulatedFreeSize()2776 size_t ArkNativeEngine::GetAccumulatedFreeSize()
2777 {
2778 HILOG_WARN("ARK does not support dfx on windows");
2779 return 0;
2780 }
2781
GetFullGCLongTimeCount()2782 size_t ArkNativeEngine::GetFullGCLongTimeCount()
2783 {
2784 HILOG_WARN("ARK does not support dfx on windows");
2785 return 0;
2786 }
2787
NotifyApplicationState(bool inBackground)2788 void ArkNativeEngine::NotifyApplicationState([[maybe_unused]] bool inBackground)
2789 {
2790 HILOG_WARN("ARK does not support dfx on windows");
2791 }
2792
NotifyIdleStatusControl(std::function<void (bool)> callback)2793 void ArkNativeEngine::NotifyIdleStatusControl([[maybe_unused]] std::function<void(bool)> callback)
2794 {
2795 HILOG_WARN("ARK does not support dfx on windows");
2796 }
2797
NotifyIdleTime(int idleMicroSec)2798 void ArkNativeEngine::NotifyIdleTime([[maybe_unused]] int idleMicroSec)
2799 {
2800 HILOG_WARN("ARK does not support dfx on windows");
2801 }
2802
NotifyMemoryPressure(bool inHighMemoryPressure)2803 void ArkNativeEngine::NotifyMemoryPressure([[maybe_unused]] bool inHighMemoryPressure)
2804 {
2805 HILOG_WARN("ARK does not support dfx on windows");
2806 }
2807
NotifyForceExpandState(int32_t value)2808 void ArkNativeEngine::NotifyForceExpandState([[maybe_unused]] int32_t value)
2809 {
2810 HILOG_WARN("ARK does not support dfx on windows");
2811 }
2812
GetArkNativeEngineByID(uint64_t tid)2813 NativeEngine* ArkNativeEngine::GetArkNativeEngineByID([[maybe_unused]] uint64_t tid)
2814 {
2815 HILOG_WARN("ARK does not support dfx on windows");
2816 return nullptr;
2817 }
2818
NotifyForceExpandState(uint64_t tid,int32_t value)2819 void ArkNativeEngine::NotifyForceExpandState([[maybe_unused]] uint64_t tid, [[maybe_unused]] int32_t value)
2820 {
2821 HILOG_WARN("ARK does not support dfx on windows");
2822 }
2823 #endif
2824
SetMockModuleList(const std::map<std::string,std::string> & list)2825 void ArkNativeEngine::SetMockModuleList(const std::map<std::string, std::string> &list)
2826 {
2827 JSNApi::SetMockModuleList(vm_, list);
2828 }
2829
OnErrorCallbackForThreadFunc(Local<ObjectRef> value,void * data)2830 static void OnErrorCallbackForThreadFunc(Local<ObjectRef> value, void *data)
2831 {
2832 if (data == nullptr) {
2833 return;
2834 }
2835 auto engine = static_cast<ArkNativeEngine *>(data);
2836 auto napiUncaughtExceptionCallback = engine->GetNapiUncaughtExceptionCallback();
2837 if (napiUncaughtExceptionCallback == nullptr) {
2838 return;
2839 }
2840 napi_env env = reinterpret_cast<napi_env>(engine);
2841 napiUncaughtExceptionCallback(ArkNativeEngine::ArkValueToNapiValue(env, value));
2842 }
2843
RegisterNapiUncaughtExceptionHandler(NapiUncaughtExceptionCallback callback)2844 void ArkNativeEngine::RegisterNapiUncaughtExceptionHandler(NapiUncaughtExceptionCallback callback)
2845 {
2846 JSNApi::EnableUserUncaughtErrorHandler(vm_);
2847 JSNApi::SetOnErrorCallback(vm_, OnErrorCallbackForThreadFunc, static_cast<void *>(this));
2848 napiUncaughtExceptionCallback_ = callback;
2849 }
2850
HandleUncaughtException()2851 void ArkNativeEngine::HandleUncaughtException()
2852 {
2853 if (napiUncaughtExceptionCallback_ == nullptr) {
2854 return;
2855 }
2856 LocalScope scope(vm_);
2857 lastException_.Empty();
2858 Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(vm_);
2859 if (!exception.IsEmpty() && !exception->IsHole()) {
2860 if (napiUncaughtExceptionCallback_ != nullptr) {
2861 napiUncaughtExceptionCallback_(ArkValueToNapiValue(reinterpret_cast<napi_env>(this), exception));
2862 }
2863 }
2864 }
2865
HasPendingException()2866 bool ArkNativeEngine::HasPendingException()
2867 {
2868 return JSNApi::HasPendingException(vm_);
2869 }
2870
RegisterPermissionCheck(PermissionCheckCallback callback)2871 void ArkNativeEngine::RegisterPermissionCheck(PermissionCheckCallback callback)
2872 {
2873 if (permissionCheckCallback_ == nullptr) {
2874 permissionCheckCallback_ = callback;
2875 }
2876 }
2877
ExecutePermissionCheck()2878 bool ArkNativeEngine::ExecutePermissionCheck()
2879 {
2880 if (permissionCheckCallback_ != nullptr) {
2881 return permissionCheckCallback_();
2882 } else {
2883 HILOG_INFO("permissionCheckCallback_ is still nullptr when executing permission check!");
2884 return true;
2885 }
2886 }
2887
RegisterTranslateBySourceMap(SourceMapCallback callback)2888 void ArkNativeEngine::RegisterTranslateBySourceMap(SourceMapCallback callback)
2889 {
2890 if (SourceMapCallback_ == nullptr) {
2891 SourceMapCallback_ = callback;
2892 }
2893 // regedit SourceMapCallback to ark_js_runtime
2894 JSNApi::SetSourceMapCallback(vm_, callback);
2895 }
2896
RegisterSourceMapTranslateCallback(SourceMapTranslateCallback callback)2897 void ArkNativeEngine::RegisterSourceMapTranslateCallback(SourceMapTranslateCallback callback)
2898 {
2899 JSNApi::SetSourceMapTranslateCallback(vm_, callback);
2900 }
2901
ExecuteTranslateBySourceMap(const std::string & rawStack)2902 std::string ArkNativeEngine::ExecuteTranslateBySourceMap(const std::string& rawStack)
2903 {
2904 if (SourceMapCallback_ != nullptr) {
2905 return SourceMapCallback_(rawStack);
2906 } else {
2907 return rawStack;
2908 }
2909 }
2910
IsMixedDebugEnabled()2911 bool ArkNativeEngine::IsMixedDebugEnabled()
2912 {
2913 return JSNApi::IsMixedDebugEnabled(vm_);
2914 }
2915
NotifyNativeCalling(const void * nativeAddress)2916 void ArkNativeEngine::NotifyNativeCalling(const void *nativeAddress)
2917 {
2918 JSNApi::NotifyNativeCalling(vm_, nativeAddress);
2919 }
2920
AllowCrossThreadExecution() const2921 void ArkNativeEngine::AllowCrossThreadExecution() const
2922 {
2923 JSNApi::AllowCrossThreadExecution(vm_);
2924 }
2925
DumpHybridStack(const EcmaVM * vm,std::string & stack,uint32_t ignore,int32_t deepth)2926 bool DumpHybridStack(const EcmaVM* vm, std::string &stack, uint32_t ignore, int32_t deepth)
2927 {
2928 #ifdef OHOS_STANDARD_PLATFORM
2929 constexpr size_t minSkiped = 2; // 2: skiped frames, include current func and unwinder
2930 const size_t skipedFrames = minSkiped + ignore;
2931 const int backtraceDeepth = (deepth < 0 || deepth > DEFAULT_MAX_FRAME_NUM) ? DEFAULT_MAX_FRAME_NUM : deepth;
2932 auto unwinder = std::make_shared<OHOS::HiviewDFX::Unwinder>();
2933 std::vector<OHOS::HiviewDFX::DfxFrame> frames;
2934 if (unwinder->UnwindLocal(false, false, backtraceDeepth, skipedFrames)) {
2935 frames = unwinder->GetFrames();
2936 } else {
2937 HILOG_ERROR("Failed to unwind local");
2938 }
2939
2940 for (auto &frame : frames) {
2941 if (frame.isJsFrame) {
2942 DFXJSNApi::TranslateJSStackInfo(vm, frame.mapName, frame.line, frame.column, frame.packageName);
2943 }
2944 }
2945
2946 stack = OHOS::HiviewDFX::Unwinder::GetFramesStr(frames);
2947 return true;
2948 #endif
2949 return false;
2950 }
2951
RegisterAppStateCallback(NapiAppStateCallback callback)2952 void ArkNativeEngine::RegisterAppStateCallback(NapiAppStateCallback callback)
2953 {
2954 interopAppState_.SetCallback(callback);
2955 }
2956
GetObjectHash(napi_env env,napi_value src)2957 int32_t ArkNativeEngine::GetObjectHash(napi_env env, napi_value src)
2958 {
2959 auto engine = reinterpret_cast<NativeEngine*>(env);
2960 auto vm = engine->GetEcmaVm();
2961 auto nativeValue = LocalValueFromJsValue(src);
2962 return DFXJSNApi::GetObjectHash(vm, nativeValue);
2963 }
2964 // LCOV_EXCL_STOP
2965
RunScriptPath(const char * path,bool checkPath)2966 bool ArkNativeEngine::RunScriptPath(const char* path, bool checkPath)
2967 {
2968 if (checkPath && !IsValidPandaFile(path)) {
2969 HILOG_ERROR("file is not exist or format is invalid");
2970 return false;
2971 }
2972 // LCOV_EXCL_START
2973 panda::JSExecutionScope executionScope(vm_);
2974 LocalScope scope(vm_);
2975 [[maybe_unused]] bool ret = JSNApi::Execute(vm_, path, PANDA_MAIN_FUNCTION);
2976 if (JSNApi::HasPendingException(vm_)) {
2977 HandleUncaughtException();
2978 return false;
2979 }
2980 // LCOV_EXCL_STOP
2981 return true;
2982 }
2983
IsValidPandaFile(const char * path)2984 bool ArkNativeEngine::IsValidPandaFile(const char* path)
2985 {
2986 if (path == nullptr) {
2987 HILOG_ERROR("file path is nullptr");
2988 return false;
2989 }
2990
2991 char filePath[PATH_MAX + 1] = { 0 };
2992 if (!RealPath(path, filePath, PATH_MAX + 1)) {
2993 HILOG_ERROR("failed to format path");
2994 return false;
2995 }
2996 struct stat fileStat;
2997 int ret = stat(filePath, &fileStat);
2998 if (ret != 0) {
2999 HILOG_ERROR("script file \"%{public}s\" is not exist", filePath);
3000 return false;
3001 }
3002
3003 if (!(fileStat.st_mode & S_IFREG)) {
3004 HILOG_ERROR("script path \"%{public}s\" is a directory", filePath);
3005 return false;
3006 }
3007 std::ifstream abcStream(filePath, std::ios::in | std::ios::binary);
3008
3009 constexpr size_t fileHeaderLength = sizeof(uint64_t);
3010 uint8_t fileHeader[fileHeaderLength] = { 0 };
3011 if (abcStream.is_open()) {
3012 size_t fileSize = fileStat.st_size;
3013 if (fileSize < fileHeaderLength) {
3014 HILOG_ERROR("faild to read file header, invalid format \"%{public}s\"", filePath);
3015 abcStream.close();
3016 return false;
3017 }
3018 abcStream.read(reinterpret_cast<char*>(fileHeader), fileHeaderLength);
3019 abcStream.close();
3020 return IsValidScriptBuffer(fileHeader, fileHeaderLength);
3021 }
3022 return false;
3023 }
3024
IsValidScriptBuffer(uint8_t * scriptBuffer,size_t bufferSize)3025 bool ArkNativeEngine::IsValidScriptBuffer(uint8_t* scriptBuffer, size_t bufferSize)
3026 {
3027 if (scriptBuffer == nullptr) {
3028 HILOG_ERROR("buffer is nullptr");
3029 return false;
3030 }
3031 constexpr size_t headerLen = sizeof(uint64_t);
3032 if (bufferSize < headerLen) {
3033 HILOG_ERROR("invalid buffer");
3034 return false;
3035 }
3036 constexpr char pandaFileHeader[headerLen] = "PANDA";
3037 const uint64_t bytePandaHeader = *reinterpret_cast<const uint64_t*>(pandaFileHeader);
3038 char fileHeader[headerLen] = { 0 };
3039 // Ensure destMax parameter is set correctly to avoid buffer overflows
3040 if (memcpy_s(fileHeader, sizeof(fileHeader), scriptBuffer, sizeof(fileHeader)) != 0) {
3041 HILOG_ERROR("faild to read file header of buffer");
3042 return false;
3043 }
3044
3045 uint64_t byteFileHeader = *reinterpret_cast<uint64_t*>(fileHeader);
3046 if (byteFileHeader != bytePandaHeader) {
3047 HILOG_ERROR("invalid format of file buffer");
3048 return false;
3049 }
3050 return true;
3051 }
3052
3053 // The security interface needs to be modified accordingly.
RunScriptBuffer(const char * path,std::vector<uint8_t> & buffer,bool isBundle,bool needUpdate)3054 napi_value ArkNativeEngine::RunScriptBuffer(const char* path, std::vector<uint8_t>& buffer, bool isBundle,
3055 bool needUpdate)
3056 {
3057 if (!IsValidScriptBuffer(buffer.data(), buffer.size())) {
3058 HILOG_ERROR("invalid script buffer");
3059 return nullptr;
3060 }
3061
3062 // LCOV_EXCL_START
3063 panda::EscapeLocalScope scope(vm_);
3064 [[maybe_unused]] bool ret = false;
3065 if (isBundle) {
3066 ret = JSNApi::Execute(vm_, buffer.data(), buffer.size(), PANDA_MAIN_FUNCTION, path);
3067 } else {
3068 ret = JSNApi::ExecuteModuleBuffer(vm_, buffer.data(), buffer.size(), path, needUpdate);
3069 }
3070
3071 if (JSNApi::HasPendingException(vm_)) {
3072 HandleUncaughtException();
3073 return nullptr;
3074 }
3075 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
3076 // LCOV_EXCL_STOP
3077 return JsValueFromLocalValue(scope.Escape(undefObj));
3078 }
3079
RunScriptBuffer(const std::string & path,uint8_t * buffer,size_t size,bool isBundle)3080 bool ArkNativeEngine::RunScriptBuffer(const std::string& path, uint8_t* buffer, size_t size, bool isBundle)
3081 {
3082 if (!IsValidScriptBuffer(buffer, size)) {
3083 HILOG_ERROR("invalid script buffer");
3084 return false;
3085 }
3086
3087 // LCOV_EXCL_START
3088 panda::JSExecutionScope executionScope(vm_);
3089 LocalScope scope(vm_);
3090 bool ret = false;
3091 if (isBundle) {
3092 ret = JSNApi::ExecuteSecure(vm_, buffer, size, PANDA_MAIN_FUNCTION, path);
3093 } else {
3094 ret = JSNApi::ExecuteModuleBufferSecure(vm_, buffer, size, path);
3095 }
3096
3097 if (JSNApi::HasPendingException(vm_)) {
3098 HandleUncaughtException();
3099 return false;
3100 }
3101 return ret;
3102 // LCOV_EXCL_STOP
3103 }
3104
RunBufferScript(std::vector<uint8_t> & buffer)3105 napi_value ArkNativeEngine::RunBufferScript(std::vector<uint8_t>& buffer)
3106 {
3107 if (!IsValidScriptBuffer(buffer.data(), buffer.size())) {
3108 HILOG_ERROR("invalid script buffer");
3109 return nullptr;
3110 }
3111
3112 // LCOV_EXCL_START
3113 panda::EscapeLocalScope scope(vm_);
3114 [[maybe_unused]] bool ret = JSNApi::Execute(vm_, buffer.data(), buffer.size(), PANDA_MAIN_FUNCTION);
3115
3116 if (JSNApi::HasPendingException(vm_)) {
3117 HandleUncaughtException();
3118 return nullptr;
3119 }
3120 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
3121 return JsValueFromLocalValue(scope.Escape(undefObj));
3122 // LCOV_EXCL_STOP
3123 }
3124
3125 #define EXECUTE_BUFFER(functionName) \
3126 if (JSNApi::IsBundle(vm_)) { \
3127 /* FA doesn't enable securemem */ \
3128 ret = JSNApi::Execute(vm_, buffer, bufferSize, PANDA_MAIN_FUNCTION, desc); \
3129 } else if (bufferSize != 0) { \
3130 if (entryPoint == nullptr) { \
3131 HILOG_DEBUG("Input entryPoint is nullptr, please input entryPoint for merged ESModule"); \
3132 /* this path for bundle and abc compiled by single module js */ \
3133 ret = JSNApi::functionName(vm_, buffer, bufferSize, PANDA_MAIN_FUNCTION, desc, false, fileMapper); \
3134 } else { \
3135 /* this path for mergeabc with specific entryPoint */ \
3136 ret = JSNApi::functionName(vm_, buffer, bufferSize, entryPoint, desc, false, fileMapper); \
3137 } \
3138 } else { \
3139 /* this path for worker */ \
3140 ret = JSNApi::Execute(vm_, desc, PANDA_MAIN_FUNCTION); \
3141 }
3142
RunActor(uint8_t * buffer,size_t bufferSize,const char * descriptor,char * entryPoint,bool checkPath,void * fileMapper)3143 napi_value ArkNativeEngine::RunActor(uint8_t* buffer, size_t bufferSize,
3144 const char* descriptor, char* entryPoint, bool checkPath, void* fileMapper)
3145 {
3146 if (buffer == nullptr && descriptor == nullptr) {
3147 HILOG_ERROR("invalid param, both buffer and descriptor are nullptr");
3148 return nullptr;
3149 }
3150
3151 if ((buffer != nullptr && !IsValidScriptBuffer(buffer, bufferSize)) &&
3152 (checkPath && descriptor != nullptr && !IsValidPandaFile(descriptor))) {
3153 HILOG_ERROR("invalid param");
3154 return nullptr;
3155 }
3156
3157 // LCOV_EXCL_START
3158 panda::EscapeLocalScope scope(vm_);
3159 std::string desc(descriptor);
3160 [[maybe_unused]] bool ret = false;
3161 // if apiVersion > API11, use secure path.
3162 if (IsApplicationApiVersionAPI11Plus()) {
3163 EXECUTE_BUFFER(ExecuteSecure);
3164 } else {
3165 EXECUTE_BUFFER(Execute);
3166 }
3167 if (JSNApi::HasPendingException(vm_)) {
3168 HandleUncaughtException();
3169 return nullptr;
3170 }
3171 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
3172 return JsValueFromLocalValue(scope.Escape(undefObj));
3173 // LCOV_EXCL_STOP
3174 }
3175
LoadArkModule(const void * buffer,int32_t len,const std::string & fileName)3176 panda::Local<panda::ObjectRef> ArkNativeEngine::LoadArkModule(const void* buffer,
3177 int32_t len, const std::string& fileName)
3178 {
3179 panda::EscapeLocalScope scope(vm_);
3180 Local<ObjectRef> undefObj(JSValueRef::Undefined(vm_));
3181 if (buffer == nullptr || len <= 0 || fileName.empty()) {
3182 HILOG_ERROR("fileName is nullptr or source code is nullptr");
3183 return scope.Escape(undefObj);
3184 }
3185 if (!IsValidScriptBuffer(reinterpret_cast<uint8_t*>(const_cast<void*>(buffer)), len)) {
3186 HILOG_ERROR("invalid script buffer");
3187 return scope.Escape(undefObj);
3188 }
3189
3190 // LCOV_EXCL_START
3191 bool res = JSNApi::ExecuteModuleFromBuffer(vm_, buffer, len, fileName);
3192 if (!res) {
3193 HILOG_ERROR("Execute module failed");
3194 return scope.Escape(undefObj);
3195 }
3196
3197 Local<ObjectRef> exportObj = JSNApi::GetExportObjectFromBuffer(vm_, fileName, "default");
3198 if (exportObj->IsNull()) {
3199 HILOG_ERROR("Get export object failed");
3200 return scope.Escape(undefObj);
3201 }
3202
3203 HILOG_DEBUG("ArkNativeEngineImpl::LoadModule end");
3204 return scope.Escape(exportObj);
3205 // LCOV_EXCL_STOP
3206 }
3207
ExecuteJsBin(const std::string & fileName,bool checkPath)3208 bool ArkNativeEngine::ExecuteJsBin(const std::string& fileName, bool checkPath)
3209 {
3210 if (checkPath && !IsValidPandaFile(fileName.c_str())) {
3211 HILOG_ERROR("faild to execute js bin, file is not exist or format is invalid");
3212 return false;
3213 }
3214 // LCOV_EXCL_START
3215 panda::JSExecutionScope executionScope(vm_);
3216 LocalScope scope(vm_);
3217 bool ret = JSNApi::Execute(vm_, fileName, PANDA_MAIN_FUNCTION);
3218 return ret;
3219 // LCOV_EXCL_STOP
3220 }
3221
EnableNapiProfiler()3222 void ArkNativeEngine::EnableNapiProfiler()
3223 {
3224 #ifdef ENABLE_HITRACE
3225 if (!ArkNativeEngine::napiProfilerParamReaded) {
3226 char napiProfilerParam[NAPI_PROFILER_PARAM_SIZE] = {0};
3227 int ret = GetParameter("persist.hiviewdfx.napiprofiler.enabled", "false",
3228 napiProfilerParam, sizeof(napiProfilerParam));
3229 if (ret > 0 && strcmp(napiProfilerParam, "true") == 0) {
3230 ArkNativeEngine::napiProfilerEnabled = true;
3231 }
3232 ArkNativeEngine::napiProfilerParamReaded = true;
3233 }
3234 #endif
3235 }
3236
SwitchContext()3237 napi_status ArkNativeEngine::SwitchContext()
3238 {
3239 if (context_.IsEmpty()) {
3240 HILOG_ERROR("no env context exists");
3241 return napi_generic_failure;
3242 }
3243
3244 panda::JSNApi::SwitchContext(vm_, context_.ToLocal(vm_));
3245 return napi_ok;
3246 }
3247
DestroyContext()3248 napi_status ArkNativeEngine::DestroyContext()
3249 {
3250 if (engineState_ != ArkNativeEngineState::RUNNING) {
3251 HILOG_ERROR("Attempt to release an env that is already marked for deletion");
3252 return napi_invalid_arg;
3253 }
3254
3255 // the original context cannot be destroyed
3256 if (isMainEnvContext_) {
3257 HILOG_ERROR("main env context cannot be destroyed");
3258 return napi_invalid_arg;
3259 }
3260
3261 // the current running context also cannot be destroyed
3262 Local<JSValueRef> currentContext = panda::JSNApi::GetCurrentContext(vm_);
3263 if (context_.ToLocal(vm_) == currentContext) {
3264 HILOG_ERROR("running env context cannot be destroyed");
3265 return napi_invalid_arg;
3266 }
3267
3268 engineState_ = ArkNativeEngineState::STOPPED;
3269 if (!HasRuntimeOwnedRef()) {
3270 Delete();
3271 }
3272 // waiting all ref callbacks done.
3273 return napi_ok;
3274 }
3275