1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ark_native_engine.h"
17
18 #ifdef ENABLE_HITRACE
19 #include <sys/prctl.h>
20 #endif
21
22 #include "ark_native_deferred.h"
23 #include "ark_native_reference.h"
24 #include "native_engine/native_property.h"
25 #include "native_engine/native_utils.h"
26 #include "securec.h"
27 #include "utils/log.h"
28 #if !defined(PREVIEW) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
29 #include "parameters.h"
30 #include <uv.h>
31 #endif
32 #ifdef ENABLE_HITRACE
33 #include "hitrace_meter.h"
34 #include "parameter.h"
35 #endif
36
37 using panda::JsiRuntimeCallInfo;
38 using panda::BooleanRef;
39 using panda::ObjectRef;
40 using panda::StringRef;
41 using panda::Global;
42 using panda::FunctionRef;
43 using panda::PrimitiveRef;
44 using panda::ArrayBufferRef;
45 using panda::TypedArrayRef;
46 using panda::PromiseCapabilityRef;
47 using panda::NativePointerRef;
48 using panda::SymbolRef;
49 using panda::IntegerRef;
50 using panda::DateRef;
51 using panda::BigIntRef;
52 static constexpr auto PANDA_MAIN_FUNCTION = "_GLOBAL::func_main_0";
53 static constexpr auto PANDA_MODULE_NAME = "_GLOBAL_MODULE_NAME";
54 static constexpr auto PANDA_MODULE_NAME_LEN = 32;
55 static std::unordered_set<std::string> NATIVE_MODULE = {"system.app", "ohos.app", "system.router",
56 "system.curves", "ohos.curves", "system.matrix4", "ohos.matrix4"};
57 static constexpr auto NATIVE_MODULE_PREFIX = "@native:";
58 static constexpr auto OHOS_MODULE_PREFIX = "@ohos:";
59 #if !defined(PREVIEW) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
60 struct JsHeapDumpWork {
61 EcmaVM *vm;
62 uv_work_t work;
63 std::condition_variable *condition;
64 size_t limitSize;
65 };
66 static constexpr uint32_t DEC_TO_INT = 100;
67 static size_t g_threshold = OHOS::system::GetUintParameter<size_t>("persist.ark.leak.threshold", 85);
68 static constexpr int TIME_OUT = 20;
69 static size_t g_checkInterval = OHOS::system::GetUintParameter<size_t>("persist.ark.leak.checkinterval", 60);
70 static constexpr int DEFAULT_SLEEP_TIME = 100000; //poll every 0.1s
71 static bool g_enableProperty = OHOS::system::GetBoolParameter("persist.ark.leak.enableproperty", true);
72 static uint64_t g_lastHeapDumpTime = 0;
73 static bool g_debugLeak = OHOS::system::GetBoolParameter("debug.arkengine.tags.enableleak", false);
74 static constexpr uint64_t HEAP_DUMP_REPORT_INTERVAL = 24 * 3600 * 1000;
75 static constexpr uint64_t SEC_TO_MILSEC = 1000;
76 #endif
77 #ifdef ENABLE_HITRACE
78 constexpr auto NAPI_PROFILER_PARAM_SIZE = 10;
79 #endif
80
81 std::string ArkNativeEngine::tempModuleName_ {""};
82 bool ArkNativeEngine::napiProfilerEnabled {false};
83 bool ArkNativeEngine::napiProfilerParamReaded {false};
84 PermissionCheckCallback ArkNativeEngine::permissionCheckCallback_ {nullptr};
85
86 // To be delete
LocalValueToLocalNapiValue(panda::Local<panda::JSValueRef> local)87 napi_value LocalValueToLocalNapiValue(panda::Local<panda::JSValueRef> local)
88 {
89 return JsValueFromLocalValue(local);
90 }
91
92 // To be delete
NapiValueToLocalValue(napi_value v)93 panda::Local<panda::JSValueRef> NapiValueToLocalValue(napi_value v)
94 {
95 return LocalValueFromJsValue(v);
96 }
97
FunctionSetContainerId(const EcmaVM * vm,panda::Local<panda::JSValueRef> & value)98 void FunctionSetContainerId(const EcmaVM *vm, panda::Local<panda::JSValueRef> &value)
99 {
100 panda::Local<panda::FunctionRef> funcValue(value);
101 if (funcValue->IsNative(vm)) {
102 return;
103 }
104
105 auto extraInfo = funcValue->GetData(vm);
106 if (extraInfo != nullptr) {
107 return;
108 }
109
110 NapiFunctionInfo *funcInfo = NapiFunctionInfo::CreateNewInstance();
111 if (funcInfo == nullptr) {
112 HILOG_ERROR("funcInfo is nullptr");
113 return;
114 }
115 funcValue->SetData(vm, reinterpret_cast<void*>(funcInfo),
116 [](void *externalPointer, void *data) {
117 auto info = reinterpret_cast<NapiFunctionInfo*>(data);
118 if (info != nullptr) {
119 delete info;
120 info = nullptr;
121 }
122 }, true);
123 }
124
125 #if !defined(PREVIEW) && !defined(IOS_PLATFORM) && !defined(IOS_PLATFORM)
IsFileNameFormat(char c)126 bool IsFileNameFormat(char c)
127 {
128 if (c >= '0' && c <= '9') {
129 return false;
130 }
131
132 if (c >= 'a' && c <= 'z') {
133 return false;
134 }
135
136 if (c >= 'A' && c <= 'Z') {
137 return false;
138 }
139
140 if (c == '.' || c == '-' || c == '_') {
141 return false;
142 }
143
144 return true;
145 }
146
GetSelfProcName()147 std::string GetSelfProcName()
148 {
149 constexpr uint16_t READ_SIZE = 128;
150 std::ifstream fin;
151 fin.open("/proc/self/comm", std::ifstream::in);
152 if (!fin.is_open()) {
153 HILOG_ERROR("fin.is_open() false");
154 return "";
155 }
156 char readStr[READ_SIZE] = {'\0'};
157 fin.getline(readStr, READ_SIZE - 1);
158 fin.close();
159
160 std::string ret = std::string(readStr);
161 ret.erase(std::remove_if(ret.begin(), ret.end(), IsFileNameFormat), ret.end());
162 return ret;
163 }
164
IsInAppspawn()165 static bool IsInAppspawn()
166 {
167 const char *env = getenv("LD_PRELOAD");
168 if (env && strstr(env, "libclang_rt.asan.so") != nullptr) {
169 return true;
170 }
171 if (GetSelfProcName().find("appspawn") != std::string::npos && getppid() == 1) {
172 return true;
173 }
174 return false;
175 }
176
177 #endif
178
NapiDefineClass(napi_env env,const char * name,NapiNativeCallback callback,void * data,const NapiPropertyDescriptor * properties,size_t length)179 panda::Local<panda::JSValueRef> NapiDefineClass(napi_env env, const char* name, NapiNativeCallback callback,
180 void* data, const NapiPropertyDescriptor* properties, size_t length)
181 {
182 auto vm = const_cast<EcmaVM*>(reinterpret_cast<NativeEngine*>(env)->GetEcmaVm());
183 std::string className(name);
184 if (ArkNativeEngine::napiProfilerEnabled) {
185 className = ArkNativeEngine::tempModuleName_ + "." + name;
186 }
187
188 NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
189 if (funcInfo == nullptr) {
190 HILOG_ERROR("funcInfo is nullptr");
191 return panda::JSValueRef::Undefined(vm);
192 }
193 funcInfo->env = env;
194 funcInfo->callback = callback;
195 funcInfo->data = data;
196
197 Local<panda::FunctionRef> fn = panda::FunctionRef::NewClassFunction(vm, ArkNativeFunctionCallBack,
198 [](void* externalPointer, void* data) {
199 auto info = reinterpret_cast<NapiFunctionInfo*>(data);
200 if (info != nullptr) {
201 delete info;
202 }
203 },
204 reinterpret_cast<void*>(funcInfo), true);
205 Local<panda::ObjectRef> classPrototype = fn->GetFunctionPrototype(vm);
206 Local<panda::StringRef> fnName = panda::StringRef::NewFromUtf8(vm, className.c_str());
207 fn->SetName(vm, fnName);
208 Local<panda::ObjectRef> fnObj = fn->ToObject(vm);
209 for (size_t i = 0; i < length; i++) {
210 if (properties[i].attributes & NATIVE_STATIC) {
211 NapiDefineProperty(env, fnObj, properties[i]);
212 } else {
213 if (classPrototype->IsUndefined()) {
214 HILOG_ERROR("ArkNativeEngineImpl::Class's prototype is null");
215 continue;
216 }
217 reinterpret_cast<ArkNativeEngine*>(env)->SetModuleName(classPrototype, className);
218 NapiDefineProperty(env, classPrototype, properties[i]);
219 }
220 }
221
222 return fn;
223 }
224
225 struct MoudleNameLocker {
MoudleNameLockerMoudleNameLocker226 explicit MoudleNameLocker(std::string moduleName)
227 {
228 ArkNativeEngine::tempModuleName_ = moduleName;
229 }
~MoudleNameLockerMoudleNameLocker230 ~MoudleNameLocker()
231 {
232 ArkNativeEngine::tempModuleName_ = "";
233 }
234 };
235
GetNativePtrCallBack(void * data)236 void* ArkNativeEngine::GetNativePtrCallBack(void* data)
237 {
238 if (data == nullptr) {
239 HILOG_ERROR("data is nullptr");
240 return nullptr;
241 }
242 auto info = reinterpret_cast<NapiFunctionInfo*>(data);
243 auto cb = reinterpret_cast<void*>(info->callback);
244 return cb;
245 }
246
CheckArkApiAllowList(NativeModule * module,panda::ecmascript::ApiCheckContext context,panda::Local<panda::ObjectRef> & exportCopy)247 bool ArkNativeEngine::CheckArkApiAllowList(
248 NativeModule* module, panda::ecmascript::ApiCheckContext context, panda::Local<panda::ObjectRef>& exportCopy)
249 {
250 std::unique_ptr<ApiAllowListChecker>& apiAllowListChecker = module->apiAllowListChecker;
251 if (apiAllowListChecker != nullptr) {
252 const std::string apiPath = context.moduleName->ToString();
253 if ((*apiAllowListChecker)(apiPath)) {
254 CopyPropertyApiFilter(apiAllowListChecker, context.ecmaVm, context.exportObj, exportCopy, apiPath);
255 }
256 return true;
257 }
258 return false;
259 }
260
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)261 void ArkNativeEngine::CopyPropertyApiFilter(const std::unique_ptr<ApiAllowListChecker>& apiAllowListChecker,
262 const EcmaVM* ecmaVm, const panda::Local<panda::ObjectRef> exportObj, panda::Local<panda::ObjectRef>& exportCopy,
263 const std::string& apiPath)
264 {
265 panda::Local<panda::ArrayRef> namesArrayRef = exportObj->GetAllPropertyNames(ecmaVm, NATIVE_DEFAULT);
266 for (uint32_t i = 0; i < namesArrayRef->Length(ecmaVm); i++) {
267 const panda::Local<panda::JSValueRef> nameValue = panda::ArrayRef::GetValueAt(ecmaVm, namesArrayRef, i);
268 const panda::Local<panda::JSValueRef> value = exportObj->Get(ecmaVm, nameValue);
269 const std::string curPath = apiPath + "." + nameValue->ToString(ecmaVm)->ToString();
270 if ((*apiAllowListChecker)(curPath)) {
271 const std::string valueType = value->Typeof(ecmaVm)->ToString();
272 if (valueType == "object") {
273 panda::Local<panda::ObjectRef> subObject = ObjectRef::New(ecmaVm);
274 CopyPropertyApiFilter(apiAllowListChecker, ecmaVm, value, subObject, curPath);
275 exportCopy->Set(ecmaVm, nameValue, subObject);
276 HILOG_DEBUG("Set the package '%{public}s' to the allow list", curPath.c_str());
277 } else if (valueType == "function") {
278 exportCopy->Set(ecmaVm, nameValue, value);
279 HILOG_DEBUG("Set the function '%{public}s' to the allow list", curPath.c_str());
280 } else {
281 exportCopy->Set(ecmaVm, nameValue, value);
282 HILOG_DEBUG("Set the element type is '%{public}s::%{public}s' to the allow list", valueType.c_str(),
283 curPath.c_str());
284 }
285 }
286 }
287 }
288
289
ArkNativeEngine(EcmaVM * vm,void * jsEngine,bool isLimitedWorker)290 ArkNativeEngine::ArkNativeEngine(EcmaVM* vm, void* jsEngine, bool isLimitedWorker) : NativeEngine(jsEngine),
291 vm_(vm),
292 topScope_(vm),
293 isLimitedWorker_(isLimitedWorker)
294 {
295 HILOG_DEBUG("ArkNativeEngine::ArkNativeEngine");
296 #ifdef ENABLE_HITRACE
297 if (!ArkNativeEngine::napiProfilerParamReaded) {
298 char napiProfilerParam[NAPI_PROFILER_PARAM_SIZE] = {0};
299 int ret = GetParameter("persist.hiviewdfx.napiprofiler.enabled", "false",
300 napiProfilerParam, sizeof(napiProfilerParam));
301 if (ret > 0 && strcmp(napiProfilerParam, "true") == 0) {
302 ArkNativeEngine::napiProfilerEnabled = true;
303 }
304 ArkNativeEngine::napiProfilerParamReaded = true;
305 }
306 #endif
307 LocalScope scope(vm_);
308 Local<StringRef> requireInternalName = StringRef::NewFromUtf8(vm, "requireInternal");
309 void* requireData = static_cast<void*>(this);
310
311 Local<FunctionRef> requireNapi =
312 FunctionRef::New(
313 vm,
314 [](JsiRuntimeCallInfo *info) -> Local<JSValueRef> {
315 EcmaVM *ecmaVm = info->GetVM();
316 panda::EscapeLocalScope scope(ecmaVm);
317 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
318 ArkNativeEngine* arkNativeEngine = static_cast<ArkNativeEngine*>(info->GetData());
319 Local<StringRef> moduleName(info->GetCallArgRef(0));
320 NativeModule* module = nullptr;
321 bool isAppModule = false;
322 #ifdef IOS_PLATFORM
323 module = moduleManager->LoadNativeModule(moduleName->ToString().c_str(), nullptr, false, false,
324 "", arkNativeEngine->isLimitedWorker_);
325 #else
326 const uint32_t lengthMax = 2;
327 if (info->GetArgsNumber() >= lengthMax) {
328 Local<BooleanRef> ret(info->GetCallArgRef(1));
329 isAppModule = ret->Value();
330 }
331 arkNativeEngine->isAppModule_ = isAppModule;
332 if (info->GetArgsNumber() == 3) { // 3:Determine if the number of parameters is equal to 3
333 Local<StringRef> path(info->GetCallArgRef(2)); // 2:Take the second parameter
334 module =
335 moduleManager->LoadNativeModule(moduleName->ToString().c_str(), path->ToString().c_str(),
336 isAppModule, false, "", arkNativeEngine->isLimitedWorker_);
337 } else if (info->GetArgsNumber() == 4) { // 4:Determine if the number of parameters is equal to 4
338 Local<StringRef> path(info->GetCallArgRef(2)); // 2:Take the second parameter
339 Local<StringRef> relativePath(info->GetCallArgRef(3)); // 3:Take the second parameter
340 module =
341 moduleManager->LoadNativeModule(moduleName->ToString().c_str(), nullptr, isAppModule, false,
342 relativePath->ToString().c_str(), arkNativeEngine->isLimitedWorker_);
343 } else {
344 module =
345 moduleManager->LoadNativeModule(moduleName->ToString().c_str(), nullptr, isAppModule, false,
346 "", arkNativeEngine->isLimitedWorker_);
347 }
348 #endif
349 Local<JSValueRef> exports(JSValueRef::Undefined(ecmaVm));
350 if (module != nullptr) {
351 auto it = arkNativeEngine->loadedModules_.find(module);
352 if (it != arkNativeEngine->loadedModules_.end()) {
353 return scope.Escape(it->second.ToLocal(ecmaVm));
354 }
355 std::string strModuleName = moduleName->ToString();
356 moduleManager->SetNativeEngine(strModuleName, arkNativeEngine);
357 MoudleNameLocker nameLocker(strModuleName);
358
359 if (module->jsCode == nullptr && module->getABCCode != nullptr) {
360 module->getABCCode(&module->jsCode, &module->jsCodeLen);
361 }
362 if (module->jsABCCode != nullptr || module->jsCode != nullptr) {
363 char fileName[NAPI_PATH_MAX] = { 0 };
364 const char* name = module->name;
365 if (sprintf_s(fileName, sizeof(fileName), "lib%s.z.so/%s.js", name, name) == -1) {
366 HILOG_ERROR("sprintf_s file name failed");
367 return scope.Escape(exports);
368 }
369 HILOG_DEBUG("load js code from %{public}s", fileName);
370 const void *buffer = nullptr;
371 if (module->jsABCCode) {
372 buffer = static_cast<const void *>(module->jsABCCode);
373 } else {
374 buffer = static_cast<const void *>(module->jsCode);
375 }
376 auto exportObject = arkNativeEngine->LoadArkModule(buffer, module->jsCodeLen, fileName);
377 if (exportObject->IsUndefined()) {
378 HILOG_ERROR("load module failed");
379 return scope.Escape(exports);
380 } else {
381 exports = exportObject;
382 arkNativeEngine->loadedModules_[module] = Global<JSValueRef>(ecmaVm, exports);
383 }
384 } else if (module->registerCallback != nullptr) {
385 Local<ObjectRef> exportObj = ObjectRef::New(ecmaVm);
386 #ifdef ENABLE_HITRACE
387 StartTrace(HITRACE_TAG_ACE, "NAPI module init, name = " + std::string(module->name));
388 #endif
389 arkNativeEngine->SetModuleName(exportObj, module->name);
390 module->registerCallback(reinterpret_cast<napi_env>(arkNativeEngine),
391 JsValueFromLocalValue(exportObj));
392 #ifdef ENABLE_HITRACE
393 FinishTrace(HITRACE_TAG_ACE);
394 #endif
395 panda::Local<panda::ObjectRef> exportCopy = panda::ObjectRef::New(ecmaVm);
396 panda::ecmascript::ApiCheckContext context{moduleManager, ecmaVm, moduleName, exportObj, scope};
397 if (CheckArkApiAllowList(module, context, exportCopy)) {
398 return scope.Escape(exportCopy);
399 }
400 exports = exportObj;
401 arkNativeEngine->loadedModules_[module] = Global<JSValueRef>(ecmaVm, exports);
402 } else {
403 HILOG_ERROR("init module failed");
404 return scope.Escape(exports);
405 }
406 }
407 return scope.Escape(exports);
408 },
409 nullptr,
410 requireData);
411
412 Local<FunctionRef> requireInternal =
413 FunctionRef::New(
414 vm,
415 [](JsiRuntimeCallInfo *info) -> Local<JSValueRef> {
416 EcmaVM *ecmaVm = info->GetVM();
417 panda::EscapeLocalScope scope(ecmaVm);
418 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
419 ArkNativeEngine* arkNativeEngine = static_cast<ArkNativeEngine*>(info->GetData());
420 Local<StringRef> moduleName(info->GetCallArgRef(0));
421 NativeModule* module = moduleManager->LoadNativeModule(moduleName->ToString().c_str(), nullptr, false,
422 false, "", arkNativeEngine->isLimitedWorker_);
423 Local<JSValueRef> exports(JSValueRef::Undefined(ecmaVm));
424 MoudleNameLocker nameLocker(moduleName->ToString());
425 if (module != nullptr && arkNativeEngine) {
426 auto it = arkNativeEngine->loadedModules_.find(module);
427 if (it != arkNativeEngine->loadedModules_.end()) {
428 return scope.Escape(it->second.ToLocal(ecmaVm));
429 }
430 std::string strModuleName = moduleName->ToString();
431 moduleManager->SetNativeEngine(strModuleName, arkNativeEngine);
432 Local<ObjectRef> exportObj = ObjectRef::New(ecmaVm);
433 if (exportObj->IsObject()) {
434 arkNativeEngine->SetModuleName(exportObj, module->name);
435 module->registerCallback(reinterpret_cast<napi_env>(arkNativeEngine),
436 JsValueFromLocalValue(exportObj));
437 exports = exportObj;
438 arkNativeEngine->loadedModules_[module] = Global<JSValueRef>(ecmaVm, exports);
439 } else {
440 HILOG_ERROR("exportObject is nullptr");
441 return scope.Escape(exports);
442 }
443 }
444 return scope.Escape(exports);
445 },
446 nullptr,
447 requireData);
448
449 Local<ObjectRef> global = panda::JSNApi::GetGlobalObject(vm);
450 #if !defined(PREVIEW)
451 Local<StringRef> requireName = StringRef::NewFromUtf8(vm, "requireNapi");
452 global->Set(vm, requireName, requireNapi);
453 #else
454 Local<StringRef> requireNapiPreview = StringRef::NewFromUtf8(vm, "requireNapiPreview");
455 global->Set(vm, requireNapiPreview, requireNapi);
456 #endif
457 global->Set(vm, requireInternalName, requireInternal);
458 JSNApi::SetNativePtrGetter(vm, reinterpret_cast<void*>(ArkNativeEngine::GetNativePtrCallBack));
459 // need to call init of base class.
460 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
461 JSNApi::SetUnloadNativeModuleCallback(vm, std::bind(&NativeModuleManager::UnloadNativeModule,
462 moduleManager, std::placeholders::_1));
463 Init();
464 panda::JSNApi::SetLoop(vm, loop_);
465 }
466
~ArkNativeEngine()467 ArkNativeEngine::~ArkNativeEngine()
468 {
469 HILOG_DEBUG("ArkNativeEngine::~ArkNativeEngine");
470 Deinit();
471 // Free cached objects
472 for (auto&& [module, exportObj] : loadedModules_) {
473 exportObj.FreeGlobalHandleAddr();
474 }
475 // Free callbackRef
476 if (promiseRejectCallbackRef_ != nullptr) {
477 delete promiseRejectCallbackRef_;
478 }
479 if (checkCallbackRef_ != nullptr) {
480 delete checkCallbackRef_;
481 }
482 StopMonitorJSHeapUsage();
483 }
484
StartNapiProfilerTrace(panda::JsiRuntimeCallInfo * runtimeInfo)485 static inline void StartNapiProfilerTrace(panda::JsiRuntimeCallInfo *runtimeInfo)
486 {
487 #ifdef ENABLE_HITRACE
488 if (ArkNativeEngine::napiProfilerEnabled) {
489 EcmaVM *vm = runtimeInfo->GetVM();
490 LocalScope scope(vm);
491 Local<panda::FunctionRef> fn = runtimeInfo->GetFunctionRef();
492 Local<panda::StringRef> nameRef = fn->GetName(vm);
493 char threadName[128];
494 prctl(PR_GET_NAME, threadName);
495 StartTraceArgs(HITRACE_TAG_ACE, "Napi called:%s, tname:%s", nameRef->ToString().c_str(), threadName);
496 }
497 #endif
498 }
499
FinishNapiProfilerTrace()500 static inline void FinishNapiProfilerTrace()
501 {
502 #ifdef ENABLE_HITRACE
503 if (ArkNativeEngine::napiProfilerEnabled) {
504 FinishTrace(HITRACE_TAG_ACE);
505 }
506 #endif
507 }
508
GetArgc() const509 size_t NapiNativeCallbackInfo::GetArgc() const
510 {
511 return static_cast<size_t>(info->GetArgsNumber());
512 }
513
GetArgv(napi_value * argv,size_t argc)514 size_t NapiNativeCallbackInfo::GetArgv(napi_value* argv, size_t argc)
515 {
516 auto *vm = info->GetVM();
517 if (argc > 0) {
518 size_t i = 0;
519 size_t buffer = GetArgc();
520 for (; i < buffer && i < argc; i++) {
521 panda::Local<panda::JSValueRef> value = info->GetCallArgRef(i);
522 if (value->IsFunction()) {
523 FunctionSetContainerId(vm, value);
524 }
525 argv[i] = JsValueFromLocalValue(value);
526 }
527 return i;
528 }
529
530 return GetArgc();
531 }
532
GetThisVar()533 napi_value NapiNativeCallbackInfo::GetThisVar()
534 {
535 return JsValueFromLocalValue(info->GetThisRef());
536 }
537
GetFunction()538 napi_value NapiNativeCallbackInfo::GetFunction()
539 {
540 auto *vm = info->GetVM();
541 panda::Local<panda::JSValueRef> newValue = info->GetNewTargetRef();
542 if (newValue->IsFunction()) {
543 FunctionSetContainerId(vm, newValue);
544 }
545
546 return JsValueFromLocalValue(newValue);
547 }
548
GetFunctionInfo()549 NapiFunctionInfo* NapiNativeCallbackInfo::GetFunctionInfo()
550 {
551 return reinterpret_cast<NapiFunctionInfo*>(info->GetData());
552 }
553
ArkNativeFunctionCallBack(JsiRuntimeCallInfo * runtimeInfo)554 panda::JSValueRef ArkNativeFunctionCallBack(JsiRuntimeCallInfo *runtimeInfo)
555 {
556 EcmaVM *vm = runtimeInfo->GetVM();
557 panda::LocalScope scope(vm);
558 bool getStackBeforeCallNapiSuccess = false;
559 JSNApi::GetStackBeforeCallNapiSuccess(vm, getStackBeforeCallNapiSuccess);
560 auto info = reinterpret_cast<NapiFunctionInfo*>(runtimeInfo->GetData());
561 auto engine = reinterpret_cast<NativeEngine*>(info->env);
562 auto cb = info->callback;
563 if (engine == nullptr) {
564 HILOG_ERROR("native engine is null");
565 return **JSValueRef::Undefined(vm);
566 }
567
568 NapiNativeCallbackInfo cbInfo(runtimeInfo);
569 StartNapiProfilerTrace(runtimeInfo);
570
571 if (JSNApi::IsMixedDebugEnabled(vm)) {
572 JSNApi::NotifyNativeCalling(vm, reinterpret_cast<void *>(cb));
573 }
574
575 napi_value result = nullptr;
576 if (cb != nullptr) {
577 result = cb(info->env, &cbInfo);
578 }
579
580 if (JSNApi::IsMixedDebugEnabled(vm)) {
581 JSNApi::NotifyNativeReturn(vm, reinterpret_cast<void *>(cb));
582 }
583
584 Local<panda::JSValueRef> localRet = panda::JSValueRef::Undefined(vm);
585 if (result != nullptr) {
586 localRet = LocalValueFromJsValue(result);
587 }
588
589 FinishNapiProfilerTrace();
590 // Fixme: Rethrow error to engine while clear lastException_
591 if (!engine->lastException_.IsEmpty()) {
592 engine->lastException_.Empty();
593 }
594
595 if (localRet.IsEmpty()) {
596 return **JSValueRef::Undefined(vm);
597 }
598 if (getStackBeforeCallNapiSuccess) {
599 JSNApi::GetStackAfterCallNapi(vm);
600 }
601 return **localRet;
602 }
603
NapiNativeCreateFunction(napi_env env,const char * name,NapiNativeCallback cb,void * value)604 Local<panda::JSValueRef> NapiNativeCreateFunction(napi_env env, const char* name, NapiNativeCallback cb, void* value)
605 {
606 auto engine = reinterpret_cast<NativeEngine*>(env);
607 auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
608 NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
609 if (funcInfo == nullptr) {
610 HILOG_ERROR("funcInfo is nullptr");
611 return JSValueRef::Undefined(vm);
612 }
613 funcInfo->env = env;
614 funcInfo->callback = cb;
615 funcInfo->data = value;
616
617 Local<panda::FunctionRef> fn = panda::FunctionRef::New(vm, ArkNativeFunctionCallBack,
618 [](void* externalPointer, void* data) {
619 auto info = reinterpret_cast<NapiFunctionInfo*>(data);
620 if (info != nullptr) {
621 delete info;
622 }
623 },
624 reinterpret_cast<void*>(funcInfo), true);
625 Local<panda::StringRef> fnName = panda::StringRef::NewFromUtf8(vm, name);
626 fn->SetName(vm, fnName);
627 return fn;
628 }
629
GetProperty(EcmaVM * vm,Local<panda::ObjectRef> & obj,const char * name)630 Local<JSValueRef> GetProperty(EcmaVM* vm, Local<panda::ObjectRef> &obj, const char* name)
631 {
632 Local<StringRef> key = StringRef::NewFromUtf8(vm, name);
633 Local<JSValueRef> val = obj->Get(vm, key);
634 return val;
635 }
636
GetCString(EcmaVM * vm,Local<StringRef> str,char * buffer,size_t size,size_t * length)637 void GetCString(EcmaVM* vm, Local<StringRef> str, char* buffer, size_t size, size_t* length)
638 {
639 if (length == nullptr) {
640 return;
641 }
642 if (buffer == nullptr) {
643 *length = str->Utf8Length(vm) - 1;
644 } else if (size != 0) {
645 int copied = str->WriteUtf8(buffer, size - 1, true) - 1;
646 buffer[copied] = '\0';
647 *length = copied;
648 } else {
649 *length = 0;
650 }
651 }
652
NapiGetModuleName(napi_env env,Local<panda::ObjectRef> & obj)653 std::string NapiGetModuleName(napi_env env, Local<panda::ObjectRef> &obj)
654 {
655 auto engine = reinterpret_cast<NativeEngine*>(env);
656 auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
657 std::string moduleName("");
658 auto nativeModuleName = GetProperty(vm, obj, PANDA_MODULE_NAME);
659 if (nativeModuleName->IsString()) {
660 char arrayName[PANDA_MODULE_NAME_LEN] = {0};
661 size_t len = 0;
662 GetCString(vm, nativeModuleName, arrayName, PANDA_MODULE_NAME_LEN, &len);
663 moduleName += arrayName;
664 moduleName += ".";
665 }
666 return moduleName;
667 }
668
NapiDefineProperty(napi_env env,Local<panda::ObjectRef> & obj,NapiPropertyDescriptor propertyDescriptor)669 bool NapiDefineProperty(napi_env env, Local<panda::ObjectRef> &obj, NapiPropertyDescriptor propertyDescriptor)
670 {
671 auto engine = reinterpret_cast<NativeEngine*>(env);
672 auto vm = engine->GetEcmaVm();
673 bool result = false;
674 Local<panda::JSValueRef> propertyName;
675 if (propertyDescriptor.utf8name != nullptr) {
676 propertyName = panda::StringRef::NewFromUtf8(vm, propertyDescriptor.utf8name);
677 } else {
678 propertyName = LocalValueFromJsValue(propertyDescriptor.name);
679 }
680
681 bool writable = (propertyDescriptor.attributes & NATIVE_WRITABLE) != 0;
682 bool enumable = (propertyDescriptor.attributes & NATIVE_ENUMERABLE) != 0;
683 bool configable = (propertyDescriptor.attributes & NATIVE_CONFIGURABLE) != 0;
684
685 std::string fullName("");
686 if (propertyDescriptor.getter != nullptr || propertyDescriptor.setter != nullptr) {
687 #ifdef ENABLE_HITRACE
688 fullName += NapiGetModuleName(env, obj);
689 #endif
690 Local<panda::JSValueRef> localGetter = panda::JSValueRef::Undefined(vm);
691 Local<panda::JSValueRef> localSetter = panda::JSValueRef::Undefined(vm);
692
693 if (propertyDescriptor.getter != nullptr) {
694 fullName += "getter";
695 localGetter = NapiNativeCreateFunction(env, fullName.c_str(),
696 propertyDescriptor.getter, propertyDescriptor.data);
697 }
698 if (propertyDescriptor.setter != nullptr) {
699 fullName += "setter";
700 localSetter = NapiNativeCreateFunction(env, fullName.c_str(),
701 propertyDescriptor.setter, propertyDescriptor.data);
702 }
703
704 PropertyAttribute attr(panda::JSValueRef::Undefined(vm), false, enumable, configable);
705 result = obj->SetAccessorProperty(vm, propertyName, localGetter, localSetter, attr);
706 } else if (propertyDescriptor.method != nullptr) {
707 #ifdef ENABLE_HITRACE
708 fullName += NapiGetModuleName(env, obj);
709 #endif
710 if (propertyDescriptor.utf8name != nullptr) {
711 fullName += propertyDescriptor.utf8name;
712 } else {
713 fullName += propertyName->IsString()
714 ? Local<panda::StringRef>(propertyName)->ToString()
715 : Local<panda::SymbolRef>(propertyName)->GetDescription(vm)->ToString();
716 }
717 Local<panda::JSValueRef> cbObj = NapiNativeCreateFunction(env, fullName.c_str(),
718 propertyDescriptor.method, propertyDescriptor.data);
719 PropertyAttribute attr(cbObj, writable, enumable, configable);
720 result = obj->DefineProperty(vm, propertyName, attr);
721 } else {
722 Local<panda::JSValueRef> val = LocalValueFromJsValue(propertyDescriptor.value);
723
724 PropertyAttribute attr(val, writable, enumable, configable);
725 result = obj->DefineProperty(vm, propertyName, attr);
726 }
727 Local<panda::ObjectRef> excep = panda::JSNApi::GetUncaughtException(vm);
728 if (!excep.IsNull()) {
729 HILOG_DEBUG("ArkNativeObject::DefineProperty occur Exception");
730 panda::JSNApi::GetAndClearUncaughtException(vm);
731 }
732 return result;
733 }
734
NapiCreateObjectWithProperties(napi_env env,size_t propertyCount,const napi_property_descriptor * properties,Local<panda::JSValueRef> * keys,PropertyAttribute * attrs)735 panda::Local<panda::ObjectRef> NapiCreateObjectWithProperties(napi_env env, size_t propertyCount,
736 const napi_property_descriptor *properties,
737 Local<panda::JSValueRef> *keys,
738 PropertyAttribute *attrs)
739 {
740 auto vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
741 panda::EscapeLocalScope scope(vm);
742 for (size_t i = 0; i < propertyCount; ++i) {
743 const napi_property_descriptor &property = properties[i];
744
745 const char* utf8name = property.utf8name;
746 uint32_t attributes = property.attributes;
747 bool writable = (attributes & NATIVE_WRITABLE) != 0;
748 bool enumable = (attributes & NATIVE_ENUMERABLE) != 0;
749 bool configable = (attributes & NATIVE_CONFIGURABLE) != 0;
750 NapiNativeCallback method = reinterpret_cast<NapiNativeCallback>(property.method);
751 NapiNativeCallback getter = reinterpret_cast<NapiNativeCallback>(property.getter);
752 NapiNativeCallback setter = reinterpret_cast<NapiNativeCallback>(property.setter);
753 napi_value value = property.value;
754 void *data = property.data;
755
756 Local<panda::JSValueRef> val = panda::JSValueRef::Undefined(vm);
757
758 std::string fullName("");
759 if (getter != nullptr || setter != nullptr) {
760 Local<panda::JSValueRef> localGetter = panda::JSValueRef::Undefined(vm);
761 Local<panda::JSValueRef> localSetter = panda::JSValueRef::Undefined(vm);
762
763 if (getter != nullptr) {
764 fullName += "getter";
765 localGetter = NapiNativeCreateFunction(env, fullName.c_str(), getter, data);
766 }
767 if (setter != nullptr) {
768 fullName += "setter";
769 localSetter = NapiNativeCreateFunction(env, fullName.c_str(), setter, data);
770 }
771
772 val = panda::ObjectRef::CreateAccessorData(vm, localGetter, localSetter);
773 writable = false;
774 } else if (method != nullptr) {
775 fullName += utf8name;
776 val = NapiNativeCreateFunction(env, fullName.c_str(), method, data);
777 } else {
778 val = LocalValueFromJsValue(value);
779 }
780 new (reinterpret_cast<void *>(&attrs[i])) PropertyAttribute(val, writable, enumable, configable);
781 keys[i] = panda::StringRef::NewFromUtf8(vm, utf8name);
782 }
783 Local<panda::ObjectRef> object = panda::ObjectRef::NewWithProperties(vm, propertyCount, keys, attrs);
784 return scope.Escape(object);
785 }
786
GetModuleFromName(const std::string & moduleName,bool isAppModule,const std::string & id,const std::string & param,const std::string & instanceName,void ** instance)787 panda::Local<panda::ObjectRef> ArkNativeEngine::GetModuleFromName(
788 const std::string& moduleName, bool isAppModule, const std::string& id, const std::string& param,
789 const std::string& instanceName, void** instance)
790 {
791 panda::EscapeLocalScope scope(vm_);
792 Local<ObjectRef> exports(JSValueRef::Undefined(vm_));
793 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
794 NativeModule* module = moduleManager->LoadNativeModule(moduleName.c_str(), nullptr, isAppModule);
795 if (module != nullptr) {
796 Local<StringRef> idStr = StringRef::NewFromUtf8(vm_, id.c_str(), id.size());
797 napi_value idValue = JsValueFromLocalValue(idStr);
798 Local<StringRef> paramStr = StringRef::NewFromUtf8(vm_, param.c_str(), param.size());
799 napi_value paramValue = JsValueFromLocalValue(paramStr);
800 Local<ObjectRef> exportObj = ObjectRef::New(vm_);
801 NapiPropertyDescriptor idProperty, paramProperty;
802 idProperty.utf8name = "id";
803 idProperty.value = idValue;
804 paramProperty.utf8name = "param";
805 paramProperty.value = paramValue;
806 SetModuleName(exportObj, module->name);
807 NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, idProperty);
808 NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, paramProperty);
809 MoudleNameLocker nameLocker(module->name);
810 module->registerCallback(reinterpret_cast<napi_env>(this), JsValueFromLocalValue(exportObj));
811 napi_value nExport = JsValueFromLocalValue(exportObj);
812 napi_value exportInstance = nullptr;
813 napi_status status = napi_get_named_property(
814 reinterpret_cast<napi_env>(this), nExport, instanceName.c_str(), &exportInstance);
815 if (status != napi_ok) {
816 HILOG_ERROR("GetModuleFromName napi_get_named_property status != napi_ok");
817 }
818
819 status = napi_unwrap(reinterpret_cast<napi_env>(this), exportInstance, reinterpret_cast<void**>(instance));
820 if (status != napi_ok) {
821 HILOG_ERROR("GetModuleFromName napi_unwrap status != napi_ok");
822 }
823 exports = exportObj;
824 }
825 return scope.Escape(exports);
826 }
827
CreatePromise(NativeDeferred ** deferred)828 napi_value ArkNativeEngine::CreatePromise(NativeDeferred** deferred)
829 {
830 panda::EscapeLocalScope scope(vm_);
831 Local<PromiseCapabilityRef> capability = PromiseCapabilityRef::New(vm_);
832 *deferred = new ArkNativeDeferred(this, capability);
833 Local<JSValueRef> promiseValue = capability->GetPromise(vm_);
834 return JsValueFromLocalValue(scope.Escape(promiseValue));
835 }
836
LoadModuleByName(const std::string & moduleName,bool isAppModule,const std::string & param,const std::string & instanceName,void * instance,const std::string & path)837 panda::Local<panda::ObjectRef> ArkNativeEngine::LoadModuleByName(const std::string& moduleName, bool isAppModule,
838 const std::string& param, const std::string& instanceName, void* instance, const std::string& path)
839 {
840 panda::EscapeLocalScope scope(vm_);
841 Local<ObjectRef> exports(JSValueRef::Undefined(vm_));
842 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
843 NativeModule* module =
844 moduleManager->LoadNativeModule(moduleName.c_str(), path.empty() ? nullptr : path.c_str(), isAppModule);
845 if (module != nullptr) {
846 Local<ObjectRef> exportObj = ObjectRef::New(vm_);
847 NapiPropertyDescriptor paramProperty, instanceProperty;
848 Local<StringRef> paramStr = StringRef::NewFromUtf8(vm_, param.c_str(), param.size());
849 napi_value paramValue = JsValueFromLocalValue(paramStr);
850 paramProperty.utf8name = "param";
851 paramProperty.value = paramValue;
852 Local<ObjectRef> instanceValue = ObjectRef::New(vm_);
853 Local<StringRef> key = StringRef::GetNapiWrapperString(vm_);
854 if (instance == nullptr && instanceValue->Has(vm_, key)) {
855 Local<ObjectRef> wrapper = instanceValue->Get(vm_, key);
856 auto ref = reinterpret_cast<NativeReference*>(wrapper->GetNativePointerField(0));
857 wrapper->SetNativePointerField(vm_, 0, nullptr, nullptr, nullptr, 0);
858 instanceValue->Delete(vm_, key);
859 delete ref;
860 } else {
861 Local<ObjectRef> object = ObjectRef::New(vm_);
862 NativeReference* ref = nullptr;
863 Local<JSValueRef> value(instanceValue);
864 ref = new ArkNativeReference(this, vm_, value, 0, true, nullptr, instance, nullptr);
865
866 object->SetNativePointerFieldCount(vm_, 1);
867 object->SetNativePointerField(vm_, 0, ref, nullptr, nullptr, 0);
868 PropertyAttribute attr(object, true, false, true);
869 instanceValue->DefineProperty(vm_, key, attr);
870 }
871 instanceProperty.utf8name = instanceName.c_str();
872 instanceProperty.value = JsValueFromLocalValue(instanceValue);
873 SetModuleName(exportObj, module->name);
874 NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, paramProperty);
875 NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, instanceProperty);
876
877 MoudleNameLocker nameLocker(module->name);
878 module->registerCallback(reinterpret_cast<napi_env>(this), JsValueFromLocalValue(exportObj));
879 exports = exportObj;
880 }
881 return scope.Escape(exports);
882 }
883
Loop(LoopMode mode,bool needSync)884 void ArkNativeEngine::Loop(LoopMode mode, bool needSync)
885 {
886 LocalScope scope(vm_);
887 NativeEngine::Loop(mode, needSync);
888 panda::JSNApi::ExecutePendingJob(vm_);
889 }
890
SetModuleName(Local<ObjectRef> & nativeObj,std::string moduleName)891 void ArkNativeEngine::SetModuleName(Local<ObjectRef> &nativeObj, std::string moduleName)
892 {
893 #ifdef ENABLE_HITRACE
894 if (ArkNativeEngine::napiProfilerEnabled) {
895 Local<StringRef> moduleNameStr = StringRef::NewFromUtf8(vm_, moduleName.c_str(), moduleName.size());
896 Local<StringRef> key = StringRef::NewFromUtf8(vm_, PANDA_MODULE_NAME);
897 nativeObj->Set(vm_, key, moduleNameStr);
898 }
899 #endif
900 }
901
ConcurrentCallbackFunc(Local<JSValueRef> result,bool success,void * taskInfo,void * data)902 static void ConcurrentCallbackFunc(Local<JSValueRef> result, bool success, void *taskInfo, void *data)
903 {
904 if (data == nullptr) {
905 return;
906 }
907 auto engine = static_cast<ArkNativeEngine *>(data);
908 auto concurrentCallbackFunc = engine->GetConcurrentCallbackFunc();
909 if (concurrentCallbackFunc == nullptr) {
910 return;
911 }
912 napi_env env = reinterpret_cast<napi_env>(engine);
913 concurrentCallbackFunc(env, ArkNativeEngine::ArkValueToNapiValue(env, result), success, taskInfo);
914 }
915
InitTaskPoolThread(NativeEngine * engine,NapiConcurrentCallback callback)916 bool ArkNativeEngine::InitTaskPoolThread(NativeEngine* engine, NapiConcurrentCallback callback)
917 {
918 concurrentCallbackFunc_ = callback;
919 return JSNApi::InitForConcurrentThread(vm_, ConcurrentCallbackFunc, static_cast<void *>(this));
920 }
921
InitTaskPoolThread(napi_env env,NapiConcurrentCallback callback)922 bool ArkNativeEngine::InitTaskPoolThread(napi_env env, NapiConcurrentCallback callback)
923 {
924 concurrentCallbackFunc_ = callback;
925 return JSNApi::InitForConcurrentThread(vm_, ConcurrentCallbackFunc, static_cast<void *>(this));
926 }
927
InitTaskPoolFunc(napi_env env,napi_value func,void * taskInfo)928 bool ArkNativeEngine::InitTaskPoolFunc(napi_env env, napi_value func, void* taskInfo)
929 {
930 LocalScope scope(vm_);
931 Local<JSValueRef> function = LocalValueFromJsValue(func);
932 return JSNApi::InitForConcurrentFunction(vm_, function, taskInfo);
933 }
934
HasPendingJob() const935 bool ArkNativeEngine::HasPendingJob() const
936 {
937 return JSNApi::HasPendingJob(vm_);
938 }
939
IsProfiling() const940 bool ArkNativeEngine::IsProfiling() const
941 {
942 return JSNApi::IsProfiling(vm_);
943 }
944
IsExecutingPendingJob() const945 bool ArkNativeEngine::IsExecutingPendingJob() const
946 {
947 return panda::JSNApi::IsExecutingPendingJob(vm_);
948 }
949
GetCurrentTaskInfo() const950 void* ArkNativeEngine::GetCurrentTaskInfo() const
951 {
952 return JSNApi::GetCurrentTaskInfo(vm_);
953 }
954
TerminateExecution() const955 void ArkNativeEngine::TerminateExecution() const
956 {
957 DFXJSNApi::TerminateExecution(vm_);
958 }
959
CallFunction(napi_value thisVar,napi_value function,napi_value const * argv,size_t argc)960 napi_value ArkNativeEngine::CallFunction(
961 napi_value thisVar, napi_value function, napi_value const* argv, size_t argc)
962 {
963 if (function == nullptr) {
964 return nullptr;
965 }
966 panda::EscapeLocalScope scope(vm_);
967 Local<JSValueRef> thisObj = JSValueRef::Undefined(vm_);
968 if (thisVar != nullptr) {
969 thisObj = LocalValueFromJsValue(thisVar);
970 }
971 Local<FunctionRef> funcObj = LocalValueFromJsValue(function);
972 std::vector<Local<JSValueRef>> args;
973 args.reserve(argc);
974 for (size_t i = 0; i < argc; i++) {
975 if (argv[i] != nullptr) {
976 args.emplace_back(LocalValueFromJsValue(argv[i]));
977 } else {
978 args.emplace_back(JSValueRef::Undefined(vm_));
979 }
980 }
981
982 Local<JSValueRef> value = funcObj->Call(vm_, thisObj, args.data(), argc);
983 if (panda::JSNApi::HasPendingException(vm_)) {
984 HILOG_ERROR("pending exception when js function called");
985 HILOG_ERROR("print exception info: ");
986 panda::JSNApi::PrintExceptionInfo(vm_);
987 return nullptr;
988 }
989
990 return JsValueFromLocalValue(scope.Escape(value));
991 }
992
RunScriptPath(const char * path)993 bool ArkNativeEngine::RunScriptPath(const char* path)
994 {
995 panda::JSExecutionScope executionScope(vm_);
996 LocalScope scope(vm_);
997 [[maybe_unused]] bool ret = panda::JSNApi::Execute(vm_, path, PANDA_MAIN_FUNCTION);
998 if (panda::JSNApi::HasPendingException(vm_)) {
999 HandleUncaughtException();
1000 return false;
1001 }
1002 return true;
1003 }
1004
1005 /*
1006 * Before: input: 1. @ohos.hilog
1007 2. @system.app (NATIVE_MODULE contains this name)
1008 * After: return: 1.@ohos:hilog
1009 * 2.@native:system.app
1010 */
GetOhmurl(const char * str)1011 std::string ArkNativeEngine::GetOhmurl(const char* str)
1012 {
1013 std::string path(str);
1014 const std::regex reg("@(ohos|system)\\.(\\S+)");
1015 path.erase(0, path.find_first_not_of(" "));
1016 path.erase(path.find_last_not_of(" ") + 1);
1017 bool ret = std::regex_match(path, reg);
1018 if (!ret) {
1019 HILOG_ERROR("ArkNativeEngine:The module name doesn't comply with the naming rules");
1020 return "";
1021 }
1022 std::string systemModule = path.substr(1);
1023 if (NATIVE_MODULE.count(systemModule)) {
1024 return NATIVE_MODULE_PREFIX + systemModule;
1025 } else {
1026 int pos = static_cast<int>(path.find('.'));
1027 std::string systemKey = path.substr(pos + 1, systemModule.size());
1028 return OHOS_MODULE_PREFIX + systemKey;
1029 }
1030 }
1031
NapiLoadModule(const char * str)1032 napi_value ArkNativeEngine::NapiLoadModule(const char* str)
1033 {
1034 if (str == nullptr) {
1035 HILOG_ERROR("ArkNativeEngine:The module name is empty");
1036 return nullptr;
1037 }
1038 std::string key = GetOhmurl(str);
1039 if (key.size() == 0) {
1040 return nullptr;
1041 }
1042 panda::EscapeLocalScope scope(vm_);
1043 Local<ObjectRef> exportObj = panda::JSNApi::ExecuteNativeModule(vm_, key);
1044 if (exportObj->IsNull()) {
1045 HILOG_ERROR("ArkNativeEngine:napi load module failed");
1046 return nullptr;
1047 }
1048 return JsValueFromLocalValue(scope.Escape(exportObj));
1049 }
1050
SuspendVMById(uint32_t tid)1051 bool ArkNativeEngine::SuspendVMById(uint32_t tid)
1052 {
1053 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1054 return DFXJSNApi::SuspendVMById(vm_, tid);
1055 #else
1056 HILOG_WARN("ARK does not support dfx on windows");
1057 return false;
1058 #endif
1059 }
1060
ResumeVMById(uint32_t tid)1061 void ArkNativeEngine::ResumeVMById(uint32_t tid)
1062 {
1063 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1064 DFXJSNApi::ResumeVMById(vm_, tid);
1065 #else
1066 HILOG_WARN("ARK does not support dfx on windows");
1067 return;
1068 #endif
1069 }
1070
1071 // The security interface needs to be modified accordingly.
RunScriptBuffer(const char * path,std::vector<uint8_t> & buffer,bool isBundle)1072 napi_value ArkNativeEngine::RunScriptBuffer(const char* path, std::vector<uint8_t>& buffer, bool isBundle)
1073 {
1074 panda::EscapeLocalScope scope(vm_);
1075 [[maybe_unused]] bool ret = false;
1076 if (isBundle) {
1077 ret = panda::JSNApi::Execute(vm_, buffer.data(), buffer.size(), PANDA_MAIN_FUNCTION, path);
1078 } else {
1079 ret = panda::JSNApi::ExecuteModuleBuffer(vm_, buffer.data(), buffer.size(), path);
1080 }
1081
1082 if (panda::JSNApi::HasPendingException(vm_)) {
1083 HandleUncaughtException();
1084 return nullptr;
1085 }
1086 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
1087 return JsValueFromLocalValue(scope.Escape(undefObj));
1088 }
1089
RunScriptBuffer(const std::string & path,uint8_t * buffer,size_t size,bool isBundle)1090 bool ArkNativeEngine::RunScriptBuffer(const std::string& path, uint8_t* buffer, size_t size, bool isBundle)
1091 {
1092 panda::JSExecutionScope executionScope(vm_);
1093 LocalScope scope(vm_);
1094 bool ret = false;
1095 if (isBundle) {
1096 ret = panda::JSNApi::ExecuteSecure(vm_, buffer, size, PANDA_MAIN_FUNCTION, path);
1097 } else {
1098 ret = panda::JSNApi::ExecuteModuleBufferSecure(vm_, buffer, size, path);
1099 }
1100
1101 if (panda::JSNApi::HasPendingException(vm_)) {
1102 HandleUncaughtException();
1103 return false;
1104 }
1105 return ret;
1106 }
1107
SetPackagePath(const std::string appLibPathKey,const std::vector<std::string> & packagePath)1108 void ArkNativeEngine::SetPackagePath(const std::string appLibPathKey, const std::vector<std::string>& packagePath)
1109 {
1110 auto moduleManager = NativeModuleManager::GetInstance();
1111 if (moduleManager && !packagePath.empty()) {
1112 moduleManager->SetAppLibPath(appLibPathKey, packagePath);
1113 }
1114 }
1115
CreateInstance(napi_value constructor,napi_value const * argv,size_t argc)1116 napi_value ArkNativeEngine::CreateInstance(napi_value constructor, napi_value const *argv, size_t argc)
1117 {
1118 if (constructor == nullptr) {
1119 return nullptr;
1120 }
1121 panda::EscapeLocalScope scope(vm_);
1122 Local<FunctionRef> value = LocalValueFromJsValue(constructor);
1123 std::vector<Local<JSValueRef>> args;
1124 args.reserve(argc);
1125 for (size_t i = 0; i < argc; i++) {
1126 if (argv[i] != nullptr) {
1127 args.emplace_back(LocalValueFromJsValue(argv[i]));
1128 } else {
1129 args.emplace_back(JSValueRef::Undefined(vm_));
1130 }
1131 }
1132 Local<JSValueRef> instance = value->Constructor(vm_, args.data(), argc);
1133 Local<ObjectRef> excep = panda::JSNApi::GetUncaughtException(vm_);
1134 if (!excep.IsNull()) {
1135 HILOG_ERROR("ArkNativeEngineImpl::CreateInstance occur Exception");
1136 return nullptr;
1137 }
1138 return JsValueFromLocalValue(scope.Escape(instance));
1139 }
1140
CreateReference(napi_value value,uint32_t initialRefcount,bool flag,NapiNativeFinalize callback,void * data,void * hint)1141 NativeReference* ArkNativeEngine::CreateReference(napi_value value, uint32_t initialRefcount,
1142 bool flag, NapiNativeFinalize callback, void* data, void* hint)
1143 {
1144 return new ArkNativeReference(this, this->GetEcmaVm(), value, initialRefcount, flag, callback, data, hint);
1145 }
1146
CreateRuntimeFunc(NativeEngine * engine,void * jsEngine,bool isLimitedWorker)1147 NativeEngine* ArkNativeEngine::CreateRuntimeFunc(NativeEngine* engine, void* jsEngine, bool isLimitedWorker)
1148 {
1149 panda::RuntimeOption option;
1150 #if defined(OHOS_PLATFORM) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
1151 int arkProperties = OHOS::system::GetIntParameter<int>("persist.ark.properties", -1);
1152 std::string bundleName = OHOS::system::GetParameter("persist.ark.arkbundlename", "");
1153 size_t gcThreadNum = OHOS::system::GetUintParameter<size_t>("persist.ark.gcthreads", 7);
1154 size_t longPauseTime = OHOS::system::GetUintParameter<size_t>("persist.ark.longpausetime", 40);
1155 bool asmInterpreterEnabled = OHOS::system::GetBoolParameter("persist.ark.asminterpreter", true);
1156 std::string asmOpcodeDisableRange = OHOS::system::GetParameter("persist.ark.asmopcodedisablerange", "");
1157 bool builtinsLazyEnabled = OHOS::system::GetBoolParameter("persist.ark.enablebuiltinslazy", true);
1158 option.SetEnableBuiltinsLazy(builtinsLazyEnabled);
1159 option.SetArkProperties(arkProperties);
1160 option.SetArkBundleName(bundleName);
1161 option.SetGcThreadNum(gcThreadNum);
1162 option.SetLongPauseTime(longPauseTime);
1163 option.SetEnableAsmInterpreter(asmInterpreterEnabled);
1164 option.SetAsmOpcodeDisableRange(asmOpcodeDisableRange);
1165 option.SetIsWorker();
1166 HILOG_DEBUG("ArkNativeEngineImpl::CreateRuntimeFunc ark properties = %{public}d, bundlename = %{public}s",
1167 arkProperties, bundleName.c_str());
1168 #endif
1169 option.SetGcType(panda::RuntimeOption::GC_TYPE::GEN_GC);
1170 const int64_t poolSize = 0x1000000;
1171 option.SetGcPoolSize(poolSize);
1172 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1173 option.SetLogLevel(panda::RuntimeOption::LOG_LEVEL::INFO);
1174 #endif
1175 option.SetDebuggerLibraryPath("");
1176 EcmaVM* vm = panda::JSNApi::CreateJSVM(option);
1177 if (vm == nullptr) {
1178 return nullptr;
1179 }
1180 // worker adaptation mergeabc
1181 const panda::ecmascript::EcmaVM* hostVM = reinterpret_cast<ArkNativeEngine*>(engine)->GetEcmaVm();
1182 panda::JSNApi::SynchronizVMInfo(vm, hostVM);
1183 ArkNativeEngine* arkEngine = new ArkNativeEngine(vm, jsEngine, isLimitedWorker);
1184 // init callback
1185 arkEngine->RegisterWorkerFunction(engine);
1186 arkEngine->SetHostEngine(engine);
1187
1188 auto cleanEnv = [vm]() {
1189 if (vm != nullptr) {
1190 HILOG_DEBUG("cleanEnv is called");
1191 panda::JSNApi::DestroyJSVM(vm);
1192 }
1193 };
1194 arkEngine->SetCleanEnv(cleanEnv);
1195
1196 if (hostVM != nullptr) {
1197 panda::JSNApi::AddWorker(const_cast<EcmaVM*>(hostVM), vm);
1198 }
1199 return arkEngine;
1200 }
1201
CreateRuntime(bool isLimitedWorker)1202 void* ArkNativeEngine::CreateRuntime(bool isLimitedWorker)
1203 {
1204 return ArkNativeEngine::CreateRuntimeFunc(this, jsEngine_, isLimitedWorker);
1205 }
1206
StartCpuProfiler(const std::string & fileName)1207 void ArkNativeEngine::StartCpuProfiler(const std::string& fileName)
1208 {
1209 JSNApi::SetNativePtrGetter(vm_, reinterpret_cast<void*>(ArkNativeEngine::GetNativePtrCallBack));
1210 DFXJSNApi::StartCpuProfilerForFile(vm_, fileName);
1211 }
1212
StopCpuProfiler()1213 void ArkNativeEngine::StopCpuProfiler()
1214 {
1215 DFXJSNApi::StopCpuProfilerForFile(vm_);
1216 JSNApi::SetNativePtrGetter(vm_, nullptr);
1217 }
1218
ResumeVM()1219 void ArkNativeEngine::ResumeVM()
1220 {
1221 DFXJSNApi::ResumeVM(vm_);
1222 }
1223
SuspendVM()1224 bool ArkNativeEngine::SuspendVM()
1225 {
1226 return DFXJSNApi::SuspendVM(vm_);
1227 }
1228
IsSuspended()1229 bool ArkNativeEngine::IsSuspended()
1230 {
1231 return DFXJSNApi::IsSuspended(vm_);
1232 }
1233
CheckSafepoint()1234 bool ArkNativeEngine::CheckSafepoint()
1235 {
1236 return DFXJSNApi::CheckSafepoint(vm_);
1237 }
1238
RunBufferScript(std::vector<uint8_t> & buffer)1239 napi_value ArkNativeEngine::RunBufferScript(std::vector<uint8_t>& buffer)
1240 {
1241 panda::EscapeLocalScope scope(vm_);
1242 [[maybe_unused]] bool ret = panda::JSNApi::Execute(vm_, buffer.data(), buffer.size(), PANDA_MAIN_FUNCTION);
1243
1244 if (panda::JSNApi::HasPendingException(vm_)) {
1245 HandleUncaughtException();
1246 return nullptr;
1247 }
1248 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
1249 return JsValueFromLocalValue(scope.Escape(undefObj));
1250 }
1251
RunActor(std::vector<uint8_t> & buffer,const char * descriptor,char * entryPoint)1252 napi_value ArkNativeEngine::RunActor(std::vector<uint8_t>& buffer, const char* descriptor, char* entryPoint)
1253 {
1254 panda::EscapeLocalScope scope(vm_);
1255 std::string desc(descriptor);
1256 [[maybe_unused]] bool ret = false;
1257 if (panda::JSNApi::IsBundle(vm_)) {
1258 ret = panda::JSNApi::Execute(vm_, buffer.data(), buffer.size(), PANDA_MAIN_FUNCTION, desc);
1259 } else if (!buffer.empty()) {
1260 if (entryPoint == nullptr) {
1261 HILOG_DEBUG("Input entryPoint is nullptr, please input entryPoint for merged ESModule");
1262 // this path for bundle and abc compiled by single module js
1263 ret = panda::JSNApi::Execute(vm_, buffer.data(), buffer.size(), PANDA_MAIN_FUNCTION, desc);
1264 } else {
1265 // this path for mergeabc with specific entryPoint
1266 // entryPoint: bundleName/moduleName/xxx/xxx
1267 panda::JSNApi::SetModuleInfo(vm_, desc, std::string(entryPoint));
1268 ret = panda::JSNApi::Execute(vm_, buffer.data(), buffer.size(), entryPoint, desc);
1269 }
1270 } else {
1271 // this path for worker
1272 ret = panda::JSNApi::Execute(vm_, desc, PANDA_MAIN_FUNCTION);
1273 }
1274
1275 if (panda::JSNApi::HasPendingException(vm_)) {
1276 HandleUncaughtException();
1277 return nullptr;
1278 }
1279 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
1280 return JsValueFromLocalValue(scope.Escape(undefObj));
1281 }
1282
GetCurrentModuleInfo(std::string & moduleName,std::string & fileName,bool needRecordName)1283 void ArkNativeEngine::GetCurrentModuleInfo(std::string& moduleName, std::string& fileName, bool needRecordName)
1284 {
1285 LocalScope scope(vm_);
1286 std::pair<std::string, std::string> moduleInfo = panda::JSNApi::GetCurrentModuleInfo(vm_, needRecordName);
1287 moduleName = moduleInfo.first; // if needRecordName is true, then moduleName is recordName.
1288 fileName = moduleInfo.second;
1289 }
1290
GetIsBundle()1291 bool ArkNativeEngine::GetIsBundle()
1292 {
1293 LocalScope scope(vm_);
1294 return panda::JSNApi::IsBundle(vm_);
1295 }
1296
LoadArkModule(const void * buffer,int32_t len,const std::string & fileName)1297 panda::Local<panda::ObjectRef> ArkNativeEngine::LoadArkModule(const void* buffer,
1298 int32_t len, const std::string& fileName)
1299 {
1300 panda::EscapeLocalScope scope(vm_);
1301 Local<ObjectRef> undefObj(JSValueRef::Undefined(vm_));
1302 if (buffer == nullptr || len <= 0 || fileName.empty()) {
1303 HILOG_ERROR("fileName is nullptr or source code is nullptr");
1304 return scope.Escape(undefObj);
1305 }
1306
1307 bool res = JSNApi::ExecuteModuleFromBuffer(vm_, buffer, len, fileName);
1308 if (!res) {
1309 HILOG_ERROR("Execute module failed");
1310 return scope.Escape(undefObj);
1311 }
1312
1313 Local<ObjectRef> exportObj = JSNApi::GetExportObjectFromBuffer(vm_, fileName, "default");
1314 if (exportObj->IsNull()) {
1315 HILOG_ERROR("Get export object failed");
1316 return scope.Escape(undefObj);
1317 }
1318
1319 HILOG_DEBUG("ArkNativeEngineImpl::LoadModule end");
1320 return scope.Escape(exportObj);
1321 }
1322
ValueToNapiValue(JSValueWrapper & value)1323 napi_value ArkNativeEngine::ValueToNapiValue(JSValueWrapper& value)
1324 {
1325 Global<JSValueRef> arkValue = value;
1326 return JsValueFromLocalValue(arkValue.ToLocal(vm_));
1327 }
1328
ArkValueToNapiValue(napi_env env,Local<JSValueRef> value)1329 napi_value ArkNativeEngine::ArkValueToNapiValue(napi_env env, Local<JSValueRef> value)
1330 {
1331 return JsValueFromLocalValue(value);
1332 }
1333
GetSourceCodeInfo(napi_value value,ErrorPos pos)1334 std::string ArkNativeEngine::GetSourceCodeInfo(napi_value value, ErrorPos pos)
1335 {
1336 if (value == nullptr || pos.first == 0) {
1337 return "";
1338 }
1339
1340 LocalScope scope(vm_);
1341 Local<panda::FunctionRef> func = LocalValueFromJsValue(value);
1342 uint32_t line = pos.first;
1343 uint32_t column = pos.second;
1344 Local<panda::StringRef> sourceCode = func->GetSourceCode(vm_, line);
1345 std::string sourceCodeStr = sourceCode->ToString();
1346 if (sourceCodeStr.empty()) {
1347 return "";
1348 }
1349 std::string sourceCodeInfo = "SourceCode:\n";
1350 sourceCodeInfo.append(sourceCodeStr).append("\n");
1351 for (uint32_t k = 0; k < column - 1; k++) {
1352 sourceCodeInfo.push_back(' ');
1353 }
1354 sourceCodeInfo.append("^\n");
1355 return sourceCodeInfo;
1356 }
1357
ExecuteJsBin(const std::string & fileName)1358 bool ArkNativeEngine::ExecuteJsBin(const std::string& fileName)
1359 {
1360 panda::JSExecutionScope executionScope(vm_);
1361 LocalScope scope(vm_);
1362 bool ret = JSNApi::Execute(vm_, fileName, PANDA_MAIN_FUNCTION);
1363 return ret;
1364 }
1365
TriggerFatalException(napi_value error)1366 bool ArkNativeEngine::TriggerFatalException(napi_value error)
1367 {
1368 return true;
1369 }
1370
AdjustExternalMemory(int64_t ChangeInBytes,int64_t * AdjustedValue)1371 bool ArkNativeEngine::AdjustExternalMemory(int64_t ChangeInBytes, int64_t* AdjustedValue)
1372 {
1373 return true;
1374 }
1375
SetPromiseRejectCallback(NativeReference * rejectCallbackRef,NativeReference * checkCallbackRef)1376 void ArkNativeEngine::SetPromiseRejectCallback(NativeReference* rejectCallbackRef, NativeReference* checkCallbackRef)
1377 {
1378 if (rejectCallbackRef == nullptr || checkCallbackRef == nullptr) {
1379 HILOG_ERROR("rejectCallbackRef or checkCallbackRef is nullptr");
1380 return;
1381 }
1382 promiseRejectCallbackRef_ = rejectCallbackRef;
1383 checkCallbackRef_ = checkCallbackRef;
1384 JSNApi::SetHostPromiseRejectionTracker(vm_, reinterpret_cast<void*>(PromiseRejectCallback),
1385 reinterpret_cast<void*>(this));
1386 }
1387
PromiseRejectCallback(void * info)1388 void ArkNativeEngine::PromiseRejectCallback(void* info)
1389 {
1390 panda::PromiseRejectInfo* promiseRejectInfo = reinterpret_cast<panda::PromiseRejectInfo*>(info);
1391 ArkNativeEngine* env = reinterpret_cast<ArkNativeEngine*>(promiseRejectInfo->GetData());
1392
1393 if (env == nullptr) {
1394 HILOG_ERROR("engine is nullptr");
1395 return;
1396 }
1397
1398 if (env->promiseRejectCallbackRef_ == nullptr || env->checkCallbackRef_ == nullptr) {
1399 HILOG_ERROR("promiseRejectCallbackRef or checkCallbackRef is nullptr");
1400 return;
1401 }
1402 panda::ecmascript::EcmaVM* vm = const_cast<EcmaVM*>(env->GetEcmaVm());
1403 LocalScope scope(vm);
1404 Local<JSValueRef> promise = promiseRejectInfo->GetPromise();
1405 Local<JSValueRef> reason = promiseRejectInfo->GetReason();
1406 panda::PromiseRejectInfo::PROMISE_REJECTION_EVENT operation = promiseRejectInfo->GetOperation();
1407
1408 Local<JSValueRef> type(IntegerRef::New(vm, static_cast<int32_t>(operation)));
1409
1410 Local<JSValueRef> args[] = {type, promise, reason};
1411
1412 napi_value promiseNapiRejectCallback = env->promiseRejectCallbackRef_->Get();
1413 Local<FunctionRef> promiseRejectCallback = LocalValueFromJsValue(promiseNapiRejectCallback);
1414 if (!promiseRejectCallback.IsEmpty()) {
1415 promiseRejectCallback->Call(vm, JSValueRef::Undefined(vm), args, 3); // 3 args size
1416 }
1417
1418 if (operation == panda::PromiseRejectInfo::PROMISE_REJECTION_EVENT::REJECT) {
1419 Local<JSValueRef> checkCallback = LocalValueFromJsValue(env->checkCallbackRef_->Get());
1420 if (!checkCallback.IsEmpty()) {
1421 JSNApi::SetHostEnqueueJob(vm, checkCallback);
1422 }
1423 }
1424 }
1425
DumpHeapSnapshot(const std::string & path,bool isVmMode,DumpFormat dumpFormat)1426 void ArkNativeEngine::DumpHeapSnapshot(const std::string& path, bool isVmMode, DumpFormat dumpFormat)
1427 {
1428 if (dumpFormat == DumpFormat::JSON) {
1429 DFXJSNApi::DumpHeapSnapshot(vm_, 0, path, isVmMode);
1430 }
1431 if (dumpFormat == DumpFormat::BINARY) {
1432 DFXJSNApi::DumpHeapSnapshot(vm_, 1, path, isVmMode);
1433 }
1434 if (dumpFormat == DumpFormat::OTHER) {
1435 DFXJSNApi::DumpHeapSnapshot(vm_, 2, path, isVmMode); // 2:enum is 2
1436 }
1437 }
1438
DumpCpuProfile(bool isVmMode,DumpFormat dumpFormat,bool isPrivate,bool isFullGC)1439 void ArkNativeEngine::DumpCpuProfile(bool isVmMode, DumpFormat dumpFormat, bool isPrivate, bool isFullGC)
1440 {
1441 if (dumpFormat == DumpFormat::JSON) {
1442 DFXJSNApi::DumpCpuProfile(vm_, 0, isVmMode, isPrivate, false, isFullGC);
1443 }
1444 if (dumpFormat == DumpFormat::BINARY) {
1445 DFXJSNApi::DumpCpuProfile(vm_, 1, isVmMode, isPrivate);
1446 }
1447 if (dumpFormat == DumpFormat::OTHER) {
1448 DFXJSNApi::DumpCpuProfile(vm_, 2, isVmMode, isPrivate); // 2:enum is 2
1449 }
1450 }
1451
DumpHeapSnapshot(bool isVmMode,DumpFormat dumpFormat,bool isPrivate,bool isFullGC)1452 void ArkNativeEngine::DumpHeapSnapshot(bool isVmMode, DumpFormat dumpFormat, bool isPrivate, bool isFullGC)
1453 {
1454 if (dumpFormat == DumpFormat::JSON) {
1455 DFXJSNApi::DumpHeapSnapshot(vm_, 0, isVmMode, isPrivate, false, isFullGC);
1456 }
1457 if (dumpFormat == DumpFormat::BINARY) {
1458 DFXJSNApi::DumpHeapSnapshot(vm_, 1, isVmMode, isPrivate);
1459 }
1460 if (dumpFormat == DumpFormat::OTHER) {
1461 DFXJSNApi::DumpHeapSnapshot(vm_, 2, isVmMode, isPrivate); // 2:enum is 2
1462 }
1463 }
1464
BuildNativeAndJsStackTrace(std::string & stackTraceStr)1465 bool ArkNativeEngine::BuildNativeAndJsStackTrace(std::string& stackTraceStr)
1466 {
1467 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1468 return DFXJSNApi::BuildNativeAndJsStackTrace(vm_, stackTraceStr);
1469 #else
1470 HILOG_WARN("ARK does not support dfx on windows");
1471 return false;
1472 #endif
1473 }
1474
BuildJsStackTrace(std::string & stackTraceStr)1475 bool ArkNativeEngine::BuildJsStackTrace(std::string& stackTraceStr)
1476 {
1477 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1478 return DFXJSNApi::BuildJsStackTrace(vm_, stackTraceStr);
1479 #else
1480 HILOG_WARN("ARK does not support dfx on windows");
1481 return false;
1482 #endif
1483 }
1484
BuildJsStackInfoList(uint32_t tid,std::vector<JsFrameInfo> & jsFrames)1485 bool ArkNativeEngine::BuildJsStackInfoList(uint32_t tid, std::vector<JsFrameInfo>& jsFrames)
1486 {
1487 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1488 std::vector<ArkJsFrameInfo> arkJsFrames;
1489 bool sign = DFXJSNApi::BuildJsStackInfoList(vm_, tid, arkJsFrames);
1490 for (auto jf : arkJsFrames) {
1491 struct JsFrameInfo jsframe;
1492 jsframe.fileName = jf.fileName;
1493 jsframe.functionName = jf.functionName;
1494 jsframe.pos = jf.pos;
1495 jsframe.nativePointer = jf.nativePointer;
1496 jsFrames.emplace_back(jsframe);
1497 }
1498 return sign;
1499 #else
1500 HILOG_WARN("ARK does not support dfx on windows");
1501 return false;
1502 #endif
1503 }
1504
DeleteWorker(NativeEngine * workerEngine)1505 bool ArkNativeEngine::DeleteWorker(NativeEngine* workerEngine)
1506 {
1507 if (workerEngine != nullptr) {
1508 #if !defined(PREVIEW)
1509 const panda::ecmascript::EcmaVM* workerVM = reinterpret_cast<ArkNativeEngine*>(workerEngine)->GetEcmaVm();
1510 if (workerVM != nullptr) {
1511 return panda::JSNApi::DeleteWorker(vm_, const_cast<EcmaVM*>(workerVM));
1512 }
1513 #else
1514 HILOG_WARN("ARK does not support dfx on windows");
1515 #endif
1516 return false;
1517 }
1518 return false;
1519 }
1520
StartHeapTracking(double timeInterval,bool isVmMode)1521 bool ArkNativeEngine::StartHeapTracking(double timeInterval, bool isVmMode)
1522 {
1523 return DFXJSNApi::StartHeapTracking(vm_, timeInterval, isVmMode);
1524 }
1525
StopHeapTracking(const std::string & filePath)1526 bool ArkNativeEngine::StopHeapTracking(const std::string &filePath)
1527 {
1528 return DFXJSNApi::StopHeapTracking(vm_, filePath);
1529 }
1530
1531 #if !defined(PREVIEW)
PrintStatisticResult()1532 void ArkNativeEngine::PrintStatisticResult()
1533 {
1534 DFXJSNApi::PrintStatisticResult(vm_);
1535 }
1536
StartRuntimeStat()1537 void ArkNativeEngine::StartRuntimeStat()
1538 {
1539 DFXJSNApi::StartRuntimeStat(vm_);
1540 }
1541
StopRuntimeStat()1542 void ArkNativeEngine::StopRuntimeStat()
1543 {
1544 DFXJSNApi::StopRuntimeStat(vm_);
1545 }
1546
GetArrayBufferSize()1547 size_t ArkNativeEngine::GetArrayBufferSize()
1548 {
1549 return DFXJSNApi::GetArrayBufferSize(vm_);
1550 }
1551
GetHeapTotalSize()1552 size_t ArkNativeEngine::GetHeapTotalSize()
1553 {
1554 return DFXJSNApi::GetHeapTotalSize(vm_);
1555 }
1556
GetHeapUsedSize()1557 size_t ArkNativeEngine::GetHeapUsedSize()
1558 {
1559 return DFXJSNApi::GetHeapUsedSize(vm_);
1560 }
1561
GetHeapObjectSize()1562 size_t ArkNativeEngine::GetHeapObjectSize()
1563 {
1564 return DFXJSNApi::GetHeapObjectSize(vm_);
1565 }
1566
GetHeapLimitSize()1567 size_t ArkNativeEngine::GetHeapLimitSize()
1568 {
1569 return DFXJSNApi::GetHeapLimitSize(vm_);
1570 }
1571
NotifyApplicationState(bool inBackground)1572 void ArkNativeEngine::NotifyApplicationState(bool inBackground)
1573 {
1574 DFXJSNApi::NotifyApplicationState(vm_, inBackground);
1575 }
1576
NotifyIdleStatusControl(std::function<void (bool)> callback)1577 void ArkNativeEngine::NotifyIdleStatusControl(std::function<void(bool)> callback)
1578 {
1579 DFXJSNApi::NotifyIdleStatusControl(vm_, callback);
1580 }
1581
NotifyIdleTime(int idleMicroSec)1582 void ArkNativeEngine::NotifyIdleTime(int idleMicroSec)
1583 {
1584 DFXJSNApi::NotifyIdleTime(vm_, idleMicroSec);
1585 }
1586
NotifyMemoryPressure(bool inHighMemoryPressure)1587 void ArkNativeEngine::NotifyMemoryPressure(bool inHighMemoryPressure)
1588 {
1589 DFXJSNApi::NotifyMemoryPressure(vm_, inHighMemoryPressure);
1590 }
1591
NotifyForceExpandState(int32_t value)1592 void ArkNativeEngine::NotifyForceExpandState(int32_t value)
1593 {
1594 switch (ForceExpandState(value)) {
1595 case ForceExpandState::FINISH_COLD_START:
1596 DFXJSNApi::NotifyFinishColdStart(vm_, true);
1597 break;
1598 case ForceExpandState::START_HIGH_SENSITIVE:
1599 DFXJSNApi::NotifyHighSensitive(vm_, true);
1600 break;
1601 case ForceExpandState::FINISH_HIGH_SENSITIVE:
1602 DFXJSNApi::NotifyHighSensitive(vm_, false);
1603 break;
1604 default:
1605 HILOG_ERROR("Invalid Force Expand State: %{public}d.", value);
1606 break;
1607 }
1608 }
1609 #else
PrintStatisticResult()1610 void ArkNativeEngine::PrintStatisticResult()
1611 {
1612 HILOG_WARN("ARK does not support dfx on windows");
1613 }
1614
StartRuntimeStat()1615 void ArkNativeEngine::StartRuntimeStat()
1616 {
1617 HILOG_WARN("ARK does not support dfx on windows");
1618 }
1619
StopRuntimeStat()1620 void ArkNativeEngine::StopRuntimeStat()
1621 {
1622 HILOG_WARN("ARK does not support dfx on windows");
1623 }
1624
GetArrayBufferSize()1625 size_t ArkNativeEngine::GetArrayBufferSize()
1626 {
1627 HILOG_WARN("ARK does not support dfx on windows");
1628 return 0;
1629 }
1630
GetHeapTotalSize()1631 size_t ArkNativeEngine::GetHeapTotalSize()
1632 {
1633 HILOG_WARN("ARK does not support dfx on windows");
1634 return 0;
1635 }
1636
GetHeapUsedSize()1637 size_t ArkNativeEngine::GetHeapUsedSize()
1638 {
1639 HILOG_WARN("ARK does not support dfx on windows");
1640 return 0;
1641 }
1642
GetHeapObjectSize()1643 size_t ArkNativeEngine::GetHeapObjectSize()
1644 {
1645 HILOG_WARN("ARK does not support dfx on windows");
1646 return 0;
1647 }
1648
GetHeapLimitSize()1649 size_t ArkNativeEngine::GetHeapLimitSize()
1650 {
1651 HILOG_WARN("ARK does not support dfx on windows");
1652 return 0;
1653 }
1654
NotifyApplicationState(bool inBackground)1655 void ArkNativeEngine::NotifyApplicationState([[maybe_unused]] bool inBackground)
1656 {
1657 HILOG_WARN("ARK does not support dfx on windows");
1658 }
1659
NotifyIdleStatusControl(std::function<void (bool)> callback)1660 void ArkNativeEngine::NotifyIdleStatusControl([[maybe_unused]] std::function<void(bool)> callback)
1661 {
1662 HILOG_WARN("ARK does not support dfx on windows");
1663 }
1664
NotifyIdleTime(int idleMicroSec)1665 void ArkNativeEngine::NotifyIdleTime([[maybe_unused]] int idleMicroSec)
1666 {
1667 HILOG_WARN("ARK does not support dfx on windows");
1668 }
1669
NotifyMemoryPressure(bool inHighMemoryPressure)1670 void ArkNativeEngine::NotifyMemoryPressure([[maybe_unused]] bool inHighMemoryPressure)
1671 {
1672 HILOG_WARN("ARK does not support dfx on windows");
1673 }
1674
NotifyForceExpandState(int32_t value)1675 void ArkNativeEngine::NotifyForceExpandState([[maybe_unused]] int32_t value)
1676 {
1677 HILOG_WARN("ARK does not support dfx on windows");
1678 }
1679 #endif
1680
SetMockModuleList(const std::map<std::string,std::string> & list)1681 void ArkNativeEngine::SetMockModuleList(const std::map<std::string, std::string> &list)
1682 {
1683 JSNApi::SetMockModuleList(vm_, list);
1684 }
1685
RegisterNapiUncaughtExceptionHandler(NapiUncaughtExceptionCallback callback)1686 void ArkNativeEngine::RegisterNapiUncaughtExceptionHandler(NapiUncaughtExceptionCallback callback)
1687 {
1688 JSNApi::EnableUserUncaughtErrorHandler(vm_);
1689 napiUncaughtExceptionCallback_ = callback;
1690 }
1691
HandleUncaughtException()1692 void ArkNativeEngine::HandleUncaughtException()
1693 {
1694 if (napiUncaughtExceptionCallback_ == nullptr) {
1695 return;
1696 }
1697 LocalScope scope(vm_);
1698 lastException_.Empty();
1699 Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(vm_);
1700 if (!exception.IsEmpty() && !exception->IsHole()) {
1701 if (napiUncaughtExceptionCallback_ != nullptr) {
1702 napiUncaughtExceptionCallback_(ArkValueToNapiValue(reinterpret_cast<napi_env>(this), exception));
1703 }
1704 }
1705 }
1706
HasPendingException()1707 bool ArkNativeEngine::HasPendingException()
1708 {
1709 return panda::JSNApi::HasPendingException(vm_);
1710 }
1711
RegisterPermissionCheck(PermissionCheckCallback callback)1712 void ArkNativeEngine::RegisterPermissionCheck(PermissionCheckCallback callback)
1713 {
1714 if (permissionCheckCallback_ == nullptr) {
1715 permissionCheckCallback_ = callback;
1716 }
1717 }
1718
ExecutePermissionCheck()1719 bool ArkNativeEngine::ExecutePermissionCheck()
1720 {
1721 if (permissionCheckCallback_ != nullptr) {
1722 return permissionCheckCallback_();
1723 } else {
1724 HILOG_INFO("permissionCheckCallback_ is still nullptr when executing permission check!");
1725 return true;
1726 }
1727 }
1728
RegisterTranslateBySourceMap(SourceMapCallback callback)1729 void ArkNativeEngine::RegisterTranslateBySourceMap(SourceMapCallback callback)
1730 {
1731 if (SourceMapCallback_ == nullptr) {
1732 SourceMapCallback_ = callback;
1733 }
1734 // regedit SourceMapCallback to ark_js_runtime
1735 panda::JSNApi::SetSourceMapCallback(vm_, callback);
1736 }
1737
RegisterSourceMapTranslateCallback(SourceMapTranslateCallback callback)1738 void ArkNativeEngine::RegisterSourceMapTranslateCallback(SourceMapTranslateCallback callback)
1739 {
1740 panda::JSNApi::SetSourceMapTranslateCallback(vm_, callback);
1741 }
1742
ExecuteTranslateBySourceMap(const std::string & rawStack)1743 std::string ArkNativeEngine::ExecuteTranslateBySourceMap(const std::string& rawStack)
1744 {
1745 if (SourceMapCallback_ != nullptr) {
1746 return SourceMapCallback_(rawStack);
1747 } else {
1748 HILOG_WARN("SourceMapCallback_ is nullptr.");
1749 return "";
1750 }
1751 }
1752
IsMixedDebugEnabled()1753 bool ArkNativeEngine::IsMixedDebugEnabled()
1754 {
1755 return JSNApi::IsMixedDebugEnabled(vm_);
1756 }
1757
NotifyNativeCalling(const void * nativeAddress)1758 void ArkNativeEngine::NotifyNativeCalling(const void *nativeAddress)
1759 {
1760 JSNApi::NotifyNativeCalling(vm_, nativeAddress);
1761 }
1762
AllowCrossThreadExecution() const1763 void ArkNativeEngine::AllowCrossThreadExecution() const
1764 {
1765 JSNApi::AllowCrossThreadExecution(vm_);
1766 }
1767
1768 #if !defined(PREVIEW) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
GetCurrentTickMillseconds()1769 uint64_t ArkNativeEngine::GetCurrentTickMillseconds()
1770 {
1771 return std::chrono::duration_cast<std::chrono::milliseconds>(
1772 std::chrono::steady_clock::now().time_since_epoch()).count();
1773 }
1774
AsyncAfterWorkCallback(uv_work_t * req,int status)1775 void AsyncAfterWorkCallback(uv_work_t* req, int status)
1776 {
1777 if (req == nullptr) {
1778 HILOG_ERROR("dumpheapSnapshot AsyncAfterWorkCallback req is nullptr");
1779 return;
1780 }
1781 if (status) {
1782 HILOG_ERROR("dumpheapSnapshot AsyncAfterWorkCallback failed");
1783 }
1784 auto work = reinterpret_cast<JsHeapDumpWork*>(req->data);
1785 if (work == nullptr) {
1786 HILOG_ERROR("dumpheapSnapshot JsHeapDumpWork is nullptr");
1787 return;
1788 }
1789 size_t heapUsedSize = DFXJSNApi::GetHeapUsedSize(work->vm);
1790 size_t nowPrecent = heapUsedSize * DEC_TO_INT / (work->limitSize);
1791 HILOG_INFO("dumpheapSnapshot nowPrecent is %{public}zu", nowPrecent);
1792 if (nowPrecent >= g_threshold) {
1793 auto vm = work->vm;
1794 DFXJSNApi::GetHeapPrepare(vm);
1795 DFXJSNApi::SetOverLimit(vm, true);
1796 HILOG_INFO("dumpheapSnapshot GetHeapPrepare done");
1797 }
1798 work->condition->notify_all();
1799 delete work;
1800 }
1801
JudgmentDump(size_t limitSize)1802 void ArkNativeEngine::JudgmentDump(size_t limitSize)
1803 {
1804 if (!limitSize) {
1805 return;
1806 }
1807 size_t nowPrecent = GetHeapObjectSize() * DEC_TO_INT / limitSize;
1808 if (g_debugLeak || (nowPrecent >= g_threshold && (g_lastHeapDumpTime == 0 ||
1809 GetCurrentTickMillseconds() - g_lastHeapDumpTime > HEAP_DUMP_REPORT_INTERVAL))) {
1810 int pid = -1;
1811 std::unique_lock<std::mutex> lock(lock_);
1812 dumpWork_ = new(std::nothrow) JsHeapDumpWork;
1813 dumpWork_->vm = vm_;
1814 dumpWork_->work.data = dumpWork_;
1815 dumpWork_->condition = &condition_;
1816 dumpWork_->limitSize = limitSize;
1817 uv_loop_t *loop = GetUVLoop();
1818 uv_queue_work(loop, &(dumpWork_->work), [](uv_work_t *) {}, AsyncAfterWorkCallback);
1819 condition_.wait(lock);
1820 // VM destructed but syncTask is executed.
1821 if (needStop_ || !DFXJSNApi::isOverLimit(vm_)) {
1822 return;
1823 }
1824 DFXJSNApi::SetOverLimit(vm_, false);
1825 HILOG_INFO("dumpheapSnapshot ready");
1826 time_t startTime = time(nullptr);
1827 g_lastHeapDumpTime = GetCurrentTickMillseconds();
1828 if((pid = fork()) < 0) {
1829 HILOG_ERROR("ready dumpheapSnapshot Fork error, err:%{public}d", errno);
1830 sleep(g_checkInterval);
1831 return;
1832 }
1833 if (pid == 0) {
1834 AllowCrossThreadExecution();
1835 DumpHeapSnapshot(true, DumpFormat::JSON, false, false);
1836 HILOG_INFO("dumpheapSnapshot successful, now you can check some file");
1837 _exit(0);
1838 }
1839 while (true) {
1840 int status = 0;
1841 pid_t p = waitpid(pid, &status, 0);
1842 if (p < 0) {
1843 HILOG_ERROR("dumpheapSnapshot Waitpid return p=%{public}d, err:%{public}d", p, errno);
1844 break;
1845 }
1846 if (p == pid) {
1847 HILOG_ERROR("dumpheapSnapshot dump process exited status is %{public}d", status);
1848 break;
1849 }
1850 if (time(nullptr) > startTime + TIME_OUT) {
1851 HILOG_ERROR("time out to wait child process, killing forkpid %{public}d", pid);
1852 kill(pid, SIGKILL);
1853 break;
1854 }
1855 usleep(DEFAULT_SLEEP_TIME);
1856 }
1857 }
1858 }
1859
JsHeapStart()1860 void ArkNativeEngine::JsHeapStart()
1861 {
1862 if (pthread_setname_np(pthread_self(), "OS_JsHeapThread") != 0) {
1863 HILOG_ERROR("Failed to set threadName for JsHeap, errno:%d", errno);
1864 }
1865 while (!needStop_) {
1866 {
1867 std::unique_lock<std::mutex> lock(lock_);
1868 condition_.wait_for(lock, std::chrono::milliseconds(g_checkInterval * SEC_TO_MILSEC));
1869 if (needStop_) {
1870 return;
1871 }
1872 }
1873 size_t limitSize = GetHeapLimitSize();
1874 JudgmentDump(limitSize);
1875 }
1876 }
1877 #endif
1878
StartMonitorJSHeapUsage()1879 void ArkNativeEngine::StartMonitorJSHeapUsage()
1880 {
1881 #if !defined(PREVIEW) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
1882 if (!g_enableProperty) {
1883 return;
1884 }
1885 if (threadJsHeap_ == nullptr && !IsInAppspawn()) {
1886 threadJsHeap_ = std::make_unique<std::thread>(&ArkNativeEngine::JsHeapStart, this);
1887 HILOG_DEBUG("JsHeapStart is OK");
1888 }
1889 #else
1890 HILOG_ERROR("StartMonitorJSHeapUsage does not support dfx");
1891 #endif
1892 }
1893
StopMonitorJSHeapUsage()1894 void ArkNativeEngine::StopMonitorJSHeapUsage()
1895 {
1896 #if !defined(PREVIEW) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
1897 if (threadJsHeap_ != nullptr) {
1898 // Free threadJsHeap_
1899 needStop_ = true;
1900 condition_.notify_all();
1901 if (threadJsHeap_->joinable()) {
1902 threadJsHeap_->join();
1903 threadJsHeap_ = nullptr;
1904 }
1905 }
1906 #else
1907 HILOG_ERROR("StopMonitorJSHeapUsage does not support dfx");
1908 #endif
1909 }
1910