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