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