• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 #include "frameworks/bridge/declarative_frontend/ng/page_router_manager.h"
17 
18 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
19 
20 #include "base/i18n/localization.h"
21 #include "base/ressched/ressched_report.h"
22 #include "base/perfmonitor/perf_monitor.h"
23 #include "bridge/js_frontend/engine/jsi/ark_js_runtime.h"
24 #include "core/common/recorder/node_data_cache.h"
25 #include "core/common/thread_checker.h"
26 #include "core/components/dialog/dialog_theme.h"
27 #include "core/components_ng/base/frame_node.h"
28 #include "core/components_ng/base/view_advanced_register.h"
29 #include "core/components_ng/pattern/stage/page_node.h"
30 #include "core/components_ng/pattern/stage/page_pattern.h"
31 #include "core/components_ng/pattern/stage/stage_manager.h"
32 #include "core/components_v2/inspector/inspector_constants.h"
33 #include "core/pipeline/base/element_register.h"
34 #include "core/pipeline_ng/pipeline_context.h"
35 #include "frameworks/bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.h"
36 
37 namespace OHOS::Ace::NG {
38 
39 namespace {
40 
41 constexpr int32_t BUNDLE_START_POS = 8;
42 constexpr int32_t INVALID_PAGE_INDEX = -1;
43 constexpr int32_t MAX_ROUTER_STACK_SIZE = 32;
44 constexpr int32_t JS_FILE_EXTENSION_LENGTH = 3;
45 constexpr int32_t ETS_TAG_LENGTH = 5;
46 constexpr char ETS_PATH[] = "/src/main/ets/";
47 constexpr char DEBUG_PATH[] = "entry/build/default/cache/default/default@CompileArkTS/esmodule/debug/";
48 constexpr char NEW_PATH[] = "entry|entry|1.0.0|src/main/ets/";
49 constexpr char TS_SUFFIX[] = ".ts";
50 constexpr char ETS_SUFFIX[] = ".ets";
51 constexpr char INTENT_PARAM_KEY[] = "ohos.insightIntent.executeParam.param";
52 constexpr char INTENT_BUNDLE_NAME_KEY[] = "ohos.insightIntent.bundleName";
53 constexpr char INTENT_MODULE_NAME_KEY[] = "ohos.insightIntent.moduleName";
54 constexpr char INTENT_PAGE_PATH_KEY[] = "ohos.insightIntent.pageParam.pagePath";
55 constexpr char ETS_TAG[] = "/ets/";
56 
ExitToDesktop()57 void ExitToDesktop()
58 {
59     auto container = Container::Current();
60     CHECK_NULL_VOID(container);
61     auto taskExecutor = container->GetTaskExecutor();
62     CHECK_NULL_VOID(taskExecutor);
63     taskExecutor->PostTask(
64         [] {
65             auto pipeline = PipelineContext::GetCurrentContext();
66             CHECK_NULL_VOID(pipeline);
67             AccessibilityEvent event;
68             event.type = AccessibilityEventType::PAGE_CHANGE;
69             pipeline->SendEventToAccessibility(event);
70             pipeline->Finish(false);
71         },
72         TaskExecutor::TaskType::UI, "ArkUIPageRouterExitToDesktop",
73         TaskExecutor::GetPriorityTypeWithCheck(PriorityType::VIP));
74 }
75 
76 } // namespace
77 
LoadOhmUrl(const RouterPageInfo & target)78 void PageRouterManager::LoadOhmUrl(const RouterPageInfo& target)
79 {
80     RouterPageInfo info = target;
81     info.path = info.url + ".js";
82     RouterOptScope scope(this);
83     LoadPage(GenerateNextPageId(), info);
84 }
85 
RunPage(const std::string & url,const std::string & params)86 void PageRouterManager::RunPage(const std::string& url, const std::string& params)
87 {
88     PerfMonitor::GetPerfMonitor()->SetAppStartStatus();
89     ACE_SCOPED_TRACE("PageRouterManager::RunPage");
90     CHECK_RUN_ON(JS);
91     RouterPageInfo info;
92     info.url = url;
93     info.params = params;
94 #if !defined(PREVIEW)
95     if (info.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
96         info.errorCallback = [](const std::string& errorMsg, int32_t errorCode) {
97             TAG_LOGE(AceLogTag::ACE_ROUTER,
98                 "Router load ohmUrl failed, probably caused by invalid ohmUrl. code:%{public}d, msg:%{public}s",
99                 errorCode, errorMsg.c_str());
100         };
101         auto loadTask = [weak = AceType::WeakClaim(this), info]() {
102                 auto pageRouterManager = weak.Upgrade();
103                 CHECK_NULL_VOID(pageRouterManager);
104                 pageRouterManager->LoadOhmUrl(info);
105             };
106         auto errorCallback = [](const std::string& errorMsg, int32_t errorCode) {
107                 TAG_LOGW(AceLogTag::ACE_ROUTER, "RunPage error code:%{public}d, msg:%{public}s",
108                     errorCode, errorMsg.c_str());
109             };
110         LoadOhmUrlPage(info.url, std::move(loadTask), errorCallback,
111             "ArkUIPageRouterLoadOhmUrl", "ArkUIPageRouterErrorLog");
112         return;
113     }
114 #endif
115     if (!info.url.empty()) {
116         info.path = manifestParser_->GetRouter()->GetPagePath(url);
117         if (info.path.empty()) {
118             return;
119         }
120     } else {
121         info.path = manifestParser_->GetRouter()->GetEntry();
122         info.url = manifestParser_->GetRouter()->GetEntry("");
123     }
124     RouterOptScope scope(this);
125     LoadPage(GenerateNextPageId(), info);
126 }
127 
RunPage(const std::shared_ptr<std::vector<uint8_t>> & content,const std::string & params)128 void PageRouterManager::RunPage(const std::shared_ptr<std::vector<uint8_t>>& content, const std::string& params)
129 {
130     CHECK_RUN_ON(JS);
131     RouterPageInfo info;
132     info.content = content;
133     info.params = params;
134 
135 #if !defined(PREVIEW)
136     auto container = Container::Current();
137     CHECK_NULL_VOID(container);
138     auto instanceId = container->GetInstanceId();
139     auto taskExecutor = container->GetTaskExecutor();
140     CHECK_NULL_VOID(taskExecutor);
141     ContainerScope scope(instanceId);
142     auto pageRouterManager = AceType::Claim(this);
143     CHECK_NULL_VOID(pageRouterManager);
144     taskExecutor->PostTask(
145         [pageRouterManager, info]() { pageRouterManager->LoadOhmUrl(info); },
146         TaskExecutor::TaskType::JS, "ArkUIPageRouterLoadOhmUrlContent",
147         TaskExecutor::GetPriorityTypeWithCheck(PriorityType::VIP));
148 #endif
149 }
150 
RunPageByNamedRouter(const std::string & name,const std::string & params)151 void PageRouterManager::RunPageByNamedRouter(const std::string& name, const std::string& params)
152 {
153     auto callback = [weak = AceType::WeakClaim(this), name, params]() {
154         auto pageRouterManager = weak.Upgrade();
155         CHECK_NULL_VOID(pageRouterManager);
156         pageRouterManager->RunPageByNamedRouterInner(name, params);
157     };
158     /**
159      * Always check if the namedRoute page needs to be preloaded.
160      * @sa PageRouterManager::RestoreRouterStack() & PageRouterManager::GetStackInfo()
161      */
162     if (TryPreloadNamedRouter(name, std::move(callback))) {
163         return;
164     }
165 
166     RunPageByNamedRouterInner(name, params);
167 }
168 
RunPageByNamedRouterInner(const std::string & name,const std::string & params)169 void PageRouterManager::RunPageByNamedRouterInner(const std::string& name, const std::string& params)
170 {
171     if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
172         TAG_LOGW(AceLogTag::ACE_ROUTER, "RunPageByNamedRouter exceeds maxStackSize.");
173         return;
174     }
175 
176     RouterPageInfo info;
177     info.url = name;
178     info.params = params;
179     info.isNamedRouterMode = true;
180     RouterOptScope scope(this);
181     LoadPage(GenerateNextPageId(), info);
182 }
183 
RunCard(const std::string & url,const std::string & params,int64_t cardId,const std::string & entryPoint)184 UIContentErrorCode PageRouterManager::RunCard(
185     const std::string& url, const std::string& params, int64_t cardId, const std::string& entryPoint)
186 {
187     CHECK_RUN_ON(JS);
188     RouterPageInfo info;
189     info.url = url;
190 #ifndef PREVIEW
191     if (!info.url.empty()) {
192         info.path = manifestParser_->GetRouter()->GetPagePath(url);
193     } else {
194         info.path = manifestParser_->GetRouter()->GetEntry();
195         info.url = manifestParser_->GetRouter()->GetEntry("");
196     }
197 #endif
198     return LoadCard(0, info, params, cardId, false, true, entryPoint);
199 }
200 
Push(const RouterPageInfo & target)201 void PageRouterManager::Push(const RouterPageInfo& target)
202 {
203     CHECK_RUN_ON(JS);
204     if (inRouterOpt_) {
205         auto context = PipelineContext::GetCurrentContext();
206         CHECK_NULL_VOID(context);
207         context->PostAsyncEvent(
208             [weak = WeakClaim(this), target]() {
209                 auto router = weak.Upgrade();
210                 CHECK_NULL_VOID(router);
211                 router->Push(target);
212             },
213             "ArkUIPageRouterPush", TaskExecutor::TaskType::JS);
214         return;
215     }
216     RouterOptScope scope(this);
217     StartPush(target);
218 }
219 
TryPreloadNamedRouter(const std::string & name,std::function<void ()> && finishCallback)220 bool PageRouterManager::TryPreloadNamedRouter(const std::string& name, std::function<void()>&& finishCallback)
221 {
222     /**
223      * Before loading the namedRoute page, we need to check if it is necessary to preload the namedRoute
224      * page code (equivalent to dynamic import in ets, eg: import('hsp'); ).
225      * After preloading, pageGenerator will be filled, @sa JsiDeclarativeEngine::namedRouterRegisterMap_
226      */
227     if (!isNamedRouterNeedPreload_ || !isNamedRouterNeedPreload_(name)) {
228         return false;
229     }
230 
231     if (!preloadNamedRouter_) {
232         TAG_LOGW(AceLogTag::ACE_ROUTER, "PreloadNamedRouter was not set!");
233         return false;
234     }
235 
236     auto container = Container::Current();
237     CHECK_NULL_RETURN(container, false);
238     auto instanceId = container->GetInstanceId();
239     auto taskExecutor = container->GetTaskExecutor();
240     CHECK_NULL_RETURN(taskExecutor, false);
241     auto preloadFinishCallback = [taskExecutor, instanceId, callback = std::move(finishCallback), name](bool success) {
242         if (!success) {
243             TAG_LOGW(AceLogTag::ACE_ROUTER, "failed to preload NamedRouter: %{public}s", name.c_str());
244             return;
245         }
246         taskExecutor->PostTask(
247             [instanceId, finishCallback = std::move(callback)]() {
248                 ContainerScope scope(instanceId);
249                 if (finishCallback) {
250                     finishCallback();
251                 }
252             }, TaskExecutor::TaskType::JS, "ArkUIPageRouterPreloadNamedRouterFinishCallback",
253             TaskExecutor::GetPriorityTypeWithCheck(PriorityType::VIP));
254     };
255     preloadNamedRouter_(name, std::move(preloadFinishCallback));
256     return true;
257 }
258 
PushNamedRoute(const RouterPageInfo & target)259 void PageRouterManager::PushNamedRoute(const RouterPageInfo& target)
260 {
261     auto callback = [weak = AceType::WeakClaim(this), target]() {
262         auto pageRouterManager = weak.Upgrade();
263         CHECK_NULL_VOID(pageRouterManager);
264         pageRouterManager->PushNamedRouteInner(target);
265     };
266     /**
267      * Always check if the namedRoute page needs to be preloaded.
268      * @sa PageRouterManager::RestoreRouterStack() & PageRouterManager::GetStackInfo()
269      */
270     if (TryPreloadNamedRouter(target.url, std::move(callback))) {
271         return;
272     }
273 
274     PushNamedRouteInner(target);
275 }
276 
PushNamedRouteInner(const RouterPageInfo & target)277 void PageRouterManager::PushNamedRouteInner(const RouterPageInfo& target)
278 {
279     CHECK_RUN_ON(JS);
280     if (inRouterOpt_) {
281         auto context = PipelineContext::GetCurrentContext();
282         CHECK_NULL_VOID(context);
283         context->PostAsyncEvent(
284             [weak = WeakClaim(this), target]() {
285                 auto router = weak.Upgrade();
286                 CHECK_NULL_VOID(router);
287                 router->PushNamedRouteInner(target);
288             },
289             "ArkUIPageRouterPushNamedRoute", TaskExecutor::TaskType::JS);
290         return;
291     }
292     RouterOptScope scope(this);
293     if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
294         TAG_LOGW(AceLogTag::ACE_ROUTER, "PushNamedRoute exceeds maxStackSize.");
295         if (target.errorCallback != nullptr) {
296             target.errorCallback("Page stack error. Too many pages are pushed.", ERROR_CODE_PAGE_STACK_FULL);
297         }
298         return;
299     }
300     CleanPageOverlay();
301     UpdateSrcPage();
302     if (target.routerMode == RouterMode::SINGLE) {
303         auto pageInfoByUrl = FindPageInStackByRouteName(target.url);
304         if (pageInfoByUrl.second) {
305             // find page in stack, move postion and update params.
306             auto pagePattern = pageInfoByUrl.second->GetPattern<PagePattern>();
307             if (pagePattern) {
308                 pagePattern->FireOnNewParam(target.params);
309             }
310             MovePageToFront(pageInfoByUrl.first, pageInfoByUrl.second, target, true);
311             return;
312         }
313         auto index = FindPageInRestoreStack(target.url);
314         if (index != INVALID_PAGE_INDEX) {
315             // find page in restore page, create page, move position and update params.
316             RestorePageWithTarget(index, false, target, RestorePageDestination::TOP);
317             return;
318         }
319     }
320     RouterPageInfo info = target;
321     info.isNamedRouterMode = true;
322     LoadPage(GenerateNextPageId(), info, true, true, true);
323 }
324 
Replace(const RouterPageInfo & target)325 void PageRouterManager::Replace(const RouterPageInfo& target)
326 {
327     CHECK_RUN_ON(JS);
328     if (inRouterOpt_) {
329         auto context = PipelineContext::GetCurrentContext();
330         CHECK_NULL_VOID(context);
331         context->PostAsyncEvent(
332             [weak = WeakClaim(this), target]() {
333                 auto router = weak.Upgrade();
334                 CHECK_NULL_VOID(router);
335                 router->Replace(target);
336             },
337             "ArkUIPageRouterReplace", TaskExecutor::TaskType::JS);
338         return;
339     }
340     RouterOptScope scope(this);
341     StartReplace(target);
342 }
343 
ReplaceNamedRoute(const RouterPageInfo & target)344 void PageRouterManager::ReplaceNamedRoute(const RouterPageInfo& target)
345 {
346     auto callback = [weak = AceType::WeakClaim(this), target]() {
347         auto pageRouterManager = weak.Upgrade();
348         CHECK_NULL_VOID(pageRouterManager);
349         pageRouterManager->ReplaceNamedRouteInner(target);
350     };
351     /**
352      * Always check if the namedRoute page needs to be preloaded.
353      * @sa PageRouterManager::RestoreRouterStack() & PageRouterManager::GetStackInfo()
354      */
355     if (TryPreloadNamedRouter(target.url, std::move(callback))) {
356         return;
357     }
358 
359     ReplaceNamedRouteInner(target);
360 }
361 
ReplaceNamedRouteInner(const RouterPageInfo & target)362 void PageRouterManager::ReplaceNamedRouteInner(const RouterPageInfo& target)
363 {
364     CHECK_RUN_ON(JS);
365     if (inRouterOpt_) {
366         auto context = PipelineContext::GetCurrentContext();
367         CHECK_NULL_VOID(context);
368         context->PostAsyncEvent(
369             [weak = WeakClaim(this), target]() {
370                 auto router = weak.Upgrade();
371                 CHECK_NULL_VOID(router);
372                 router->ReplaceNamedRouteInner(target);
373             },
374             "ArkUIPageRouterReplaceNamedRoute", TaskExecutor::TaskType::JS);
375         return;
376     }
377     RouterOptScope scope(this);
378     CleanPageOverlay();
379     UpdateSrcPage();
380     RouterPageInfo info = target;
381     info.isNamedRouterMode = true;
382     DealReplacePage(info);
383 }
384 
BackWithTarget(const RouterPageInfo & target)385 void PageRouterManager::BackWithTarget(const RouterPageInfo& target)
386 {
387     CHECK_RUN_ON(JS);
388     TAG_LOGI(AceLogTag::ACE_ROUTER, "Router back path:%{public}s", target.url.c_str());
389     if (inRouterOpt_) {
390         auto context = PipelineContext::GetCurrentContext();
391         CHECK_NULL_VOID(context);
392         context->PostAsyncEvent(
393             [weak = WeakClaim(this), target]() {
394                 auto router = weak.Upgrade();
395                 CHECK_NULL_VOID(router);
396                 router->BackWithTarget(target);
397             },
398             "ArkUIPageRouterBackWithTarget", TaskExecutor::TaskType::JS);
399         return;
400     }
401     RouterOptScope scope(this);
402     BackCheckAlert(target);
403 }
404 
BackToIndexWithTarget(int32_t index,const std::string & params)405 void PageRouterManager::BackToIndexWithTarget(int32_t index, const std::string& params)
406 {
407     CHECK_RUN_ON(JS);
408     if (!CheckIndexValid(index)) {
409         return;
410     }
411     if (inRouterOpt_) {
412         auto context = PipelineContext::GetCurrentContext();
413         CHECK_NULL_VOID(context);
414         context->PostAsyncEvent(
415             [weak = WeakClaim(this), index, params]() {
416                 auto router = weak.Upgrade();
417                 CHECK_NULL_VOID(router);
418                 router->BackToIndexWithTarget(index, params);
419             },
420             "ArkUIPageRouterBackToIndex", TaskExecutor::TaskType::JS);
421         return;
422     }
423     RouterOptScope scope(this);
424     BackToIndexCheckAlert(index, params);
425 }
426 
Clear()427 void PageRouterManager::Clear()
428 {
429     CHECK_RUN_ON(JS);
430     if (inRouterOpt_) {
431         auto context = PipelineContext::GetCurrentContext();
432         CHECK_NULL_VOID(context);
433         context->PostAsyncEvent(
434             [weak = WeakClaim(this)]() {
435                 auto router = weak.Upgrade();
436                 CHECK_NULL_VOID(router);
437                 router->Clear();
438             },
439             "ArkUIPageRouterClear", TaskExecutor::TaskType::JS);
440         return;
441     }
442     RouterOptScope scope(this);
443     StartClean();
444 }
445 
EnableAlertBeforeBackPage(const std::string & message,std::function<void (int32_t)> && callback)446 void PageRouterManager::EnableAlertBeforeBackPage(const std::string& message, std::function<void(int32_t)>&& callback)
447 {
448     auto currentPage = GetCurrentPageNode();
449     CHECK_NULL_VOID(currentPage);
450     auto pagePattern = currentPage->GetPattern<PagePattern>();
451     CHECK_NULL_VOID(pagePattern);
452     auto pageInfo = pagePattern->GetPageInfo();
453     CHECK_NULL_VOID(pageInfo);
454     auto pipeline = PipelineContext::GetCurrentContextSafely();
455     CHECK_NULL_VOID(pipeline);
456     auto dialogTheme = pipeline->GetTheme<DialogTheme>();
457     CHECK_NULL_VOID(dialogTheme);
458 
459     DialogProperties dialogProperties = {
460         .content = message,
461         .autoCancel = false,
462         .buttons = { { .text = dialogTheme->GetCancelText(), .textColor = "" },
463             { .text = dialogTheme->GetConfirmText(), .textColor = "" } },
464         .onSuccess =
465             [weak = AceType::WeakClaim(this), weakPageInfo = AceType::WeakClaim(AceType::RawPtr(pageInfo))](
466                 int32_t successType, int32_t successIndex) {
467                 auto pageInfo = weakPageInfo.Upgrade();
468                 if (pageInfo && pageInfo->GetAlertCallback() && !successType) {
469                     pageInfo->GetAlertCallback()(successIndex);
470                     if (successIndex) {
471                         auto router = weak.Upgrade();
472                         CHECK_NULL_VOID(router);
473                         router->StartBack(router->ngBackTarget_);
474                     }
475                 }
476             },
477     };
478 
479     pageInfo->SetDialogProperties(dialogProperties);
480     pageInfo->SetAlertCallback(std::move(callback));
481 }
482 
DisableAlertBeforeBackPage()483 void PageRouterManager::DisableAlertBeforeBackPage()
484 {
485     if (pageRouterStack_.empty()) {
486         return;
487     }
488     auto currentPage = GetCurrentPageNode();
489     CHECK_NULL_VOID(currentPage);
490     auto pagePattern = currentPage->GetPattern<PagePattern>();
491     CHECK_NULL_VOID(pagePattern);
492     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
493     CHECK_NULL_VOID(pageInfo);
494     pageInfo->SetAlertCallback(nullptr);
495 }
496 
StartClean()497 void PageRouterManager::StartClean()
498 {
499     UpdateSrcPage();
500     if (pageRouterStack_.size() > 1) {
501         restorePageStack_.clear();
502         std::list<WeakPtr<FrameNode>> temp;
503         std::swap(temp, pageRouterStack_);
504         pageRouterStack_.emplace_back(temp.back());
505         if (!OnCleanPageStack()) {
506             std::swap(temp, pageRouterStack_);
507         } else {
508             RefreshPageIndex(pageRouterStack_.begin(), 0);
509         }
510         return;
511     }
512 
513     if (pageRouterStack_.size() == 1) {
514         restorePageStack_.clear();
515         return;
516     }
517 }
518 
Pop()519 bool PageRouterManager::Pop()
520 {
521     CHECK_RUN_ON(JS);
522     if (inRouterOpt_) {
523         TAG_LOGI(AceLogTag::ACE_ROUTER, "router pop is in routeropt");
524         return false;
525     }
526     RouterOptScope scope(this);
527     return StartPop();
528 }
529 
StartPop()530 bool PageRouterManager::StartPop()
531 {
532     CHECK_RUN_ON(JS);
533     auto currentPage = GetCurrentPageNode();
534     CHECK_NULL_RETURN(currentPage, false);
535     auto pagePattern = currentPage->GetPattern<PagePattern>();
536     CHECK_NULL_RETURN(pagePattern, false);
537     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
538     CHECK_NULL_RETURN(pageInfo, false);
539     if (pageInfo->GetAlertCallback()) {
540         TAG_LOGI(AceLogTag::ACE_ROUTER, "pop alert check start");
541         BackCheckAlert(RouterPageInfo());
542         return true;
543     }
544 
545     if (pageRouterStack_.size() <= 1) {
546         if (!restorePageStack_.empty()) {
547             StartRestore(RouterPageInfo());
548             return true;
549         }
550         // the last page.
551         return false;
552     }
553     UpdateSrcPage();
554     // pop top page in page stack
555     auto preWeakNode = pageRouterStack_.back();
556     pageRouterStack_.pop_back();
557 
558     // clean prev top page params
559     currentPage = GetCurrentPageNode();
560     CHECK_NULL_RETURN(currentPage, false);
561     pagePattern = currentPage->GetPattern<PagePattern>();
562     CHECK_NULL_RETURN(pagePattern, false);
563     pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
564     CHECK_NULL_RETURN(pageInfo, false);
565     std::string params = pageInfo->GetPageParams();
566     pageInfo->ReplacePageParams("");
567 
568     // do pop page
569     if (!OnPopPage(true, true)) {
570         pageRouterStack_.emplace_back(preWeakNode);
571         pageInfo->ReplacePageParams(params);
572         return false;
573     }
574     return true;
575 }
576 
StartRestore(const RouterPageInfo & target)577 void PageRouterManager::StartRestore(const RouterPageInfo& target)
578 {
579     RouterPageInfo info = target;
580     auto tempStack = restorePageStack_;
581     if (!target.url.empty()) {
582         while (!tempStack.empty() && tempStack.back().url != info.url) {
583             tempStack.pop_back();
584         }
585         if (tempStack.empty()) {
586             return;
587         }
588     }
589     info.url = tempStack.back().url;
590     info.params = target.params;
591     info.recoverable = true;
592     info.isNamedRouterMode = tempStack.back().isNamedRouter;
593     tempStack.pop_back();
594     restorePageStack_ = tempStack;
595 
596     if (info.isNamedRouterMode) {
597         if (manifestParser_) {
598             if (manifestParser_->GetRouter()->GetPagePath(info.url).empty()) {
599                 manifestParser_->SetPagePath(info.url);
600             }
601         }
602     }
603 
604     if (info.isNamedRouterMode) {
605         auto callback = [weak = AceType::WeakClaim(this), info]() {
606             auto pageRouterManager = weak.Upgrade();
607             CHECK_NULL_VOID(pageRouterManager);
608             pageRouterManager->RestorePageWithTargetInner(info, RestorePageDestination::BELLOW_TOP);
609         };
610         /**
611          * Always check if the namedRoute page needs to be preloaded.
612          * @sa PageRouterManager::RestoreRouterStack() & PageRouterManager::GetStackInfo()
613          */
614         if (TryPreloadNamedRouter(info.url, std::move(callback))) {
615             return;
616         }
617     }
618 
619     RestorePageWithTargetInner(info, RestorePageDestination::BELLOW_TOP);
620 }
621 
GetStackSize() const622 int32_t PageRouterManager::GetStackSize() const
623 {
624     CHECK_RUN_ON(JS);
625     auto stackSize = static_cast<int32_t>(pageRouterStack_.size() + restorePageStack_.size());
626     if (isNewPageReplacing_) {
627         stackSize--;
628     }
629     return stackSize;
630 }
631 
GetCurrentPageIndex() const632 int32_t PageRouterManager::GetCurrentPageIndex() const
633 {
634     /**
635      * In various page stack operations, pages may be inserted into different positions on the page stack,
636      * and corresponding pages may also have different indexes.
637      */
638     CHECK_RUN_ON(JS);
639     if (insertPageProcessingType_ == InsertPageProcessingType::INSERT_BELLOW_TOP) {
640         // Page has been inserted into position bellow top page of pageRouterStack_.
641         return static_cast<int32_t>(restorePageStack_.size() + pageRouterStack_.size()) - 1;
642     } else if (insertPageProcessingType_ == InsertPageProcessingType::INSERT_BOTTOM) {
643         // Page has been inserted into bottom position of pageRouterStack_.
644         return static_cast<int32_t>(restorePageStack_.size()) + 1;
645     } else {
646         // Page has been inserted into top position of pageRouterStack_.
647         auto index = static_cast<int32_t>(restorePageStack_.size() + pageRouterStack_.size());
648         if (isNewPageReplacing_) {
649             /**
650              * example:
651              *  stack bottom -> stack top
652              *  [1]PageA -> [2]PageB
653              *   call router.replace(PageC)
654              *   then we need keep index of PageC same with PageB, that is 2
655              */
656             index--;
657         }
658         return index;
659     }
660 }
661 
GetPageInfoByIndex(int32_t index,const std::string & params)662 RouterPageInfo PageRouterManager::GetPageInfoByIndex(int32_t index, const std::string& params)
663 {
664     RouterPageInfo emptyForReturn;
665     if (!CheckIndexValid(index) &&
666         index != (GetStackSize() + 1) /* in case the page is on popping */) {
667         return emptyForReturn;
668     }
669 
670     if (index <= static_cast<int32_t>(restorePageStack_.size())) {
671         auto it = restorePageStack_.begin();
672         std::advance(it, index - 1);
673         RouterPageInfo info;
674         info.url = it->url;
675         info.params = params;
676         info.recoverable = true;
677         info.isNamedRouterMode = it->isNamedRouter;
678         return info;
679     }
680 
681     auto createPageInfo = [&params](const RefPtr<NG::EntryPageInfo>& pageInfo) -> RouterPageInfo {
682         RouterPageInfo info;
683         info.url = pageInfo->GetPageUrl();
684         info.params = params;
685         info.recoverable = pageInfo->IsRecoverable();
686         info.isNamedRouterMode = pageInfo->IsCreateByNamedRouter();
687         return info;
688     };
689     if (index <= static_cast<int32_t>(restorePageStack_.size() + pageRouterStack_.size())) {
690         auto it = pageRouterStack_.begin();
691         std::advance(it, index - static_cast<int32_t>(restorePageStack_.size()) - 1);
692         auto pageNode = it->Upgrade();
693         CHECK_NULL_RETURN(pageNode, emptyForReturn);
694         auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
695         CHECK_NULL_RETURN(pagePattern, emptyForReturn);
696         auto pageInfo = AceType::DynamicCast<NG::EntryPageInfo>(pagePattern->GetPageInfo());
697         CHECK_NULL_RETURN(pageInfo, emptyForReturn);
698         return createPageInfo(pageInfo);
699     }
700 
701     // in case the page is on popping
702     auto pipelineContext = PipelineContext::GetCurrentContext();
703     CHECK_NULL_RETURN(pipelineContext, emptyForReturn);
704     auto stageManager = pipelineContext->GetStageManager();
705     CHECK_NULL_RETURN(stageManager, emptyForReturn);
706     auto popPage = stageManager->GetLastPage();
707     CHECK_NULL_RETURN(popPage, emptyForReturn);
708     auto pagePattern = popPage->GetPattern<NG::PagePattern>();
709     CHECK_NULL_RETURN(pagePattern, emptyForReturn);
710     auto pageInfo = AceType::DynamicCast<NG::EntryPageInfo>(pagePattern->GetPageInfo());
711     // make sure the last page is the one with 'index'
712     if (pageInfo && pageInfo->GetPageIndex() == index) {
713         return createPageInfo(pageInfo);
714     }
715 
716     return emptyForReturn;
717 }
718 
GetState(int32_t & index,std::string & name,std::string & path)719 void PageRouterManager::GetState(int32_t& index, std::string& name, std::string& path)
720 {
721     CHECK_RUN_ON(JS);
722     if (pageRouterStack_.empty()) {
723         return;
724     }
725     index = static_cast<int32_t>(pageRouterStack_.size() + restorePageStack_.size());
726     if (isNewPageReplacing_) {
727         if (index <= 1) {
728             TAG_LOGD(AceLogTag::ACE_ROUTER, "router stack size invalid while replacing");
729         } else {
730             index = index - 1;
731         }
732     }
733     auto pageNode = GetCurrentPageNode();
734     CHECK_NULL_VOID(pageNode);
735     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
736     CHECK_NULL_VOID(pagePattern);
737     auto pageInfo = pagePattern->GetPageInfo();
738     CHECK_NULL_VOID(pageInfo);
739     auto url = pageInfo->GetPageUrl();
740     GetPageNameAndPath(url, name, path);
741 }
742 
GetStateByIndex(int32_t index,std::string & name,std::string & path,std::string & params)743 void PageRouterManager::GetStateByIndex(int32_t index, std::string& name, std::string& path, std::string& params)
744 {
745     CHECK_RUN_ON(JS);
746     if (!CheckIndexValid(index) &&
747         index != (GetStackSize() + 1) /* in case the page is on popping */) {
748         return;
749     }
750 
751     if (index <= static_cast<int32_t>(restorePageStack_.size())) {
752         auto it = restorePageStack_.begin();
753         std::advance(it, index - 1);
754         GetPageNameAndPath(it->url, name, path);
755         params = it->params;
756         return;
757     }
758 
759     if (index <= static_cast<int32_t>(restorePageStack_.size() + pageRouterStack_.size())) {
760         auto it = pageRouterStack_.begin();
761         std::advance(it, index - static_cast<int32_t>(restorePageStack_.size()) - 1);
762         auto pageNode = it->Upgrade();
763         CHECK_NULL_VOID(pageNode);
764         auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
765         CHECK_NULL_VOID(pagePattern);
766         auto pageInfo = AceType::DynamicCast<NG::EntryPageInfo>(pagePattern->GetPageInfo());
767         CHECK_NULL_VOID(pageInfo);
768         auto url = pageInfo->GetPageUrl();
769         GetPageNameAndPath(url, name, path);
770         params = pageInfo->GetPageParams();
771         return;
772     }
773 
774     // in case the page is on popping
775     auto pipelineContext = PipelineContext::GetCurrentContext();
776     CHECK_NULL_VOID(pipelineContext);
777     auto stageManager = pipelineContext->GetStageManager();
778     CHECK_NULL_VOID(stageManager);
779     auto popPage = stageManager->GetLastPage();
780     CHECK_NULL_VOID(popPage);
781     auto pagePattern = popPage->GetPattern<NG::PagePattern>();
782     CHECK_NULL_VOID(pagePattern);
783     auto pageInfo = pagePattern->GetPageInfo();
784     // make sure the last page is the one with 'index'
785     if (pageInfo && pageInfo->GetPageIndex() == index) {
786         auto url = pageInfo->GetPageUrl();
787         GetPageNameAndPath(url, name, path);
788         auto entryPageInfo = DynamicCast<NG::EntryPageInfo>(pageInfo);
789         CHECK_NULL_VOID(entryPageInfo);
790         params = entryPageInfo->GetPageParams();
791     }
792 }
793 
GetStateByUrl(std::string & url,std::vector<Framework::StateInfo> & stateArray)794 void PageRouterManager::GetStateByUrl(std::string& url, std::vector<Framework::StateInfo>& stateArray)
795 {
796     CHECK_RUN_ON(JS);
797     int32_t counter = 1;
798     Framework::StateInfo stateInfo;
799     GetPageNameAndPath(url, stateInfo.name, stateInfo.path);
800 
801     for (const auto& record : restorePageStack_) {
802         if (record.url == url) {
803             stateInfo.params = record.params;
804             stateInfo.index = counter;
805             stateArray.emplace_back(stateInfo);
806         }
807         counter++;
808     }
809     for (auto& iter : pageRouterStack_) {
810         auto pageNode = iter.Upgrade();
811         CHECK_NULL_VOID(pageNode);
812         auto pagePattern = pageNode->GetPattern<PagePattern>();
813         CHECK_NULL_VOID(pagePattern);
814         auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
815         CHECK_NULL_VOID(pageInfo);
816         if (pageInfo->GetPageUrl() == url) {
817             stateInfo.params = pageInfo->GetPageParams();
818             stateInfo.index = counter;
819             stateArray.emplace_back(stateInfo);
820         }
821         counter++;
822     }
823 }
824 
GetPageNameAndPath(const std::string & url,std::string & name,std::string & path)825 void PageRouterManager::GetPageNameAndPath(const std::string& url, std::string& name, std::string& path)
826 {
827     std::string tempUrl = url;
828     auto pagePath = Framework::JsiDeclarativeEngine::GetPagePath(url);
829     if (!pagePath.empty()) {
830         tempUrl = pagePath;
831     }
832     auto pos = tempUrl.rfind(".js");
833     if (pos == tempUrl.length() - JS_FILE_EXTENSION_LENGTH) {
834         tempUrl = tempUrl.substr(0, pos);
835     }
836     pos = tempUrl.rfind("/");
837     if (pos != std::string::npos) {
838         name = tempUrl.substr(pos + 1);
839         path = tempUrl.substr(0, pos + 1);
840     }
841     if (name.size() == 0) {
842         name = "index";
843     }
844     if (path.size() == 0) {
845         path = "/" + tempUrl;
846     }
847 }
848 
GetInitParams() const849 std::string PageRouterManager::GetInitParams() const
850 {
851     CHECK_RUN_ON(JS);
852     RefPtr<FrameNode> pageNode = nullptr;
853     if (insertPageProcessingType_ == InsertPageProcessingType::INSERT_BELLOW_TOP) {
854         constexpr size_t STACK_SIZE = 2;
855         if (pageRouterStack_.size() < STACK_SIZE) {
856             return "";
857         }
858         auto it = pageRouterStack_.rbegin();
859         ++it;
860         pageNode = it->Upgrade();
861     } else if (insertPageProcessingType_ == InsertPageProcessingType::INSERT_BOTTOM) {
862         if (pageRouterStack_.empty()) {
863             return "";
864         }
865         pageNode = pageRouterStack_.front().Upgrade();
866     } else {
867         if (pageRouterStack_.empty()) {
868             return "";
869         }
870         pageNode = GetCurrentPageNode();
871     }
872 
873     CHECK_NULL_RETURN(pageNode, "");
874     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
875     CHECK_NULL_RETURN(pagePattern, "");
876     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
877     CHECK_NULL_RETURN(pageInfo, "");
878     return pageInfo->GetPageInitParams();
879 }
880 
GetParams() const881 std::string PageRouterManager::GetParams() const
882 {
883     CHECK_RUN_ON(JS);
884     RefPtr<FrameNode> pageNode = nullptr;
885     if (insertPageProcessingType_ == InsertPageProcessingType::INSERT_BELLOW_TOP) {
886         constexpr size_t STACK_SIZE = 2;
887         if (pageRouterStack_.size() < STACK_SIZE) {
888             return "";
889         }
890         auto it = pageRouterStack_.rbegin();
891         ++it;
892         pageNode = it->Upgrade();
893     } else if (insertPageProcessingType_ == InsertPageProcessingType::INSERT_BOTTOM) {
894         if (pageRouterStack_.empty()) {
895             return "";
896         }
897         pageNode = pageRouterStack_.front().Upgrade();
898     } else {
899         if (pageRouterStack_.empty()) {
900             return "";
901         }
902         pageNode = GetCurrentPageNode();
903     }
904 
905     CHECK_NULL_RETURN(pageNode, "");
906     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
907     CHECK_NULL_RETURN(pagePattern, "");
908     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
909     CHECK_NULL_RETURN(pageInfo, "");
910     return pageInfo->GetPageParams();
911 }
912 
GetIndexByUrl(const std::string & url) const913 int32_t PageRouterManager::GetIndexByUrl(const std::string& url) const
914 {
915     int32_t index = 0;
916     for (auto iter : pageRouterStack_) {
917         auto pageNode = iter.Upgrade();
918         if (!pageNode) {
919             continue;
920         }
921         auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
922         auto localUrl = pagePattern->GetPageInfo()->GetPageUrl();
923         if (localUrl == url) {
924             return index;
925         }
926         ++index;
927     }
928     return INVALID_PAGE_INDEX;
929 }
930 
GetCurrentPageUrl()931 std::string PageRouterManager::GetCurrentPageUrl()
932 {
933     CHECK_RUN_ON(JS);
934     if (pageRouterStack_.empty()) {
935         return "";
936     }
937     auto pageNode = GetCurrentPageNode();
938     CHECK_NULL_RETURN(pageNode, "");
939     auto pagePattern = pageNode->GetPattern<PagePattern>();
940     CHECK_NULL_RETURN(pagePattern, "");
941     auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
942     CHECK_NULL_RETURN(entryPageInfo, "");
943     return entryPageInfo->GetPagePath();
944 }
945 
946 // Get the currently running JS page information in NG structure.
GetCurrentPageSourceMap(const RefPtr<AssetManager> & assetManager)947 RefPtr<Framework::RevSourceMap> PageRouterManager::GetCurrentPageSourceMap(const RefPtr<AssetManager>& assetManager)
948 {
949     CHECK_RUN_ON(JS);
950     if (pageRouterStack_.empty()) {
951         return nullptr;
952     }
953     auto pageNode = GetCurrentPageNode();
954     CHECK_NULL_RETURN(pageNode, nullptr);
955     auto pagePattern = pageNode->GetPattern<PagePattern>();
956     CHECK_NULL_RETURN(pagePattern, nullptr);
957     auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
958     CHECK_NULL_RETURN(entryPageInfo, nullptr);
959     auto pageMap = entryPageInfo->GetPageMap();
960     if (pageMap) {
961         return pageMap;
962     }
963     // initialize page map.
964     std::string jsSourceMap;
965     // stage mode
966     auto container = Container::Current();
967     CHECK_NULL_RETURN(container, nullptr);
968     if (container->IsUseStageModel()) {
969         auto pagePath = entryPageInfo->GetPagePath();
970         auto moduleName = container->GetModuleName();
971         std::string judgePath = "";
972         if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE)) {
973             judgePath = DEBUG_PATH + moduleName + ETS_PATH +
974                         pagePath.substr(0, pagePath.size() - JS_FILE_EXTENSION_LENGTH) + TS_SUFFIX;
975         } else {
976             judgePath = moduleName + ETS_PATH +
977                         pagePath.substr(0, pagePath.size() - JS_FILE_EXTENSION_LENGTH) + ETS_SUFFIX;
978         }
979         if (Framework::GetAssetContentImpl(assetManager, "sourceMaps.map", jsSourceMap)) {
980             auto jsonPages = JsonUtil::ParseJsonString(jsSourceMap);
981             auto child = jsonPages->GetChild();
982             if (!child->GetValue("entry-package-info")->IsNull()) {
983                 judgePath = NEW_PATH + pagePath.substr(0, pagePath.size() - JS_FILE_EXTENSION_LENGTH) + TS_SUFFIX;
984             }
985             auto jsonPage = jsonPages->GetValue(judgePath)->ToString();
986             auto stagePageMap = MakeRefPtr<Framework::RevSourceMap>();
987             stagePageMap->Init(jsonPage);
988             entryPageInfo->SetPageMap(stagePageMap);
989             return stagePageMap;
990         }
991     } else {
992         if (Framework::GetAssetContentImpl(assetManager, entryPageInfo->GetPagePath() + ".map", jsSourceMap)) {
993             auto faPageMap = MakeRefPtr<Framework::RevSourceMap>();
994             faPageMap->Init(jsSourceMap);
995             entryPageInfo->SetPageMap(faPageMap);
996             return faPageMap;
997         }
998     }
999     return nullptr;
1000 }
1001 
GetStackInfo(ContentInfoType type)1002 std::unique_ptr<JsonValue> PageRouterManager::GetStackInfo(ContentInfoType type)
1003 {
1004     auto jsonRouterStack = JsonUtil::CreateArray(true);
1005     auto restoreIter = restorePageStack_.begin();
1006     while (restoreIter != restorePageStack_.end()) {
1007         auto jsonItem = JsonUtil::Create(true);
1008         jsonItem->Put("url", restoreIter->url.c_str());
1009         if (type == ContentInfoType::RESOURCESCHEDULE_RECOVERY) {
1010             jsonItem->Put("params", restoreIter->params.c_str());
1011             jsonItem->Put("isNamedRoute", restoreIter->isNamedRouter);
1012         }
1013         jsonRouterStack->Put(jsonItem);
1014         ++restoreIter;
1015     }
1016     auto iter = pageRouterStack_.begin();
1017     while (iter != pageRouterStack_.end()) {
1018         auto pageNode = iter->Upgrade();
1019         CHECK_NULL_RETURN(pageNode, jsonRouterStack);
1020         auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
1021         CHECK_NULL_RETURN(pagePattern, jsonRouterStack);
1022         auto pageInfo = AceType::DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1023         CHECK_NULL_RETURN(pageInfo, jsonRouterStack);
1024         if (type == ContentInfoType::RESOURCESCHEDULE_RECOVERY && !pageInfo->IsRecoverable()) {
1025             ++iter;
1026             continue;
1027         }
1028         auto url = pageInfo->GetPageUrl();
1029         auto jsonItem = JsonUtil::Create(true);
1030         jsonItem->Put("url", url.c_str());
1031         if (type == ContentInfoType::RESOURCESCHEDULE_RECOVERY) {
1032             jsonItem->Put("params", pageInfo->GetPageParams().c_str());
1033             jsonItem->Put("isNamedRoute", pageInfo->IsCreateByNamedRouter());
1034         }
1035         jsonRouterStack->Put(jsonItem);
1036         ++iter;
1037     }
1038     return jsonRouterStack;
1039 }
1040 
GetNamedRouterInfo()1041 std::unique_ptr<JsonValue> PageRouterManager::GetNamedRouterInfo()
1042 {
1043     if (getNamedRouterInfo_) {
1044         return getNamedRouterInfo_();
1045     }
1046     return nullptr;
1047 }
1048 
RestoreRouterStack(std::unique_ptr<JsonValue> stackInfo,ContentInfoType type)1049 std::pair<RouterRecoverRecord, UIContentErrorCode> PageRouterManager::RestoreRouterStack(
1050     std::unique_ptr<JsonValue> stackInfo, ContentInfoType type)
1051 {
1052     if (!stackInfo->IsValid() || !stackInfo->IsArray()) {
1053         return std::make_pair(RouterRecoverRecord(), UIContentErrorCode::WRONG_PAGE_ROUTER);
1054     }
1055     int32_t stackSize = stackInfo->GetArraySize();
1056     if (stackSize < 1) {
1057         return std::make_pair(RouterRecoverRecord(), UIContentErrorCode::WRONG_PAGE_ROUTER);
1058     }
1059 
1060     auto container = Container::Current();
1061     CHECK_NULL_RETURN(container,
1062         std::make_pair(RouterRecoverRecord(), UIContentErrorCode::NULL_POINTER));
1063     auto pipeline = container->GetPipelineContext();
1064     CHECK_NULL_RETURN(pipeline,
1065         std::make_pair(RouterRecoverRecord(), UIContentErrorCode::WRONG_PAGE_ROUTER));
1066     auto context = DynamicCast<NG::PipelineContext>(pipeline);
1067     auto stageManager = context ? context->GetStageManager() : nullptr;
1068     CHECK_NULL_RETURN(stageManager,
1069         std::make_pair(RouterRecoverRecord(), UIContentErrorCode::WRONG_PAGE_ROUTER));
1070 
1071     RouterRecoverRecord topRecord;
1072     for (int32_t index = 0; index < stackSize; ++index) {
1073         auto item = stackInfo->GetArrayItem(index);
1074         bool isNamedRoute = false;
1075         std::string params;
1076         if (type == ContentInfoType::RESOURCESCHEDULE_RECOVERY) {
1077             auto isNamedRouteJson = item->GetValue("isNamedRoute");
1078             if (isNamedRouteJson && isNamedRouteJson->IsBool()) {
1079                 isNamedRoute = isNamedRouteJson->GetBool();
1080             }
1081             auto paramsJson = item->GetValue("params");
1082             if (paramsJson && paramsJson->IsString()) {
1083                 params = paramsJson->GetString();
1084             }
1085         }
1086 
1087         std::string url = item->GetValue("url")->ToString();
1088         // remove 2 useless character, as "XXX" to XXX
1089         url = url.substr(1, url.size() - 2);
1090         if (index < stackSize - 1) {
1091             restorePageStack_.emplace_back(url, params, isNamedRoute);
1092         } else {
1093             topRecord = RouterRecoverRecord(url, params, isNamedRoute);
1094         }
1095     }
1096     return std::make_pair(topRecord, UIContentErrorCode::NO_ERRORS);
1097 }
1098 
RestoreNamedRouterInfo(std::unique_ptr<JsonValue> namedRouterInfo)1099 void PageRouterManager::RestoreNamedRouterInfo(std::unique_ptr<JsonValue> namedRouterInfo)
1100 {
1101     if (restoreNamedRouterInfo_) {
1102         restoreNamedRouterInfo_(std::move(namedRouterInfo));
1103     }
1104 }
1105 
GetFullPathInfo()1106 std::unique_ptr<JsonValue> PageRouterManager::GetFullPathInfo()
1107 {
1108     if (getFullPathInfo_) {
1109         return getFullPathInfo_();
1110     }
1111     return nullptr;
1112 }
1113 
RestoreFullPathInfo(std::unique_ptr<JsonValue> fullPathInfo)1114 void PageRouterManager::RestoreFullPathInfo(std::unique_ptr<JsonValue> fullPathInfo)
1115 {
1116     if (restoreFullPathInfo_) {
1117         restoreFullPathInfo_(std::move(fullPathInfo));
1118     }
1119 }
1120 
IsUnrestoreByIndex(int32_t index)1121 bool PageRouterManager::IsUnrestoreByIndex(int32_t index)
1122 {
1123     return index > 0 && index <= static_cast<int32_t>(restorePageStack_.size());
1124 }
1125 
GenerateNextPageId()1126 int32_t PageRouterManager::GenerateNextPageId()
1127 {
1128     return ++pageId_;
1129 }
1130 
FindPageInStack(const std::string & url,bool needIgnoreBegin)1131 std::pair<int32_t, RefPtr<FrameNode>> PageRouterManager::FindPageInStack(const std::string& url, bool needIgnoreBegin)
1132 {
1133     auto iter = std::find_if(needIgnoreBegin ? ++pageRouterStack_.rbegin() : pageRouterStack_.rbegin(),
1134         pageRouterStack_.rend(), [url](const WeakPtr<FrameNode>& item) {
1135             auto pageNode = item.Upgrade();
1136             CHECK_NULL_RETURN(pageNode, false);
1137             auto pagePattern = pageNode->GetPattern<PagePattern>();
1138             CHECK_NULL_RETURN(pagePattern, false);
1139             auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1140             CHECK_NULL_RETURN(entryPageInfo, false);
1141             return entryPageInfo->GetPageUrl() == url;
1142         });
1143     if (iter == pageRouterStack_.rend()) {
1144         return { INVALID_PAGE_INDEX, nullptr };
1145     }
1146     // Returns to the forward position.
1147     return { std::distance(iter, pageRouterStack_.rend()) - 1, iter->Upgrade() };
1148 }
1149 
FindPageInStackByRouteName(const std::string & name,bool needIgnoreBegin)1150 std::pair<int32_t, RefPtr<FrameNode>> PageRouterManager::FindPageInStackByRouteName(
1151     const std::string& name, bool needIgnoreBegin)
1152 {
1153     auto iter = std::find_if(needIgnoreBegin ? ++pageRouterStack_.rbegin() : pageRouterStack_.rbegin(),
1154         pageRouterStack_.rend(), [name](const WeakPtr<FrameNode>& item) {
1155             auto pageNode = item.Upgrade();
1156             CHECK_NULL_RETURN(pageNode, false);
1157             auto pagePattern = pageNode->GetPattern<PagePattern>();
1158             CHECK_NULL_RETURN(pagePattern, false);
1159             auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1160             CHECK_NULL_RETURN(entryPageInfo, false);
1161             return entryPageInfo->GetRouteName() == name;
1162         });
1163     if (iter == pageRouterStack_.rend()) {
1164         return { INVALID_PAGE_INDEX, nullptr };
1165     }
1166     // Returns to the forward position.
1167     return { std::distance(iter, pageRouterStack_.rend()) - 1, iter->Upgrade() };
1168 }
1169 
FindPageInRestoreStack(const std::string & url)1170 int32_t PageRouterManager::FindPageInRestoreStack(const std::string& url)
1171 {
1172     auto iter = std::find_if(restorePageStack_.rbegin(), restorePageStack_.rend(),
1173         [&url](const RouterRecoverRecord& record) {
1174             return record.url == url;
1175         });
1176     if (iter == restorePageStack_.rend()) {
1177         return INVALID_PAGE_INDEX;
1178     }
1179 
1180     return std::distance(iter, restorePageStack_.rend()) - 1;
1181 }
1182 
PushOhmUrl(const RouterPageInfo & target)1183 void PageRouterManager::PushOhmUrl(const RouterPageInfo& target)
1184 {
1185     RouterOptScope scope(this);
1186     if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
1187         TAG_LOGW(AceLogTag::ACE_ROUTER, "PushOhmUrl exceeds maxStackSize.");
1188         if (target.errorCallback != nullptr) {
1189             target.errorCallback("Page stack error. Too many pages are pushed.", ERROR_CODE_PAGE_STACK_FULL);
1190         }
1191         return;
1192     }
1193     RouterPageInfo info = target;
1194     info.path = info.url + ".js";
1195 
1196     if (target.routerMode == RouterMode::SINGLE) {
1197         auto pageInfo = FindPageInStack(info.url);
1198         if (pageInfo.second) {
1199             // find page in stack, move postion and update params.
1200             auto pagePattern = pageInfo.second->GetPattern<PagePattern>();
1201             if (pagePattern) {
1202                 pagePattern->FireOnNewParam(info.params);
1203             }
1204             MovePageToFront(pageInfo.first, pageInfo.second, info, true);
1205             return;
1206         }
1207         auto index = FindPageInRestoreStack(info.url);
1208         if (index != INVALID_PAGE_INDEX) {
1209             // find page in restore page, create page, move position and update params.
1210             RestorePageWithTarget(index, false, info, RestorePageDestination::TOP);
1211             return;
1212         }
1213     }
1214 
1215     LoadPage(GenerateNextPageId(), info, true, true, true);
1216     auto container = Container::Current();
1217     CHECK_NULL_VOID(container);
1218     auto pageUrlChecker = container->GetPageUrlChecker();
1219     CHECK_NULL_VOID(pageUrlChecker);
1220     auto taskExecutor = container->GetTaskExecutor();
1221     CHECK_NULL_VOID(taskExecutor);
1222     taskExecutor->PostTask([pageUrlChecker, url = target.url]() { pageUrlChecker->CheckPreload(url); },
1223         TaskExecutor::TaskType::BACKGROUND, "ArkUIPageRouterPushOhmUrl",
1224         TaskExecutor::GetPriorityTypeWithCheck(PriorityType::HIGH));
1225 }
1226 
StartPush(const RouterPageInfo & target)1227 void PageRouterManager::StartPush(const RouterPageInfo& target)
1228 {
1229     CHECK_RUN_ON(JS);
1230     RouterOptScope scope(this);
1231     if (target.url.empty()) {
1232         TAG_LOGE(AceLogTag::ACE_ROUTER, "push url is empty");
1233         return;
1234     }
1235 #if !defined(PREVIEW)
1236     if (target.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1237         auto loadTask = [weak = AceType::WeakClaim(this), target]() {
1238                 auto pageRouterManager = weak.Upgrade();
1239                 CHECK_NULL_VOID(pageRouterManager);
1240                 pageRouterManager->UpdateSrcPage();
1241                 pageRouterManager->PushOhmUrl(target);
1242             };
1243         LoadOhmUrlPage(target.url, std::move(loadTask), target.errorCallback,
1244             "ArkUIPageRouterPushOhmUrl", "ArkUIPageRouterPushErrorCallback");
1245         return;
1246     }
1247 #endif
1248     if (!manifestParser_) {
1249         return;
1250     }
1251     auto context = PipelineContext::GetCurrentContext();
1252     CHECK_NULL_VOID(context);
1253     auto stageManager = context->GetStageManager();
1254     CHECK_NULL_VOID(stageManager);
1255     if (GetStackSize() >= MAX_ROUTER_STACK_SIZE && !stageManager->GetForceSplitEnable()) {
1256         TAG_LOGW(AceLogTag::ACE_ROUTER, "StartPush exceeds maxStackSize.");
1257         if (target.errorCallback != nullptr) {
1258             target.errorCallback("Page stack error. Too many pages are pushed.", ERROR_CODE_PAGE_STACK_FULL);
1259         }
1260         return;
1261     }
1262     RouterPageInfo info = target;
1263     info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
1264     if (info.path.empty()) {
1265         TAG_LOGW(AceLogTag::ACE_ROUTER, "empty path found in StartPush with url: %{public}s", info.url.c_str());
1266         if (info.errorCallback != nullptr) {
1267             info.errorCallback("The URI of the page to redirect is incorrect or does not exist.", ERROR_CODE_URI_ERROR);
1268         }
1269         return;
1270     }
1271 
1272     CleanPageOverlay();
1273     UpdateSrcPage();
1274 
1275     if (info.routerMode == RouterMode::SINGLE) {
1276         auto pageInfo = FindPageInStack(info.url);
1277         if (pageInfo.second) {
1278             // find page in stack, move postion and update params.
1279             auto pagePattern = pageInfo.second->GetPattern<PagePattern>();
1280             if (pagePattern) {
1281                 pagePattern->FireOnNewParam(info.params);
1282             }
1283             MovePageToFront(pageInfo.first, pageInfo.second, info, true);
1284             return;
1285         }
1286         auto index = FindPageInRestoreStack(info.url);
1287         if (index != INVALID_PAGE_INDEX) {
1288             // find page in restore page, create page, move position and update params.
1289             RestorePageWithTarget(index, false, info, RestorePageDestination::TOP);
1290             return;
1291         }
1292     }
1293 
1294     LoadPage(GenerateNextPageId(), info, true, true, true);
1295 }
1296 
ReplaceOhmUrl(const RouterPageInfo & target)1297 void PageRouterManager::ReplaceOhmUrl(const RouterPageInfo& target)
1298 {
1299     RouterOptScope scope(this);
1300     RouterPageInfo info = target;
1301     info.path = info.url + ".js";
1302 
1303     PopPage("", false, false);
1304 
1305     if (info.routerMode == RouterMode::SINGLE) {
1306         auto pageInfo = FindPageInStack(info.url);
1307         if (pageInfo.second) {
1308             // find page in stack, move postion and update params.
1309             auto pagePattern = pageInfo.second->GetPattern<PagePattern>();
1310             if (pagePattern) {
1311                 pagePattern->FireOnNewParam(target.params);
1312             }
1313             MovePageToFront(pageInfo.first, pageInfo.second, info, false, true, false);
1314             return;
1315         }
1316         auto index = FindPageInRestoreStack(info.url);
1317         if (index != INVALID_PAGE_INDEX) {
1318             // find page in restore page, create page, move position and update params.
1319             RestorePageWithTarget(index, false, info, RestorePageDestination::TOP, false);
1320             return;
1321         }
1322     }
1323 
1324     LoadPage(GenerateNextPageId(), info, false, false);
1325     auto container = Container::Current();
1326     CHECK_NULL_VOID(container);
1327     auto pageUrlChecker = container->GetPageUrlChecker();
1328     CHECK_NULL_VOID(pageUrlChecker);
1329     auto taskExecutor = container->GetTaskExecutor();
1330     CHECK_NULL_VOID(taskExecutor);
1331     taskExecutor->PostTask([pageUrlChecker, url = target.url]() { pageUrlChecker->CheckPreload(url); },
1332         TaskExecutor::TaskType::BACKGROUND, "ArkUIPageRouterReplaceOhmUrl",
1333         TaskExecutor::GetPriorityTypeWithCheck(PriorityType::HIGH));
1334 }
1335 
StartReplace(const RouterPageInfo & target)1336 void PageRouterManager::StartReplace(const RouterPageInfo& target)
1337 {
1338     CHECK_RUN_ON(JS);
1339     CleanPageOverlay();
1340     RouterOptScope scope(this);
1341     if (target.url.empty()) {
1342         return;
1343     }
1344 #if !defined(PREVIEW)
1345     if (target.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1346         auto loadTask = [weak = AceType::WeakClaim(this), target]() {
1347                 auto pageRouterManager = weak.Upgrade();
1348                 CHECK_NULL_VOID(pageRouterManager);
1349                 pageRouterManager->UpdateSrcPage();
1350                 pageRouterManager->ReplaceOhmUrl(target);
1351             };
1352         LoadOhmUrlPage(target.url, std::move(loadTask), target.errorCallback,
1353             "ArkUIPageRouterReplaceOhmUrl", "ArkUIPageRouterReplaceErrorCallback");
1354         return;
1355     }
1356 #endif
1357     if (!manifestParser_) {
1358         return;
1359     }
1360     RouterPageInfo info = target;
1361     info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
1362     if (info.path.empty()) {
1363         TAG_LOGW(AceLogTag::ACE_ROUTER, "empty path found in StartReplace with url: %{public}s", info.url.c_str());
1364         if (info.errorCallback != nullptr) {
1365             info.errorCallback(
1366                 "Uri error. The URI of the page to be used for replacement is incorrect or does not exist.",
1367                 ERROR_CODE_URI_ERROR_LITE);
1368         }
1369         return;
1370     }
1371     UpdateSrcPage();
1372     DealReplacePage(info);
1373 }
1374 
StartBack(const RouterPageInfo & target)1375 void PageRouterManager::StartBack(const RouterPageInfo& target)
1376 {
1377     CleanPageOverlay();
1378     UpdateSrcPage();
1379     if (target.url.empty()) {
1380         size_t pageRouteSize = pageRouterStack_.size();
1381         if (pageRouteSize <= 1) {
1382             if (!restorePageStack_.empty()) {
1383                 auto newInfo = RouterPageInfo();
1384                 newInfo.params = target.params;
1385                 StartRestore(newInfo);
1386                 return;
1387             }
1388             TAG_LOGI(AceLogTag::ACE_ROUTER, "Router back start ExitToDesktop");
1389             ExitToDesktop();
1390             return;
1391         }
1392         TAG_LOGI(AceLogTag::ACE_ROUTER, "Router back start PopPage");
1393         PopPage(target.params, true, true);
1394         return;
1395     }
1396 
1397     auto pageInfo = FindPageInStack(target.url, true);
1398     if (pageInfo.second) {
1399         // find page in stack, pop to specified index.
1400         RouterPageInfo info = target;
1401 #if !defined(PREVIEW)
1402         if (info.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1403             info.path = info.url + ".js";
1404             PopPageToIndex(pageInfo.first, info.params, true, true);
1405             return;
1406         }
1407 #endif
1408         if (!manifestParser_) {
1409             return;
1410         }
1411 
1412         info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
1413         if (info.path.empty()) {
1414             TAG_LOGW(AceLogTag::ACE_ROUTER, "empty path found in StartBack with url: %{public}s", info.url.c_str());
1415             return;
1416         }
1417         PopPageToIndex(pageInfo.first, info.params, true, true);
1418         return;
1419     }
1420 
1421     auto index = FindPageInRestoreStack(target.url);
1422     if (index == INVALID_PAGE_INDEX) {
1423         return;
1424     }
1425 
1426     RestorePageWithTarget(index, true, target, RestorePageDestination::BOTTOM);
1427 }
1428 
StartBackToIndex(int32_t index,const std::string & params)1429 void PageRouterManager::StartBackToIndex(int32_t index, const std::string& params)
1430 {
1431     CleanPageOverlay();
1432     if (!manifestParser_) {
1433         return;
1434     }
1435 
1436     if (index > static_cast<int32_t>(restorePageStack_.size())) {
1437         PopPageToIndex(index - static_cast<int32_t>(restorePageStack_.size()) - 1, params, true, true);
1438         return;
1439     }
1440 
1441     RouterPageInfo info;
1442     info.params = params;
1443     RestorePageWithTarget(index - 1, true, info, RestorePageDestination::BOTTOM);
1444 }
1445 
BackCheckAlert(const RouterPageInfo & target)1446 void PageRouterManager::BackCheckAlert(const RouterPageInfo& target)
1447 {
1448     RouterOptScope scope(this);
1449     if (pageRouterStack_.empty()) {
1450         TAG_LOGW(AceLogTag::ACE_ROUTER, "Page router stack size is zero, can not back");
1451         return;
1452     }
1453     auto currentPage = GetCurrentPageNode();
1454     CHECK_NULL_VOID(currentPage);
1455     auto pagePattern = currentPage->GetPattern<PagePattern>();
1456     CHECK_NULL_VOID(pagePattern);
1457     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1458     CHECK_NULL_VOID(pageInfo);
1459     if (pageInfo->GetAlertCallback()) {
1460         ngBackTarget_ = target;
1461         auto pipelineContext = PipelineContext::GetCurrentContext();
1462         auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
1463         CHECK_NULL_VOID(overlayManager);
1464         overlayManager->ShowDialog(
1465             pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
1466         return;
1467     }
1468     StartBack(target);
1469 }
1470 
BackToIndexCheckAlert(int32_t index,const std::string & params)1471 void PageRouterManager::BackToIndexCheckAlert(int32_t index, const std::string& params)
1472 {
1473     RouterOptScope scope(this);
1474     if (pageRouterStack_.empty()) {
1475         return;
1476     }
1477     RouterPageInfo target = GetPageInfoByIndex(index, params);
1478     auto currentPage = GetCurrentPageNode();
1479     CHECK_NULL_VOID(currentPage);
1480     auto pagePattern = currentPage->GetPattern<PagePattern>();
1481     CHECK_NULL_VOID(pagePattern);
1482     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1483     CHECK_NULL_VOID(pageInfo);
1484     if (pageInfo->GetAlertCallback()) {
1485         ngBackTarget_ = target;
1486         auto pipelineContext = PipelineContext::GetCurrentContext();
1487         auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
1488         CHECK_NULL_VOID(overlayManager);
1489         overlayManager->ShowDialog(
1490             pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
1491         return;
1492     }
1493     UpdateSrcPage();
1494     StartBackToIndex(index, params);
1495 }
1496 
LoadPage(int32_t pageId,const RouterPageInfo & target,bool needHideLast,bool needTransition,bool)1497 void PageRouterManager::LoadPage(int32_t pageId, const RouterPageInfo& target, bool needHideLast, bool needTransition,
1498     bool  /*isPush*/)
1499 {
1500     ACE_SCOPED_TRACE_COMMERCIAL("load page: %s(id:%d)", target.url.c_str(), pageId);
1501     CHECK_RUN_ON(JS);
1502     auto pageNode = CreatePage(pageId, target);
1503     if (!pageNode) {
1504         TAG_LOGE(AceLogTag::ACE_ROUTER, "failed to create page in LoadPage");
1505         return;
1506     }
1507 
1508     pageRouterStack_.emplace_back(pageNode);
1509     if (intentInfo_.has_value()) {
1510         if (!OnPageReadyAndHandleIntent(pageNode, needHideLast)) {
1511             intentInfo_.reset();
1512             pageRouterStack_.pop_back();
1513             TAG_LOGW(AceLogTag::ACE_ROUTER, "OnPageReadyAndHandleIntent Failed");
1514             return;
1515         }
1516     } else if (!OnPageReady(pageNode, needHideLast, needTransition)) {
1517         pageRouterStack_.pop_back();
1518         TAG_LOGW(AceLogTag::ACE_ROUTER, "LoadPage OnPageReady Failed");
1519         return;
1520     }
1521     TAG_LOGI(AceLogTag::ACE_ROUTER, "LoadPage Success");
1522     auto pipeline = pageNode->GetContext();
1523     CHECK_NULL_VOID(pipeline);
1524     pipeline->AddAccessibilityCallbackEvent(AccessibilityCallbackEventId::ON_LOAD_PAGE,
1525         pageNode->GetAccessibilityId());
1526 }
1527 
CreatePage(int32_t pageId,const RouterPageInfo & target)1528 RefPtr<FrameNode> PageRouterManager::CreatePage(int32_t pageId, const RouterPageInfo& target)
1529 {
1530     ACE_SCOPED_TRACE("PageRouterManager::CreatePage");
1531     CHECK_RUN_ON(JS);
1532     TAG_LOGI(AceLogTag::ACE_ROUTER, "Page router manager is creating page[%{public}d]: url: %{public}s path: "
1533         "%{public}s, recoverable: %{public}s, namedRouter: %{public}s", pageId, target.url.c_str(),
1534         target.path.c_str(), (target.recoverable ? "yes" : "no"), (target.isNamedRouterMode ? "yes" : "no"));
1535     auto entryPageInfo = AceType::MakeRefPtr<EntryPageInfo>(
1536         pageId, target.url, target.path, target.params, target.recoverable, target.isNamedRouterMode);
1537     auto pagePattern = ViewAdvancedRegister::GetInstance()->CreatePagePattern(entryPageInfo);
1538     std::unordered_map<std::string, std::string> reportData { { "pageUrl", target.url } };
1539     ResSchedReportScope reportScope("push_page", reportData);
1540     auto pageNode = PageNode::CreatePageNode(ElementRegister::GetInstance()->MakeUniqueId(), pagePattern);
1541     pageNode->SetHostPageId(pageId);
1542     // !!! must push_back first for UpdateRootComponent
1543     pageRouterStack_.emplace_back(pageNode);
1544 
1545     if (target.content && !target.content->empty()) {
1546         loadJsByBuffer_(target.content, target.errorCallback, target.params);
1547     } else {
1548         loadJs_(target.path, target.errorCallback);
1549     }
1550     // record full path info of every pageNode
1551     auto pageInfo = pagePattern->GetPageInfo();
1552     if (!pageInfo) {
1553         pageRouterStack_.pop_back();
1554         return nullptr;
1555     }
1556     auto keyInfo = target.url;
1557     if (keyInfo.empty() && manifestParser_) {
1558         auto router = manifestParser_->GetRouter();
1559         if (router) {
1560             keyInfo = router->GetEntry("");
1561         }
1562     }
1563 #if !defined(PREVIEW)
1564     if (keyInfo.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1565         // deal with @bundle url
1566         // @bundle format: @bundle:bundleName/moduleName/pagePath/fileName(without file extension)
1567         // @bundle example: @bundle:com.example.applicationHsp/hsp/ets/mylib/pages/Index
1568         // only moduleName and pagePath/fileName is needed: hspmylib/pages/Index
1569         size_t bundleEndPos = keyInfo.find('/');
1570         size_t moduleStartPos = bundleEndPos + 1;
1571         size_t moduleEndPos = keyInfo.find('/', moduleStartPos);
1572         std::string moduleName = keyInfo.substr(moduleStartPos, moduleEndPos - moduleStartPos);
1573         size_t pageInfoStartPos = keyInfo.find('/', moduleEndPos + 1);
1574         keyInfo = keyInfo.substr(pageInfoStartPos + 1);
1575         keyInfo = moduleName + keyInfo;
1576     }
1577 #endif
1578     SetPageInfoRouteName(entryPageInfo);
1579     auto pagePath = Framework::JsiDeclarativeEngine::GetFullPathInfo(keyInfo);
1580     if (pagePath.empty()) {
1581         auto container = Container::Current();
1582         if (!container) {
1583             pageRouterStack_.pop_back();
1584             return nullptr;
1585         }
1586         auto moduleName = container->GetModuleName();
1587         keyInfo = moduleName + keyInfo;
1588         pagePath = Framework::JsiDeclarativeEngine::GetFullPathInfo(keyInfo);
1589     }
1590     pageInfo->SetFullPath(pagePath);
1591 
1592 #if defined(PREVIEW)
1593     if (!isComponentPreview_()) {
1594 #endif
1595     if (!GenerateRouterPageInner(target)) {
1596         TAG_LOGE(AceLogTag::ACE_ROUTER, "Update RootComponent Failed or LoadNamedRouter Failed");
1597 #if !defined(PREVIEW)
1598         if (!target.isNamedRouterMode && target.url.substr(0, strlen(BUNDLE_TAG)) != BUNDLE_TAG) {
1599             const std::string errorMsg =
1600                 "Load Page Failed: " + target.url + ", probably caused by reasons as follows:\n"
1601                 "1. there is a js error in target page;\n"
1602                 "2. invalid moduleName or bundleName in target page.";
1603             ThrowError(errorMsg, ERROR_CODE_INTERNAL_ERROR);
1604         }
1605 #endif
1606         pageRouterStack_.pop_back();
1607         return nullptr;
1608     }
1609 
1610     if (target.isNamedRouterMode) {
1611         if (manifestParser_) {
1612             manifestParser_->SetPagePath(target.url);
1613         } else {
1614             TAG_LOGE(AceLogTag::ACE_ROUTER, "set routeName in manifest failed, manifestParser is null!");
1615         }
1616     }
1617 
1618     if (target.errorCallback != nullptr) {
1619         target.errorCallback("", ERROR_CODE_NO_ERROR);
1620     }
1621 #if defined(PREVIEW)
1622     }
1623 #endif
1624 
1625     pageRouterStack_.pop_back();
1626     return pageNode;
1627 }
1628 
LoadCard(int32_t pageId,const RouterPageInfo & target,const std::string & params,int64_t cardId,bool,bool needHideLast,const std::string & entryPoint)1629 UIContentErrorCode PageRouterManager::LoadCard(int32_t pageId, const RouterPageInfo& target, const std::string& params,
1630     int64_t cardId, bool /* isRestore */, bool needHideLast, const std::string& entryPoint)
1631 {
1632     CHECK_RUN_ON(JS);
1633     auto entryPageInfo = AceType::MakeRefPtr<EntryPageInfo>(pageId, target.url, target.path, params);
1634     auto pagePattern = ViewAdvancedRegister::GetInstance()->CreatePagePattern(entryPageInfo);
1635     auto pageNode =
1636         FrameNode::CreateFrameNode(V2::PAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), pagePattern);
1637     pageNode->SetHostPageId(pageId);
1638     pageRouterStack_.emplace_back(pageNode);
1639 
1640     if (!loadCard_) {
1641         return UIContentErrorCode::NULL_CARD_CALLBACK;
1642     }
1643     auto result = loadCard_(target.url, cardId, entryPoint);
1644     if (!result) {
1645         pageRouterStack_.pop_back();
1646         return UIContentErrorCode::NULL_CARD_RES;
1647     }
1648 
1649     if (!OnPageReady(pageNode, needHideLast, false, isCardRouter_, cardId)) {
1650         TAG_LOGE(AceLogTag::ACE_ROUTER, "LoadCard OnPageReady Failed");
1651         pageRouterStack_.pop_back();
1652         return UIContentErrorCode::CARD_PAGE_NOT_READY;
1653     }
1654     TAG_LOGI(AceLogTag::ACE_ROUTER, "LoadCard Success");
1655     return UIContentErrorCode::NO_ERRORS;
1656 }
1657 
MovePageToFront(int32_t index,const RefPtr<FrameNode> & pageNode,const RouterPageInfo & target,bool needHideLast,bool forceShowCurrent,bool needTransition)1658 void PageRouterManager::MovePageToFront(int32_t index, const RefPtr<FrameNode>& pageNode, const RouterPageInfo& target,
1659     bool needHideLast, bool forceShowCurrent, bool needTransition)
1660 {
1661     TAG_LOGI(AceLogTag::ACE_ROUTER, "Move page to front to index: %{public}d", index);
1662     if (target.errorCallback != nullptr) {
1663         target.errorCallback("", ERROR_CODE_NO_ERROR);
1664     }
1665 
1666     // update param first.
1667     CHECK_NULL_VOID(pageNode);
1668     auto pagePattern = pageNode->GetPattern<PagePattern>();
1669     CHECK_NULL_VOID(pagePattern);
1670     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1671     CHECK_NULL_VOID(pageInfo);
1672 
1673     if (index == static_cast<int32_t>(pageRouterStack_.size()) - 1) {
1674         pageInfo->ReplacePageParams(target.params);
1675         pageInfo->ReplaceRecoverable(target.recoverable);
1676         if (forceShowCurrent) {
1677             pagePattern->ResetPageTransitionEffect();
1678             StageManager::FirePageShow(pageNode, PageTransitionType::NONE);
1679         }
1680         return;
1681     }
1682 
1683     auto container = Container::Current();
1684     CHECK_NULL_VOID(container);
1685     auto pipeline = container->GetPipelineContext();
1686     CHECK_NULL_VOID(pipeline);
1687     auto context = DynamicCast<NG::PipelineContext>(pipeline);
1688     auto stageManager = context ? context->GetStageManager() : nullptr;
1689     CHECK_NULL_VOID(stageManager);
1690 
1691     // clean pageNode on index position.
1692     auto iter = pageRouterStack_.begin();
1693     std::advance(iter, index);
1694     auto last = pageRouterStack_.erase(iter);
1695     // push pageNode to top.
1696     pageRouterStack_.emplace_back(pageNode);
1697     std::string tempParam = pageInfo->ReplacePageParams(target.params);
1698     bool tempRecoverable = pageInfo->ReplaceRecoverable(target.recoverable);
1699     if (!stageManager->MovePageToFront(pageNode, needHideLast, needTransition)) {
1700         // restore position and param.
1701         pageRouterStack_.pop_back();
1702         pageRouterStack_.insert(last, pageNode);
1703         if (!tempParam.empty()) {
1704             pageInfo->ReplacePageParams(tempParam);
1705         }
1706         pageInfo->ReplaceRecoverable(tempRecoverable);
1707     }
1708 
1709     // update index in pageInfo
1710     int32_t restorePageNumber = static_cast<int32_t>(restorePageStack_.size());
1711     RefreshPageIndex(last, index + restorePageNumber);
1712 }
1713 
RefreshPageIndex(std::list<WeakPtr<FrameNode>>::iterator startIter,int32_t startIndex)1714 void PageRouterManager::RefreshPageIndex(std::list<WeakPtr<FrameNode>>::iterator startIter, int32_t startIndex)
1715 {
1716     for (; startIter != pageRouterStack_.end(); ++startIter, ++startIndex) {
1717         auto pageNode = startIter->Upgrade();
1718         if (!pageNode) {
1719             continue;
1720         }
1721         auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
1722         if (pagePattern) {
1723             pagePattern->GetPageInfo()->SetPageIndex(startIndex + 1);
1724         }
1725     }
1726 }
1727 
RefreshAllPageIndex()1728 void PageRouterManager::RefreshAllPageIndex()
1729 {
1730     int32_t restorePageNumber = static_cast<int32_t>(restorePageStack_.size());
1731     RefreshPageIndex(pageRouterStack_.begin(), restorePageNumber);
1732 }
1733 
RestorePageWithTarget(int32_t index,bool removeRestorePages,const RouterPageInfo & target,RestorePageDestination dest,bool needTransition)1734 void PageRouterManager::RestorePageWithTarget(int32_t index, bool removeRestorePages,
1735     const RouterPageInfo& target, RestorePageDestination dest, bool needTransition)
1736 {
1737     TAG_LOGI(AceLogTag::ACE_ROUTER, "restore page with target, index: %{public}d, removeRestorePages: %{public}s, "
1738         "target.url: %{public}s, dest: %{public}d", index, removeRestorePages ? "yes" : "no", target.url.c_str(), dest);
1739     RouterPageInfo info = target;
1740     auto iter = restorePageStack_.begin();
1741     std::advance(iter, index);
1742     info.url = iter->url;
1743     info.isNamedRouterMode = iter->isNamedRouter;
1744     info.recoverable = true;
1745     if (!info.errorCallback) {
1746         info.errorCallback = [](const std::string& errorMsg, int32_t errorCode) {
1747             TAG_LOGE(AceLogTag::ACE_ROUTER, "restore page with target error: %{public}d, msg: %{public}s",
1748                 errorCode, errorMsg.c_str());
1749         };
1750     }
1751     if (removeRestorePages) {
1752         restorePageStack_.erase(iter, restorePageStack_.end());
1753     } else {
1754         restorePageStack_.erase(iter);
1755     }
1756 
1757     if (info.isNamedRouterMode) {
1758         if (manifestParser_) {
1759             if (manifestParser_->GetRouter()->GetPagePath(info.url).empty()) {
1760                 manifestParser_->SetPagePath(info.url);
1761             }
1762         }
1763     }
1764 
1765     if (info.isNamedRouterMode) {
1766         auto callback = [weak = AceType::WeakClaim(this), info, dest, needTransition]() {
1767             auto pageRouterManager = weak.Upgrade();
1768             CHECK_NULL_VOID(pageRouterManager);
1769             pageRouterManager->RestorePageWithTargetInner(info, dest, needTransition);
1770         };
1771         /**
1772          * Always check if the namedRoute page needs to be preloaded.
1773          * @sa PageRouterManager::RestoreRouterStack() & PageRouterManager::GetStackInfo()
1774          */
1775         if (TryPreloadNamedRouter(info.url, std::move(callback))) {
1776             return;
1777         }
1778     }
1779 
1780     RestorePageWithTargetInner(info, dest, needTransition);
1781 }
1782 
RestorePageWithTargetInner(const RouterPageInfo & target,RestorePageDestination dest,bool needTransition)1783 void PageRouterManager::RestorePageWithTargetInner(
1784     const RouterPageInfo& target, RestorePageDestination dest, bool needTransition)
1785 {
1786     /**
1787      * use 'A' to represent pages in restorePageStack_, use 'B' to represent pages in pageRouterStack_
1788      *
1789      * Case1(RestorePageDestination::TOP), eg: router.pushUrl(options, RouterMode.SINGLE)
1790      *  +---+---+---+---+---+        +---+---+---+
1791      *  | A | A | A | A | A |        | B | B |   |
1792      *  +---+---+---+---+---+        +---+---+ ^ +
1793      *            |                            |
1794      *            +----------------------------+
1795      *
1796      * Case2(RestorePageDestination::BELLOW_TOP), eg:
1797      *  router.back()
1798      *  +---+---+---+---+---+    +---+---+
1799      *  | A | A | A | A | A |    |   | B |
1800      *  +---+---+---+---+---+    + ^ +---+
1801      *                    |        |
1802      *                    +--------+
1803      *
1804      *  router.replacePath({url: 'page/Index'}, RouterMode.SINGLE) (newLifeCycle)
1805      *  +---+---+---+---+---+        +---+---+
1806      *  | A | A | A | A | A |        | B | B |
1807      *  +---+---+---+---+---+        +---+---+
1808      *            |                      ^
1809      *            |                      |
1810      *            +----------------------+
1811      *
1812      * Case3(RestorePageDestination::BOTTOM), eg: router.back(3), router.back({url: 'page/Index'})
1813      *  +---+---+---+---+---+    +---+---+---+
1814      *  | A | A | A | A | A |    |   | B | B |
1815      *  +---+---+---+---+---+    + ^ +---+---+
1816      *            |                |
1817      *            +----------------+
1818      *
1819      * Router page restore steps:
1820      * 1. create page
1821      * 2. insert page
1822      * 3. pop page (optional)
1823      * 4. refresh all page's index (optional)
1824      */
1825     std::function<void()> callback = nullptr;
1826     // step3 & step4 pop page, refresh all page's index
1827     if (dest == RestorePageDestination::TOP) {
1828         callback = [weak = WeakClaim(this)] {
1829             auto mgr = weak.Upgrade();
1830             CHECK_NULL_VOID(mgr);
1831             mgr->RefreshAllPageIndex();
1832         };
1833     } else if (dest == RestorePageDestination::BELLOW_TOP) {
1834         callback = [weak = WeakClaim(this), needTransition] {
1835             auto mgr = weak.Upgrade();
1836             CHECK_NULL_VOID(mgr);
1837             mgr->PopPage("", true, needTransition, false);
1838         };
1839     } else if (dest == RestorePageDestination::BOTTOM) {
1840         callback = [weak = WeakClaim(this), params = target.params] {
1841             auto mgr = weak.Upgrade();
1842             CHECK_NULL_VOID(mgr);
1843             mgr->PopPageToIndex(0, params, true, true);
1844             mgr->RefreshAllPageIndex();
1845         };
1846     }
1847 
1848     StartRestorePageWithTarget(target, std::move(callback), dest, needTransition);
1849 }
1850 
StartRestorePageWithTarget(const RouterPageInfo & target,std::function<void ()> && finishCallback,RestorePageDestination dest,bool needTransition)1851 void PageRouterManager::StartRestorePageWithTarget(const RouterPageInfo& target,
1852     std::function<void()>&& finishCallback, RestorePageDestination dest, bool needTransition)
1853 {
1854     if (target.url.empty()) {
1855         return;
1856     }
1857 
1858     CHECK_RUN_ON(JS);
1859     if (inRouterOpt_) {
1860         auto context = PipelineContext::GetCurrentContext();
1861         CHECK_NULL_VOID(context);
1862         context->PostAsyncEvent(
1863             [weak = WeakClaim(this), target, callback = std::move(finishCallback), dest, needTransition]() mutable {
1864                 auto router = weak.Upgrade();
1865                 CHECK_NULL_VOID(router);
1866                 router->StartRestorePageWithTarget(target, std::move(callback), dest, needTransition);
1867             }, "ArkUIPageRouterRestorePageWithTarget", TaskExecutor::TaskType::JS);
1868         return;
1869     }
1870 
1871     RouterOptScope scope(this);
1872     RefPtr<FrameNode> pageNode = nullptr;
1873     // step1: create page
1874     if (target.isNamedRouterMode) {
1875         CleanPageOverlay();
1876         pageNode = CreatePage(GenerateNextPageId(), target);
1877     } else {
1878 #if !defined(PREVIEW)
1879         if (target.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1880             auto restoreTask = [weak = AceType::WeakClaim(this), target, finishCb = std::move(finishCallback),
1881                 dest, needTransition]() mutable {
1882                     auto pageRouterManager = weak.Upgrade();
1883                     CHECK_NULL_VOID(pageRouterManager);
1884                     pageRouterManager->RestoreOhmUrl(target, std::move(finishCb), dest, needTransition);
1885                 };
1886             LoadOhmUrlPage(target.url, std::move(restoreTask), target.errorCallback,
1887                 "ArkUIPageRouterRestoreOhmUrl", "ArkUIPageRouterRestoreErrorCallback");
1888             return;
1889         }
1890 #endif
1891         if (!manifestParser_) {
1892             return;
1893         }
1894 
1895         RouterPageInfo info = target;
1896         info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
1897         if (info.path.empty()) {
1898             TAG_LOGW(AceLogTag::ACE_ROUTER,
1899                 "empty path found in StartRestorePageWithTarget with url: %{public}s", info.url.c_str());
1900             if (info.errorCallback != nullptr) {
1901                 info.errorCallback("The URI of the page to redirect is incorrect or does not exist.",
1902                     ERROR_CODE_URI_ERROR);
1903             }
1904             return;
1905         }
1906 
1907         CleanPageOverlay();
1908         pageNode = CreatePage(GenerateNextPageId(), info);
1909     }
1910     if (!pageNode) {
1911         return;
1912     }
1913 
1914     // step2: insert page
1915     if (dest == RestorePageDestination::TOP) {
1916         PushPageToTop(pageNode, std::move(finishCallback), needTransition);
1917     } else if (dest == RestorePageDestination::BELLOW_TOP) {
1918         InsertPageBellowTop(pageNode, std::move(finishCallback));
1919     } else if (dest == RestorePageDestination::BOTTOM) {
1920         InsertPageToBottom(pageNode, std::move(finishCallback));
1921     }
1922 }
1923 
FlushFrontend()1924 void PageRouterManager::FlushFrontend()
1925 {
1926     auto currentPage = GetCurrentPageNode();
1927     CHECK_NULL_VOID(currentPage);
1928     auto customNode = DynamicCast<CustomNode>(currentPage->GetFirstChild());
1929     CHECK_NULL_VOID(customNode);
1930     customNode->FlushReload();
1931 }
1932 
PopPage(const std::string & params,bool needShowNext,bool needTransition,bool needReplaceParams)1933 void PageRouterManager::PopPage(
1934     const std::string& params, bool needShowNext, bool needTransition, bool needReplaceParams)
1935 {
1936     CHECK_RUN_ON(JS);
1937     if (pageRouterStack_.empty()) {
1938         TAG_LOGW(AceLogTag::ACE_ROUTER, "Page router stack size is zero, can not pop");
1939         return;
1940     }
1941     if (needShowNext && (pageRouterStack_.size() == 1)) {
1942         TAG_LOGW(AceLogTag::ACE_ROUTER, "Page router stack size is only one, can not show next");
1943         return;
1944     }
1945     auto topNode = pageRouterStack_.back();
1946     pageRouterStack_.pop_back();
1947     if (!needShowNext) {
1948         if (!OnPopPage(needShowNext, needTransition)) {
1949             pageRouterStack_.emplace_back(topNode);
1950         }
1951         return;
1952     }
1953 
1954     // update param first.
1955     auto nextNode = GetCurrentPageNode();
1956     CHECK_NULL_VOID(nextNode);
1957     auto pagePattern = nextNode->GetPattern<PagePattern>();
1958     CHECK_NULL_VOID(pagePattern);
1959     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1960     CHECK_NULL_VOID(pageInfo);
1961     std::string oldParams;
1962     if (needReplaceParams) {
1963         oldParams = pageInfo->ReplacePageParams(params);
1964     }
1965 
1966     if (OnPopPage(needShowNext, needTransition)) {
1967         return;
1968     }
1969     // restore stack and pageParam.
1970     pageRouterStack_.emplace_back(topNode);
1971     if (needReplaceParams) {
1972         pageInfo->ReplacePageParams(oldParams);
1973     }
1974 }
1975 
PopPageToIndex(int32_t index,const std::string & params,bool needShowNext,bool needTransition)1976 void PageRouterManager::PopPageToIndex(int32_t index, const std::string& params, bool needShowNext, bool needTransition)
1977 {
1978     TAG_LOGI(AceLogTag::ACE_ROUTER, "pop page to %{public}d", index);
1979     std::list<WeakPtr<FrameNode>> temp;
1980     std::swap(temp, pageRouterStack_);
1981     auto iter = temp.begin();
1982     for (int32_t current = 0; current <= index; ++current) {
1983         pageRouterStack_.emplace_back(*iter);
1984         ++iter;
1985     }
1986 
1987     // update param first.
1988     auto nextNode = GetCurrentPageNode();
1989     CHECK_NULL_VOID(nextNode);
1990     auto pagePattern = nextNode->GetPattern<PagePattern>();
1991     CHECK_NULL_VOID(pagePattern);
1992     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1993     CHECK_NULL_VOID(pageInfo);
1994     auto tempParam = pageInfo->ReplacePageParams(params);
1995     if (OnPopPageToIndex(index, needShowNext, needTransition)) {
1996         return;
1997     }
1998 
1999     // restore stack and pageParam.
2000     std::swap(temp, pageRouterStack_);
2001     pageInfo->ReplacePageParams(tempParam);
2002 }
2003 
OnPageReady(const RefPtr<FrameNode> & pageNode,bool needHideLast,bool needTransition,bool isCardRouter,int64_t cardId)2004 bool PageRouterManager::OnPageReady(const RefPtr<FrameNode>& pageNode, bool needHideLast, bool needTransition,
2005     bool isCardRouter, int64_t cardId)
2006 {
2007     Recorder::NodeDataCache::Get().OnPageReady();
2008     auto container = Container::Current();
2009     CHECK_NULL_RETURN(container, false);
2010     RefPtr<PipelineBase> pipeline;
2011     if (isCardRouter) {
2012         auto weak = container->GetCardPipeline(cardId);
2013         pipeline = weak.Upgrade();
2014         CHECK_NULL_RETURN(pipeline, false);
2015     } else {
2016         pipeline = container->GetPipelineContext();
2017         CHECK_NULL_RETURN(pipeline, false);
2018     }
2019 
2020     auto context = DynamicCast<NG::PipelineContext>(pipeline);
2021     auto stageManager = context ? context->GetStageManager() : nullptr;
2022     if (stageManager) {
2023         return stageManager->PushPage(pageNode, needHideLast, needTransition);
2024     }
2025     return false;
2026 }
2027 
OnPageReadyAndHandleIntent(const RefPtr<FrameNode> & pageNode,bool needHideLast)2028 bool PageRouterManager::OnPageReadyAndHandleIntent(const RefPtr<FrameNode>& pageNode, bool needHideLast)
2029 {
2030     auto container = Container::Current();
2031     CHECK_NULL_RETURN(container, false);
2032     auto pipeline = container->GetPipelineContext();
2033     CHECK_NULL_RETURN(pipeline, false);
2034     auto context = DynamicCast<NG::PipelineContext>(pipeline);
2035     CHECK_NULL_RETURN(context, false);
2036     auto stageManager = context->GetStageManager();
2037     CHECK_NULL_RETURN(stageManager, false);
2038     std::function<bool()> pushIntentPageCallback = [weak = AceType::WeakClaim(this)]() {
2039         auto pageRouterManager = weak.Upgrade();
2040         CHECK_NULL_RETURN(pageRouterManager, false);
2041         pageRouterManager->RunIntentPage();
2042         return true;
2043     };
2044     return stageManager->PushPage(pageNode, needHideLast, false, std::move(pushIntentPageCallback));
2045 }
2046 
OnPopPage(bool needShowNext,bool needTransition)2047 bool PageRouterManager::OnPopPage(bool needShowNext, bool needTransition)
2048 {
2049     auto container = Container::Current();
2050     CHECK_NULL_RETURN(container, false);
2051     auto pipeline = container->GetPipelineContext();
2052     CHECK_NULL_RETURN(pipeline, false);
2053     auto context = DynamicCast<NG::PipelineContext>(pipeline);
2054     auto stageManager = context ? context->GetStageManager() : nullptr;
2055     if (stageManager) {
2056         Recorder::NodeDataCache::Get().OnBeforePagePop();
2057         return stageManager->PopPage(GetCurrentPageNode(), needShowNext, needTransition);
2058     }
2059     return false;
2060 }
2061 
OnPopPageToIndex(int32_t index,bool needShowNext,bool needTransition)2062 bool PageRouterManager::OnPopPageToIndex(int32_t index, bool needShowNext, bool needTransition)
2063 {
2064     auto container = Container::Current();
2065     CHECK_NULL_RETURN(container, false);
2066     auto pipeline = container->GetPipelineContext();
2067     CHECK_NULL_RETURN(pipeline, false);
2068     auto context = DynamicCast<NG::PipelineContext>(pipeline);
2069     auto stageManager = context ? context->GetStageManager() : nullptr;
2070     if (stageManager) {
2071         Recorder::NodeDataCache::Get().OnBeforePagePop();
2072         return stageManager->PopPageToIndex(index, needShowNext, needTransition);
2073     }
2074     return false;
2075 }
2076 
OnCleanPageStack()2077 bool PageRouterManager::OnCleanPageStack()
2078 {
2079     auto container = Container::Current();
2080     CHECK_NULL_RETURN(container, false);
2081     auto pipeline = container->GetPipelineContext();
2082     CHECK_NULL_RETURN(pipeline, false);
2083     auto context = DynamicCast<NG::PipelineContext>(pipeline);
2084     auto stageManager = context ? context->GetStageManager() : nullptr;
2085     if (stageManager) {
2086         return stageManager->CleanPageStack();
2087     }
2088     return false;
2089 }
2090 
CleanPageOverlay()2091 void PageRouterManager::CleanPageOverlay()
2092 {
2093     auto container = Container::Current();
2094     CHECK_NULL_VOID(container);
2095     auto pipeline = container->GetPipelineContext();
2096     CHECK_NULL_VOID(pipeline);
2097     auto context = DynamicCast<NG::PipelineContext>(pipeline);
2098     CHECK_NULL_VOID(context);
2099     auto overlayManager = context->GetOverlayManager();
2100     CHECK_NULL_VOID(overlayManager);
2101     auto taskExecutor = context->GetTaskExecutor();
2102     CHECK_NULL_VOID(taskExecutor);
2103     auto sharedManager = context->GetSharedOverlayManager();
2104     if (sharedManager) {
2105         sharedManager->StopSharedTransition();
2106     }
2107 
2108     overlayManager->RemoveOverlay(true, true);
2109 }
2110 
DealReplacePage(const RouterPageInfo & info)2111 void PageRouterManager::DealReplacePage(const RouterPageInfo& info)
2112 {
2113     UiSessionManager::GetInstance()->OnRouterChange(info.url, "routerReplacePage");
2114     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
2115         ReplacePageInNewLifecycle(info);
2116         return;
2117     }
2118     TAG_LOGI(AceLogTag::ACE_ROUTER,
2119         "router replace in old lifecycle(API version < 12), replace mode: %{public}d, url: %{public}s",
2120         static_cast<int32_t>(info.routerMode), info.url.c_str());
2121     PopPage("", false, false);
2122     if (info.routerMode == RouterMode::SINGLE) {
2123         auto pageInfo = FindPageInStack(info.url);
2124         if (pageInfo.second) {
2125             // find page in stack, move position and update params.
2126             MovePageToFront(pageInfo.first, pageInfo.second, info, false, true, false);
2127             return;
2128         }
2129         auto index = FindPageInRestoreStack(info.url);
2130         if (index != INVALID_PAGE_INDEX) {
2131             // find page in restore page, create page, move position and update params.
2132             RestorePageWithTarget(index, false, info, RestorePageDestination::TOP, false);
2133             return;
2134         }
2135     }
2136     LoadPage(GenerateNextPageId(), info, false, false);
2137 }
2138 
CheckIndexValid(int32_t index) const2139 bool PageRouterManager::CheckIndexValid(int32_t index) const
2140 {
2141     if (index > GetStackSize() || index <= 0) {
2142         TAG_LOGW(AceLogTag::ACE_ROUTER,
2143             "The index is less than or equal to zero or exceeds the maximum length of the page stack");
2144         return false;
2145     }
2146     return true;
2147 }
2148 
CheckOhmUrlValid(const std::string & ohmUrl)2149 bool PageRouterManager::CheckOhmUrlValid(const std::string& ohmUrl)
2150 {
2151     size_t bundleEndPos = ohmUrl.find('/');
2152     std::string bundleName = ohmUrl.substr(BUNDLE_START_POS, bundleEndPos - BUNDLE_START_POS);
2153     size_t moduleStartPos = bundleEndPos + 1;
2154     size_t moduleEndPos = ohmUrl.find('/', moduleStartPos);
2155     std::string moduleName = ohmUrl.substr(moduleStartPos, moduleEndPos - moduleStartPos);
2156     auto runtime = std::static_pointer_cast<Framework::ArkJSRuntime>(
2157         Framework::JsiDeclarativeEngineInstance::GetCurrentRuntime());
2158     return runtime->IsExecuteModuleInAbcFile(bundleName, moduleName, ohmUrl);
2159 }
2160 
ThrowError(const std::string & msg,int32_t code)2161 void PageRouterManager::ThrowError(const std::string& msg, int32_t code)
2162 {
2163     auto runtime = std::static_pointer_cast<Framework::ArkJSRuntime>(
2164         Framework::JsiDeclarativeEngineInstance::GetCurrentRuntime());
2165     runtime->ThrowError(msg, code);
2166 }
2167 
GetPageIndex(const WeakPtr<FrameNode> & page)2168 int32_t PageRouterManager::GetPageIndex(const WeakPtr<FrameNode>& page)
2169 {
2170     auto pageNode = page.Upgrade();
2171     CHECK_NULL_RETURN(pageNode, INVALID_PAGE_INDEX);
2172     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
2173     CHECK_NULL_RETURN(pagePattern, INVALID_PAGE_INDEX);
2174     auto ret = pagePattern->GetPageInfo()->GetPageIndex();
2175     // frontend index counts from 1, so need -1 for backend use
2176     return ret == INVALID_PAGE_INDEX ? INVALID_PAGE_INDEX : ret - 1;
2177 }
2178 
ReplacePageInNewLifecycle(const RouterPageInfo & info)2179 void PageRouterManager::ReplacePageInNewLifecycle(const RouterPageInfo& info)
2180 {
2181     auto pipelineContext = PipelineContext::GetCurrentContext();
2182     CHECK_NULL_VOID(pipelineContext);
2183     auto stageManager = pipelineContext->GetStageManager();
2184     CHECK_NULL_VOID(stageManager);
2185     TAG_LOGI(AceLogTag::ACE_ROUTER,
2186         "router replace in new lifecycle(API version > 11), replace mode: %{public}d, url: %{public}s",
2187         static_cast<int32_t>(info.routerMode), info.url.c_str());
2188     auto popNode = GetCurrentPageNode();
2189     int32_t popIndex = static_cast<int32_t>(pageRouterStack_.size()) - 1;
2190     bool findPage = false;
2191     if (info.routerMode == RouterMode::SINGLE) {
2192         auto pageInfo = FindPageInStack(info.url);
2193         // haven't find page by named route's name. Try again with its page path.
2194         if (pageInfo.second == nullptr && info.isNamedRouterMode) {
2195             std::string pagePath = Framework::JsiDeclarativeEngine::GetPagePath(info.url);
2196             pageInfo = FindPageInStack(pagePath);
2197         }
2198         if (pageInfo.first == popIndex) {
2199             // replace top self in SINGLE mode, do nothing.
2200             CHECK_NULL_VOID(pageInfo.second);
2201             auto pagePattern = pageInfo.second->GetPattern<PagePattern>();
2202             if (pagePattern) {
2203                 pagePattern->FireOnNewParam(info.params);
2204             }
2205             return;
2206         }
2207         if (pageInfo.second) {
2208             // find page in stack, move position and update params.
2209 #if defined(ENABLE_SPLIT_MODE)
2210             stageManager->SetIsNewPageReplacing(true);
2211 #endif
2212             MovePageToFront(pageInfo.first, pageInfo.second, info, false, true, false);
2213 #if defined(ENABLE_SPLIT_MODE)
2214             stageManager->SetIsNewPageReplacing(false);
2215 #endif
2216             popIndex = popIndex - 1;
2217             findPage = true;
2218             auto pagePattern = pageInfo.second->GetPattern<PagePattern>();
2219             if (pagePattern) {
2220                 pagePattern->FireOnNewParam(info.params);
2221             }
2222         } else {
2223             auto index = FindPageInRestoreStack(info.url);
2224             if (index != INVALID_PAGE_INDEX) {
2225                 // find page in restore page, create page, move position and update params.
2226                 RestorePageWithTarget(index, false, info, RestorePageDestination::BELLOW_TOP, false);
2227                 return;
2228             }
2229         }
2230     }
2231     if (!findPage) {
2232         isNewPageReplacing_ = true;
2233 #if defined(ENABLE_SPLIT_MODE)
2234         stageManager->SetIsNewPageReplacing(true);
2235 #endif
2236         LoadPage(GenerateNextPageId(), info, true, false);
2237 #if defined(ENABLE_SPLIT_MODE)
2238         stageManager->SetIsNewPageReplacing(false);
2239 #endif
2240         isNewPageReplacing_ = false;
2241     }
2242     if (popIndex < 0 || popNode == GetCurrentPageNode() || GetPageIndex(popNode) != popIndex) {
2243         return;
2244     }
2245     auto iter = pageRouterStack_.begin();
2246     std::advance(iter, popIndex);
2247     auto lastIter = pageRouterStack_.erase(iter);
2248     pageRouterStack_.emplace_back(WeakPtr<FrameNode>(AceType::DynamicCast<FrameNode>(popNode)));
2249     popNode->MovePosition(GetLastPageIndex());
2250     for (auto iter = lastIter; iter != pageRouterStack_.end(); ++iter, ++popIndex) {
2251         auto page = iter->Upgrade();
2252         if (!page) {
2253             continue;
2254         }
2255         if (page == popNode) {
2256             // do not change index of page that will be replaced.
2257             continue;
2258         }
2259         auto pagePattern = page->GetPattern<NG::PagePattern>();
2260         pagePattern->GetPageInfo()->SetPageIndex(popIndex + 1);
2261     }
2262 #if defined(ENABLE_SPLIT_MODE)
2263     stageManager->SetIsNewPageReplacing(true);
2264 #endif
2265     PopPage("", false, false);
2266 #if defined(ENABLE_SPLIT_MODE)
2267     stageManager->SetIsNewPageReplacing(false);
2268 #endif
2269 }
2270 
RestoreOhmUrl(const RouterPageInfo & target,std::function<void ()> && finishCallback,RestorePageDestination dest,bool needTransition)2271 void PageRouterManager::RestoreOhmUrl(const RouterPageInfo& target, std::function<void()>&& finishCallback,
2272     RestorePageDestination dest, bool needTransition)
2273 {
2274     RouterPageInfo info = target;
2275     info.path = info.url + ".js";
2276     auto pageNode = CreatePage(GenerateNextPageId(), info);
2277     if (!pageNode) {
2278         return;
2279     }
2280 
2281     if (dest == RestorePageDestination::TOP) {
2282         PushPageToTop(pageNode, std::move(finishCallback), needTransition);
2283     } else if (dest == RestorePageDestination::BELLOW_TOP) {
2284         InsertPageBellowTop(pageNode, std::move(finishCallback));
2285     } else if (dest == RestorePageDestination::BOTTOM) {
2286         InsertPageToBottom(pageNode, std::move(finishCallback));
2287     }
2288 }
2289 
InsertPageBellowTop(RefPtr<FrameNode> & pageNode,std::function<void ()> && finishCallback)2290 void PageRouterManager::InsertPageBellowTop(RefPtr<FrameNode>& pageNode, std::function<void()>&& finishCallback)
2291 {
2292     auto context = DynamicCast<NG::PipelineContext>(PipelineContext::GetCurrentContext());
2293     auto stageManager = context ? context->GetStageManager() : nullptr;
2294     if (!stageManager) {
2295         return;
2296     }
2297 
2298     if (pageRouterStack_.empty()) {
2299         TAG_LOGE(AceLogTag::ACE_ROUTER, "empty stack when insert page bellow top");
2300         return;
2301     }
2302     auto backupStack = pageRouterStack_;
2303     auto it = pageRouterStack_.end();
2304     --it;
2305     pageRouterStack_.insert(it, WeakPtr<FrameNode>(pageNode));
2306 
2307     insertPageProcessingType_ = InsertPageProcessingType::INSERT_BELLOW_TOP;
2308     if (!stageManager->InsertPage(pageNode, true)) {
2309         insertPageProcessingType_ = InsertPageProcessingType::NONE;
2310         std::swap(backupStack, pageRouterStack_);
2311         return;
2312     }
2313     insertPageProcessingType_ = InsertPageProcessingType::NONE;
2314 
2315     if (finishCallback) {
2316         finishCallback();
2317     }
2318 }
2319 
PushPageToTop(RefPtr<FrameNode> & pageNode,std::function<void ()> && finishCallback,bool needTransition)2320 void PageRouterManager::PushPageToTop(
2321     RefPtr<FrameNode>& pageNode, std::function<void()>&& finishCallback, bool needTransition)
2322 {
2323     pageRouterStack_.emplace_back(pageNode);
2324     if (!OnPageReady(pageNode, true, needTransition)) {
2325         pageRouterStack_.pop_back();
2326     }
2327 
2328     if (finishCallback) {
2329         finishCallback();
2330     }
2331 }
2332 
InsertPageToBottom(RefPtr<FrameNode> & pageNode,std::function<void ()> && finishCallback)2333 void PageRouterManager::InsertPageToBottom(RefPtr<FrameNode>& pageNode, std::function<void()>&& finishCallback)
2334 {
2335     auto context = DynamicCast<NG::PipelineContext>(PipelineContext::GetCurrentContext());
2336     auto stageManager = context ? context->GetStageManager() : nullptr;
2337     if (!stageManager) {
2338         return;
2339     }
2340 
2341     if (pageRouterStack_.empty()) {
2342         TAG_LOGW(AceLogTag::ACE_ROUTER, "empty stack when insert page to bottom");
2343         return;
2344     }
2345     pageRouterStack_.insert(pageRouterStack_.begin(), WeakPtr<FrameNode>(pageNode));
2346 
2347     insertPageProcessingType_ = InsertPageProcessingType::INSERT_BOTTOM;
2348     if (!stageManager->InsertPage(pageNode, false)) {
2349         insertPageProcessingType_ = InsertPageProcessingType::NONE;
2350         if (!pageRouterStack_.empty()) {
2351             pageRouterStack_.pop_front();
2352         }
2353         return;
2354     }
2355     insertPageProcessingType_ = InsertPageProcessingType::NONE;
2356 
2357     if (finishCallback) {
2358         finishCallback();
2359     }
2360 }
2361 
LoadOhmUrlPage(const std::string & url,std::function<void ()> && finishCallback,const std::function<void (const std::string & errorMsg,int32_t errorCode)> & errorCallback,const std::string & finishCallbackTaskName,const std::string & errorCallbackTaskName)2362 void PageRouterManager::LoadOhmUrlPage(const std::string& url, std::function<void()>&& finishCallback,
2363     const std::function<void(const std::string& errorMsg, int32_t errorCode)>& errorCallback,
2364     const std::string& finishCallbackTaskName, const std::string& errorCallbackTaskName)
2365 {
2366     auto container = Container::Current();
2367     CHECK_NULL_VOID(container);
2368     auto pageUrlChecker = container->GetPageUrlChecker();
2369     CHECK_NULL_VOID(pageUrlChecker);
2370     auto instanceId = container->GetInstanceId();
2371     auto taskExecutor = container->GetTaskExecutor();
2372     CHECK_NULL_VOID(taskExecutor);
2373     auto callback = [taskExecutor, instanceId, task = std::move(finishCallback), finishCallbackTaskName]() {
2374             ContainerScope scope(instanceId);
2375             taskExecutor->PostTask(task, TaskExecutor::TaskType::JS, finishCallbackTaskName,
2376                 TaskExecutor::GetPriorityTypeWithCheck(PriorityType::VIP));
2377         };
2378 
2379     auto silentInstallErrorCallBack = [errorCb = errorCallback, taskExecutor, instanceId, errorCallbackTaskName](
2380         int32_t errorCode, const std::string& errorMsg) {
2381         if (!errorCb) {
2382             TAG_LOGW(AceLogTag::ACE_ROUTER, "errorCallback is null");
2383             return;
2384         }
2385         ContainerScope scope(instanceId);
2386         taskExecutor->PostTask([errorCb, errorCode, errorMsg]() { errorCb(errorMsg, errorCode); },
2387             TaskExecutor::TaskType::JS, errorCallbackTaskName,
2388             TaskExecutor::GetPriorityTypeWithCheck(PriorityType::VIP));
2389     };
2390     pageUrlChecker->LoadPageUrl(url, callback, silentInstallErrorCallBack);
2391 }
2392 
SetPageInfoRouteName(const RefPtr<EntryPageInfo> & info)2393 void PageRouterManager::SetPageInfoRouteName(const RefPtr<EntryPageInfo>& info)
2394 {
2395     std::optional<std::string> routeName = std::nullopt;
2396     if (info->IsCreateByNamedRouter()) {
2397         // info->GetPageUrl() represents the name of namedRoute
2398         routeName = info->GetPageUrl();
2399     } else {
2400         auto container = Container::Current();
2401         CHECK_NULL_VOID(container);
2402         // info->GetPageUrl() represents the url of destination page
2403         routeName = Framework::JsiDeclarativeEngine::GetRouteNameByUrl(
2404             info->GetPageUrl(), container->GetBundleName(), container->GetModuleName());
2405     }
2406     info->SetRouteName(routeName);
2407 }
2408 
UpdateSrcPage()2409 void PageRouterManager::UpdateSrcPage()
2410 {
2411     auto pipelineContext = PipelineContext::GetCurrentContext();
2412     CHECK_NULL_VOID(pipelineContext);
2413     auto stageManager = pipelineContext->GetStageManager();
2414     CHECK_NULL_VOID(stageManager);
2415     stageManager->SetSrcPage(GetCurrentPageNode());
2416 }
2417 
RunIntentPage()2418 void PageRouterManager::RunIntentPage()
2419 {
2420     if (!intentInfo_.has_value()) {
2421         return;
2422     }
2423     auto pageInfo = FindIntentPageInStack();
2424     if (pageInfo.second) {
2425         bool routerNeedTransition = pageInfo.first != static_cast<int32_t>(pageRouterStack_.size()) - 1;
2426         if (!routerNeedTransition && intentInfo_.value().isColdStart) {
2427             // cold start case, fire router home page's onPageShow
2428             StageManager::FirePageShow(pageInfo.second, PageTransitionType::NONE);
2429         }
2430         // fire navigation's intent firstly
2431         bool fireNavigationIntentActivelySuccess = FireNavigationIntentActively(
2432             pageInfo.second->GetId(), !routerNeedTransition);
2433         // find page in stack, move postion and update params.
2434         if (!fireNavigationIntentActivelySuccess) {
2435             auto pagePattern = pageInfo.second->GetPattern<PagePattern>();
2436             if (pagePattern) {
2437                 pagePattern->FireOnNewParam(intentInfo_.value().param);
2438             }
2439         }
2440         RouterPageInfo newInfo;
2441         newInfo.params = intentInfo_.value().param;
2442         intentInfo_.reset();
2443         MovePageToFront(pageInfo.first, pageInfo.second, newInfo, true);
2444         return;
2445     }
2446     auto loadPageCallback = intentInfo_.value().loadPageCallback;
2447     if (loadPageCallback) {
2448         loadPageCallback();
2449     }
2450     RouterPageInfo info;
2451     info.intentInfo = intentInfo_.value();
2452     info.isUseIntent = true;
2453     info.url = intentInfo_.value().pagePath;
2454     info.params = intentInfo_.value().param;
2455     intentInfo_.reset();
2456     RouterOptScope scope(this);
2457     UpdateSrcPage();
2458     LoadPage(GenerateNextPageId(), info, true, !info.intentInfo.isColdStart);
2459 }
2460 
GenerateRouterPageInner(const RouterPageInfo & target)2461 bool PageRouterManager::GenerateRouterPageInner(const RouterPageInfo& target)
2462 {
2463     if (target.isUseIntent) {
2464         auto intentInfo = target.intentInfo;
2465         return generateIntentPageCallback_(intentInfo.bundleName, intentInfo.moduleName, intentInfo.pagePath);
2466     }
2467     if (loadNamedRouter_(target.url, target.isNamedRouterMode)) {
2468         return true;
2469     }
2470     if (!target.isNamedRouterMode) {
2471         return updateRootComponent_();
2472     }
2473     if (target.errorCallback) {
2474         target.errorCallback("The named route is not exist.", ERROR_CODE_NAMED_ROUTE_ERROR);
2475     }
2476     return false;
2477 }
2478 
SetRouterIntentInfo(const std::string & intentInfoSerialized,bool isColdStart,const std::function<void ()> && loadPageCallback)2479 void PageRouterManager::SetRouterIntentInfo(const std::string& intentInfoSerialized, bool isColdStart,
2480     const std::function<void()>&& loadPageCallback)
2481 {
2482     if (intentInfoSerialized.empty()) {
2483         TAG_LOGE(AceLogTag::ACE_ROUTER, "error, serialized intent info is empty!");
2484         return;
2485     }
2486     intentInfo_ = ParseRouterIntentInfo(intentInfoSerialized);
2487     intentInfo_.value().isColdStart = isColdStart;
2488     intentInfo_.value().loadPageCallback = std::move(loadPageCallback);
2489 }
2490 
ParseRouterIntentInfo(const std::string & intentInfoSerialized)2491 RouterIntentInfo PageRouterManager::ParseRouterIntentInfo(const std::string& intentInfoSerialized)
2492 {
2493     RouterIntentInfo intentInfo;
2494     auto intentJson = JsonUtil::ParseJsonString(intentInfoSerialized);
2495     if (!intentJson || !intentJson->IsObject()) {
2496         TAG_LOGE(AceLogTag::ACE_ROUTER, "error, intent info is an invalid json object!");
2497         return intentInfo;
2498     }
2499     intentInfo.bundleName = intentJson->GetString(INTENT_BUNDLE_NAME_KEY, "");
2500     intentInfo.moduleName = intentJson->GetString(INTENT_MODULE_NAME_KEY, "");
2501     intentInfo.pagePath = ParseUrlNameFromOhmUrl(intentJson->GetString(INTENT_PAGE_PATH_KEY, ""));
2502     intentInfo.param = intentJson->GetObject(INTENT_PARAM_KEY)->ToString();
2503     return intentInfo;
2504 }
2505 
FindIntentPageInStack() const2506 std::pair<int32_t, RefPtr<FrameNode>> PageRouterManager::FindIntentPageInStack() const
2507 {
2508     if (!intentInfo_.has_value()) {
2509         return { INVALID_PAGE_INDEX, nullptr };
2510     }
2511     auto iter = std::find_if(pageRouterStack_.rbegin(), pageRouterStack_.rend(),
2512         [pagePath = intentInfo_.value().pagePath](const WeakPtr<FrameNode>& item) {
2513             auto pageNode = item.Upgrade();
2514             CHECK_NULL_RETURN(pageNode, false);
2515             auto pagePattern = pageNode->GetPattern<PagePattern>();
2516             CHECK_NULL_RETURN(pagePattern, false);
2517             auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
2518             CHECK_NULL_RETURN(entryPageInfo, false);
2519             return entryPageInfo->GetPageUrl() == pagePath;
2520         });
2521     if (iter == pageRouterStack_.rend()) {
2522         return { INVALID_PAGE_INDEX, nullptr };
2523     }
2524     // Returns to the forward position.
2525     return { std::distance(iter, pageRouterStack_.rend()) - 1, iter->Upgrade() };
2526 }
2527 
FireNavigationIntentActively(int32_t pageId,bool needTransition)2528 bool PageRouterManager::FireNavigationIntentActively(int32_t pageId, bool needTransition)
2529 {
2530     auto pipeline = PipelineContext::GetCurrentContext();
2531     if (!pipeline) {
2532         return false;
2533     }
2534     auto navigationManager = pipeline->GetNavigationManager();
2535     if (!navigationManager) {
2536         return false;
2537     }
2538     auto fireSuccess = navigationManager->FireNavigationIntentActively(pageId, needTransition);
2539     navigationManager->ResetNavigationIntentInfo();
2540     return fireSuccess;
2541 }
2542 
ParseUrlNameFromOhmUrl(const std::string & ohmUrl)2543 std::string PageRouterManager::ParseUrlNameFromOhmUrl(const std::string& ohmUrl)
2544 {
2545     if (ohmUrl.empty()) {
2546         return "";
2547     }
2548     auto etsTagIndex = ohmUrl.rfind(ETS_TAG);
2549     if (etsTagIndex == std::string::npos) {
2550         return "";
2551     }
2552     auto pageUrlIndex = etsTagIndex + ETS_TAG_LENGTH;
2553     auto andTagIndex = ohmUrl.rfind('&');
2554     if (andTagIndex == std::string::npos || andTagIndex < etsTagIndex) {
2555         andTagIndex = ohmUrl.size();
2556     }
2557     return ohmUrl.substr(pageUrlIndex, andTagIndex - pageUrlIndex);
2558 }
2559 
GetTopNavDestinationInfo(bool onlyFullScreen,bool needParam)2560 std::string PageRouterManager::GetTopNavDestinationInfo(bool onlyFullScreen, bool needParam)
2561 {
2562     std::string serializedEmpty = "{}";
2563     auto pipeline = PipelineContext::GetCurrentContext();
2564     CHECK_NULL_RETURN(pipeline, serializedEmpty);
2565     auto navigationManager = pipeline->GetNavigationManager();
2566     CHECK_NULL_RETURN(navigationManager, serializedEmpty);
2567     auto currentPageNode = GetCurrentPageNode();
2568     if (!currentPageNode) {
2569         TAG_LOGE(AceLogTag::ACE_ROUTER, "current router page node is nullptr!");
2570         return serializedEmpty;
2571     }
2572     return navigationManager->GetTopNavDestinationInfo(currentPageNode->GetId(), onlyFullScreen, needParam);
2573 }
2574 } // namespace OHOS::Ace::NG
2575