1 /*
2 * Copyright (c) 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 #include "frameworks/bridge/declarative_frontend/ng/declarative_frontend_ng.h"
17
18 #include "base/log/dump_log.h"
19 #include "core/common/recorder/node_data_cache.h"
20 #include "core/common/thread_checker.h"
21 #include "frameworks/bridge/common/utils/utils.h"
22 #include "frameworks/bridge/declarative_frontend/ng/page_router_manager_factory.h"
23
24 namespace OHOS::Ace {
25
~DeclarativeFrontendNG()26 DeclarativeFrontendNG::~DeclarativeFrontendNG() noexcept
27 {
28 LOG_DESTROY();
29 }
30
Destroy()31 void DeclarativeFrontendNG::Destroy()
32 {
33 // The call doesn't change the page pop status
34 Recorder::NodeDataCache::Get().OnBeforePagePop(true);
35 CHECK_RUN_ON(JS);
36 // To guarantee the jsEngine_ and delegate_ released in js thread
37 delegate_.Reset();
38 jsEngine_->Destroy();
39 jsEngine_.Reset();
40 }
41
Initialize(FrontendType type,const RefPtr<TaskExecutor> & taskExecutor)42 bool DeclarativeFrontendNG::Initialize(FrontendType type, const RefPtr<TaskExecutor>& taskExecutor)
43 {
44 type_ = type;
45 taskExecutor_ = taskExecutor;
46 ACE_DCHECK(type_ == FrontendType::DECLARATIVE_JS);
47 InitializeDelegate(taskExecutor);
48 bool needPostJsTask = true;
49 auto container = Container::Current();
50 if (container) {
51 const auto& setting = container->GetSettings();
52 needPostJsTask = !(setting.usePlatformAsUIThread && setting.useUIAsJSThread);
53 }
54 auto initJSEngineTask = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_), delegate = delegate_] {
55 auto jsEngine = weakEngine.Upgrade();
56 if (!jsEngine) {
57 return;
58 }
59 jsEngine->Initialize(delegate);
60 };
61 if (needPostJsTask) {
62 taskExecutor->PostTask(initJSEngineTask, TaskExecutor::TaskType::JS, "ArkUIInitJsEngine");
63 } else {
64 initJSEngineTask();
65 }
66 return true;
67 }
68
AttachPipelineContext(const RefPtr<PipelineBase> & context)69 void DeclarativeFrontendNG::AttachPipelineContext(const RefPtr<PipelineBase>& context)
70 {
71 if (delegate_) {
72 delegate_->AttachPipelineContext(context);
73 }
74 }
75
AttachSubPipelineContext(const RefPtr<PipelineBase> & context)76 void DeclarativeFrontendNG::AttachSubPipelineContext(const RefPtr<PipelineBase>& context)
77 {
78 if (!delegate_) {
79 return;
80 }
81 delegate_->AttachSubPipelineContext(context);
82 }
83
SetAssetManager(const RefPtr<AssetManager> & assetManager)84 void DeclarativeFrontendNG::SetAssetManager(const RefPtr<AssetManager>& assetManager)
85 {
86 if (delegate_) {
87 delegate_->SetAssetManager(assetManager);
88 }
89 }
90
InitializeDelegate(const RefPtr<TaskExecutor> & taskExecutor)91 void DeclarativeFrontendNG::InitializeDelegate(const RefPtr<TaskExecutor>& taskExecutor)
92 {
93 auto pageRouterManager = NG::PageRouterManagerFactory::CreateManager();
94 auto loadPageCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](const std::string& url,
95 const std::function<void(const std::string&, int32_t)>& errorCallback) {
96 auto jsEngine = weakEngine.Upgrade();
97 if (!jsEngine) {
98 return false;
99 }
100 return jsEngine->LoadPageSource(url, errorCallback);
101 };
102
103 auto loadPageByBufferCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
104 const std::shared_ptr<std::vector<uint8_t>>& content,
105 const std::function<void(const std::string&, int32_t)>& errorCallback,
106 const std::string& contentName) {
107 auto jsEngine = weakEngine.Upgrade();
108 if (!jsEngine) {
109 return false;
110 }
111 return jsEngine->LoadPageSource(content, errorCallback, contentName);
112 };
113
114 auto mediaQueryCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
115 const std::string& callbackId, const std::string& args) {
116 auto jsEngine = weakEngine.Upgrade();
117 if (!jsEngine) {
118 return;
119 }
120 jsEngine->MediaQueryCallback(callbackId, args);
121 };
122
123 auto layoutInspectorCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
124 const std::string& componentId) {
125 auto jsEngine = weakEngine.Upgrade();
126 if (!jsEngine) {
127 return;
128 }
129 jsEngine->LayoutInspectorCallback(componentId);
130 };
131
132 auto drawInspectorCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
133 const std::string& componentId) {
134 auto jsEngine = weakEngine.Upgrade();
135 if (!jsEngine) {
136 return;
137 }
138 jsEngine->DrawInspectorCallback(componentId);
139 };
140
141 auto onStartContinuationCallBack = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)]() -> bool {
142 auto jsEngine = weakEngine.Upgrade();
143 if (!jsEngine) {
144 return false;
145 }
146 return jsEngine->OnStartContinuation();
147 };
148
149 auto onCompleteContinuationCallBack = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](int32_t code) {
150 auto jsEngine = weakEngine.Upgrade();
151 if (!jsEngine) {
152 return;
153 }
154 jsEngine->OnCompleteContinuation(code);
155 };
156
157 auto onSaveDataCallBack = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](std::string& savedData) {
158 auto jsEngine = weakEngine.Upgrade();
159 if (!jsEngine) {
160 return;
161 }
162 jsEngine->OnSaveData(savedData);
163 };
164
165 auto onRemoteTerminatedCallBack = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)]() {
166 auto jsEngine = weakEngine.Upgrade();
167 if (!jsEngine) {
168 return;
169 }
170 jsEngine->OnRemoteTerminated();
171 };
172
173 auto onRestoreDataCallBack = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
174 const std::string& data) -> bool {
175 auto jsEngine = weakEngine.Upgrade();
176 if (!jsEngine) {
177 return false;
178 }
179 return jsEngine->OnRestoreData(data);
180 };
181
182 auto destroyApplicationCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
183 const std::string& packageName) {
184 auto jsEngine = weakEngine.Upgrade();
185 if (!jsEngine) {
186 return;
187 }
188 jsEngine->DestroyApplication(packageName);
189 };
190
191 auto updateApplicationStateCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
192 const std::string& packageName, Frontend::State state) {
193 auto jsEngine = weakEngine.Upgrade();
194 if (!jsEngine) {
195 return;
196 }
197 jsEngine->UpdateApplicationState(packageName, state);
198 };
199
200 auto onWindowDisplayModeChangedCallBack = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
201 bool isShownInMultiWindow, const std::string& data) {
202 auto jsEngine = weakEngine.Upgrade();
203 if (!jsEngine) {
204 return;
205 }
206 jsEngine->OnWindowDisplayModeChanged(isShownInMultiWindow, data);
207 };
208
209 auto externalEventCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
210 const std::string& componentId, const uint32_t nodeId,
211 const bool isDestroy) {
212 auto jsEngine = weakEngine.Upgrade();
213 if (!jsEngine) {
214 return;
215 }
216 jsEngine->FireExternalEvent(componentId, nodeId, isDestroy);
217 };
218
219 auto timerCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
220 const std::string& callbackId, const std::string& delay, bool isInterval) {
221 auto jsEngine = weakEngine.Upgrade();
222 if (!jsEngine) {
223 return;
224 }
225 jsEngine->TimerCallback(callbackId, delay, isInterval);
226 };
227
228 auto loadNamedRouterCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
229 const std::string& namedRouter, bool isTriggeredByJs) {
230 auto jsEngine = weakEngine.Upgrade();
231 if (!jsEngine) {
232 return false;
233 }
234 return jsEngine->LoadNamedRouterSource(namedRouter, isTriggeredByJs);
235 };
236
237 auto updateRootComponentCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)]() {
238 auto jsEngine = weakEngine.Upgrade();
239 if (!jsEngine) {
240 return false;
241 }
242 return jsEngine->UpdateRootComponent();
243 };
244
245 pageRouterManager->SetLoadJsCallback(std::move(loadPageCallback));
246 pageRouterManager->SetLoadJsByBufferCallback(std::move(loadPageByBufferCallback));
247 pageRouterManager->SetLoadNamedRouterCallback(std::move(loadNamedRouterCallback));
248 pageRouterManager->SetUpdateRootComponentCallback(std::move(updateRootComponentCallback));
249
250 delegate_ = AceType::MakeRefPtr<Framework::FrontendDelegateDeclarativeNG>(taskExecutor);
251 delegate_->SetMediaQueryCallback(std::move(mediaQueryCallback));
252 delegate_->SetLayoutInspectorCallback(std::move(layoutInspectorCallback));
253 delegate_->SetDrawInspectorCallback(std::move(drawInspectorCallback));
254 delegate_->SetOnStartContinuationCallBack(std::move(onStartContinuationCallBack));
255 delegate_->SetOnCompleteContinuationCallBack(std::move(onCompleteContinuationCallBack));
256 delegate_->SetOnSaveDataCallBack(std::move(onSaveDataCallBack));
257 delegate_->SetOnRemoteTerminatedCallBack(std::move(onRemoteTerminatedCallBack));
258 delegate_->SetOnRestoreDataCallBack(std::move(onRestoreDataCallBack));
259 delegate_->SetDestroyApplicationCallback(std::move(destroyApplicationCallback));
260 delegate_->SetUpdateApplicationStateCallback(std::move(updateApplicationStateCallback));
261 delegate_->SetOnWindowDisplayModeChangedCallback(std::move(onWindowDisplayModeChangedCallBack));
262 delegate_->SetExternalEventCallback(std::move(externalEventCallback));
263 delegate_->SetTimerCallback(std::move(timerCallback));
264
265 delegate_->SetPageRouterManager(pageRouterManager);
266 if (jsEngine_) {
267 delegate_->SetGroupJsBridge(jsEngine_->GetGroupJsBridge());
268 }
269 }
270
GetPageRouterManager() const271 RefPtr<NG::PageRouterManager> DeclarativeFrontendNG::GetPageRouterManager() const
272 {
273 CHECK_NULL_RETURN(delegate_, nullptr);
274 return delegate_->GetPageRouterManager();
275 }
276
UpdateState(Frontend::State state)277 void DeclarativeFrontendNG::UpdateState(Frontend::State state)
278 {
279 if (!delegate_ || state == Frontend::State::ON_CREATE) {
280 return;
281 }
282 bool needPostJsTask = true;
283 auto container = Container::Current();
284 CHECK_NULL_VOID(container);
285 const auto& setting = container->GetSettings();
286 needPostJsTask = !(setting.usePlatformAsUIThread && setting.useUIAsJSThread);
287 if (needPostJsTask) {
288 delegate_->UpdateApplicationState(delegate_->GetAppID(), state);
289 return;
290 }
291 if (jsEngine_) {
292 jsEngine_->UpdateApplicationState(delegate_->GetAppID(), state);
293 }
294 }
295
OnConfigurationUpdated(const std::string & data)296 void DeclarativeFrontendNG::OnConfigurationUpdated(const std::string& data)
297 {
298 if (delegate_) {
299 delegate_->OnConfigurationUpdated(data);
300 }
301 }
302
OnActive()303 void DeclarativeFrontendNG::OnActive()
304 {
305 if (delegate_) {
306 foregroundFrontend_ = true;
307 delegate_->InitializeAccessibilityCallback();
308 }
309 }
310
OnCompleteContinuation(int32_t code)311 void DeclarativeFrontendNG::OnCompleteContinuation(int32_t code)
312 {
313 if (delegate_) {
314 delegate_->OnCompleteContinuation(code);
315 }
316 }
317
OnSaveData(std::string & data)318 void DeclarativeFrontendNG::OnSaveData(std::string& data)
319 {
320 if (delegate_) {
321 delegate_->OnSaveData(data);
322 }
323 }
324
OnRemoteTerminated()325 void DeclarativeFrontendNG::OnRemoteTerminated()
326 {
327 if (delegate_) {
328 delegate_->OnRemoteTerminated();
329 }
330 }
331
NotifyAppStorage(const std::string & key,const std::string & value)332 void DeclarativeFrontendNG::NotifyAppStorage(const std::string& key, const std::string& value)
333 {
334 if (!delegate_) {
335 return;
336 }
337 delegate_->NotifyAppStorage(jsEngine_, key, value);
338 }
339
GetRouterSize() const340 int32_t DeclarativeFrontendNG::GetRouterSize() const
341 {
342 if (delegate_) {
343 return delegate_->GetStackSize();
344 }
345 return -1;
346 }
347
OnStartContinuation()348 bool DeclarativeFrontendNG::OnStartContinuation()
349 {
350 if (!delegate_) {
351 return false;
352 }
353 return delegate_->OnStartContinuation();
354 }
355
OnRestoreData(const std::string & data)356 bool DeclarativeFrontendNG::OnRestoreData(const std::string& data)
357 {
358 if (!delegate_) {
359 return false;
360 }
361 return delegate_->OnRestoreData(data);
362 }
363
RunPage(const std::string & url,const std::string & params)364 UIContentErrorCode DeclarativeFrontendNG::RunPage(const std::string& url, const std::string& params)
365 {
366 auto container = Container::Current();
367 auto isStageModel = container ? container->IsUseStageModel() : false;
368 if (!isStageModel) {
369 // In NG structure and fa mode, first load app.js
370 auto taskExecutor = container ? container->GetTaskExecutor() : nullptr;
371 CHECK_NULL_RETURN(taskExecutor, UIContentErrorCode::NULL_POINTER);
372 taskExecutor->PostTask(
373 [weak = AceType::WeakClaim(this)]() {
374 auto frontend = weak.Upgrade();
375 CHECK_NULL_VOID(frontend);
376 CHECK_NULL_VOID(frontend->jsEngine_);
377 frontend->jsEngine_->LoadFaAppSource();
378 },
379 TaskExecutor::TaskType::JS, "ArkUILoadFaAppSource");
380 }
381 // Not use this pageId from backend, manage it in FrontendDelegateDeclarativeNg.
382 if (delegate_) {
383 delegate_->RunPage(url, params, pageProfile_);
384 return UIContentErrorCode::NO_ERRORS;
385 }
386
387 return UIContentErrorCode::NULL_POINTER;
388 }
389
RunPage(const std::shared_ptr<std::vector<uint8_t>> & content,const std::string & params)390 UIContentErrorCode DeclarativeFrontendNG::RunPage(
391 const std::shared_ptr<std::vector<uint8_t>>& content, const std::string& params)
392 {
393 auto container = Container::Current();
394 auto isStageModel = container ? container->IsUseStageModel() : false;
395 if (!isStageModel) {
396 LOGE("RunPage by buffer must be run under stage model.");
397 return UIContentErrorCode::NO_STAGE;
398 }
399
400 if (delegate_) {
401 delegate_->RunPage(content, params, pageProfile_);
402 return UIContentErrorCode::NO_ERRORS;
403 }
404
405 return UIContentErrorCode::NULL_POINTER;
406 }
407
ReplacePage(const std::string & url,const std::string & params)408 void DeclarativeFrontendNG::ReplacePage(const std::string& url, const std::string& params)
409 {
410 if (delegate_) {
411 delegate_->Replace(url, params);
412 }
413 }
414
PushPage(const std::string & url,const std::string & params)415 void DeclarativeFrontendNG::PushPage(const std::string& url, const std::string& params)
416 {
417 if (delegate_) {
418 delegate_->Push(url, params);
419 }
420 }
421
422
GetContextValue()423 napi_value DeclarativeFrontendNG::GetContextValue()
424 {
425 return jsEngine_->GetContextValue();
426 }
427
GetFrameNodeValueByNodeId(int32_t nodeId)428 napi_value DeclarativeFrontendNG::GetFrameNodeValueByNodeId(int32_t nodeId)
429 {
430 return jsEngine_->GetFrameNodeValueByNodeId(nodeId);
431 }
432
NavigatePage(uint8_t type,const PageTarget & target,const std::string & params)433 void DeclarativeFrontendNG::NavigatePage(uint8_t type, const PageTarget& target, const std::string& params)
434 {
435 if (delegate_) {
436 delegate_->NavigatePage(type, target, params);
437 }
438 }
439
OnWindowDisplayModeChanged(bool isShownInMultiWindow,const std::string & data)440 void DeclarativeFrontendNG::OnWindowDisplayModeChanged(bool isShownInMultiWindow, const std::string& data)
441 {
442 delegate_->OnWindowDisplayModeChanged(isShownInMultiWindow, data);
443 }
444
GetAccessibilityManager() const445 RefPtr<AccessibilityManager> DeclarativeFrontendNG::GetAccessibilityManager() const
446 {
447 if (!delegate_) {
448 return nullptr;
449 }
450 return delegate_->GetJSAccessibilityManager();
451 }
452
GetWindowConfig()453 WindowConfig& DeclarativeFrontendNG::GetWindowConfig()
454 {
455 if (!delegate_) {
456 static WindowConfig windowConfig;
457 return windowConfig;
458 }
459 return delegate_->GetWindowConfig();
460 }
461
OnBackPressed()462 bool DeclarativeFrontendNG::OnBackPressed()
463 {
464 CHECK_NULL_RETURN(delegate_, false);
465 return delegate_->OnPageBackPress();
466 }
467
OnShow()468 void DeclarativeFrontendNG::OnShow()
469 {
470 foregroundFrontend_ = true;
471 CHECK_NULL_VOID(delegate_);
472 delegate_->OnPageShow();
473 }
474
OnHide()475 void DeclarativeFrontendNG::OnHide()
476 {
477 foregroundFrontend_ = false;
478 CHECK_NULL_VOID(delegate_);
479 delegate_->OnPageHide();
480 }
481
CallRouterBack()482 void DeclarativeFrontendNG::CallRouterBack()
483 {
484 if (delegate_) {
485 if (delegate_->GetStackSize() == 1 && isSubWindow_) {
486 LOGW("Can't back because this is the last page of sub window!");
487 return;
488 }
489 delegate_->Back("", "");
490 }
491 }
492
OnSurfaceChanged(int32_t width,int32_t height)493 void DeclarativeFrontendNG::OnSurfaceChanged(int32_t width, int32_t height)
494 {
495 // TODO: update media query infos
496 if (delegate_) {
497 delegate_->OnSurfaceChanged();
498 }
499 }
500
OnLayoutCompleted(const std::string & componentId)501 void DeclarativeFrontendNG::OnLayoutCompleted(const std::string& componentId)
502 {
503 if (delegate_) {
504 delegate_->OnLayoutCompleted(componentId);
505 }
506 }
507
OnDrawCompleted(const std::string & componentId)508 void DeclarativeFrontendNG::OnDrawCompleted(const std::string& componentId)
509 {
510 if (delegate_) {
511 delegate_->OnDrawCompleted(componentId);
512 }
513 }
514
DumpFrontend() const515 void DeclarativeFrontendNG::DumpFrontend() const
516 {
517 if (!delegate_) {
518 return;
519 }
520 int32_t routerIndex = 0;
521 std::string routerName;
522 std::string routerPath;
523 delegate_->GetState(routerIndex, routerName, routerPath);
524
525 if (DumpLog::GetInstance().GetDumpFile()) {
526 DumpLog::GetInstance().AddDesc("Components: " + std::to_string(delegate_->GetComponentsCount()));
527 DumpLog::GetInstance().AddDesc("Path: " + routerPath);
528 DumpLog::GetInstance().AddDesc("Length: " + std::to_string(routerIndex));
529 DumpLog::GetInstance().Print(0, routerName, 0);
530 }
531 }
532
GetPagePath() const533 std::string DeclarativeFrontendNG::GetPagePath() const
534 {
535 if (!delegate_) {
536 return "";
537 }
538 int32_t routerIndex = 0;
539 std::string routerName;
540 std::string routerPath;
541 delegate_->GetState(routerIndex, routerName, routerPath);
542 return routerPath + routerName;
543 }
544
TriggerGarbageCollection()545 void DeclarativeFrontendNG::TriggerGarbageCollection()
546 {
547 if (jsEngine_) {
548 jsEngine_->RunGarbageCollection();
549 }
550 }
551
DumpHeapSnapshot(bool isPrivate)552 void DeclarativeFrontendNG::DumpHeapSnapshot(bool isPrivate)
553 {
554 if (jsEngine_) {
555 jsEngine_->DumpHeapSnapshot(isPrivate);
556 }
557 }
558
NotifyUIIdle()559 void DeclarativeFrontendNG::NotifyUIIdle()
560 {
561 if (jsEngine_) {
562 jsEngine_->NotifyUIIdle();
563 }
564 }
565
RestoreRouterStack(const std::string & contentInfo)566 std::pair<std::string, UIContentErrorCode> DeclarativeFrontendNG::RestoreRouterStack(const std::string& contentInfo)
567 {
568 if (delegate_) {
569 return delegate_->RestoreRouterStack(contentInfo);
570 }
571 return std::make_pair("", UIContentErrorCode::NULL_POINTER);
572 }
573
GetContentInfo() const574 std::string DeclarativeFrontendNG::GetContentInfo() const
575 {
576 if (delegate_) {
577 return delegate_->GetContentInfo();
578 }
579 return "";
580 }
581
SetColorMode(ColorMode colorMode)582 void DeclarativeFrontendNG::SetColorMode(ColorMode colorMode)
583 {
584 // TODO: update media query infos
585 if (delegate_) {
586 delegate_->SetColorMode(colorMode);
587 }
588 }
589
RebuildAllPages()590 void DeclarativeFrontendNG::RebuildAllPages()
591 {
592 if (delegate_) {
593 delegate_->RebuildAllPages();
594 }
595 }
596
FlushReload()597 void DeclarativeFrontendNG::FlushReload()
598 {
599 if (jsEngine_) {
600 jsEngine_->FlushReload();
601 }
602 }
603
HotReload()604 void DeclarativeFrontendNG::HotReload()
605 {
606 auto manager = GetPageRouterManager();
607 CHECK_NULL_VOID(manager);
608 manager->FlushFrontend();
609 }
610
GetCurrentPageUrl() const611 std::string DeclarativeFrontendNG::GetCurrentPageUrl() const
612 {
613 auto pageRouterManager = GetPageRouterManager();
614 if (pageRouterManager) {
615 return pageRouterManager->GetCurrentPageUrl();
616 }
617 return "";
618 }
619 } // namespace OHOS::Ace
620