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