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