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