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