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