1 /*
2  * Copyright (c) 2020 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 "ability_stack_manager.h"
17 
18 #include "util/abilityms_helper.h"
19 
20 namespace OHOS {
GeneratePageAbility(const AbilityInfo & target,const Want & want,const PageAbilityRecord * topAbility,AbilityMgrContext & amsContext) const21 PageAbilityRecord *AbilityStackManager::GeneratePageAbility(const AbilityInfo &target,
22     const Want &want, const PageAbilityRecord *topAbility, AbilityMgrContext &amsContext) const
23 {
24     CHECK_NULLPTR_RETURN_PTR(target.name, "AbilityStackManager", "target ability name is nullptr");
25     auto stack = const_cast<AbilityMissionStack *>(amsContext.GetTargetMissionStack(target.bundleName));
26     CHECK_NULLPTR_RETURN_PTR(stack, "AbilityStackManager", "missionStack is nullptr");
27 
28     PageAbilityRecord *targetAbility = nullptr;
29     AbilityMissionRecord *targetMission = stack->GetTargetMissionRecord(target.bundleName);
30     auto topMissionRecord = stack->GetTopMissionRecord();
31     /* launcher -> default or default -> launcher */
32     if (topAbility == nullptr || AbilityMsHelper::IsAceAbility(target.name) ||
33         (!topAbility->IsLauncherAbility() && AbilityMsHelper::IsLauncherAbility(target.bundleName)) ||
34         (topAbility->IsLauncherAbility() && !AbilityMsHelper::IsLauncherAbility(target.bundleName))) {
35         // Get the mission record of the current bundleName
36         PRINTD("AbilityStackManager", "launcher jumps to default or default jumps to launcher");
37         if (targetMission == nullptr) {
38             targetMission = new AbilityMissionRecord(stack, target.bundleName);
39             targetAbility = new PageAbilityRecord(target, want);
40             targetMission->PushPageAbility(*targetAbility);
41             stack->PushTopMissionRecord(*targetMission);
42         } else {
43             targetAbility = const_cast<PageAbilityRecord *>(targetMission->GetTopPageAbility());
44             stack->MoveMissionRecordToTop(*targetMission);
45         }
46     } else {
47         PRINTD("AbilityStackManager", "default application jumps to another default");
48         if (targetMission == nullptr) {
49             targetMission = new AbilityMissionRecord(stack, target.bundleName);
50             stack->PushTopMissionRecord(*targetMission);
51             targetAbility = new PageAbilityRecord(target, want);
52             targetMission->PushPageAbility(*targetAbility);
53         } else {
54             PageAbilityRecord *targetTopAbility = const_cast<PageAbilityRecord *>(targetMission->GetTopPageAbility());
55             if (targetTopAbility != nullptr && targetTopAbility->IsSamePageAbility(want)) {
56                 targetAbility = targetTopAbility;
57             } else {
58                 targetAbility = new PageAbilityRecord(target, want);
59                 targetMission->PushPageAbility(*targetAbility);
60             }
61             stack->MoveMissionRecordToTop(*targetMission);
62         }
63     }
64 
65     // default jumps to default, then return to default
66     if (topAbility != nullptr && !topAbility->IsLauncherAbility() &&
67         targetAbility != nullptr && !targetAbility->IsLauncherAbility()) {
68         if (targetMission != nullptr && topMissionRecord != nullptr && targetMission != topMissionRecord) {
69             targetMission->SetPrevMissionRecord(topMissionRecord);
70         }
71     }
72 
73     amsContext.SetTopMissionStacks(stack);
74     return targetAbility;
75 }
76 
GetTopPageAbility(const AbilityMgrContext & amsContext) const77 const PageAbilityRecord *AbilityStackManager::GetTopPageAbility(const AbilityMgrContext &amsContext) const
78 {
79     const AbilityMissionStack *topMissionStack = amsContext.GetTopMissionStacks();
80     CHECK_NULLPTR_RETURN_PTR(topMissionStack, "AbilityStackManager", "topMissionStack is nullptr");
81     return topMissionStack->GetTopPageAbility();
82 }
83 
RemovePageAbility(const PageAbilityRecord & target,AbilityMgrContext & amsContext)84 void AbilityStackManager::RemovePageAbility(const PageAbilityRecord &target, AbilityMgrContext &amsContext)
85 {
86     AbilityMissionRecord *missionRecord = const_cast<AbilityMissionRecord *>(target.GetMissionRecord());
87     CHECK_NULLPTR_RETURN(missionRecord, "AbilityStackManager", "missionRecord is nullptr");
88     missionRecord->RemovePageAbility(target);
89     // Current mission reocrd is empty
90     if (missionRecord->IsEmpty()) {
91         AbilityMissionStack *stack = const_cast<AbilityMissionStack *>(missionRecord->GetMissionStack());
92         if (stack != nullptr) {
93             stack->RemoveMissionRecord(*missionRecord);
94         }
95         auto prevMissionRecord = const_cast<AbilityMissionRecord *>(missionRecord->GetPrevMissionRecord());
96         if (stack != nullptr && prevMissionRecord != nullptr) {
97             stack->MoveMissionRecordToTop(*prevMissionRecord);
98         } else {
99             amsContext.SetTopMissionStacks(amsContext.GetLauncherMissionStacks());
100         }
101         delete missionRecord;
102     }
103 }
104 
ClearAbilityStack(const char * bundleName,AbilityMgrContext & amsContext) const105 void AbilityStackManager::ClearAbilityStack(const char *bundleName, AbilityMgrContext &amsContext) const
106 {
107     CHECK_NULLPTR_RETURN(bundleName, "AbilityStackManager", "invalid argument");
108     AbilityConnectMission *connectMission = const_cast<AbilityConnectMission *>(amsContext.GetServiceConnects());
109     if (connectMission != nullptr) {
110         connectMission->RemoveServiceRecord(bundleName);
111     }
112     // get target mission record
113     auto missionStack = const_cast<AbilityMissionStack *>(amsContext.GetTargetMissionStack(bundleName));
114     CHECK_NULLPTR_RETURN(missionStack, "AbilityStackManager", "missionStack is nullptr");
115     AbilityMissionRecord *missionRecord = missionStack->GetTargetMissionRecord(bundleName);
116     if (missionRecord != nullptr) {
117         // if default application jumps to another default, return prev application
118         auto prevMissionRecord = const_cast<AbilityMissionRecord *>(missionRecord->GetPrevMissionRecord());
119         if (prevMissionRecord != nullptr) {
120             missionStack->MoveMissionRecordToTop(*prevMissionRecord);
121         } else {
122             // return launcher application
123             const AbilityMissionStack *topMissionStack = amsContext.GetTopMissionStacks();
124             if (topMissionStack != nullptr && topMissionStack->IsTopMissionRecord(bundleName)) {
125                 amsContext.SetTopMissionStacks(amsContext.GetLauncherMissionStacks());
126             }
127         }
128     }
129 
130     missionStack->RemoveMissionRecord(connectMission, bundleName);
131 }
132 
FindPageAbility(const AbilityMgrContext & amsContext,uint64_t token) const133 PageAbilityRecord *AbilityStackManager::FindPageAbility(const AbilityMgrContext &amsContext, uint64_t token) const
134 {
135     PageAbilityRecord *record = nullptr;
136     const AbilityMissionStack *stack = amsContext.GetDefaultMissionStacks();
137     if (stack != nullptr) {
138         record = stack->FindPageAbility(token);
139         if (record != nullptr) {
140             return record;
141         }
142     }
143     stack = amsContext.GetLauncherMissionStacks();
144     if (stack != nullptr) {
145         record = stack->FindPageAbility(token);
146     }
147 
148     // find service ability
149     if (record == nullptr) {
150         auto serviceConnects = amsContext.GetServiceConnects();
151         if (serviceConnects != nullptr) {
152             record = serviceConnects->FindServiceRecord(token);
153         }
154     }
155     return record;
156 }
157 
FindPageAbility(const AbilityMgrContext & amsContext,const Want & want) const158 const PageAbilityRecord *AbilityStackManager::FindPageAbility(const AbilityMgrContext &amsContext,
159     const Want &want) const
160 {
161     CHECK_NULLPTR_RETURN_PTR(want.element, "AbilityStackManager", "element is nullptr");
162     auto missionStack = amsContext.GetTargetMissionStack(want.element->bundleName);
163     CHECK_NULLPTR_RETURN_PTR(missionStack, "AbilityStackManager", "target mission stack is nullptr");
164     PageAbilityRecord *record = missionStack->FindPageAbility(want);
165     if (record != nullptr) {
166         return record;
167     }
168     const AbilityConnectMission *connectMission = amsContext.GetServiceConnects();
169     CHECK_NULLPTR_RETURN_PTR(connectMission, "AbilityStackManager", "service connect is nullptr");
170     return connectMission->FindServiceRecord(want.element->bundleName, want.element->abilityName);
171 }
172 
GetPrevPageAbility(const AbilityMgrContext & amsContext,const PageAbilityRecord & current) const173 const PageAbilityRecord *AbilityStackManager::GetPrevPageAbility(const AbilityMgrContext &amsContext,
174     const PageAbilityRecord &current) const
175 {
176     AbilityMissionRecord *currentMission = const_cast<AbilityMissionRecord *>(current.GetMissionRecord());
177     if (currentMission != nullptr) {
178         PageAbilityRecord *prevAbility = currentMission->GetPrevPageAbility(current);
179         if (prevAbility != nullptr) {
180             return prevAbility;
181         } else {
182             auto prevMission = currentMission->GetPrevMissionRecord();
183             if (prevMission != nullptr) {
184                 return prevMission->GetTopPageAbility();
185             }
186         }
187     }
188     auto launcherStack = amsContext.GetLauncherMissionStacks();
189     CHECK_NULLPTR_RETURN_PTR(launcherStack, "AbilityStackManager", "launcherStack is nullptr");
190     return launcherStack->GetTopPageAbility();
191 }
192 
ExistAppInStack(const AbilityInfo & target,AbilityMgrContext & amsContext) const193 bool AbilityStackManager::ExistAppInStack(const AbilityInfo &target, AbilityMgrContext &amsContext) const
194 {
195     auto stack = amsContext.GetTargetMissionStack(target.bundleName);
196     if (stack == nullptr) {
197         return false;
198     }
199     AbilityMissionRecord *targetMission = stack->GetTargetMissionRecord(target.bundleName);
200     return targetMission != nullptr;
201 }
202 
203 #ifdef OHOS_DEBUG
DumpAllAbilityRecord(const AbilityMgrContext & amsContext) const204 AbilityMsStatus AbilityStackManager::DumpAllAbilityRecord(const AbilityMgrContext &amsContext) const
205 {
206     AbilityMsStatus result = AbilityMsStatus::DumpStatus("");
207     const AbilityMissionStack *stack = amsContext.GetTopMissionStacks();
208     if (stack != nullptr) {
209         result.DumpAppend(stack->DumpMissionStack());
210         if (stack->GetStackType() == LAUNCHER) {
211             stack = amsContext.GetDefaultMissionStacks();
212             if (stack != nullptr) {
213                 result.DumpAppend(stack->DumpMissionStack());
214             }
215         } else if (stack->GetStackType() == DEFAULT) {
216             stack = amsContext.GetLauncherMissionStacks();
217             if (stack != nullptr) {
218                 result.DumpAppend(stack->DumpMissionStack());
219             }
220         }
221     }
222     const AbilityConnectMission *mission = amsContext.GetServiceConnects();
223     if (mission != nullptr) {
224         result.DumpAppend(mission->DumpConnectMission());
225     }
226     return result;
227 }
228 #endif
229 
FindServiceAbility(const AbilityMgrContext & amsContext,uint64_t token) const230 PageAbilityRecord *AbilityStackManager::FindServiceAbility(const AbilityMgrContext &amsContext, uint64_t token) const
231 {
232     auto serviceConnects = amsContext.GetServiceConnects();
233     CHECK_NULLPTR_RETURN_PTR(serviceConnects, "AbilityStackManager", "serviceConnects is nullptr");
234     return serviceConnects->FindServiceRecord(token);
235 }
236 
FindServiceAbility(const AbilityMgrContext & amsContext,const char * bundleName,const char * abilityName) const237 PageAbilityRecord *AbilityStackManager::FindServiceAbility(const AbilityMgrContext &amsContext,
238     const char *bundleName, const char *abilityName) const
239 {
240     auto serviceConnects = amsContext.GetServiceConnects();
241     CHECK_NULLPTR_RETURN_PTR(serviceConnects, "AbilityStackManager", "serviceConnects is nullptr");
242     return serviceConnects->FindServiceRecord(bundleName, abilityName);
243 }
244 }
245