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