• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_ENGINE_V8_V8_DECLARATIVE_ENGINE_H
17 #define FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_ENGINE_V8_V8_DECLARATIVE_ENGINE_H
18 
19 #include <mutex>
20 #include <string>
21 #include <vector>
22 
23 #include "third_party/v8/include/libplatform/libplatform.h"
24 #include "third_party/v8/include/v8.h"
25 
26 #include "base/log/log.h"
27 #include "base/memory/ace_type.h"
28 #include "base/utils/noncopyable.h"
29 #include "core/common/ace_application_info.h"
30 #include "core/common/ace_page.h"
31 #include "frameworks/bridge/js_frontend/engine/common/js_engine.h"
32 #include "frameworks/bridge/js_frontend/js_ace_page.h"
33 #include "frameworks/core/components/xcomponent/native_interface_xcomponent_impl.h"
34 
35 namespace OHOS::Ace::Framework {
36 
37 template<typename T>
38 using CopyablePersistent = v8::Persistent<T, v8::CopyablePersistentTraits<T>>;
39 
40 // IsolateWrapper make sure isolate disposed with thread.
41 class IsolateWrapper {
42 public:
43     IsolateWrapper() = default;
IsolateWrapper(v8::Isolate * isolate)44     explicit IsolateWrapper(v8::Isolate* isolate) : isolate_(isolate) {}
~IsolateWrapper()45     ~IsolateWrapper()
46     {
47         LOG_DESTROY();
48         if (isolate_) {
49             LOGI("Dispose thread isolate.");
50             isolate_->Dispose();
51         }
52     }
53 
Wrap(v8::Isolate * isolate)54     void Wrap(v8::Isolate* isolate)
55     {
56         if (isolate_ && isolate_ != isolate) {
57             isolate_->Dispose();
58         }
59         isolate_ = isolate;
60     }
61 
Invalidate()62     void Invalidate()
63     {
64         valid_ = false;
65     }
66 
IsEmpty()67     bool IsEmpty() const
68     {
69         return isolate_ == nullptr || !valid_;
70     }
71 
72     v8::Isolate* operator->() const
73     {
74         return isolate_;
75     }
76 
Get()77     v8::Isolate* Get()
78     {
79         return valid_ ? isolate_ : nullptr;
80     }
81 
82 private:
83     bool valid_ = true;
84     v8::Isolate* isolate_ = nullptr;
85 };
86 
87 class V8DeclarativeEngineInstance final : public AceType, public JsEngineInstance {
88     DECLARE_ACE_TYPE(V8DeclarativeEngineInstance, AceType)
89 public:
90     enum IsolateData {
91         FRONTEND_DELEGATE = 0,
92         RUNNING_PAGE = 1,
93         STAGING_PAGE = 2,
94         DISPATCHER = 3,
95     };
96 
97     static void CallJs(v8::Isolate* isolate,
98         v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>> pcontext, const std::string& callbackId,
99         const std::string& args, bool keepAlive = false, bool isGlobal = false);
100 
V8DeclarativeEngineInstance(const RefPtr<FrontendDelegate> & delegate)101     explicit V8DeclarativeEngineInstance(const RefPtr<FrontendDelegate>& delegate) : frontendDelegate_(delegate) {}
102     ~V8DeclarativeEngineInstance() override;
103 
104     void FlushCommandBuffer(void* context, const std::string& command) override;
105 
106     static void PersistRootViewHandle(v8::Isolate* isolate, v8::Local<v8::Object> obj);
107     void DestroyPersistRootViewHandle(int32_t pageId);
108     void DestroyAllPersistRootViewHandle();
109 
110     bool InitJSEnv();
111 
112     static void InitJsConsoleObject(v8::Local<v8::Context>& context, v8::Isolate* isolate);
113 
114     void InitJsPerfUtilObject(v8::Local<v8::Context>& context);
115 
116     void InitJsNativeModuleObject(v8::Local<v8::Context>& context);
117 
118     void InitJsExportsUtilObject(v8::Local<v8::Context>& context);
119 
120     void InitJSContext();
121 
122     static void InitAceModules(const char* start, const char* end, v8::Isolate* isolate);
123 
124     void InitGlobalObjectTemplate();
125 
GetV8Isolate()126     static v8::Isolate* GetV8Isolate()
127     {
128         return isolate_.Get();
129     }
130 
GetV8Context()131     v8::Local<v8::Context> GetV8Context() const
132     {
133         return context_.Get(isolate_.Get());
134     }
135 
GetContext()136     v8::Persistent<v8::Context>& GetContext()
137     {
138         return context_;
139     }
140 
141     bool FireJsEvent(const std::string& param);
142 
SetRunningPage(const RefPtr<JsAcePage> & page)143     void SetRunningPage(const RefPtr<JsAcePage>& page)
144     {
145         std::lock_guard<std::mutex> lock(mutex_);
146         runningPage_ = page;
147         isolate_->SetData(RUNNING_PAGE, static_cast<void*>(&runningPage_));
148     }
149 
150     static RefPtr<JsAcePage> GetCurrentPage();
151     static RefPtr<JsAcePage> GetRunningPage(v8::Isolate* isolate);
152     static RefPtr<JsAcePage> GetStagingPage(v8::Isolate* isolate);
153 
GetRunningPage()154     RefPtr<JsAcePage> GetRunningPage() const
155     {
156         std::lock_guard<std::mutex> lock(mutex_);
157         return runningPage_;
158     }
159 
SetStagingPage(const RefPtr<JsAcePage> & page)160     void SetStagingPage(const RefPtr<JsAcePage>& page)
161     {
162         std::lock_guard<std::mutex> lock(mutex_);
163         stagingPage_ = page;
164         isolate_->SetData(STAGING_PAGE, static_cast<void*>(&stagingPage_));
165     }
166 
GetStagingPage()167     RefPtr<JsAcePage> GetStagingPage() const
168     {
169         std::lock_guard<std::mutex> lock(mutex_);
170         return stagingPage_;
171     }
172 
ResetStagingPage(const RefPtr<JsAcePage> & page)173     void ResetStagingPage(const RefPtr<JsAcePage>& page)
174     {
175         stagingPage_ = page;
176         isolate_->SetData(STAGING_PAGE, static_cast<void*>(&stagingPage_));
177     }
178 
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher)179     void SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher)
180     {
181         dispatcher_ = dispatcher;
182         isolate_->SetData(DISPATCHER, static_cast<void*>(&dispatcher_));
183     }
184 
GetDelegate()185     const RefPtr<FrontendDelegate>& GetDelegate() const
186     {
187         return frontendDelegate_;
188     }
189 
GetDelegateForV8Data()190     void* GetDelegateForV8Data()
191     {
192         return static_cast<void*>(&frontendDelegate_);
193     }
194 
GetJsMessageDispatcherForV8Data()195     void* GetJsMessageDispatcherForV8Data()
196     {
197         return static_cast<void*>(&dispatcher_);
198     }
199 
200 
SetDelegate(v8::Isolate * isolate)201     void SetDelegate(v8::Isolate* isolate)
202     {
203         isolate->SetData(FRONTEND_DELEGATE, static_cast<void*>(&frontendDelegate_));
204     }
205 
SetDispatcher(v8::Isolate * isolate)206     void SetDispatcher(v8::Isolate* isolate)
207     {
208         isolate->SetData(DISPATCHER, static_cast<void*>(&dispatcher_));
209     }
210 
211     static void TriggerPageUpdate();
212     static void PostJsTask(std::function<void()>&& task);
213     static std::unique_ptr<JsonValue> GetI18nStringResource(const std::string& targetStringKey,
214         const std::string& targetStringValue);
215     static std::string GetMediaResource(const std::string& targetFileName);
216     static RefPtr<PipelineContext> GetPipelineContext();
217 
218 private:
219     static thread_local IsolateWrapper isolate_;
220     v8::Isolate::CreateParams create_params_;
221     v8::Persistent<v8::Context> context_;
222     v8::Persistent<v8::ObjectTemplate> globalObjectTemplate_;
223     RefPtr<FrontendDelegate> frontendDelegate_;
224     static std::unique_ptr<JsonValue> currentConfigResourceData_;
225     static std::map<std::string, std::string> mediaResourceFileMap_;
226 
227     // runningPage_ is the page that is loaded and rendered successfully, while stagingPage_ is to
228     // handle all page routing situation, which include two stages:
229     // - Loading stage: when a new page is loaded by qjs engine but not rendered, stagingPage_ point to
230     //   a new created page, which is different with runningPage_, the DOM build operations should call
231     //   this one, such as domCreateBody, domAddElement.
232     // - Running stage: If the stagingPage_ rendered successfully, the runningPage_ will update to stagingPage_.
233     //   If the stagingPage_ render failed, it will reset to runningPage_. So in running stage, runningPage_
234     //   and stagingPage_ point to the same page. But it's better to use runningPage_ in dom update tasks,
235     //   such as removeElement, updateElementAttrs and updateElementStyles.
236     RefPtr<JsAcePage> runningPage_;
237     RefPtr<JsAcePage> stagingPage_;
238 
239     WeakPtr<JsMessageDispatcher> dispatcher_;
240     mutable std::mutex mutex_;
241 
242     static thread_local std::unordered_map<int32_t, CopyablePersistent<v8::Object>> persistentRootViewMap_;
243 
244     ACE_DISALLOW_COPY_AND_MOVE(V8DeclarativeEngineInstance);
245 };
246 
247 class V8DeclarativeEngine : public JsEngine {
DECLARE_ACE_TYPE(V8DeclarativeEngine,JsEngine)248     DECLARE_ACE_TYPE(V8DeclarativeEngine, JsEngine)
249 public:
250     explicit V8DeclarativeEngine(int32_t instanceId) : instanceId_(instanceId) {}
251     ~V8DeclarativeEngine() override;
252 
253     bool Initialize(const RefPtr<FrontendDelegate>& delegate) override;
254 
255     // Load and initialize a JS bundle into the JS Framework
256     void LoadJs(const std::string& url, const RefPtr<JsAcePage>& page, bool isMainPage) override;
257 
258     // Update running page
259     void UpdateRunningPage(const RefPtr<JsAcePage>& page) override;
260 
261     // Update staging page
262     void UpdateStagingPage(const RefPtr<JsAcePage>& page) override;
263 
264     // Reset staging page
265     void ResetStagingPage() override;
266 
267     void SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher) override;
268 
269     // Fire AsyncEvent on JS
270     void FireAsyncEvent(const std::string& eventId, const std::string& param) override;
271 
272     // Fire SyncEvent on JS
273     void FireSyncEvent(const std::string& eventId, const std::string& param) override;
274 
275     void FireExternalEvent(const std::string& componentId, const uint32_t nodeId, const bool isDestroy) override;
276 
277     // Timer callback
278     void TimerCallback(const std::string& callbackId, const std::string& delay, bool isInterval) override;
279 
280     // Destroy page instance
281     void DestroyPageInstance(int32_t pageId) override;
282 
283     // Destroy application instance according to packageName
284     void DestroyApplication(const std::string& packageName) override;
285 
286     void UpdateApplicationState(const std::string& packageName, Frontend::State state) override;
287 
288     void OnWindowDisplayModeChanged(bool isShownInMultiWindow, const std::string& data) override;
289 
290     void OnNewWant(const std::string& data) override;
291 
292     void OnSaveAbilityState(std::string& data) override;
293 
294     void OnRestoreAbilityState(const std::string& data) override;
295 
296     void OnConfigurationUpdated(const std::string& data) override;
297 
298     bool OnStartContinuation() override;
299 
300     void OnRemoteTerminated() override;
301 
302     void OnActive() override;
303 
304     void OnInactive() override;
305 
306     void OnMemoryLevel(const int32_t level) override;
307 
308     void OnCompleteContinuation(const int32_t code) override;
309 
310     bool OnRestoreData(const std::string& data) override;
311 
312     void OnSaveData(std::string& saveData) override;
313 
314     void MediaQueryCallback(const std::string& callbackId, const std::string& args) override;
315 
316     void RequestAnimationCallback(const std::string& callbackId, uint64_t timeStamp) override;
317 
318     void JsCallback(const std::string& callbackId, const std::string& args) override;
319 
320     void RunGarbageCollection() override;
321 
322     void NotifyAppStorage(const std::string& key, const std::string& value) override;
323 
324     RefPtr<GroupJsBridge> GetGroupJsBridge() override;
325 
GetFrontend()326     FrontendDelegate* GetFrontend() override
327     {
328         return AceType::RawPtr(engineInstance_->GetDelegate());
329     }
330 
331     static std::unique_ptr<v8::Platform>& GetPlatform();
332 
GetRenderContext()333     v8::Local<v8::Object> GetRenderContext() const
334     {
335         return renderContextXComp_.Get(isolateXComp_);
336     }
337 
338 private:
339     void CallAppFunc(v8::Isolate* isolate, const v8::Local<v8::Context>& context, std::string appFuncName);
340 
341     bool CallAppFunc(v8::Isolate* isolate, const v8::Local<v8::Context>& context, std::string appFuncName,
342         int argc, v8::Local<v8::Value>* argv);
343 
344     void RegisterWorker();
345 
346     void RegisterInitWorkerFunc();
347 
348     void RegisterAssetFunc();
349 
350     void RegisterOffWorkerFunc();
351 
352     void SetPostTask(NativeEngine* nativeEngine);
353 
354     void TimerCallJs(const std::string& callbackId, bool isInterval);
355 
356     void InitXComponent();
357     bool InitXComponent(const std::string& componentId);
358 
359     RefPtr<V8DeclarativeEngineInstance> engineInstance_;
360 
361     RefPtr<NativeXComponentImpl> nativeXComponentImpl_;
362 
363     OH_NativeXComponent *nativeXComponent_ = nullptr;
364 
365     int32_t instanceId_ = 0;
366     v8::Isolate* isolateXComp_ = nullptr;
367     v8::Persistent<v8::Object> renderContextXComp_;
368     v8::Persistent<v8::Context> ctxXComp_;
369 
370     ACE_DISALLOW_COPY_AND_MOVE(V8DeclarativeEngine);
371 };
372 
373 } // namespace OHOS::Ace::Framework
374 
375 #endif // FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_ENGINE_V8_V8_DECLARATIVE_ENGINE_H
376