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