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