1 /*
2  * Copyright (c) 2021-2024 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 FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_ENGINE_JSI_JSI_DECLARATIVE_ENGINE_H
17 #define FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_ENGINE_JSI_JSI_DECLARATIVE_ENGINE_H
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <mutex>
22 #include <shared_mutex>
23 #include <string>
24 #include <vector>
25 
26 #include "ecmascript/napi/include/jsnapi.h"
27 #include "native_engine/impl/ark/ark_native_engine.h"
28 
29 #include "base/memory/ace_type.h"
30 #include "base/subwindow/subwindow_manager.h"
31 #include "base/utils/noncopyable.h"
32 #include "core/common/ace_application_info.h"
33 #include "core/common/ace_page.h"
34 #include "core/components/xcomponent/native_interface_xcomponent_impl.h"
35 #include "core/components_ng/base/ui_node.h"
36 #include "frameworks/bridge/js_frontend/engine/common/js_engine.h"
37 #include "frameworks/bridge/js_frontend/engine/jsi/js_runtime.h"
38 #include "frameworks/bridge/js_frontend/js_ace_page.h"
39 
40 namespace OHOS::Ace::Framework {
41 
42 struct NamedRouterProperty {
43     panda::Global<panda::FunctionRef> pageGenerator;
44     std::string bundleName;
45     std::string moduleName;
46     std::string pagePath;
47     std::string ohmUrl;
48 };
49 
50 class JsiDeclarativeEngineInstance final : public AceType, public JsEngineInstance {
DECLARE_ACE_TYPE(JsiDeclarativeEngineInstance,AceType)51     DECLARE_ACE_TYPE(JsiDeclarativeEngineInstance, AceType)
52 public:
53     explicit JsiDeclarativeEngineInstance(const RefPtr<FrontendDelegate>& delegate) : frontendDelegate_(delegate) {}
54     ~JsiDeclarativeEngineInstance() override;
55 
56     void FlushCommandBuffer(void* context, const std::string& command) override;
57 
58     bool InitJsEnv(bool debuggerMode, const std::unordered_map<std::string, void*>& extraNativeObject,
59         const shared_ptr<JsRuntime>& runtime = nullptr);
60     void InitJsObject();
61 
62     bool FireJsEvent(const std::string& eventStr);
63 
64     // add Console object to worker
65     void InitConsoleModule(ArkNativeEngine* engine);
66 
67     static void RootViewHandle(panda::Local<panda::ObjectRef> value);
68     void DestroyRootViewHandle(int32_t pageId);
69     void DestroyAllRootViewHandle();
70     void FlushReload();
71     napi_value GetContextValue();
72     napi_value GetFrameNodeValueByNodeId(int32_t nodeId);
73 
74     static std::unique_ptr<JsonValue> GetI18nStringResource(
75         const std::string& targetStringKey, const std::string& targetStringValue);
76     static std::string GetMediaResource(const std::string& targetFileName);
77 
78     static RefPtr<JsAcePage> GetRunningPage(int32_t instanceId);
79     static RefPtr<JsAcePage> GetStagingPage(int32_t instanceId);
80     static shared_ptr<JsRuntime> GetCurrentRuntime();
81     static void PostJsTask(const shared_ptr<JsRuntime>&, std::function<void()>&& task, const std::string& name);
82     static void TriggerPageUpdate(const shared_ptr<JsRuntime>&);
83     static RefPtr<PipelineBase> GetPipelineContext(const shared_ptr<JsRuntime>& runtime);
84     static void PreloadAceModule(void* runtime);
85     static void PreloadAceModuleWorker(void* runtime);
86 
GetJsMessageDispatcher()87     WeakPtr<JsMessageDispatcher> GetJsMessageDispatcher() const
88     {
89         return dispatcher_;
90     }
91 
SetRunningPage(const RefPtr<JsAcePage> & page)92     void SetRunningPage(const RefPtr<JsAcePage>& page)
93     {
94         std::lock_guard<std::mutex> lock(mutex_);
95         runningPage_ = page;
96     }
97 
GetRunningPage()98     RefPtr<JsAcePage> GetRunningPage() const
99     {
100         std::lock_guard<std::mutex> lock(mutex_);
101         return runningPage_;
102     }
103 
SetStagingPage(const RefPtr<JsAcePage> & page)104     void SetStagingPage(const RefPtr<JsAcePage>& page)
105     {
106         std::lock_guard<std::mutex> lock(mutex_);
107         stagingPage_ = page;
108     }
109 
GetStagingPage()110     RefPtr<JsAcePage> GetStagingPage() const
111     {
112         std::lock_guard<std::mutex> lock(mutex_);
113         return stagingPage_;
114     }
115 
ResetStagingPage(const RefPtr<JsAcePage> & page)116     void ResetStagingPage(const RefPtr<JsAcePage>& page)
117     {
118         stagingPage_ = page;
119     }
120 
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher)121     void SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher)
122     {
123         dispatcher_ = dispatcher;
124     }
125 
GetDelegate()126     RefPtr<FrontendDelegate> GetDelegate() const
127     {
128         return frontendDelegate_;
129     }
130 
GetJsRuntime()131     shared_ptr<JsRuntime> GetJsRuntime()
132     {
133         return runtime_;
134     }
135 
SetDebugMode(bool isDebugMode)136     void SetDebugMode(bool isDebugMode)
137     {
138         isDebugMode_ = isDebugMode;
139     }
140 
141     void SetDebuggerPostTask();
142 
SetInstanceId(int32_t instanceId)143     void SetInstanceId(int32_t instanceId)
144     {
145         instanceId_ = instanceId;
146     }
147 
SetRootView(int32_t pageId,panda::Global<panda::ObjectRef> value)148     void SetRootView(int32_t pageId, panda::Global<panda::ObjectRef> value)
149     {
150         rootViewMap_.emplace(pageId, value);
151     }
152 
IsEngineInstanceInitialized()153     bool IsEngineInstanceInitialized()
154     {
155         return isEngineInstanceInitialized_;
156     }
157 
158     void RegisterFaPlugin(); // load ReatureAbility plugin
159 
SetContextValue(shared_ptr<JsValue> uiContext)160     void SetContextValue(shared_ptr<JsValue> uiContext)
161     {
162         uiContext_ = uiContext;
163     }
164 
165 #if defined(PREVIEW)
SetPkgNameList(const std::map<std::string,std::string> & map)166     void SetPkgNameList(const std::map<std::string, std::string>& map)
167     {
168         pkgNameMap_ = map;
169     }
170 
SetPkgAliasList(const std::map<std::string,std::string> & map)171     void SetPkgAliasList(const std::map<std::string, std::string>& map)
172     {
173         pkgAliasMap_ = map;
174     }
175 
SetpkgContextInfoList(const std::map<std::string,std::vector<std::vector<std::string>>> & map)176     void SetpkgContextInfoList(const std::map<std::string, std::vector<std::vector<std::string>>>& map)
177     {
178         pkgContextInfoMap_ = map;
179     }
180 
CallCurlFunction(const OHOS::Ace::RequestData & requestData,int32_t callbackId)181     bool CallCurlFunction(const OHOS::Ace::RequestData& requestData, int32_t callbackId)
182     {
183         auto dispatcher = dispatcher_.Upgrade();
184         if (dispatcher) {
185             dispatcher->CallCurlFunction(requestData, callbackId);
186             return true;
187         } else {
188             return false;
189         }
190     }
191 
InitAceModule(const uint8_t * start,size_t length)192     bool InitAceModule(const uint8_t* start, size_t length)
193     {
194         if (!runtime_) {
195             return false;
196         }
197         bool result = runtime_->EvaluateJsCode(start, length);
198         if (!result) {
199             return false;
200         }
201         return true;
202     }
203 #endif
204 
205     // ArkTsCard start
206     static void PreloadAceModuleCard(void* runtime, const std::unordered_set<std::string>& formModuleList);
207     static void ReloadAceModuleCard(void* runtime, const std::unordered_set<std::string>& formModuleList);
208     // ArkTsCard end
209     static bool IsPlugin();
210     static bool RegisterStringCacheTable(const EcmaVM* vm, int32_t size);
211     static panda::Local<panda::StringRef> GetCachedString(const EcmaVM *vm, int32_t propertyIndex);
212     static void SetCachedString(const EcmaVM* vm);
213 
214 private:
215     void InitGlobalObjectTemplate();
216     void InitConsoleModule();  // add Console object to global
217     void InitAceModule();      // add ace object to global
218     void InitPerfUtilModule(); // add perfutil object to global
219     void InitJsExportsUtilObject();
220     void InitJsNativeModuleObject();
221     void InitJsContextModuleObject();
222     void InitGroupJsBridge();
223     static shared_ptr<JsRuntime> InnerGetCurrentRuntime();
224     shared_ptr<JsValue> CallGetUIContextFunc(
225         const shared_ptr<JsRuntime>& runtime, const std::vector<shared_ptr<JsValue>>& argv);
226     shared_ptr<JsValue> CallGetFrameNodeByNodeIdFunc(
227         const shared_ptr<JsRuntime>& runtime, const std::vector<shared_ptr<JsValue>>& argv);
228     std::unordered_map<int32_t, panda::Global<panda::ObjectRef>> rootViewMap_;
229     static std::unique_ptr<JsonValue> currentConfigResourceData_;
230     static std::map<std::string, std::string> mediaResourceFileMap_;
231     static std::shared_mutex sharedMutex_;
232 
233     // runningPage_ is the page that is loaded and rendered successfully, while stagingPage_ is to
234     // handle all page routing situation, which include two stages:
235     // - Loading stage: when a new page is loaded by qjs engine but not rendered, stagingPage_ point to
236     //   a new created page, which is different with runningPage_, the DOM build operations should call
237     //   this one, such as domCreateBody, domAddElement.
238     // - Running stage: If the stagingPage_ rendered successfully, the runningPage_ will update to stagingPage_.
239     //   If the stagingPage_ render failed, it will reset to runningPage_. So in running stage, runningPage_
240     //   and stagingPage_ point to the same page. But it's better to use runningPage_ in dom update tasks,
241     //   such as removeElement, updateElementAttrs and updateElementStyles.
242 #if defined(PREVIEW)
243     std::map<std::string, std::string> pkgNameMap_;
244     std::map<std::string, std::string> pkgAliasMap_;
245     std::map<std::string, std::vector<std::vector<std::string>>> pkgContextInfoMap_;
246 #endif
247     RefPtr<JsAcePage> runningPage_;
248     RefPtr<JsAcePage> stagingPage_;
249 
250     shared_ptr<JsRuntime> runtime_;
251     RefPtr<FrontendDelegate> frontendDelegate_;
252     WeakPtr<JsMessageDispatcher> dispatcher_;
253     mutable std::mutex mutex_;
254     bool isDebugMode_ = true;
255     bool usingSharedRuntime_ = false;
256     bool isEngineInstanceInitialized_ = false;
257     int32_t instanceId_ = 0;
258     static bool isModulePreloaded_;
259     static bool isModuleInitialized_;
260     static shared_ptr<JsRuntime> globalRuntime_;
261     shared_ptr<JsValue> uiContext_;
262     static std::shared_mutex globalRuntimeMutex_;
263 
264     ACE_DISALLOW_COPY_AND_MOVE(JsiDeclarativeEngineInstance);
265 };
266 
267 class JsiDeclarativeEngine : public JsEngine {
DECLARE_ACE_TYPE(JsiDeclarativeEngine,JsEngine)268     DECLARE_ACE_TYPE(JsiDeclarativeEngine, JsEngine)
269 public:
270     JsiDeclarativeEngine(int32_t instanceId, void* runtime) : instanceId_(instanceId), runtime_(runtime) {}
JsiDeclarativeEngine(int32_t instanceId)271     explicit JsiDeclarativeEngine(int32_t instanceId) : instanceId_(instanceId) {}
272     ~JsiDeclarativeEngine() override;
273 
274     bool Initialize(const RefPtr<FrontendDelegate>& delegate) override;
275     void EngineTask(bool sharedRuntime);
276 
277     void Destroy() override;
278 
279     // Load and initialize a JS bundle into the JS Framework
280     void LoadJs(const std::string& url, const RefPtr<JsAcePage>& page, bool isMainPage) override;
281 #if !defined(PREVIEW)
282     bool IsModule();
283 
284     void LoadJsWithModule(
285         std::string& urlName, const std::function<void(const std::string&, int32_t)>& errorCallback = nullptr);
286 
287     void LoadPluginJsWithModule(std::string& urlName);
288 
289 #endif
290     // Load the app.js file of the FA model in NG structure..
291     bool LoadFaAppSource() override;
292 
293     // Load the je file of the page in NG structure..
294     bool LoadPageSource(const std::string& url,
295         const std::function<void(const std::string&, int32_t)>& errorCallback = nullptr) override;
296     bool LoadPageSource(const std::shared_ptr<std::vector<uint8_t>>& content,
297         const std::function<void(const std::string&, int32_t)>& errorCallback = nullptr,
298         const std::string& contentName = "") override;
299     int32_t LoadNavDestinationSource(const std::string& pageUrl, const std::string& bundleName,
300         const std::string& moduleName, bool isSingleton) override;
301 
302     bool LoadCard(const std::string& url, int64_t cardId, const std::string& entryPoint) override;
303 
304     // Update running page
305     void UpdateRunningPage(const RefPtr<JsAcePage>& page) override;
306 
307     // Update staging page
308     void UpdateStagingPage(const RefPtr<JsAcePage>& page) override;
309 
310     // Reset staging page
311     void ResetStagingPage() override;
312 
313     void SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher) override;
314 
315     // Fire AsyncEvent on JS
316     void FireAsyncEvent(const std::string& eventId, const std::string& param) override;
317 
318     // Fire SyncEvent on JS
319     void FireSyncEvent(const std::string& eventId, const std::string& param) override;
320 
321     void FireExternalEvent(const std::string& componentId, uint32_t nodeId, bool isDestroy) override;
322 
323     // Timer callback
324     void TimerCallback(const std::string& callbackId, const std::string& delay, bool isInterval) override;
325 
326     // Destroy page instance
327     void DestroyPageInstance(int32_t pageId) override;
328 
329     void OnActive() override;
330 
331     void OnInactive() override;
332 
333     void OnNewWant(const std::string& data) override;
334 
335     bool OnStartContinuation() override;
336 
337     void OnCompleteContinuation(int32_t code) override;
338 
339     void OnRemoteTerminated() override;
340 
341     void OnSaveData(std::string& data) override;
342 
343     bool OnRestoreData(const std::string& data) override;
344 
345     // Destroy application instance according to packageName
346     void DestroyApplication(const std::string& packageName) override;
347 
348     void UpdateApplicationState(const std::string& packageName, Frontend::State state) override;
349 
350     void OnWindowDisplayModeChanged(bool isShownInMultiWindow, const std::string& data) override;
351 
352     void MediaQueryCallback(const std::string& callbackId, const std::string& args) override;
353 
354     void RequestAnimationCallback(const std::string& callbackId, uint64_t timeStamp) override;
355 
356     void JsCallback(const std::string& callbackId, const std::string& args) override;
357 
358     void RunGarbageCollection() override;
359 
360     void RunFullGarbageCollection() override;
361 
362     void DumpHeapSnapshot(bool isPrivate) override;
363 
364     void NotifyUIIdle() override;
365 
366     std::string GetStacktraceMessage() override;
367 
368     void GetStackTrace(std::string& trace) override;
369 
370     static std::string GetPagePath(const std::string& url);
371 
372     static std::string GetFullPathInfo(const std::string& url);
373 
374     static std::optional<std::string> GetRouteNameByUrl(
375         const std::string& url, const std::string& bundleName, const std::string& moduleName);
376 
377     void SetLocalStorage(int32_t instanceId, NativeReference* storage) override;
378 
379     void SetContext(int32_t instanceId, NativeReference* context) override;
380 
381     void SetErrorEventHandler(std::function<void(const std::string&, const std::string&)>&& errorCallback) override;
382 
383     RefPtr<GroupJsBridge> GetGroupJsBridge() override;
384 
GetFrontend()385     RefPtr<FrontendDelegate> GetFrontend() override
386     {
387         return engineInstance_->GetDelegate();
388     }
389 
GetEngineInstance()390     RefPtr<JsiDeclarativeEngineInstance> GetEngineInstance()
391     {
392         return engineInstance_;
393     }
394 
FlushReload()395     void FlushReload() override
396     {
397         if (engineInstance_) {
398             engineInstance_->FlushReload();
399         }
400     }
401 
RunNativeEngineLoop()402     void RunNativeEngineLoop() override
403     {
404         static bool hasPendingExpection = false;
405         if (nativeEngine_ && !hasPendingExpection) {
406             hasPendingExpection = nativeEngine_->HasPendingException();
407             nativeEngine_->Loop(LOOP_NOWAIT, false);
408         }
409     }
410 
SetPluginBundleName(const std::string & pluginBundleName)411     void SetPluginBundleName(const std::string& pluginBundleName) override
412     {
413         pluginBundleName_ = pluginBundleName;
414     }
415 
SetPluginModuleName(const std::string & pluginModuleName)416     void SetPluginModuleName(const std::string& pluginModuleName) override
417     {
418         pluginModuleName_ = pluginModuleName;
419     }
420 
GetContextValue()421     napi_value GetContextValue() override
422     {
423         return engineInstance_->GetContextValue();
424     }
425 
GetFrameNodeValueByNodeId(int32_t nodeId)426     napi_value GetFrameNodeValueByNodeId(int32_t nodeId) override
427     {
428         return engineInstance_->GetFrameNodeValueByNodeId(nodeId);
429     }
430 
431     void JsStateProfilerResgiter();
432 
433 #if defined(PREVIEW)
434     void ReplaceJSContent(const std::string& url, const std::string componentName) override;
435     RefPtr<Component> GetNewComponentWithJsCode(const std::string& jsCode, const std::string& viewID) override;
436     bool ExecuteJsForFastPreview(const std::string& jsCode, const std::string& viewID) override;
437 
InitializeModuleSearcher(const std::string & bundleName,const std::string & moduleName,const std::string assetPath,bool isBundle)438     void InitializeModuleSearcher(const std::string& bundleName, const std::string& moduleName,
439         const std::string assetPath, bool isBundle) override
440     {
441         bundleName_ = bundleName;
442         moduleName_ = moduleName;
443         assetPath_ = assetPath;
444         isBundle_ = isBundle;
445     }
446     // Support the hsp on the previewer
447     void SetHspBufferTrackerCallback(
448         std::function<bool(const std::string&, uint8_t**, size_t*, std::string&)>&& callback);
449     // Support to execute the ets code mocked by developer
450     void SetMockModuleList(const std::map<std::string, std::string>& mockJsonInfo);
451     bool IsComponentPreview() override;
452 #endif
453     static void AddToNamedRouterMap(const EcmaVM* vm, panda::Global<panda::FunctionRef> pageGenerator,
454         const std::string& namedRoute, panda::Local<panda::ObjectRef> params);
455     static void AddToNavigationBuilderMap(std::string name,
456         panda::Global<panda::ObjectRef> builderFunc);
457     bool LoadNamedRouterSource(const std::string& namedRoute, bool isTriggeredByJs) override;
458     std::unique_ptr<JsonValue> GetFullPathInfo() override;
459     void RestoreFullPathInfo(std::unique_ptr<JsonValue> namedRouterInfo) override;
460     std::unique_ptr<JsonValue> GetNamedRouterInfo() override;
461     void RestoreNamedRouterInfo(std::unique_ptr<JsonValue> namedRouterInfo) override;
462     bool IsNamedRouterNeedPreload(const std::string& name) override;
463     void PreloadNamedRouter(const std::string& name, std::function<void(bool)>&& loadFinishCallback) override;
464     std::string SearchRouterRegisterMap(const std::string& pageName) override;
465     bool UpdateRootComponent() override;
466     bool LoadPluginComponent(const std::string& url, const RefPtr<JsAcePage>& page, bool isMainPage) override;
SetEntryObject(const panda::Global<panda::ObjectRef> & obj)467     static void SetEntryObject(const panda::Global<panda::ObjectRef>& obj)
468     {
469         obj_ = obj;
470     }
471     bool ExecuteJs(const uint8_t* content, int32_t size) override;
472 
473     panda::Global<panda::ObjectRef> GetNavigationBuilder(std::string name);
474 
475 private:
476     bool CallAppFunc(const std::string& appFuncName);
477 
478     bool CallAppFunc(const std::string& appFuncName, std::vector<shared_ptr<JsValue>>& argv);
479 
480     void SetPostTask(NativeEngine* nativeEngine);
481 
482     void TimerCallJs(const std::string& callbackId) const;
483 
484     void InitXComponent(const std::string& componentId);
485 
486     void RegisterWorker();
487     void RegisterInitWorkerFunc();
488     void RegisterOffWorkerFunc();
489     void RegisterAssetFunc();
490     bool ExecuteAbc(const std::string& fileName);
491     bool ExecuteCardAbc(const std::string& fileName, int64_t cardId);
492     bool ExecuteDynamicAbc(const std::string& fileName, const std::string& entryPoint);
493 
494     RefPtr<JsiDeclarativeEngineInstance> engineInstance_;
495 
496     RefPtr<NativeXComponentImpl> nativeXComponentImpl_;
497 
498     OH_NativeXComponent* nativeXComponent_ = nullptr;
499 
500     int32_t instanceId_ = 0;
501     void* runtime_ = nullptr;
502 #if defined(PREVIEW)
SetPkgNameList(const std::map<std::string,std::string> & map)503     void SetPkgNameList(const std::map<std::string, std::string>& map) override
504     {
505         pkgNameMap_ = map;
506     }
507 
SetPkgAliasList(const std::map<std::string,std::string> & map)508     void SetPkgAliasList(const std::map<std::string, std::string>& map) override
509     {
510         pkgAliasMap_ = map;
511     }
512 
SetpkgContextInfoList(const std::map<std::string,std::vector<std::vector<std::string>>> & map)513     void SetpkgContextInfoList(const std::map<std::string, std::vector<std::vector<std::string>>>& map) override
514     {
515         pkgContextInfoMap_ = map;
516     }
517 
518     std::map<std::string, std::string> pkgNameMap_;
519     std::map<std::string, std::string> pkgAliasMap_;
520     std::map<std::string, std::vector<std::vector<std::string>>> pkgContextInfoMap_;
521 
522     std::string assetPath_;
523     std::string bundleName_;
524     std::string moduleName_;
525     bool isBundle_ = true;
526 #endif
527     std::string pluginBundleName_;
528     std::string pluginModuleName_;
529     static thread_local std::unordered_map<std::string, NamedRouterProperty> namedRouterRegisterMap_;
530     static thread_local std::unordered_map<std::string, std::string> routerPathInfoMap_;
531     static thread_local std::unordered_map<std::string, panda::Global<panda::ObjectRef>> builderMap_;
532     bool isFirstCallShow_ = true;
533     static thread_local panda::Global<panda::ObjectRef> obj_;
534     ACE_DISALLOW_COPY_AND_MOVE(JsiDeclarativeEngine);
535 };
536 
537 } // namespace OHOS::Ace::Framework
538 
539 #endif // FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_ENGINE_JSI_JSI_DECLARATIVE_ENGINE_H
540