• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &param = *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*> &param = 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