1 /* 2 * Copyright (c) 2021 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_FRAMEWORKS_BRIDGE_JS_FRONTEND_ENGINE_V8_V8_ENGINE_H 17 #define FOUNDATION_ACE_FRAMEWORKS_BRIDGE_JS_FRONTEND_ENGINE_V8_V8_ENGINE_H 18 19 #include <memory> 20 #include <mutex> 21 #include <string> 22 #include <vector> 23 24 #include "third_party/v8/include/libplatform/libplatform.h" 25 #include "third_party/v8/include/v8.h" 26 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 "native_engine/impl/v8/v8_native_engine.h" 34 35 namespace OHOS::Ace::Framework { 36 37 class V8EngineInstance final : public AceType, public JsEngineInstance { 38 public: 39 enum IsolateData { 40 FRONTEND_DELEGATE = 0, 41 RUNNING_PAGE = 1, 42 STAGING_PAGE = 2, 43 DISPATCHER = 3, 44 }; 45 46 static void CallJs(v8::Isolate* isolate, 47 v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>> pcontext, const std::string& callbackId, 48 const std::string& args, bool keepAlive = false, bool isGlobal = false); 49 V8EngineInstance(const RefPtr<FrontendDelegate> & delegate,int32_t instanceId)50 explicit V8EngineInstance(const RefPtr<FrontendDelegate>& delegate, int32_t instanceId) 51 : frontendDelegate_(delegate), instanceId_(instanceId) 52 {} 53 ~V8EngineInstance() override; 54 55 void FlushCommandBuffer(void* context, const std::string& command) override; 56 57 bool InitJsEnv(); 58 59 void InitJsConsoleObject(v8::Local<v8::Context>& context, v8::Isolate* isolate); 60 void InitJsDocumentObject(v8::Local<v8::Context>& context, v8::Isolate* isolate); 61 62 void InitJsPerfUtilObject(v8::Local<v8::Context>& context); 63 64 void InitJsContext(); 65 66 void InitGlobalObjectTemplate(); 67 68 void CallJs(const std::string& callbackId, const std::string& args, bool keepAlive = false, bool isGlobal = false); 69 GetV8Isolate()70 v8::Isolate* GetV8Isolate() const 71 { 72 return isolate_; 73 } 74 GetV8Context()75 v8::Local<v8::Context> GetV8Context() const 76 { 77 return context_.Get(isolate_); 78 } 79 GetContext()80 v8::Persistent<v8::Context>& GetContext() 81 { 82 return context_; 83 } 84 85 bool FireJsEvent(const std::string& param); 86 SetRunningPage(const RefPtr<JsAcePage> & page)87 void SetRunningPage(const RefPtr<JsAcePage>& page) 88 { 89 std::lock_guard<std::mutex> lock(mutex_); 90 runningPage_ = page; 91 isolate_->SetData(RUNNING_PAGE, static_cast<void*>(&runningPage_)); 92 } 93 GetRunningPage()94 RefPtr<JsAcePage> GetRunningPage() const 95 { 96 std::lock_guard<std::mutex> lock(mutex_); 97 return runningPage_; 98 } 99 SetStagingPage(const RefPtr<JsAcePage> & page)100 void SetStagingPage(const RefPtr<JsAcePage>& page) 101 { 102 std::lock_guard<std::mutex> lock(mutex_); 103 stagingPage_ = page; 104 isolate_->SetData(STAGING_PAGE, static_cast<void*>(&stagingPage_)); 105 } 106 GetStagingPage()107 RefPtr<JsAcePage> GetStagingPage() const 108 { 109 std::lock_guard<std::mutex> lock(mutex_); 110 return stagingPage_; 111 } 112 ResetStagingPage(const RefPtr<JsAcePage> & page)113 void ResetStagingPage(const RefPtr<JsAcePage>& page) 114 { 115 stagingPage_ = page; 116 isolate_->SetData(STAGING_PAGE, static_cast<void*>(&stagingPage_)); 117 } 118 SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher)119 void SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher) 120 { 121 dispatcher_ = dispatcher; 122 isolate_->SetData(DISPATCHER, static_cast<void*>(&dispatcher_)); 123 } 124 GetJsMessageDispatcher()125 WeakPtr<JsMessageDispatcher> GetJsMessageDispatcher() const 126 { 127 return dispatcher_; 128 } 129 GetInstanceId()130 int32_t GetInstanceId() const 131 { 132 return instanceId_; 133 } 134 GetDelegate()135 RefPtr<FrontendDelegate> GetDelegate() const 136 { 137 return frontendDelegate_; 138 } 139 SetV8NativeEngine(std::shared_ptr<V8NativeEngine> nativeEngine)140 void SetV8NativeEngine(std::shared_ptr<V8NativeEngine> nativeEngine) 141 { 142 nativeEngine_ = nativeEngine; 143 } 144 GetV8NativeEngine()145 std::shared_ptr<V8NativeEngine> GetV8NativeEngine() const 146 { 147 return nativeEngine_.lock(); 148 } 149 150 private: 151 v8::Isolate* isolate_ = nullptr; 152 v8::Isolate::CreateParams create_params_; 153 v8::Persistent<v8::Context> context_; 154 v8::Persistent<v8::ObjectTemplate> globalObjectTemplate_; 155 RefPtr<FrontendDelegate> frontendDelegate_; 156 int32_t instanceId_ = 0; 157 158 // runningPage_ is the page that is loaded and rendered successfully, while stagingPage_ is to 159 // handle all page routing situation, which include two stages: 160 // - Loading stage: when a new page is loaded by qjs engine but not rendered, stagingPage_ point to 161 // a new created page, which is different with runningPage_, the DOM build operations should call 162 // this one, such as domCreateBody, domAddElement. 163 // - Running stage: If the stagingPage_ rendered successfully, the runningPage_ will update to stagingPage_. 164 // If the stagingPage_ render failed, it will reset to runningPage_. So in running stage, runningPage_ 165 // and stagingPage_ point to the same page. But it's better to use runningPage_ in dom update tasks, 166 // such as removeElement, updateElementAttrs and updateElementStyles. 167 RefPtr<JsAcePage> runningPage_; 168 RefPtr<JsAcePage> stagingPage_; 169 170 WeakPtr<JsMessageDispatcher> dispatcher_; 171 std::weak_ptr<V8NativeEngine> nativeEngine_; 172 mutable std::mutex mutex_; 173 174 ACE_DISALLOW_COPY_AND_MOVE(V8EngineInstance); 175 }; 176 177 class V8Engine : public JsEngine { 178 public: 179 explicit V8Engine(int32_t instanceId); 180 ~V8Engine() override; 181 182 bool Initialize(const RefPtr<FrontendDelegate>& delegate) override; 183 184 // Load and initialize a JS bundle into the JS Framework 185 void LoadJs(const std::string& url, const RefPtr<JsAcePage>& page, bool isMainPage) override; 186 187 // Update running page 188 void UpdateRunningPage(const RefPtr<JsAcePage>& page) override; 189 190 // Update staging page 191 void UpdateStagingPage(const RefPtr<JsAcePage>& page) override; 192 193 // Reset staging page 194 void ResetStagingPage() override; 195 196 void SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher) override; 197 198 // Fire AsyncEvent on JS 199 void FireAsyncEvent(const std::string& eventId, const std::string& param) override; 200 201 // Fire SyncEvent on JS 202 void FireSyncEvent(const std::string& eventId, const std::string& param) override; 203 204 // Fire external event on JS thread 205 void FireExternalEvent(const std::string& componentId, const uint32_t nodeId, const bool isDestroy) override; 206 207 // Timer callback 208 void TimerCallback(const std::string& callbackId, const std::string& delay, bool isInterval) override; 209 210 // Destroy page instance 211 void DestroyPageInstance(int32_t pageId) override; 212 213 // Destroy application instance according to packageName DestroyApplication(const std::string & packageName)214 void DestroyApplication(const std::string& packageName) override {} 215 216 void UpdateApplicationState(const std::string& packageName, Frontend::State state) override; 217 218 void MediaQueryCallback(const std::string& callbackId, const std::string& args) override; 219 220 void RequestAnimationCallback(const std::string& callbackId, uint64_t timeStamp) override; 221 222 void JsCallback(const std::string& callbackId, const std::string& args) override; 223 224 void RunGarbageCollection() override; 225 226 RefPtr<GroupJsBridge> GetGroupJsBridge() override; 227 GetFrontend()228 FrontendDelegate* GetFrontend() override 229 { 230 return AceType::RawPtr(engineInstance_->GetDelegate()); 231 } 232 233 static std::unique_ptr<v8::Platform>& GetPlatform(); 234 235 private: 236 void GetLoadOptions(std::string& optionStr, bool isMainPage, const RefPtr<JsAcePage>& page); 237 void RegisterWorker(); 238 void RegisterInitWorkerFunc(); 239 void RegisterAssetFunc(); 240 void RegisterOffWorkerFunc(); 241 void SetPostTask(); 242 243 RefPtr<V8EngineInstance> engineInstance_; 244 int32_t instanceId_ = 0; 245 std::shared_ptr<V8NativeEngine> nativeEngine_; 246 247 ACE_DISALLOW_COPY_AND_MOVE(V8Engine); 248 }; 249 250 } // namespace OHOS::Ace::Framework 251 252 #endif // FOUNDATION_ACE_FRAMEWORKS_BRIDGE_JS_FRONTEND_ENGINE_V8_V8_ENGINE_H 253