• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "frameworks/bridge/declarative_frontend/ng/page_router_manager.h"
17 
18 #include <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         auto container = Container::Current();
96         CHECK_NULL_VOID(container);
97         auto pageUrlChecker = container->GetPageUrlChecker();
98         CHECK_NULL_VOID(pageUrlChecker);
99         auto instanceId = container->GetInstanceId();
100         auto taskExecutor = container->GetTaskExecutor();
101         CHECK_NULL_VOID(taskExecutor);
102         info.errorCallback = [](const std::string& errorMsg, int32_t errorCode) {};
103         auto callback = [weak = AceType::WeakClaim(this), info, taskExecutor, instanceId]() {
104             ContainerScope scope(instanceId);
105             auto pageRouterManager = weak.Upgrade();
106             CHECK_NULL_VOID(pageRouterManager);
107             taskExecutor->PostTask(
108                 [pageRouterManager, info]() { pageRouterManager->LoadOhmUrl(info); },
109                 TaskExecutor::TaskType::JS, "ArkUIPageRouterLoadOhmUrl");
110         };
111 
112         auto silentInstallErrorCallBack = [taskExecutor, instanceId](int32_t errorCode, const std::string& errorMsg) {
113             ContainerScope scope(instanceId);
114             taskExecutor->PostTask(
115                 [errorCode, errorMsg]() {
116                     LOGW("Run page error = %{public}d, errorMsg = %{public}s", errorCode, errorMsg.c_str());
117                 },
118                 TaskExecutor::TaskType::JS, "ArkUIPageRouterErrorLog");
119         };
120 
121         pageUrlChecker->LoadPageUrl(url, callback, silentInstallErrorCallBack);
122         return;
123     }
124 #endif
125     if (!info.url.empty()) {
126         info.path = manifestParser_->GetRouter()->GetPagePath(url);
127         if (info.path.empty()) {
128             return;
129         }
130     } else {
131         info.path = manifestParser_->GetRouter()->GetEntry();
132         info.url = manifestParser_->GetRouter()->GetEntry("");
133     }
134     RouterOptScope scope(this);
135     LoadPage(GenerateNextPageId(), info);
136 }
137 
RunPage(const std::shared_ptr<std::vector<uint8_t>> & content,const std::string & params)138 void PageRouterManager::RunPage(const std::shared_ptr<std::vector<uint8_t>>& content, const std::string& params)
139 {
140     CHECK_RUN_ON(JS);
141     RouterPageInfo info;
142     info.content = content;
143     info.params = params;
144 
145 #if !defined(PREVIEW)
146     auto container = Container::Current();
147     CHECK_NULL_VOID(container);
148     auto instanceId = container->GetInstanceId();
149     auto taskExecutor = container->GetTaskExecutor();
150     CHECK_NULL_VOID(taskExecutor);
151     ContainerScope scope(instanceId);
152     auto pageRouterManager = AceType::Claim(this);
153     CHECK_NULL_VOID(pageRouterManager);
154     taskExecutor->PostTask(
155         [pageRouterManager, info]() { pageRouterManager->LoadOhmUrl(info); },
156         TaskExecutor::TaskType::JS, "ArkUIPageRouterLoadOhmUrlContent");
157 #endif
158 }
159 
RunPageByNamedRouter(const std::string & name,const std::string & params)160 void PageRouterManager::RunPageByNamedRouter(const std::string& name, const std::string& params)
161 {
162     RouterPageInfo info { name, params };
163     info.isNamedRouterMode = true;
164     RouterOptScope scope(this);
165     LoadPage(GenerateNextPageId(), info);
166 }
167 
RunCard(const std::string & url,const std::string & params,int64_t cardId,const std::string & entryPoint)168 UIContentErrorCode PageRouterManager::RunCard(
169     const std::string& url, const std::string& params, int64_t cardId, const std::string& entryPoint)
170 {
171     CHECK_RUN_ON(JS);
172     RouterPageInfo info { url };
173 #ifndef PREVIEW
174     if (!info.url.empty()) {
175         info.path = manifestParser_->GetRouter()->GetPagePath(url);
176     } else {
177         info.path = manifestParser_->GetRouter()->GetEntry();
178         info.url = manifestParser_->GetRouter()->GetEntry("");
179     }
180 #endif
181     return LoadCard(0, info, params, cardId, false, true, entryPoint);
182 }
183 
Push(const RouterPageInfo & target)184 void PageRouterManager::Push(const RouterPageInfo& target)
185 {
186     CHECK_RUN_ON(JS);
187     if (inRouterOpt_) {
188         auto context = PipelineContext::GetCurrentContext();
189         CHECK_NULL_VOID(context);
190         context->PostAsyncEvent(
191             [weak = WeakClaim(this), target]() {
192                 auto router = weak.Upgrade();
193                 CHECK_NULL_VOID(router);
194                 router->Push(target);
195             },
196             "ArkUIPageRouterPush", TaskExecutor::TaskType::JS);
197         return;
198     }
199     RouterOptScope scope(this);
200     StartPush(target);
201 }
202 
PushNamedRoute(const RouterPageInfo & target)203 void PageRouterManager::PushNamedRoute(const RouterPageInfo& target)
204 {
205     CHECK_RUN_ON(JS);
206     if (inRouterOpt_) {
207         auto context = PipelineContext::GetCurrentContext();
208         CHECK_NULL_VOID(context);
209         context->PostAsyncEvent(
210             [weak = WeakClaim(this), target]() {
211                 auto router = weak.Upgrade();
212                 CHECK_NULL_VOID(router);
213                 router->PushNamedRoute(target);
214             },
215             "ArkUIPageRouterPushNamedRoute", TaskExecutor::TaskType::JS);
216         return;
217     }
218     RouterOptScope scope(this);
219     if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
220         LOGW("router stack size is larger than max size 32.");
221         if (target.errorCallback != nullptr) {
222             target.errorCallback("The pages are pushed too much.", ERROR_CODE_PAGE_STACK_FULL);
223         }
224         return;
225     }
226     CleanPageOverlay();
227     if (target.routerMode == RouterMode::SINGLE) {
228         auto PageInfoByUrl = FindPageInStackByRouteName(target.url);
229         if (PageInfoByUrl.second) {
230             // find page in stack, move postion and update params.
231             MovePageToFront(PageInfoByUrl.first, PageInfoByUrl.second, target, true);
232             return;
233         }
234     }
235     RouterPageInfo info = target;
236     info.isNamedRouterMode = true;
237     LoadPage(GenerateNextPageId(), info, true, true, true);
238 }
239 
Replace(const RouterPageInfo & target)240 void PageRouterManager::Replace(const RouterPageInfo& target)
241 {
242     CHECK_RUN_ON(JS);
243     if (inRouterOpt_) {
244         auto context = PipelineContext::GetCurrentContext();
245         CHECK_NULL_VOID(context);
246         context->PostAsyncEvent(
247             [weak = WeakClaim(this), target]() {
248                 auto router = weak.Upgrade();
249                 CHECK_NULL_VOID(router);
250                 router->Replace(target);
251             },
252             "ArkUIPageRouterReplace", TaskExecutor::TaskType::JS);
253         return;
254     }
255     RouterOptScope scope(this);
256     StartReplace(target);
257 }
258 
ReplaceNamedRoute(const RouterPageInfo & target)259 void PageRouterManager::ReplaceNamedRoute(const RouterPageInfo& target)
260 {
261     CHECK_RUN_ON(JS);
262     if (inRouterOpt_) {
263         auto context = PipelineContext::GetCurrentContext();
264         CHECK_NULL_VOID(context);
265         context->PostAsyncEvent(
266             [weak = WeakClaim(this), target]() {
267                 auto router = weak.Upgrade();
268                 CHECK_NULL_VOID(router);
269                 router->ReplaceNamedRoute(target);
270             },
271             "ArkUIPageRouterReplaceNamedRoute", TaskExecutor::TaskType::JS);
272         return;
273     }
274     RouterOptScope scope(this);
275     CleanPageOverlay();
276     RouterPageInfo info = target;
277     info.isNamedRouterMode = true;
278     DealReplacePage(info);
279 }
280 
BackWithTarget(const RouterPageInfo & target)281 void PageRouterManager::BackWithTarget(const RouterPageInfo& target)
282 {
283     CHECK_RUN_ON(JS);
284     LOGI("Router back path = %{private}s", target.url.c_str());
285     if (inRouterOpt_) {
286         auto context = PipelineContext::GetCurrentContext();
287         CHECK_NULL_VOID(context);
288         context->PostAsyncEvent(
289             [weak = WeakClaim(this), target]() {
290                 auto router = weak.Upgrade();
291                 CHECK_NULL_VOID(router);
292                 router->BackWithTarget(target);
293             },
294             "ArkUIPageRouterBackWithTarget", TaskExecutor::TaskType::JS);
295         return;
296     }
297     RouterOptScope scope(this);
298     BackCheckAlert(target);
299 }
300 
BackToIndexWithTarget(int32_t index,const std::string & params)301 void PageRouterManager::BackToIndexWithTarget(int32_t index, const std::string& params)
302 {
303     CHECK_RUN_ON(JS);
304     if (!CheckIndexValid(index)) {
305         return;
306     }
307     if (inRouterOpt_) {
308         auto context = PipelineContext::GetCurrentContext();
309         CHECK_NULL_VOID(context);
310         context->PostAsyncEvent(
311             [weak = WeakClaim(this), index, params]() {
312                 auto router = weak.Upgrade();
313                 CHECK_NULL_VOID(router);
314                 router->BackToIndexWithTarget(index, params);
315             },
316             "ArkUIPageRouterBackToIndex", TaskExecutor::TaskType::JS);
317         return;
318     }
319     RouterOptScope scope(this);
320     BackToIndexCheckAlert(index, params);
321 }
322 
Clear()323 void PageRouterManager::Clear()
324 {
325     CHECK_RUN_ON(JS);
326     if (inRouterOpt_) {
327         auto context = PipelineContext::GetCurrentContext();
328         CHECK_NULL_VOID(context);
329         context->PostAsyncEvent(
330             [weak = WeakClaim(this)]() {
331                 auto router = weak.Upgrade();
332                 CHECK_NULL_VOID(router);
333                 router->Clear();
334             },
335             "ArkUIPageRouterClear", TaskExecutor::TaskType::JS);
336         return;
337     }
338     RouterOptScope scope(this);
339     StartClean();
340 }
341 
EnableAlertBeforeBackPage(const std::string & message,std::function<void (int32_t)> && callback)342 void PageRouterManager::EnableAlertBeforeBackPage(const std::string& message, std::function<void(int32_t)>&& callback)
343 {
344     auto currentPage = GetCurrentPageNode();
345     CHECK_NULL_VOID(currentPage);
346     auto pagePattern = currentPage->GetPattern<PagePattern>();
347     CHECK_NULL_VOID(pagePattern);
348     auto pageInfo = pagePattern->GetPageInfo();
349     CHECK_NULL_VOID(pageInfo);
350 
351     DialogProperties dialogProperties = {
352         .content = message,
353         .autoCancel = false,
354         .buttons = { { .text = Localization::GetInstance()->GetEntryLetters("common.cancel"), .textColor = "" },
355             { .text = Localization::GetInstance()->GetEntryLetters("common.ok"), .textColor = "" } },
356         .onSuccess =
357             [weak = AceType::WeakClaim(this), weakPageInfo = AceType::WeakClaim(AceType::RawPtr(pageInfo))](
358                 int32_t successType, int32_t successIndex) {
359                 auto pageInfo = weakPageInfo.Upgrade();
360                 if (pageInfo && pageInfo->GetAlertCallback() && !successType) {
361                     pageInfo->GetAlertCallback()(successIndex);
362                     if (successIndex) {
363                         auto router = weak.Upgrade();
364                         CHECK_NULL_VOID(router);
365                         router->StartBack(router->ngBackTarget_);
366                     }
367                 }
368             },
369     };
370 
371     pageInfo->SetDialogProperties(dialogProperties);
372     pageInfo->SetAlertCallback(std::move(callback));
373 }
374 
DisableAlertBeforeBackPage()375 void PageRouterManager::DisableAlertBeforeBackPage()
376 {
377     if (pageRouterStack_.empty()) {
378         return;
379     }
380     auto currentPage = GetCurrentPageNode();
381     CHECK_NULL_VOID(currentPage);
382     auto pagePattern = currentPage->GetPattern<PagePattern>();
383     CHECK_NULL_VOID(pagePattern);
384     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
385     CHECK_NULL_VOID(pageInfo);
386     pageInfo->SetAlertCallback(nullptr);
387 }
388 
StartClean()389 void PageRouterManager::StartClean()
390 {
391     if (pageRouterStack_.size() <= 1) {
392         return;
393     }
394     std::list<WeakPtr<FrameNode>> temp;
395     std::swap(temp, pageRouterStack_);
396     pageRouterStack_.emplace_back(temp.back());
397     if (!OnCleanPageStack()) {
398         std::swap(temp, pageRouterStack_);
399     } else {
400         auto pageNode = pageRouterStack_.back().Upgrade();
401         if (!pageNode) {
402             return;
403         }
404         auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
405         if (pagePattern) {
406             // the size of pageRouterStack_ should be 1
407             pagePattern->GetPageInfo()->SetPageIndex(static_cast<int32_t>(pageRouterStack_.size()));
408         }
409     }
410 }
411 
Pop()412 bool PageRouterManager::Pop()
413 {
414     CHECK_RUN_ON(JS);
415     if (inRouterOpt_) {
416         TAG_LOGI(AceLogTag::ACE_ROUTER, "router pop is in routeropt");
417         return false;
418     }
419     RouterOptScope scope(this);
420     return StartPop();
421 }
422 
StartPop()423 bool PageRouterManager::StartPop()
424 {
425     CHECK_RUN_ON(JS);
426     auto currentPage = GetCurrentPageNode();
427     CHECK_NULL_RETURN(currentPage, false);
428     auto pagePattern = currentPage->GetPattern<PagePattern>();
429     CHECK_NULL_RETURN(pagePattern, false);
430     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
431     CHECK_NULL_RETURN(pageInfo, false);
432     if (pageInfo->GetAlertCallback()) {
433         TAG_LOGI(AceLogTag::ACE_ROUTER, "pop alert check start");
434         BackCheckAlert(RouterPageInfo());
435         return true;
436     }
437 
438     if (pageRouterStack_.size() <= 1) {
439         if (!restorePageStack_.empty()) {
440             StartRestore(RouterPageInfo());
441             return true;
442         }
443         // the last page.
444         return false;
445     }
446 
447     // pop top page in page stack
448     auto preWeakNode = pageRouterStack_.back();
449     pageRouterStack_.pop_back();
450 
451     // clean prev top page params
452     currentPage = GetCurrentPageNode();
453     CHECK_NULL_RETURN(currentPage, false);
454     pagePattern = currentPage->GetPattern<PagePattern>();
455     CHECK_NULL_RETURN(pagePattern, false);
456     pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
457     CHECK_NULL_RETURN(pageInfo, false);
458     std::string params = pageInfo->GetPageParams();
459     pageInfo->ReplacePageParams("");
460 
461     // do pop page
462     if (!OnPopPage(true, true)) {
463         pageRouterStack_.emplace_back(preWeakNode);
464         pageInfo->ReplacePageParams(params);
465         return false;
466     }
467     return true;
468 }
469 
StartRestore(const RouterPageInfo & target)470 void PageRouterManager::StartRestore(const RouterPageInfo& target)
471 {
472     RouterPageInfo info = target;
473     auto tempStack = restorePageStack_;
474     if (target.url.empty()) {
475         info.url = tempStack.back();
476         tempStack.pop_back();
477     } else {
478         info.url = target.url;
479         while (!tempStack.empty() && tempStack.back() != info.url) {
480             tempStack.pop_back();
481         }
482         if (tempStack.empty()) {
483             return;
484         }
485         tempStack.pop_back();
486     }
487 
488     restorePageStack_ = tempStack;
489     StartClean();
490     PopPage("", false, false);
491     StartPush(info);
492 }
493 
GetStackSize() const494 int32_t PageRouterManager::GetStackSize() const
495 {
496     CHECK_RUN_ON(JS);
497     auto realSize = isNewPageReplacing_ ? pageRouterStack_.size() - 1 : pageRouterStack_.size();
498     return static_cast<int32_t>(realSize);
499 }
500 
GetPageInfoByIndex(int32_t index,const std::string & params)501 RouterPageInfo PageRouterManager::GetPageInfoByIndex(int32_t index, const std::string& params)
502 {
503     RouterPageInfo emptyForReturn;
504     if (!CheckIndexValid(index) &&
505         index != static_cast<int32_t>(pageRouterStack_.size() + 1) /* in case the page is on popping */) {
506         return emptyForReturn;
507     }
508     std::string url;
509     int32_t counter = 1;
510     for (const auto& iter : pageRouterStack_) {
511         if (counter == index) {
512             auto pageNode = iter.Upgrade();
513             CHECK_NULL_RETURN(pageNode, emptyForReturn);
514             auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
515             CHECK_NULL_RETURN(pagePattern, emptyForReturn);
516             auto pageInfo = pagePattern->GetPageInfo();
517             CHECK_NULL_RETURN(pageInfo, emptyForReturn);
518             return NG::RouterPageInfo({ pageInfo->GetPageUrl(), params });
519         }
520         counter++;
521     }
522 
523     // in case the page is on popping
524     auto pipelineContext = PipelineContext::GetCurrentContext();
525     CHECK_NULL_RETURN(pipelineContext, emptyForReturn);
526     auto stageManager = pipelineContext->GetStageManager();
527     CHECK_NULL_RETURN(stageManager, emptyForReturn);
528     auto popPage = stageManager->GetLastPage();
529     CHECK_NULL_RETURN(popPage, emptyForReturn);
530     auto pagePattern = popPage->GetPattern<NG::PagePattern>();
531     CHECK_NULL_RETURN(pagePattern, emptyForReturn);
532     auto pageInfo = pagePattern->GetPageInfo();
533     // make sure the last page is the one with 'index'
534     if (pageInfo && pageInfo->GetPageIndex() == index) {
535         return NG::RouterPageInfo({ pageInfo->GetPageUrl(), params });
536     }
537     return emptyForReturn;
538 }
539 
GetState(int32_t & index,std::string & name,std::string & path)540 void PageRouterManager::GetState(int32_t& index, std::string& name, std::string& path)
541 {
542     CHECK_RUN_ON(JS);
543     if (pageRouterStack_.empty()) {
544         return;
545     }
546     index = static_cast<int32_t>(pageRouterStack_.size());
547     if (isNewPageReplacing_) {
548         if (index <= 1) {
549             TAG_LOGD(AceLogTag::ACE_ROUTER, "router stack size invalid while replacing");
550         } else {
551             index = index - 1;
552         }
553     }
554     auto pageNode = GetCurrentPageNode();
555     CHECK_NULL_VOID(pageNode);
556     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
557     CHECK_NULL_VOID(pagePattern);
558     auto pageInfo = pagePattern->GetPageInfo();
559     CHECK_NULL_VOID(pageInfo);
560     auto url = pageInfo->GetPageUrl();
561     auto pagePath = Framework::JsiDeclarativeEngine::GetPagePath(url);
562     if (!pagePath.empty()) {
563         url = pagePath;
564     }
565     auto pos = url.rfind(".js");
566     if (pos == url.length() - JS_FILE_EXTENSION_LENGTH) {
567         url = url.substr(0, pos);
568     }
569     pos = url.rfind("/");
570     if (pos != std::string::npos) {
571         name = url.substr(pos + 1);
572         path = url.substr(0, pos + 1);
573     }
574     if (name.size() == 0) {
575         name = "index";
576     }
577     if (path.size() == 0) {
578         path = "/" + url;
579     }
580 }
581 
GetStateByIndex(int32_t index,std::string & name,std::string & path,std::string & params)582 void PageRouterManager::GetStateByIndex(int32_t index, std::string& name, std::string& path, std::string& params)
583 {
584     CHECK_RUN_ON(JS);
585     if (!CheckIndexValid(index) &&
586         index != static_cast<int32_t>(pageRouterStack_.size() + 1) /* in case the page is on popping */) {
587         return;
588     }
589 
590     int32_t counter = 1;
591     for (const auto& iter : pageRouterStack_) {
592         if (counter == index) {
593             auto pageNode = iter.Upgrade();
594             CHECK_NULL_VOID(pageNode);
595             GetPageNameAndPath(pageNode, name, path);
596             auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
597             CHECK_NULL_VOID(pagePattern);
598             auto pageInfo = DynamicCast<NG::EntryPageInfo>(pagePattern->GetPageInfo());
599             CHECK_NULL_VOID(pageInfo);
600             params = pageInfo->GetPageParams();
601             return;
602         }
603         counter++;
604     }
605 
606     // in case the page is on popping
607     auto pipelineContext = PipelineContext::GetCurrentContext();
608     CHECK_NULL_VOID(pipelineContext);
609     auto stageManager = pipelineContext->GetStageManager();
610     CHECK_NULL_VOID(stageManager);
611     auto popPage = stageManager->GetLastPage();
612     CHECK_NULL_VOID(popPage);
613     auto pagePattern = popPage->GetPattern<NG::PagePattern>();
614     CHECK_NULL_VOID(pagePattern);
615     auto pageInfo = pagePattern->GetPageInfo();
616     // make sure the last page is the one with 'index'
617     if (pageInfo && pageInfo->GetPageIndex() == index) {
618         GetPageNameAndPath(popPage, name, path);
619         auto entryPageInfo = DynamicCast<NG::EntryPageInfo>(pageInfo);
620         CHECK_NULL_VOID(entryPageInfo);
621         params = entryPageInfo->GetPageParams();
622     }
623 }
624 
GetStateByUrl(std::string & url,std::vector<Framework::StateInfo> & stateArray)625 void PageRouterManager::GetStateByUrl(std::string& url, std::vector<Framework::StateInfo>& stateArray)
626 {
627     CHECK_RUN_ON(JS);
628     int32_t counter = 1;
629     Framework::StateInfo stateInfo;
630     for (auto& iter : pageRouterStack_) {
631         auto pageNode = iter.Upgrade();
632         CHECK_NULL_VOID(pageNode);
633         auto pagePattern = pageNode->GetPattern<PagePattern>();
634         CHECK_NULL_VOID(pagePattern);
635         auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
636         CHECK_NULL_VOID(pageInfo);
637         std::string tempUrl;
638         if (pageInfo->GetPageUrl() == url) {
639             stateInfo.params = pageInfo->GetPageParams();
640             stateInfo.index = counter;
641             auto pos = url.rfind(".js");
642             if (pos == url.length() - JS_FILE_EXTENSION_LENGTH) {
643                 tempUrl = url.substr(0, pos);
644             }
645             tempUrl = url;
646             auto pagePath = Framework::JsiDeclarativeEngine::GetPagePath(url);
647             if (!pagePath.empty()) {
648                 tempUrl = pagePath;
649             }
650             pos = tempUrl.rfind("/");
651             if (pos != std::string::npos) {
652                 stateInfo.name = tempUrl.substr(pos + 1);
653                 stateInfo.path = tempUrl.substr(0, pos + 1);
654             }
655             if (stateInfo.name.size() == 0) {
656                 stateInfo.name = "index";
657             }
658             if (stateInfo.path.size() == 0) {
659                 stateInfo.path = "/" + tempUrl;
660             }
661             stateArray.emplace_back(stateInfo);
662         }
663         counter++;
664     }
665 }
666 
GetPageNameAndPath(const RefPtr<FrameNode> & pageNode,std::string & name,std::string & path)667 void PageRouterManager::GetPageNameAndPath(const RefPtr<FrameNode>& pageNode, std::string& name, std::string& path)
668 {
669     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
670     CHECK_NULL_VOID(pagePattern);
671     auto pageInfo = pagePattern->GetPageInfo();
672     CHECK_NULL_VOID(pageInfo);
673     auto url = pageInfo->GetPageUrl();
674     auto pagePath = Framework::JsiDeclarativeEngine::GetPagePath(url);
675     if (!pagePath.empty()) {
676         url = pagePath;
677     }
678     auto pos = url.rfind(".js");
679     if (pos == url.length() - JS_FILE_EXTENSION_LENGTH) {
680         url = url.substr(0, pos);
681     }
682     pos = url.rfind("/");
683     if (pos != std::string::npos) {
684         name = url.substr(pos + 1);
685         path = url.substr(0, pos + 1);
686     }
687     if (name.size() == 0) {
688         name = "index";
689     }
690     if (path.size() == 0) {
691         path = "/" + url;
692     }
693 }
694 
GetParams() const695 std::string PageRouterManager::GetParams() const
696 {
697     CHECK_RUN_ON(JS);
698     if (pageRouterStack_.empty()) {
699         return "";
700     }
701     auto pageNode = pageRouterStack_.back().Upgrade();
702     CHECK_NULL_RETURN(pageNode, "");
703     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
704     CHECK_NULL_RETURN(pagePattern, "");
705     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
706     CHECK_NULL_RETURN(pageInfo, "");
707     return pageInfo->GetPageParams();
708 }
709 
GetIndexByUrl(const std::string & url) const710 int32_t PageRouterManager::GetIndexByUrl(const std::string& url) const
711 {
712     int32_t index = 0;
713     for (auto iter : pageRouterStack_) {
714         auto pageNode = iter.Upgrade();
715         if (!pageNode) {
716             continue;
717         }
718         auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
719         auto localUrl = pagePattern->GetPageInfo()->GetPageUrl();
720         if (localUrl == url) {
721             return index;
722         }
723         ++index;
724     }
725     return INVALID_PAGE_INDEX;
726 }
727 
GetCurrentPageUrl()728 std::string PageRouterManager::GetCurrentPageUrl()
729 {
730     CHECK_RUN_ON(JS);
731     if (pageRouterStack_.empty()) {
732         return "";
733     }
734     auto pageNode = GetCurrentPageNode();
735     CHECK_NULL_RETURN(pageNode, "");
736     auto pagePattern = pageNode->GetPattern<PagePattern>();
737     CHECK_NULL_RETURN(pagePattern, "");
738     auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
739     CHECK_NULL_RETURN(entryPageInfo, "");
740     return entryPageInfo->GetPagePath();
741 }
742 
743 // Get the currently running JS page information in NG structure.
GetCurrentPageSourceMap(const RefPtr<AssetManager> & assetManager)744 RefPtr<Framework::RevSourceMap> PageRouterManager::GetCurrentPageSourceMap(const RefPtr<AssetManager>& assetManager)
745 {
746     CHECK_RUN_ON(JS);
747     if (pageRouterStack_.empty()) {
748         return nullptr;
749     }
750     auto pageNode = GetCurrentPageNode();
751     CHECK_NULL_RETURN(pageNode, nullptr);
752     auto pagePattern = pageNode->GetPattern<PagePattern>();
753     CHECK_NULL_RETURN(pagePattern, nullptr);
754     auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
755     CHECK_NULL_RETURN(entryPageInfo, nullptr);
756     auto pageMap = entryPageInfo->GetPageMap();
757     if (pageMap) {
758         return pageMap;
759     }
760     // initialize page map.
761     std::string jsSourceMap;
762     // stage mode
763     auto container = Container::Current();
764     CHECK_NULL_RETURN(container, nullptr);
765     if (container->IsUseStageModel()) {
766         auto pagePath = entryPageInfo->GetPagePath();
767         auto moduleName = container->GetModuleName();
768         std::string judgePath = "";
769         if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE)) {
770             judgePath = DEBUG_PATH + moduleName + ETS_PATH +
771                         pagePath.substr(0, pagePath.size() - JS_FILE_EXTENSION_LENGTH) + TS_SUFFIX;
772         } else {
773             judgePath = moduleName + ETS_PATH +
774                         pagePath.substr(0, pagePath.size() - JS_FILE_EXTENSION_LENGTH) + ETS_SUFFIX;
775         }
776         if (Framework::GetAssetContentImpl(assetManager, "sourceMaps.map", jsSourceMap)) {
777             auto jsonPages = JsonUtil::ParseJsonString(jsSourceMap);
778             auto child = jsonPages->GetChild();
779             if (!child->GetValue("entry-package-info")->IsNull()) {
780                 judgePath = NEW_PATH + pagePath.substr(0, pagePath.size() - JS_FILE_EXTENSION_LENGTH) + TS_SUFFIX;
781             }
782             auto jsonPage = jsonPages->GetValue(judgePath)->ToString();
783             auto stagePageMap = MakeRefPtr<Framework::RevSourceMap>();
784             stagePageMap->Init(jsonPage);
785             entryPageInfo->SetPageMap(stagePageMap);
786             return stagePageMap;
787         }
788     } else {
789         if (Framework::GetAssetContentImpl(assetManager, entryPageInfo->GetPagePath() + ".map", jsSourceMap)) {
790             auto faPageMap = MakeRefPtr<Framework::RevSourceMap>();
791             faPageMap->Init(jsSourceMap);
792             entryPageInfo->SetPageMap(faPageMap);
793             return faPageMap;
794         }
795     }
796     return nullptr;
797 }
798 
GetStackInfo()799 std::unique_ptr<JsonValue> PageRouterManager::GetStackInfo()
800 {
801     auto jsonRouterStack = JsonUtil::CreateArray(true);
802     auto restoreIter = restorePageStack_.begin();
803     while (restoreIter != restorePageStack_.end()) {
804         auto jsonItem = JsonUtil::Create(true);
805         jsonItem->Put("url", restoreIter->c_str());
806         jsonRouterStack->Put(jsonItem);
807         ++restoreIter;
808     }
809     auto iter = pageRouterStack_.begin();
810     while (iter != pageRouterStack_.end()) {
811         auto pageNode = iter->Upgrade();
812         CHECK_NULL_RETURN(pageNode, jsonRouterStack);
813         auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
814         CHECK_NULL_RETURN(pagePattern, jsonRouterStack);
815         auto pageInfo = pagePattern->GetPageInfo();
816         CHECK_NULL_RETURN(pageInfo, jsonRouterStack);
817         auto url = pageInfo->GetPageUrl();
818         auto jsonItem = JsonUtil::Create(true);
819         jsonItem->Put("url", url.c_str());
820         jsonRouterStack->Put(jsonItem);
821         ++iter;
822     }
823     return jsonRouterStack;
824 }
825 
RestoreRouterStack(std::unique_ptr<JsonValue> stackInfo)826 std::pair<std::string, UIContentErrorCode> PageRouterManager::RestoreRouterStack(std::unique_ptr<JsonValue> stackInfo)
827 {
828     if (!stackInfo->IsValid() || !stackInfo->IsArray()) {
829         return std::make_pair("", UIContentErrorCode::WRONG_PAGE_ROUTER);
830     }
831     int32_t stackSize = stackInfo->GetArraySize();
832     if (stackSize < 1) {
833         return std::make_pair("", UIContentErrorCode::WRONG_PAGE_ROUTER);
834     }
835 
836     auto container = Container::Current();
837     CHECK_NULL_RETURN(container, std::make_pair("", UIContentErrorCode::NULL_POINTER));
838     auto pipeline = container->GetPipelineContext();
839     CHECK_NULL_RETURN(pipeline, std::make_pair("", UIContentErrorCode::WRONG_PAGE_ROUTER));
840     auto context = DynamicCast<NG::PipelineContext>(pipeline);
841     auto stageManager = context ? context->GetStageManager() : nullptr;
842     CHECK_NULL_RETURN(stageManager, std::make_pair("", UIContentErrorCode::WRONG_PAGE_ROUTER));
843 
844     for (int32_t index = 0; index < stackSize - 1; ++index) {
845         std::string url = stackInfo->GetArrayItem(index)->GetValue("url")->ToString();
846         // remove 2 useless character, as "XXX" to XXX
847         url = url.substr(1, url.size() - 2);
848         restorePageStack_.emplace_back(url);
849     }
850     std::string startUrl = stackInfo->GetArrayItem(stackSize - 1)->GetValue("url")->ToString();
851     // remove 2 useless character, as "XXX" to XXX
852     return std::make_pair(startUrl.substr(1, startUrl.size() - 2), UIContentErrorCode::NO_ERRORS);
853 }
854 
GenerateNextPageId()855 int32_t PageRouterManager::GenerateNextPageId()
856 {
857     return ++pageId_;
858 }
859 
FindPageInStack(const std::string & url,bool needIgnoreBegin)860 std::pair<int32_t, RefPtr<FrameNode>> PageRouterManager::FindPageInStack(const std::string& url, bool needIgnoreBegin)
861 {
862     auto iter = std::find_if(needIgnoreBegin ? ++pageRouterStack_.rbegin() : pageRouterStack_.rbegin(),
863         pageRouterStack_.rend(), [url](const WeakPtr<FrameNode>& item) {
864             auto pageNode = item.Upgrade();
865             CHECK_NULL_RETURN(pageNode, false);
866             auto pagePattern = pageNode->GetPattern<PagePattern>();
867             CHECK_NULL_RETURN(pagePattern, false);
868             auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
869             CHECK_NULL_RETURN(entryPageInfo, false);
870             return entryPageInfo->GetPageUrl() == url;
871         });
872     if (iter == pageRouterStack_.rend()) {
873         return { -1, nullptr };
874     }
875     // Returns to the forward position.
876     return { std::distance(iter, pageRouterStack_.rend()) - 1, iter->Upgrade() };
877 }
878 
FindPageInStackByRouteName(const std::string & name) const879 std::pair<int32_t, RefPtr<FrameNode>> PageRouterManager::FindPageInStackByRouteName(const std::string& name) const
880 {
881     auto iter = std::find_if(pageRouterStack_.rbegin(), pageRouterStack_.rend(),
882         [name](const WeakPtr<FrameNode>& item) {
883             auto pageNode = item.Upgrade();
884             CHECK_NULL_RETURN(pageNode, false);
885             auto pagePattern = pageNode->GetPattern<PagePattern>();
886             CHECK_NULL_RETURN(pagePattern, false);
887             auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
888             CHECK_NULL_RETURN(entryPageInfo, false);
889             return entryPageInfo->GetRouteName() == name;
890         });
891     if (iter == pageRouterStack_.rend()) {
892         return { INVALID_PAGE_INDEX, nullptr };
893     }
894     // Returns to the forward position.
895     return { std::distance(iter, pageRouterStack_.rend()) - 1, iter->Upgrade() };
896 }
897 
PushOhmUrl(const RouterPageInfo & target)898 void PageRouterManager::PushOhmUrl(const RouterPageInfo& target)
899 {
900     RouterOptScope scope(this);
901     if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
902         LOGW("Router stack size is larger than max size 32.");
903         if (target.errorCallback != nullptr) {
904             target.errorCallback("The pages are pushed too much.", ERROR_CODE_PAGE_STACK_FULL);
905         }
906         return;
907     }
908     RouterPageInfo info = target;
909     info.path = info.url + ".js";
910 
911     if (target.routerMode == RouterMode::SINGLE) {
912         auto pageInfo = FindPageInStack(info.url);
913         if (pageInfo.second) {
914             // find page in stack, move postion and update params.
915             MovePageToFront(pageInfo.first, pageInfo.second, info, true);
916             return;
917         }
918     }
919 
920     LoadPage(GenerateNextPageId(), info);
921     auto container = Container::Current();
922     CHECK_NULL_VOID(container);
923     auto pageUrlChecker = container->GetPageUrlChecker();
924     CHECK_NULL_VOID(pageUrlChecker);
925     auto taskExecutor = container->GetTaskExecutor();
926     CHECK_NULL_VOID(taskExecutor);
927     taskExecutor->PostTask([pageUrlChecker, url = target.url]() { pageUrlChecker->CheckPreload(url); },
928         TaskExecutor::TaskType::BACKGROUND, "ArkUIPageRouterPushOhmUrl");
929 }
930 
StartPush(const RouterPageInfo & target)931 void PageRouterManager::StartPush(const RouterPageInfo& target)
932 {
933     CHECK_RUN_ON(JS);
934     RouterOptScope scope(this);
935     if (target.url.empty()) {
936         TAG_LOGE(AceLogTag::ACE_ROUTER, "push url is empty");
937         return;
938     }
939 #if !defined(PREVIEW)
940     if (target.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
941         auto container = Container::Current();
942         CHECK_NULL_VOID(container);
943         auto pageUrlChecker = container->GetPageUrlChecker();
944         CHECK_NULL_VOID(pageUrlChecker);
945         auto instanceId = container->GetInstanceId();
946         auto taskExecutor = container->GetTaskExecutor();
947         CHECK_NULL_VOID(taskExecutor);
948         auto callback = [weak = AceType::WeakClaim(this), target, taskExecutor, instanceId]() {
949             ContainerScope scope(instanceId);
950             auto pageRouterManager = weak.Upgrade();
951             CHECK_NULL_VOID(pageRouterManager);
952             taskExecutor->PostTask(
953                 [pageRouterManager, target]() { pageRouterManager->PushOhmUrl(target); },
954                 TaskExecutor::TaskType::JS, "ArkUIPageRouterPushOhmUrl");
955         };
956 
957         auto silentInstallErrorCallBack = [errorCallback = target.errorCallback, taskExecutor, instanceId](
958                                               int32_t errorCode, const std::string& errorMsg) {
959             if (!errorCallback) {
960                 return;
961             }
962             ContainerScope scope(instanceId);
963             taskExecutor->PostTask([errorCallback, errorCode, errorMsg]() { errorCallback(errorMsg, errorCode); },
964                 TaskExecutor::TaskType::JS, "ArkUIPageRouterPushErrorCallback");
965         };
966 
967         pageUrlChecker->LoadPageUrl(target.url, callback, silentInstallErrorCallBack);
968         return;
969     }
970 #endif
971     if (!manifestParser_) {
972         return;
973     }
974     auto context = PipelineContext::GetCurrentContext();
975     CHECK_NULL_VOID(context);
976     if (GetStackSize() >= MAX_ROUTER_STACK_SIZE && !context->GetForceSplitEnable()) {
977         LOGW("Router stack size is larger than max size 32.");
978         if (target.errorCallback != nullptr) {
979             target.errorCallback("The pages are pushed too much.", ERROR_CODE_PAGE_STACK_FULL);
980         }
981         return;
982     }
983     RouterPageInfo info = target;
984     info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
985     if (info.path.empty()) {
986         LOGW("[Engine Log] this uri is empty, not support in route push.");
987         if (info.errorCallback != nullptr) {
988             info.errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR);
989         }
990         return;
991     }
992 
993     CleanPageOverlay();
994 
995     if (info.routerMode == RouterMode::SINGLE) {
996         auto pageInfo = FindPageInStack(info.url);
997         if (pageInfo.second) {
998             // find page in stack, move postion and update params.
999             MovePageToFront(pageInfo.first, pageInfo.second, info, true);
1000             return;
1001         }
1002     }
1003 
1004     LoadPage(GenerateNextPageId(), info, true, true, true);
1005 }
1006 
ReplaceOhmUrl(const RouterPageInfo & target)1007 void PageRouterManager::ReplaceOhmUrl(const RouterPageInfo& target)
1008 {
1009     RouterOptScope scope(this);
1010     RouterPageInfo info = target;
1011     info.path = info.url + ".js";
1012 
1013     PopPage("", false, false);
1014 
1015     if (info.routerMode == RouterMode::SINGLE) {
1016         auto pageInfo = FindPageInStack(info.url);
1017         if (pageInfo.second) {
1018             // find page in stack, move postion and update params.
1019             MovePageToFront(pageInfo.first, pageInfo.second, info, false, true, false);
1020             return;
1021         }
1022     }
1023 
1024     LoadPage(GenerateNextPageId(), info, false, false);
1025     auto container = Container::Current();
1026     CHECK_NULL_VOID(container);
1027     auto pageUrlChecker = container->GetPageUrlChecker();
1028     CHECK_NULL_VOID(pageUrlChecker);
1029     auto taskExecutor = container->GetTaskExecutor();
1030     CHECK_NULL_VOID(taskExecutor);
1031     taskExecutor->PostTask([pageUrlChecker, url = target.url]() { pageUrlChecker->CheckPreload(url); },
1032         TaskExecutor::TaskType::BACKGROUND, "ArkUIPageRouterReplaceOhmUrl");
1033 }
1034 
StartReplace(const RouterPageInfo & target)1035 void PageRouterManager::StartReplace(const RouterPageInfo& target)
1036 {
1037     CHECK_RUN_ON(JS);
1038     CleanPageOverlay();
1039     RouterOptScope scope(this);
1040     if (target.url.empty()) {
1041         return;
1042     }
1043 #if !defined(PREVIEW)
1044     if (target.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1045         auto container = Container::Current();
1046         CHECK_NULL_VOID(container);
1047         auto pageUrlChecker = container->GetPageUrlChecker();
1048         CHECK_NULL_VOID(pageUrlChecker);
1049         auto instanceId = container->GetInstanceId();
1050         auto taskExecutor = container->GetTaskExecutor();
1051         CHECK_NULL_VOID(taskExecutor);
1052         auto callback = [weak = AceType::WeakClaim(this), target, taskExecutor, instanceId]() {
1053             ContainerScope scope(instanceId);
1054             auto pageRouterManager = weak.Upgrade();
1055             CHECK_NULL_VOID(pageRouterManager);
1056             taskExecutor->PostTask([pageRouterManager, target]() { pageRouterManager->ReplaceOhmUrl(target); },
1057                 TaskExecutor::TaskType::JS, "ArkUIPageRouterReplaceOhmUrl");
1058         };
1059 
1060         auto silentInstallErrorCallBack = [errorCallback = target.errorCallback, taskExecutor, instanceId](
1061                                               int32_t errorCode, const std::string& errorMsg) {
1062             if (!errorCallback) {
1063                 return;
1064             }
1065             ContainerScope scope(instanceId);
1066             taskExecutor->PostTask([errorCallback, errorCode, errorMsg]() { errorCallback(errorMsg, errorCode); },
1067                 TaskExecutor::TaskType::JS, "ArkUIPageRouterReplaceErrorCallback");
1068         };
1069 
1070         pageUrlChecker->LoadPageUrl(target.url, callback, silentInstallErrorCallBack);
1071         return;
1072     }
1073 #endif
1074     if (!manifestParser_) {
1075         return;
1076     }
1077     RouterPageInfo info = target;
1078     info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
1079     if (info.path.empty()) {
1080         LOGW("[Engine Log] this uri is empty, not support in route push.");
1081         if (info.errorCallback != nullptr) {
1082             info.errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR_LITE);
1083         }
1084         return;
1085     }
1086 
1087     DealReplacePage(info);
1088 }
1089 
StartBack(const RouterPageInfo & target)1090 void PageRouterManager::StartBack(const RouterPageInfo& target)
1091 {
1092     CleanPageOverlay();
1093     if (target.url.empty()) {
1094         size_t pageRouteSize = pageRouterStack_.size();
1095         if (pageRouteSize <= 1) {
1096             if (!restorePageStack_.empty()) {
1097                 auto newInfo = RouterPageInfo();
1098                 newInfo.params = target.params;
1099                 StartRestore(newInfo);
1100                 return;
1101             }
1102             LOGI("Router back start ExitToDesktop");
1103             ExitToDesktop();
1104             return;
1105         }
1106         LOGI("Router back start PopPage");
1107         PopPage(target.params, true, true);
1108         return;
1109     }
1110 
1111     auto pageInfo = FindPageInStack(target.url, true);
1112     if (pageInfo.second) {
1113         // find page in stack, pop to specified index.
1114         RouterPageInfo info = target;
1115 #if !defined(PREVIEW)
1116         if (info.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1117             info.path = info.url + ".js";
1118             PopPageToIndex(pageInfo.first, info.params, true, true);
1119             return;
1120         }
1121 #endif
1122         if (!manifestParser_) {
1123             return;
1124         }
1125 
1126         info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
1127         if (info.path.empty()) {
1128             LOGW("[Engine Log] this uri is empty, not support in route push.");
1129             return;
1130         }
1131         PopPageToIndex(pageInfo.first, info.params, true, true);
1132         return;
1133     }
1134     if (!restorePageStack_.empty()) {
1135         StartRestore(target);
1136     }
1137 }
1138 
StartBackToIndex(int32_t index,const std::string & params)1139 void PageRouterManager::StartBackToIndex(int32_t index, const std::string& params)
1140 {
1141     CleanPageOverlay();
1142     RouterPageInfo target = GetPageInfoByIndex(index, params);
1143     if (!manifestParser_) {
1144         return;
1145     }
1146     PopPageToIndex(index - 1, params, true, true);
1147     return;
1148 }
1149 
BackCheckAlert(const RouterPageInfo & target)1150 void PageRouterManager::BackCheckAlert(const RouterPageInfo& target)
1151 {
1152     RouterOptScope scope(this);
1153     if (pageRouterStack_.empty()) {
1154         TAG_LOGW(AceLogTag::ACE_ROUTER, "Page router stack size is zero, can not back");
1155         return;
1156     }
1157     auto currentPage = GetCurrentPageNode();
1158     CHECK_NULL_VOID(currentPage);
1159     auto pagePattern = currentPage->GetPattern<PagePattern>();
1160     CHECK_NULL_VOID(pagePattern);
1161     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1162     CHECK_NULL_VOID(pageInfo);
1163     if (pageInfo->GetAlertCallback()) {
1164         ngBackTarget_ = target;
1165         auto pipelineContext = PipelineContext::GetCurrentContext();
1166         auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
1167         CHECK_NULL_VOID(overlayManager);
1168         overlayManager->ShowDialog(
1169             pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
1170         return;
1171     }
1172     StartBack(target);
1173 }
1174 
BackToIndexCheckAlert(int32_t index,const std::string & params)1175 void PageRouterManager::BackToIndexCheckAlert(int32_t index, const std::string& params)
1176 {
1177     RouterOptScope scope(this);
1178     if (pageRouterStack_.empty()) {
1179         return;
1180     }
1181     RouterPageInfo target = GetPageInfoByIndex(index, params);
1182     auto currentPage = GetCurrentPageNode();
1183     CHECK_NULL_VOID(currentPage);
1184     auto pagePattern = currentPage->GetPattern<PagePattern>();
1185     CHECK_NULL_VOID(pagePattern);
1186     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1187     CHECK_NULL_VOID(pageInfo);
1188     if (pageInfo->GetAlertCallback()) {
1189         ngBackTarget_ = target;
1190         auto pipelineContext = PipelineContext::GetCurrentContext();
1191         auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
1192         CHECK_NULL_VOID(overlayManager);
1193         overlayManager->ShowDialog(
1194             pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
1195         return;
1196     }
1197     StartBackToIndex(index, params);
1198 }
1199 
LoadPage(int32_t pageId,const RouterPageInfo & target,bool needHideLast,bool needTransition,bool)1200 void PageRouterManager::LoadPage(int32_t pageId, const RouterPageInfo& target, bool needHideLast, bool needTransition,
1201     bool  /*isPush*/)
1202 {
1203     ACE_SCOPED_TRACE_COMMERCIAL("load page: %s(id:%d)", target.url.c_str(), pageId);
1204     CHECK_RUN_ON(JS);
1205     auto pageNode = CreatePage(pageId, target);
1206     if (!pageNode) {
1207         return;
1208     }
1209 
1210     pageRouterStack_.emplace_back(pageNode);
1211     if (!OnPageReady(pageNode, needHideLast, needTransition)) {
1212         pageRouterStack_.pop_back();
1213         LOGW("LoadPage OnPageReady Failed");
1214         return;
1215     }
1216     AccessibilityEventType type = AccessibilityEventType::CHANGE;
1217     pageNode->OnAccessibilityEvent(type);
1218 }
1219 
CreatePage(int32_t pageId,const RouterPageInfo & target)1220 RefPtr<FrameNode> PageRouterManager::CreatePage(int32_t pageId, const RouterPageInfo& target)
1221 {
1222     ACE_SCOPED_TRACE("PageRouterManager::CreatePage");
1223     CHECK_RUN_ON(JS);
1224     LOGI("Page router manager is loading page[%{public}d]: %{public}s.", pageId, target.url.c_str());
1225     auto entryPageInfo = AceType::MakeRefPtr<EntryPageInfo>(pageId, target.url, target.path, target.params);
1226     auto pagePattern = ViewAdvancedRegister::GetInstance()->CreatePagePattern(entryPageInfo);
1227     std::unordered_map<std::string, std::string> reportData { { "pageUrl", target.url } };
1228     ResSchedReportScope reportScope("push_page", reportData);
1229     auto pageNode =
1230         FrameNode::CreateFrameNode(V2::PAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), pagePattern);
1231     pageNode->SetHostPageId(pageId);
1232     pageRouterStack_.emplace_back(pageNode);
1233 
1234     if (target.content && !target.content->empty()) {
1235         loadJsByBuffer_(target.content, target.errorCallback, target.params);
1236     } else {
1237         loadJs_(target.path, target.errorCallback);
1238     }
1239     // record full path info of every pageNode
1240     auto pageInfo = pagePattern->GetPageInfo();
1241     if (!pageInfo) {
1242         pageRouterStack_.pop_back();
1243         return nullptr;
1244     }
1245     auto keyInfo = target.url;
1246     if (keyInfo.empty() && manifestParser_) {
1247         auto router = manifestParser_->GetRouter();
1248         if (router) {
1249             keyInfo = router->GetEntry("");
1250         }
1251     }
1252 #if !defined(PREVIEW)
1253     if (keyInfo.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1254         // deal with @bundle url
1255         // @bundle format: @bundle:bundleName/moduleName/pagePath/fileName(without file extension)
1256         // @bundle example: @bundle:com.example.applicationHsp/hsp/ets/pages/Index
1257         // only moduleName and lastPagePath/fileName is needed: hsppages/Index
1258         size_t bundleEndPos = keyInfo.find('/');
1259         size_t moduleStartPos = bundleEndPos + 1;
1260         size_t moduleEndPos = keyInfo.find('/', moduleStartPos);
1261         std::string moduleName = keyInfo.substr(moduleStartPos, moduleEndPos - moduleStartPos);
1262         size_t fileNameStartPos = keyInfo.rfind('/');
1263         size_t pageInfoStartPos = keyInfo.rfind('/', fileNameStartPos - 1);
1264         keyInfo = keyInfo.substr(pageInfoStartPos + 1);
1265         keyInfo = moduleName + keyInfo;
1266     }
1267 #endif
1268     SetPageInfoRouteName(entryPageInfo, target.isNamedRouterMode);
1269     auto pagePath = Framework::JsiDeclarativeEngine::GetFullPathInfo(keyInfo);
1270     if (pagePath.empty()) {
1271         auto container = Container::Current();
1272         if (!container) {
1273             pageRouterStack_.pop_back();
1274             return nullptr;
1275         }
1276         auto moduleName = container->GetModuleName();
1277         keyInfo = moduleName + keyInfo;
1278         pagePath = Framework::JsiDeclarativeEngine::GetFullPathInfo(keyInfo);
1279     }
1280     pageInfo->SetFullPath(pagePath);
1281 
1282 #if defined(PREVIEW)
1283     if (!isComponentPreview_()) {
1284 #endif
1285     auto result = loadNamedRouter_(target.url, target.isNamedRouterMode);
1286     if (!result) {
1287         if (!target.isNamedRouterMode) {
1288             result = updateRootComponent_();
1289         } else if (target.errorCallback) {
1290             target.errorCallback("The named route is not exist.", ERROR_CODE_NAMED_ROUTE_ERROR);
1291         }
1292     }
1293 
1294     if (!result) {
1295 #if !defined(PREVIEW)
1296         if (!target.isNamedRouterMode && target.url.substr(0, strlen(BUNDLE_TAG)) != BUNDLE_TAG) {
1297             ThrowError("Load Page Failed: " + target.url, ERROR_CODE_LOAD_PAGE_ERROR);
1298         }
1299 #endif
1300         pageRouterStack_.pop_back();
1301         return nullptr;
1302     }
1303 
1304     if (target.isNamedRouterMode) {
1305         manifestParser_->SetPagePath(target.url);
1306     }
1307 
1308     if (target.errorCallback != nullptr) {
1309         target.errorCallback("", ERROR_CODE_NO_ERROR);
1310     }
1311 #if defined(PREVIEW)
1312     }
1313 #endif
1314 
1315     pageRouterStack_.pop_back();
1316     return pageNode;
1317 }
1318 
LoadCard(int32_t pageId,const RouterPageInfo & target,const std::string & params,int64_t cardId,bool,bool needHideLast,const std::string & entryPoint)1319 UIContentErrorCode PageRouterManager::LoadCard(int32_t pageId, const RouterPageInfo& target, const std::string& params,
1320     int64_t cardId, bool /* isRestore */, bool needHideLast, const std::string& entryPoint)
1321 {
1322     CHECK_RUN_ON(JS);
1323     auto entryPageInfo = AceType::MakeRefPtr<EntryPageInfo>(pageId, target.url, target.path, params);
1324     auto pagePattern = ViewAdvancedRegister::GetInstance()->CreatePagePattern(entryPageInfo);
1325     auto pageNode =
1326         FrameNode::CreateFrameNode(V2::PAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), pagePattern);
1327     pageNode->SetHostPageId(pageId);
1328     pageRouterStack_.emplace_back(pageNode);
1329 
1330     if (!loadCard_) {
1331         return UIContentErrorCode::NULL_CARD_CALLBACK;
1332     }
1333     auto result = loadCard_(target.url, cardId, entryPoint);
1334     if (!result) {
1335         pageRouterStack_.pop_back();
1336         return UIContentErrorCode::NULL_CARD_RES;
1337     }
1338 
1339     if (!OnPageReady(pageNode, needHideLast, false, isCardRouter_, cardId)) {
1340         LOGE("LoadCard OnPageReady Failed");
1341         pageRouterStack_.pop_back();
1342         return UIContentErrorCode::CARD_PAGE_NOT_READY;
1343     }
1344     LOGI("LoadCard Success");
1345     return UIContentErrorCode::NO_ERRORS;
1346 }
1347 
MovePageToFront(int32_t index,const RefPtr<FrameNode> & pageNode,const RouterPageInfo & target,bool needHideLast,bool forceShowCurrent,bool needTransition)1348 void PageRouterManager::MovePageToFront(int32_t index, const RefPtr<FrameNode>& pageNode, const RouterPageInfo& target,
1349     bool needHideLast, bool forceShowCurrent, bool needTransition)
1350 {
1351     LOGI("Move page to front to index: %{public}d", index);
1352     if (target.errorCallback != nullptr) {
1353         target.errorCallback("", ERROR_CODE_NO_ERROR);
1354     }
1355 
1356     // update param first.
1357     CHECK_NULL_VOID(pageNode);
1358     auto pagePattern = pageNode->GetPattern<PagePattern>();
1359     CHECK_NULL_VOID(pagePattern);
1360     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1361     CHECK_NULL_VOID(pageInfo);
1362 
1363     if (index == static_cast<int32_t>(pageRouterStack_.size()) - 1) {
1364         pageInfo->ReplacePageParams(target.params);
1365         if (forceShowCurrent) {
1366             pageNode->GetRenderContext()->ResetPageTransitionEffect();
1367             StageManager::FirePageShow(pageNode, PageTransitionType::NONE);
1368         }
1369         return;
1370     }
1371     CHECK_NULL_VOID(pageNode);
1372     auto container = Container::Current();
1373     CHECK_NULL_VOID(container);
1374     auto pipeline = container->GetPipelineContext();
1375     CHECK_NULL_VOID(pipeline);
1376     auto context = DynamicCast<NG::PipelineContext>(pipeline);
1377     auto stageManager = context ? context->GetStageManager() : nullptr;
1378     CHECK_NULL_VOID(stageManager);
1379 
1380     // clean pageNode on index position.
1381     auto iter = pageRouterStack_.begin();
1382     std::advance(iter, index);
1383     auto last = pageRouterStack_.erase(iter);
1384     // push pageNode to top.
1385     pageRouterStack_.emplace_back(pageNode);
1386     std::string tempParam = pageInfo->ReplacePageParams(target.params);
1387     if (!stageManager->MovePageToFront(pageNode, needHideLast, needTransition)) {
1388         // restore position and param.
1389         pageRouterStack_.pop_back();
1390         pageRouterStack_.insert(last, pageNode);
1391         if (!tempParam.empty()) {
1392             pageInfo->ReplacePageParams(tempParam);
1393         }
1394     }
1395 
1396     // update index in pageInfo
1397     for (auto iter = last; iter != pageRouterStack_.end(); ++iter, ++index) {
1398         auto pageNode = iter->Upgrade();
1399         if (!pageNode) {
1400             continue;
1401         }
1402         auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
1403         if (pagePattern) {
1404             pagePattern->GetPageInfo()->SetPageIndex(index + 1);
1405         }
1406     }
1407 }
1408 
FlushFrontend()1409 void PageRouterManager::FlushFrontend()
1410 {
1411     auto currentPage = GetCurrentPageNode();
1412     CHECK_NULL_VOID(currentPage);
1413     auto customNode = DynamicCast<CustomNode>(currentPage->GetFirstChild());
1414     CHECK_NULL_VOID(customNode);
1415     customNode->FlushReload();
1416 }
1417 
PopPage(const std::string & params,bool needShowNext,bool needTransition)1418 void PageRouterManager::PopPage(const std::string& params, bool needShowNext, bool needTransition)
1419 {
1420     CHECK_RUN_ON(JS);
1421     if (pageRouterStack_.empty()) {
1422         LOGW("Page router stack size is zero, can not pop");
1423         return;
1424     }
1425     if (needShowNext && (pageRouterStack_.size() == 1)) {
1426         LOGW("Page router stack size is only one, can not show next");
1427         return;
1428     }
1429     auto topNode = pageRouterStack_.back();
1430     pageRouterStack_.pop_back();
1431     if (!needShowNext) {
1432         if (!OnPopPage(needShowNext, needTransition)) {
1433             pageRouterStack_.emplace_back(topNode);
1434         }
1435         return;
1436     }
1437 
1438     // update param first.
1439     auto nextNode = GetCurrentPageNode();
1440     CHECK_NULL_VOID(nextNode);
1441     auto pagePattern = nextNode->GetPattern<PagePattern>();
1442     CHECK_NULL_VOID(pagePattern);
1443     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1444     CHECK_NULL_VOID(pageInfo);
1445     auto temp = pageInfo->ReplacePageParams(params);
1446 
1447     if (OnPopPage(needShowNext, needTransition)) {
1448         return;
1449     }
1450     // restore stack and pageParam.
1451     pageRouterStack_.emplace_back(topNode);
1452     pageInfo->ReplacePageParams(temp);
1453 }
1454 
PopPageToIndex(int32_t index,const std::string & params,bool needShowNext,bool needTransition)1455 void PageRouterManager::PopPageToIndex(int32_t index, const std::string& params, bool needShowNext, bool needTransition)
1456 {
1457     TAG_LOGI(AceLogTag::ACE_ROUTER, "pop page to %{public}d", index);
1458     std::list<WeakPtr<FrameNode>> temp;
1459     std::swap(temp, pageRouterStack_);
1460     auto iter = temp.begin();
1461     for (int32_t current = 0; current <= index; ++current) {
1462         pageRouterStack_.emplace_back(*iter);
1463         ++iter;
1464     }
1465 
1466     // update param first.
1467     auto nextNode = GetCurrentPageNode();
1468     CHECK_NULL_VOID(nextNode);
1469     auto pagePattern = nextNode->GetPattern<PagePattern>();
1470     CHECK_NULL_VOID(pagePattern);
1471     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1472     CHECK_NULL_VOID(pageInfo);
1473     auto tempParam = pageInfo->ReplacePageParams(params);
1474 
1475     if (OnPopPageToIndex(index, needShowNext, needTransition)) {
1476         return;
1477     }
1478     // restore stack and pageParam.
1479     std::swap(temp, pageRouterStack_);
1480     pageInfo->ReplacePageParams(tempParam);
1481 }
1482 
OnPageReady(const RefPtr<FrameNode> & pageNode,bool needHideLast,bool needTransition,bool isCardRouter,int64_t cardId)1483 bool PageRouterManager::OnPageReady(const RefPtr<FrameNode>& pageNode, bool needHideLast, bool needTransition,
1484     bool isCardRouter, int64_t cardId)
1485 {
1486     Recorder::NodeDataCache::Get().OnPageReady();
1487     auto container = Container::Current();
1488     CHECK_NULL_RETURN(container, false);
1489     RefPtr<PipelineBase> pipeline;
1490     if (isCardRouter) {
1491         auto weak = container->GetCardPipeline(cardId);
1492         pipeline = weak.Upgrade();
1493         CHECK_NULL_RETURN(pipeline, false);
1494     } else {
1495         pipeline = container->GetPipelineContext();
1496         CHECK_NULL_RETURN(pipeline, false);
1497     }
1498 
1499     auto context = DynamicCast<NG::PipelineContext>(pipeline);
1500     auto stageManager = context ? context->GetStageManager() : nullptr;
1501     if (stageManager) {
1502         return stageManager->PushPage(pageNode, needHideLast, needTransition);
1503     }
1504     return false;
1505 }
1506 
OnPopPage(bool needShowNext,bool needTransition)1507 bool PageRouterManager::OnPopPage(bool needShowNext, bool needTransition)
1508 {
1509     auto container = Container::Current();
1510     CHECK_NULL_RETURN(container, false);
1511     auto pipeline = container->GetPipelineContext();
1512     CHECK_NULL_RETURN(pipeline, false);
1513     auto context = DynamicCast<NG::PipelineContext>(pipeline);
1514     auto stageManager = context ? context->GetStageManager() : nullptr;
1515     if (stageManager) {
1516         Recorder::NodeDataCache::Get().OnBeforePagePop();
1517         return stageManager->PopPage(needShowNext, needTransition);
1518     }
1519     return false;
1520 }
1521 
OnPopPageToIndex(int32_t index,bool needShowNext,bool needTransition)1522 bool PageRouterManager::OnPopPageToIndex(int32_t index, bool needShowNext, bool needTransition)
1523 {
1524     auto container = Container::Current();
1525     CHECK_NULL_RETURN(container, false);
1526     auto pipeline = container->GetPipelineContext();
1527     CHECK_NULL_RETURN(pipeline, false);
1528     auto context = DynamicCast<NG::PipelineContext>(pipeline);
1529     auto stageManager = context ? context->GetStageManager() : nullptr;
1530     if (stageManager) {
1531         Recorder::NodeDataCache::Get().OnBeforePagePop();
1532         return stageManager->PopPageToIndex(index, needShowNext, needTransition);
1533     }
1534     return false;
1535 }
1536 
OnCleanPageStack()1537 bool PageRouterManager::OnCleanPageStack()
1538 {
1539     auto container = Container::Current();
1540     CHECK_NULL_RETURN(container, false);
1541     auto pipeline = container->GetPipelineContext();
1542     CHECK_NULL_RETURN(pipeline, false);
1543     auto context = DynamicCast<NG::PipelineContext>(pipeline);
1544     auto stageManager = context ? context->GetStageManager() : nullptr;
1545     if (stageManager) {
1546         return stageManager->CleanPageStack();
1547     }
1548     return false;
1549 }
1550 
CleanPageOverlay()1551 void PageRouterManager::CleanPageOverlay()
1552 {
1553     auto container = Container::Current();
1554     CHECK_NULL_VOID(container);
1555     auto pipeline = container->GetPipelineContext();
1556     CHECK_NULL_VOID(pipeline);
1557     auto context = DynamicCast<NG::PipelineContext>(pipeline);
1558     CHECK_NULL_VOID(context);
1559     auto overlayManager = context->GetOverlayManager();
1560     CHECK_NULL_VOID(overlayManager);
1561     auto taskExecutor = context->GetTaskExecutor();
1562     CHECK_NULL_VOID(taskExecutor);
1563     auto sharedManager = context->GetSharedOverlayManager();
1564     if (sharedManager) {
1565         sharedManager->StopSharedTransition();
1566     }
1567 
1568     overlayManager->RemoveOverlay(true, true);
1569 }
1570 
CheckIndexValid(int32_t index) const1571 bool PageRouterManager::CheckIndexValid(int32_t index) const
1572 {
1573     if (index > static_cast<int32_t>(pageRouterStack_.size()) || index <= 0) {
1574         LOGW("The index is less than or equal to zero or exceeds the maximum length of the page stack");
1575         return false;
1576     }
1577     return true;
1578 }
1579 
DealReplacePage(const RouterPageInfo & info)1580 void PageRouterManager::DealReplacePage(const RouterPageInfo& info)
1581 {
1582     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1583         ReplacePageInNewLifecycle(info);
1584         return;
1585     }
1586     PopPage("", false, false);
1587     if (info.routerMode == RouterMode::SINGLE) {
1588         auto pageInfo = FindPageInStack(info.url);
1589         if (pageInfo.second) {
1590             // find page in stack, move position and update params.
1591             MovePageToFront(pageInfo.first, pageInfo.second, info, false, true, false);
1592             return;
1593         }
1594     }
1595     LoadPage(GenerateNextPageId(), info, false, false);
1596 }
1597 
CheckOhmUrlValid(const std::string & ohmUrl)1598 bool PageRouterManager::CheckOhmUrlValid(const std::string& ohmUrl)
1599 {
1600     size_t bundleEndPos = ohmUrl.find('/');
1601     std::string bundleName = ohmUrl.substr(BUNDLE_START_POS, bundleEndPos - BUNDLE_START_POS);
1602     size_t moduleStartPos = bundleEndPos + 1;
1603     size_t moduleEndPos = ohmUrl.find('/', moduleStartPos);
1604     std::string moduleName = ohmUrl.substr(moduleStartPos, moduleEndPos - moduleStartPos);
1605     auto runtime = std::static_pointer_cast<Framework::ArkJSRuntime>(
1606         Framework::JsiDeclarativeEngineInstance::GetCurrentRuntime());
1607     return runtime->IsExecuteModuleInAbcFile(bundleName, moduleName, ohmUrl);
1608 }
1609 
ThrowError(const std::string & msg,int32_t code)1610 void PageRouterManager::ThrowError(const std::string& msg, int32_t code)
1611 {
1612     auto runtime = std::static_pointer_cast<Framework::ArkJSRuntime>(
1613         Framework::JsiDeclarativeEngineInstance::GetCurrentRuntime());
1614     runtime->ThrowError(msg, code);
1615 }
1616 
GetPageIndex(const WeakPtr<FrameNode> & page)1617 int32_t PageRouterManager::GetPageIndex(const WeakPtr<FrameNode>& page)
1618 {
1619     auto pageNode = page.Upgrade();
1620     CHECK_NULL_RETURN(pageNode, INVALID_PAGE_INDEX);
1621     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
1622     CHECK_NULL_RETURN(pagePattern, INVALID_PAGE_INDEX);
1623     auto ret = pagePattern->GetPageInfo()->GetPageIndex();
1624     // frontend index counts from 1, so need -1 for backend use
1625     return ret == INVALID_PAGE_INDEX ? INVALID_PAGE_INDEX : ret - 1;
1626 }
1627 
ReplacePageInNewLifecycle(const RouterPageInfo & info)1628 void PageRouterManager::ReplacePageInNewLifecycle(const RouterPageInfo& info)
1629 {
1630     auto pipelineContext = PipelineContext::GetCurrentContext();
1631     CHECK_NULL_VOID(pipelineContext);
1632 #if defined(ENABLE_SPLIT_MODE)
1633     auto stageManager = pipelineContext->GetStageManager();
1634     CHECK_NULL_VOID(stageManager);
1635 #endif
1636     TAG_LOGI(AceLogTag::ACE_ROUTER,
1637         "router replace in new lifecycle(API version > 11), replace mode: %{public}d, url: %{public}s",
1638         static_cast<int32_t>(info.routerMode), info.url.c_str());
1639     auto popNode = GetCurrentPageNode();
1640     int32_t popIndex = static_cast<int32_t>(pageRouterStack_.size()) - 1;
1641     bool findPage = false;
1642     if (info.routerMode == RouterMode::SINGLE) {
1643         auto pageInfo = FindPageInStack(info.url);
1644         // haven't find page by named route's name. Try again with its page path.
1645         if (pageInfo.second == nullptr && info.isNamedRouterMode) {
1646             std::string pagePath = Framework::JsiDeclarativeEngine::GetPagePath(info.url);
1647             pageInfo = FindPageInStack(pagePath);
1648         }
1649         if (pageInfo.first == popIndex) {
1650             // replace top self in SINGLE mode, do nothing.
1651             return;
1652         }
1653         if (pageInfo.second) {
1654             // find page in stack, move position and update params.
1655 #if defined(ENABLE_SPLIT_MODE)
1656             stageManager->SetIsNewPageReplacing(true);
1657 #endif
1658             MovePageToFront(pageInfo.first, pageInfo.second, info, false, true, false);
1659 #if defined(ENABLE_SPLIT_MODE)
1660             stageManager->SetIsNewPageReplacing(false);
1661 #endif
1662             popIndex = popIndex - 1;
1663             findPage = true;
1664         }
1665     }
1666     if (!findPage) {
1667         isNewPageReplacing_ = true;
1668 #if defined(ENABLE_SPLIT_MODE)
1669         stageManager->SetIsNewPageReplacing(true);
1670 #endif
1671         LoadPage(GenerateNextPageId(), info, true, false);
1672 #if defined(ENABLE_SPLIT_MODE)
1673         stageManager->SetIsNewPageReplacing(false);
1674 #endif
1675         isNewPageReplacing_ = false;
1676     }
1677     if (popIndex < 0 || popNode == GetCurrentPageNode() || GetPageIndex(popNode) != popIndex) {
1678         return;
1679     }
1680     auto iter = pageRouterStack_.begin();
1681     std::advance(iter, popIndex);
1682     auto lastIter = pageRouterStack_.erase(iter);
1683     pageRouterStack_.emplace_back(WeakPtr<FrameNode>(AceType::DynamicCast<FrameNode>(popNode)));
1684     popNode->MovePosition(GetLastPageIndex());
1685     for (auto iter = lastIter; iter != pageRouterStack_.end(); ++iter, ++popIndex) {
1686         auto page = iter->Upgrade();
1687         if (!page) {
1688             continue;
1689         }
1690         if (page == popNode) {
1691             // do not change index of page that will be replaced.
1692             continue;
1693         }
1694         auto pagePattern = page->GetPattern<NG::PagePattern>();
1695         pagePattern->GetPageInfo()->SetPageIndex(popIndex + 1);
1696     }
1697 #if defined(ENABLE_SPLIT_MODE)
1698     stageManager->SetIsNewPageReplacing(true);
1699 #endif
1700     PopPage("", false, false);
1701 #if defined(ENABLE_SPLIT_MODE)
1702     stageManager->SetIsNewPageReplacing(false);
1703 #endif
1704 }
1705 
SetPageInfoRouteName(const RefPtr<EntryPageInfo> & info,bool isNamedRouterMode)1706 void PageRouterManager::SetPageInfoRouteName(const RefPtr<EntryPageInfo>& info, bool isNamedRouterMode)
1707 {
1708     std::optional<std::string> routeName = std::nullopt;
1709     if (isNamedRouterMode) {
1710         // info->GetPageUrl() represents the name of namedRoute
1711         routeName = info->GetPageUrl();
1712     } else {
1713         auto container = Container::Current();
1714         CHECK_NULL_VOID(container);
1715         // info->GetPageUrl() represents the url of destination page
1716         routeName = Framework::JsiDeclarativeEngine::GetRouteNameByUrl(
1717             info->GetPageUrl(), container->GetBundleName(), container->GetModuleName());
1718     }
1719     info->SetRouteName(routeName);
1720 }
1721 } // namespace OHOS::Ace::NG
1722