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