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