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 #ifndef FOUNDATION_ACE_NAPI_NATIVE_ENGINE_IMPL_ARK_ARK_NATIVE_ENGINE_H
17 #define FOUNDATION_ACE_NAPI_NATIVE_ENGINE_IMPL_ARK_ARK_NATIVE_ENGINE_H
18 
19 #include <memory>
20 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
21 #include <sys/wait.h>
22 #include <sys/types.h>
23 #endif
24 #include <unistd.h>
25 #include <map>
26 #include <mutex>
27 #include <thread>
28 #include <iostream>
29 #include <regex>
30 
31 #include "ecmascript/napi/include/dfx_jsnapi.h"
32 #include "ecmascript/napi/include/jsnapi.h"
33 #include "native_engine/impl/ark/ark_finalizers_pack.h"
34 #include "native_engine/native_engine.h"
35 #include "ark_idle_monitor.h"
36 #include "ark_native_options.h"
37 
38 
39 namespace panda::ecmascript {
40 struct JsHeapDumpWork;
41 struct JsFrameInfo {
42     std::string functionName;
43     std::string fileName;
44     std::string pos;
45     uintptr_t* nativePointer = nullptr;
46 };
47 struct ApiCheckContext {
48     NativeModuleManager* moduleManager;
49     EcmaVM* ecmaVm;
50     panda::Local<panda::StringRef>& moduleName;
51     panda::Local<panda::ObjectRef>& exportObj;
52     panda::EscapeLocalScope& scope;
53 };
54 }
55 using JsFrameInfo = panda::ecmascript::JsFrameInfo;
56 using DFXJSNApi = panda::DFXJSNApi;
57 using LocalScope = panda::LocalScope;
58 using JSNApi = panda::JSNApi;
59 using JSValueRef = panda::JSValueRef;
60 using JsiRuntimeCallInfo = panda::JsiRuntimeCallInfo;
61 using PropertyAttribute = panda::PropertyAttribute;
62 using NativePointerCallbackData = panda::NativePointerCallbackData;
63 using AsyncNativeCallbacksPack = panda::AsyncNativeCallbacksPack;
64 using TriggerGCTaskCallback = panda::TriggerGCTaskCallback;
65 using TriggerGCData = panda::TriggerGCData;
66 using ArkIdleMonitor = panda::ecmascript::ArkIdleMonitor;
67 
68 // indirect used by ace_engine and(or) ability_runtime
69 using panda::Local;
70 
71 template <bool changeState = true>
72 panda::JSValueRef ArkNativeFunctionCallBack(JsiRuntimeCallInfo *runtimeInfo);
73 void NapiDefinePropertyInner(napi_env env,
74                              Local<panda::ObjectRef> &obj,
75                              NapiPropertyDescriptor &propertyDescriptor,
76                              Local<panda::JSValueRef> &propertyName,
77                              bool &result);
78 bool NapiDefineProperty(napi_env env, panda::Local<panda::ObjectRef> &obj, NapiPropertyDescriptor propertyDescriptor);
79 NAPI_EXPORT panda::Local<panda::JSValueRef> NapiValueToLocalValue(napi_value v);
80 NAPI_EXPORT napi_value LocalValueToLocalNapiValue(panda::Local<panda::JSValueRef> local);
81 #ifdef ENABLE_CONTAINER_SCOPE
82 void FunctionSetContainerId(const EcmaVM *vm, panda::Local<panda::JSValueRef> &local);
83 #endif
84 #if !defined(is_arkui_x) && defined(OHOS_PLATFORM)
85 std::string DumpHybridStack(const EcmaVM* vm);
86 #endif
87 panda::Local<panda::JSValueRef> NapiDefineClass(napi_env env, const char* name, NapiNativeCallback callback,
88                                                 void* data, const NapiPropertyDescriptor* properties, size_t length);
89 Local<JSValueRef> NapiDefineSendableClass(napi_env env,
90                                           const char* name,
91                                           NapiNativeCallback callback,
92                                           void* data,
93                                           const NapiPropertyDescriptor* properties,
94                                           size_t propertiesLength,
95                                           napi_value parent);
96 panda::Local<panda::ObjectRef> NapiCreateSObjectWithProperties(napi_env env,
97                                                                size_t propertyCount,
98                                                                const NapiPropertyDescriptor* properties);
99 panda::Local<panda::ObjectRef> NapiCreateObjectWithProperties(napi_env env, size_t propertyCount,
100                                                               const napi_property_descriptor *properties,
101                                                               Local<panda::JSValueRef> *keys,
102                                                               panda::PropertyAttribute *attrs);
103 
104 enum class ForceExpandState : int32_t {
105     FINISH_COLD_START = 0,
106     START_HIGH_SENSITIVE,
107     FINISH_HIGH_SENSITIVE,
108 };
109 
110 enum class ModuleTypes : uint8_t {
111     NATIVE_MODULE = 0x01,
112     MODULE_INNER_FILE,
113     UNKNOWN
114 };
115 
116 class SerializationData {
117 public:
SerializationData()118     SerializationData() : data_(nullptr), size_(0) {}
119     ~SerializationData() = default;
120 
GetData() const121     uint8_t* GetData() const
122     {
123         return data_.get();
124     }
GetSize() const125     size_t GetSize() const
126     {
127         return size_;
128     }
129 
130 private:
131     struct DataDeleter {
operator ()SerializationData::DataDeleter132         void operator()(uint8_t* p) const
133         {
134             free(p);
135         }
136     };
137 
138     std::unique_ptr<uint8_t, DataDeleter> data_;
139     size_t size_;
140 };
141 
142 class NAPI_EXPORT ArkNativeEngine : public NativeEngine {
143 friend struct MoudleNameLocker;
144 public:
145     // ArkNativeEngine constructor
146     ArkNativeEngine(EcmaVM* vm, void* jsEngine, bool isLimitedWorker = false);
147     // ArkNativeEngine destructor
148     ~ArkNativeEngine() override;
149 
GetEcmaVm() const150     inline NAPI_EXPORT const EcmaVM* GetEcmaVm() const
151     {
152         return vm_;
153     }
154 
155     void Loop(LoopMode mode, bool needSync = false) override;
156     void SetPromiseRejectCallback(NativeReference* rejectCallbackRef, NativeReference* checkCallbackRef) override;
157     // For concurrent
158     bool InitTaskPoolThread(NativeEngine* engine, NapiConcurrentCallback callback) override;
159     bool InitTaskPoolThread(napi_env env, NapiConcurrentCallback callback) override;
160     bool InitTaskPoolFunc(napi_env env, napi_value func, void* taskInfo) override;
161     void ClearCurrentTaskInfo() override;
162     bool HasPendingJob() const override;
163     bool IsProfiling() const override;
164     bool IsExecutingPendingJob() const override;
165     void* GetCurrentTaskInfo() const override;
166     void TerminateExecution() const override;
167     void NotifyTaskBegin() const override;
168     void NotifyTaskFinished() const override;
169 
170     // judge_typedarray
171     bool NapiNewTypedArray(const EcmaVM* vm, NativeTypedArrayType typedArrayType,
172                            Local<panda::ArrayBufferRef> arrayBuf,
173                            size_t byte_offset, size_t length, napi_value* result) override;
174     bool NapiNewSendableTypedArray(const EcmaVM* vm, NativeTypedArrayType typedArrayType,
175                                    Local<panda::SendableArrayBufferRef> arrayBuf,
176                                    size_t byte_offset, size_t length, napi_value* result) override;
177     NativeTypedArrayType GetTypedArrayType(panda::Local<panda::TypedArrayRef> typedArray) override;
178     NativeTypedArrayType GetSendableTypedArrayType(panda::Local<panda::SendableTypedArrayRef> typedArray) override;
179     // Call function
180     napi_value CallFunction(napi_value thisVar,
181                             napi_value function,
182                             napi_value const* argv,
183                             size_t argc) override;
184     bool RunScriptPath(const char* path, bool checkPath = false) override;
185 
186     napi_value RunScriptBuffer(const char* path, std::vector<uint8_t>& buffer, bool isBundle) override;
187     bool RunScriptBuffer(const std::string& path, uint8_t* buffer, size_t size, bool isBundle) override;
188 
189     // Run buffer script
190     napi_value RunBufferScript(std::vector<uint8_t>& buffer) override;
191     napi_value RunActor(uint8_t* buffer, size_t size, const char* descriptor,
192         char* entryPoint = nullptr, bool checkPath = false) override;
193     // Set lib path
194     NAPI_EXPORT void SetPackagePath(const std::string appLinPathKey, const std::vector<std::string>& packagePath);
195     napi_value CreateInstance(napi_value constructor, napi_value const* argv, size_t argc) override;
196 
197     // Create native reference
198     NativeReference* CreateReference(napi_value value, uint32_t initialRefcount, bool flag = false,
199         NapiNativeFinalize callback = nullptr, void* data = nullptr, void* hint = nullptr,
200         size_t nativeBindingSize = 0) override;
201     NativeReference* CreateAsyncReference(napi_value value, uint32_t initialRefcount, bool flag = false,
202         NapiNativeFinalize callback = nullptr, void* data = nullptr, void* hint = nullptr) override;
203     napi_value CreatePromise(NativeDeferred** deferred) override;
204     void* CreateRuntime(bool isLimitedWorker = false) override;
205     panda::Local<panda::ObjectRef> LoadArkModule(const void *buffer, int32_t len, const std::string& fileName);
206     napi_value ValueToNapiValue(JSValueWrapper& value) override;
207     NAPI_EXPORT static napi_value ArkValueToNapiValue(napi_env env, Local<JSValueRef> value);
208 
209     std::string GetSourceCodeInfo(napi_value value, ErrorPos pos) override;
210 
211     NAPI_EXPORT bool ExecuteJsBin(const std::string& fileName, bool checkPath = false);
212     static bool IsValidPandaFile(const char* path);
213     static bool IsValidScriptBuffer(uint8_t* scriptBuffer, size_t bufferSize);
214     NAPI_EXPORT panda::Local<panda::ObjectRef> LoadModuleByName(const std::string& moduleName, bool isAppModule,
215         const std::string& param, const std::string& instanceName, void* instance, const std::string& path = "");
216 
217     void TriggerFatalException(panda::Local<panda::JSValueRef> exceptionValue) override;
218     bool AdjustExternalMemory(int64_t ChangeInBytes, int64_t* AdjustedValue) override;
219 
220     // Set jsdump thresholds
221     void SetJsDumpThresholds(size_t thresholds) override;
222 
223     // Set Appfreeze Filter
224     void SetAppFreezeFilterCallback(AppFreezeFilterCallback callback) override;
225 
226     // Detect performance to obtain cpuprofiler file
227     void StartCpuProfiler(const std::string& fileName = "") override;
228     void StopCpuProfiler() override;
229 
230     void ResumeVM() override;
231     bool SuspendVM() override;
232     bool IsSuspended() override;
233     bool CheckSafepoint() override;
234     bool SuspendVMById(uint32_t tid) override;
235     void ResumeVMById(uint32_t tid) override;
236 
237     // isVmMode means the internal class in vm is visible.
238     // isPrivate means the number and string is not visible.
239     void DumpHeapSnapshot(const std::string& path, bool isVmMode = true,
240         DumpFormat dumpFormat = DumpFormat::JSON, bool isPrivate = false, bool captureNumericValue = false) override;
241     void DumpCpuProfile() override;
242     // Dump the file into faultlog for heap leak.
243     void DumpHeapSnapshot(bool isVmMode = true, DumpFormat dumpFormat = DumpFormat::JSON,
244         bool isPrivate = false, bool isFullGC = true) override;
245     bool BuildNativeAndJsStackTrace(std::string& stackTraceStr) override;
246     bool BuildJsStackTrace(std::string& stackTraceStr) override;
247     bool BuildJsStackInfoListWithCustomDepth(std::vector<JsFrameInfo>& jsFrames)
248         override;
249 
250     bool DeleteWorker(NativeEngine* workerEngine) override;
251     bool StartHeapTracking(double timeInterval, bool isVmMode = true) override;
252     bool StopHeapTracking(const std::string& filePath) override;
253 
254     void PrintStatisticResult() override;
255     void StartRuntimeStat() override;
256     void StopRuntimeStat() override;
257     size_t GetArrayBufferSize() override;
258     size_t GetHeapTotalSize() override;
259     size_t GetHeapUsedSize() override;
260     size_t GetHeapObjectSize() override;
261     size_t GetHeapLimitSize() override;
262     size_t GetProcessHeapLimitSize() override;
263     size_t GetGCCount() override;
264     size_t GetGCDuration() override;
265     size_t GetAccumulatedAllocateSize() override;
266     size_t GetAccumulatedFreeSize() override;
267     size_t GetFullGCLongTimeCount() override;
268     void NotifyApplicationState(bool inBackground) override;
269     void NotifyIdleStatusControl(std::function<void(bool)> callback) override;
270     void NotifyIdleTime(int idleMicroSec) override;
271     void NotifyMemoryPressure(bool inHighMemoryPressure = false) override;
272     void NotifyForceExpandState(int32_t value) override;
273 
274     void AllowCrossThreadExecution() const override;
275     static void PromiseRejectCallback(void* values);
276 
277     void SetMockModuleList(const std::map<std::string, std::string> &list) override;
278     int32_t GetObjectHash(napi_env env, napi_value src) override;
279 
280     // debugger
281     bool IsMixedDebugEnabled();
282     void JsHeapStart();
283     uint64_t GetCurrentTickMillseconds();
284     bool JudgmentDumpExecuteTask(int pid);
285     void JudgmentDump(size_t limitSize);
286     void NotifyNativeCalling(const void *nativeAddress);
287 
288     void PostFinalizeTasks();
289     void PostAsyncTask(AsyncNativeCallbacksPack *callbacksPack);
290     void PostTriggerGCTask(TriggerGCData& data);
291 
GetArkFinalizersPack()292     ArkFinalizersPack &GetArkFinalizersPack()
293     {
294         return arkFinalizersPack_;
295     }
296 
GetPendingAsyncFinalizers()297     std::vector<RefFinalizer> &GetPendingAsyncFinalizers()
298     {
299         return pendingAsyncFinalizers_;
300     }
301 
302     void RegisterNapiUncaughtExceptionHandler(NapiUncaughtExceptionCallback callback) override;
303     void HandleUncaughtException() override;
304     bool HasPendingException() override;
305     void RegisterPermissionCheck(PermissionCheckCallback callback) override;
306     bool ExecutePermissionCheck() override;
307     void RegisterTranslateBySourceMap(SourceMapCallback callback) override;
308     std::string ExecuteTranslateBySourceMap(const std::string& rawStack) override;
309         void RegisterSourceMapTranslateCallback(SourceMapTranslateCallback callback) override;
310     panda::Local<panda::ObjectRef> GetModuleFromName(
311         const std::string& moduleName, bool isAppModule, const std::string& id, const std::string& param,
312         const std::string& instanceName, void** instance);
313     napi_value NapiLoadModule(const char* path, const char* module_info) override;
314     napi_value NapiLoadModuleWithInfo(const char* path, const char* module_info) override;
315     std::string GetOhmurl(std::string str);
316     Local<JSValueRef> NapiLoadNativeModule(std::string path);
317     ModuleTypes CheckLoadType(const std::string &path);
GetPromiseRejectCallBackRef()318     NativeReference* GetPromiseRejectCallBackRef()
319     {
320         return promiseRejectCallbackRef_;
321     }
322 
323     void SetPromiseRejectCallBackRef(NativeReference* rejectCallbackRef) override
324     {
325         promiseRejectCallbackRef_ = rejectCallbackRef;
326     }
327 
GetConcurrentCallbackFunc()328     NapiConcurrentCallback GetConcurrentCallbackFunc()
329     {
330         return concurrentCallbackFunc_;
331     }
332 
GetCheckCallbackRef()333     NativeReference* GetCheckCallbackRef()
334     {
335         return checkCallbackRef_;
336     }
337 
338     void SetCheckCallbackRef(NativeReference* checkCallbackRef) override
339     {
340         checkCallbackRef_ = checkCallbackRef;
341     }
342 
343     NapiUncaughtExceptionCallback GetNapiUncaughtExceptionCallback() override
344     {
345         return napiUncaughtExceptionCallback_;
346     }
347 
348     void* GetPromiseRejectCallback() override
349     {
350         return reinterpret_cast<void*>(PromiseRejectCallback);
351     }
352 
353     void SetModuleName(panda::Local<panda::ObjectRef> &nativeObj, std::string moduleName);
354     void GetCurrentModuleInfo(std::string& moduleName, std::string& fileName, bool needRecordName) override;
355     bool GetIsBundle() override;
356     bool GetIsNormalizedOhmUrlPack() override;
357     bool GetIsDebugModeEnabled() override;
358     std::string GetBundleName() override;
359     std::string GetPkgName(const std::string &moduleName) override;
360     bool IsExecuteModuleInAbcFile(std::string bundleName, std::string moduleName, std::string ohmurl) override;
361     int GetProcessStartRealTime() override;
362     void PostLooperTriggerIdleGCTask();
363 
364     static bool napiProfilerEnabled;
365     static std::string tempModuleName_;
366 
367     static void* GetNativePtrCallBack(void* data);
368     static void CopyPropertyApiFilter(const std::unique_ptr<ApiAllowListChecker>& apiAllowListChecker,
369         const EcmaVM* ecmaVm, const panda::Local<panda::ObjectRef> exportObj,
370         panda::Local<panda::ObjectRef>& exportCopy, const std::string& apiPath);
371 
372     inline bool IsCrossThreadCheckEnabled() const override
373     {
374         return crossThreadCheck_;
375     }
376     static constexpr size_t FINALIZERS_PACK_PENDING_NATIVE_BINDING_SIZE_THRESHOLD = 500 * 1024 * 1024;  // 500 MB
377 
378 private:
379     inline NapiOptions *GetNapiOptions() const override
380     {
381         return options_;
382     }
383 
384     static void RunCallbacks(ArkFinalizersPack *finalizersPack);
385     static void RunAsyncCallbacks(std::vector<RefFinalizer> *finalizers);
386     static void RunCallbacks(AsyncNativeCallbacksPack *callbacks);
387     static void RunCallbacks(TriggerGCData *triggerGCData);
388     static void SetAttribute(bool isLimitedWorker, panda::RuntimeOption &option);
389     static NativeEngine* CreateRuntimeFunc(NativeEngine* engine, void* jsEngine, bool isLimitedWorker = false);
390     static bool CheckArkApiAllowList(
391         NativeModule* module, panda::ecmascript::ApiCheckContext context, panda::Local<panda::ObjectRef>& exportCopy);
IncreasePendingFinalizersPackNativeBindingSize(size_t nativeBindingSize)392     void IncreasePendingFinalizersPackNativeBindingSize(size_t nativeBindingSize)
393     {
394         pendingFinalizersPackNativeBindingSize_ += nativeBindingSize;
395     }
DecreasePendingFinalizersPackNativeBindingSize(size_t nativeBindingSize)396     void DecreasePendingFinalizersPackNativeBindingSize(size_t nativeBindingSize)
397     {
398         pendingFinalizersPackNativeBindingSize_ -= nativeBindingSize;
399     }
400 
401     bool needStop_ = false;
402     panda::LocalScope topScope_;
403     NapiConcurrentCallback concurrentCallbackFunc_ { nullptr };
404     NativeReference* promiseRejectCallbackRef_ { nullptr };
405     NativeReference* checkCallbackRef_ { nullptr };
406     std::map<NativeModule*, panda::Global<panda::JSValueRef>> loadedModules_ {};
407     static PermissionCheckCallback permissionCheckCallback_;
408     NapiUncaughtExceptionCallback napiUncaughtExceptionCallback_ { nullptr };
409     SourceMapCallback SourceMapCallback_ { nullptr };
410     static bool napiProfilerParamReaded;
411     bool isLimitedWorker_ = false;
412     size_t pendingFinalizersPackNativeBindingSize_ {0};
413     ArkFinalizersPack arkFinalizersPack_ {};
414     std::vector<RefFinalizer> pendingAsyncFinalizers_ {};
415     // napi options and its cache
416     NapiOptions* options_ { nullptr };
417     bool crossThreadCheck_ { false };
418     ArkIdleMonitor *arkIdleMonitor_ {nullptr};
419 };
420 #endif /* FOUNDATION_ACE_NAPI_NATIVE_ENGINE_IMPL_ARK_ARK_NATIVE_ENGINE_H */
421