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 "page_ability_record.h"
17 
18 #include "ability_connect_mission.h"
19 #include "ability_info_utils.h"
20 #include "ability_mission_record.h"
21 #include "adapter.h"
22 #include "app_manager.h"
23 #include "bundle_info_utils.h"
24 #include "securec.h"
25 #include "token_generate.h"
26 #include "util/abilityms_helper.h"
27 
28 namespace OHOS {
29 
30 namespace {
31     constexpr static uint16_t CONNECT_RECORDS_LIST_CAPACITY = 10240;
32 }
33 
PageAbilityRecord(const AbilityInfo & abilityInfo,const Want & want)34 PageAbilityRecord::PageAbilityRecord(const AbilityInfo &abilityInfo, const Want &want)
35 {
36     if (want.element != nullptr) {
37         SetWantElement(&want_, *(want.element));
38     }
39     if (want.data != nullptr) {
40         SetWantData(&want_, want.data, want.dataLength);
41     }
42     if (want.sid != nullptr) {
43         SetWantSvcIdentity(&want_, *(want.sid));
44     }
45     AbilityInfoUtils::CopyAbilityInfo(&abilityInfo_, abilityInfo);
46     Initialize();
47     PRINTD("PageAbilityRecord", "Constructor");
48 }
49 
~PageAbilityRecord()50 PageAbilityRecord::~PageAbilityRecord()
51 {
52     if (appRecord_ != nullptr) {
53         appRecord_->ClearPendingAbility(this);
54         appRecord_ = nullptr;
55     }
56     ClearWant(&want_);
57     ClearAbilityInfo(&abilityInfo_);
58     ClearBundleInfo(&bundleInfo_);
59     missionRecord_ = nullptr;
60     prevPageAbility_ = nullptr;
61     nextPageAbility_ = nullptr;
62 
63     for (auto iterator = connectRecords_.begin(); iterator != connectRecords_.end(); ++iterator) {
64         auto record = *iterator;
65         delete record;
66     }
67     connectRecords_.clear();
68     PRINTD("AbilityRecord", "Destructor");
69 }
70 
Initialize()71 void PageAbilityRecord::Initialize()
72 {
73     token_ = TokenGenerate::GenerateToken();
74     appRecord_ = AppManager::GetInstance().GetAppRecordByBundleName(abilityInfo_.bundleName);
75 }
76 
GetAbilityInfo() const77 const AbilityInfo& PageAbilityRecord::GetAbilityInfo() const
78 {
79     return abilityInfo_;
80 }
81 
GetBundleInfo() const82 const BundleInfo& PageAbilityRecord::GetBundleInfo() const
83 {
84     return bundleInfo_;
85 }
86 
SetBundleInfo(const BundleInfo & bundleInfo)87 void PageAbilityRecord::SetBundleInfo(const BundleInfo &bundleInfo)
88 {
89     if (memset_s(&bundleInfo_, sizeof(BundleInfo), 0, sizeof(BundleInfo)) == EOK) {
90         BundleInfoUtils::CopyBundleInfo(0, &bundleInfo_, bundleInfo);
91     }
92 }
93 
IsSamePageAbility(const PageAbilityRecord & target) const94 bool PageAbilityRecord::IsSamePageAbility(const PageAbilityRecord &target) const
95 {
96     return token_ == target.GetToken();
97 }
98 
IsSamePageAbility(const Want & want) const99 bool PageAbilityRecord::IsSamePageAbility(const Want &want) const
100 {
101     if (want.element == nullptr || want.element->bundleName == nullptr || want.element->abilityName == nullptr) {
102         return false;
103     }
104     if (abilityInfo_.bundleName == nullptr || abilityInfo_.name == nullptr) {
105         return false;
106     }
107     if (strcmp(abilityInfo_.bundleName, want.element->bundleName) == 0 &&
108         strcmp(abilityInfo_.name, want.element->abilityName) == 0) {
109         return true;
110     }
111     return false;
112 }
113 
IsSamePageAbility(const char * bundleName) const114 bool PageAbilityRecord::IsSamePageAbility(const char *bundleName) const
115 {
116     if (bundleName == nullptr || abilityInfo_.bundleName == nullptr) {
117         return false;
118     }
119     return strcmp(bundleName, abilityInfo_.bundleName) == 0;
120 }
121 
IsBottomPageAbility() const122 bool PageAbilityRecord::IsBottomPageAbility() const
123 {
124     if (missionRecord_ != nullptr) {
125         const PageAbilityRecord *bottomAbililty = missionRecord_->GetBottomPageAbility();
126         if (bottomAbililty != nullptr && bottomAbililty->GetToken() == token_) {
127             return true;
128         }
129     }
130     return false;
131 }
132 
GetConnectStatus() const133 ConnectStatus PageAbilityRecord::GetConnectStatus() const
134 {
135     return connectStatus_;
136 }
137 
IsPerformStop() const138 bool PageAbilityRecord::IsPerformStop() const
139 {
140     return connectStatus_ == ConnectStatus::STOPPING || connectStatus_ == ConnectStatus::STOPPED;
141 }
142 
SetConnectStatus(ConnectStatus connectStatus)143 void PageAbilityRecord::SetConnectStatus(ConnectStatus connectStatus)
144 {
145     connectStatus_ = connectStatus;
146 }
147 
SetStartDone(bool startDone)148 void PageAbilityRecord::SetStartDone(bool startDone)
149 {
150     startDone_ = startDone;
151 }
152 
GetToken() const153 uint64_t PageAbilityRecord::GetToken() const
154 {
155     return token_;
156 }
157 
SetCurrentState(State state)158 void PageAbilityRecord::SetCurrentState(State state)
159 {
160     currentState_ = state;
161 }
162 
GetCurrentState() const163 State PageAbilityRecord::GetCurrentState() const
164 {
165     return currentState_;
166 }
167 
SetMissionRecord(AbilityMissionRecord * missionRecord)168 void PageAbilityRecord::SetMissionRecord(AbilityMissionRecord *missionRecord)
169 {
170     missionRecord_ = missionRecord;
171 }
172 
GetMissionRecord() const173 const AbilityMissionRecord *PageAbilityRecord::GetMissionRecord() const
174 {
175     return missionRecord_;
176 }
177 
SetNextPageAbility(PageAbilityRecord * next)178 void PageAbilityRecord::SetNextPageAbility(PageAbilityRecord *next)
179 {
180     nextPageAbility_ = next;
181 }
182 
GetNextPageAbility() const183 const PageAbilityRecord *PageAbilityRecord::GetNextPageAbility() const
184 {
185     return nextPageAbility_;
186 }
187 
SetPrevPageAbility(PageAbilityRecord * prev)188 void PageAbilityRecord::SetPrevPageAbility(PageAbilityRecord *prev)
189 {
190     prevPageAbility_ = prev;
191 }
192 
GetPrevPageAbility() const193 const PageAbilityRecord *PageAbilityRecord::GetPrevPageAbility() const
194 {
195     return prevPageAbility_;
196 }
197 
SetConnectMission(AbilityConnectMission * connectMission)198 void PageAbilityRecord::SetConnectMission(AbilityConnectMission *connectMission)
199 {
200     connectMission_ = connectMission;
201 }
202 
GetConnectMission() const203 const AbilityConnectMission *PageAbilityRecord::GetConnectMission() const
204 {
205     return connectMission_;
206 }
207 
SetServiceSid(const SvcIdentity & serviceSid)208 void PageAbilityRecord::SetServiceSid(const SvcIdentity &serviceSid)
209 {
210     serviceSid_ = serviceSid;
211 }
212 
GetServiceSid() const213 const SvcIdentity PageAbilityRecord::GetServiceSid() const
214 {
215     return serviceSid_;
216 }
217 
GetConnectRecord(const SvcIdentity & serviceSid) const218 AbilityConnectRecord *PageAbilityRecord::GetConnectRecord(const SvcIdentity &serviceSid) const
219 {
220     for (const auto record : connectRecords_) {
221         if (record != nullptr && record->GetConnectSid().handle == serviceSid.handle &&
222             record->GetConnectSid().token == serviceSid.token) {
223             return record;
224         }
225     }
226     return nullptr;
227 }
228 
pushConnectRecord(AbilityConnectRecord * connectRecord)229 void PageAbilityRecord::pushConnectRecord(AbilityConnectRecord *connectRecord)
230 {
231     if (connectRecords_.size() >= CONNECT_RECORDS_LIST_CAPACITY) {
232         return;
233     }
234     connectRecords_.emplace_back(connectRecord);
235 }
236 
RemoveConnectRecord(const SvcIdentity & serviceSid)237 void PageAbilityRecord::RemoveConnectRecord(const SvcIdentity &serviceSid)
238 {
239     for (auto iterator = connectRecords_.begin(); iterator != connectRecords_.end(); ++iterator) {
240         auto record = *iterator;
241         if (record != nullptr && record->GetConnectSid().handle == serviceSid.handle &&
242             record->GetConnectSid().token == serviceSid.token) {
243             connectRecords_.erase(iterator);
244             delete record;
245             return;
246         }
247     }
248 }
249 
IsLauncherAbility() const250 bool PageAbilityRecord::IsLauncherAbility() const
251 {
252     return AbilityMsHelper::IsLauncherAbility(abilityInfo_.bundleName);
253 }
254 
StartAbility()255 AbilityMsStatus PageAbilityRecord::StartAbility()
256 {
257     if (appRecord_ == nullptr) {
258         // If process is not exist, start process.
259         appRecord_ = AppManager::GetInstance().StartAppProcess(bundleInfo_);
260         if (appRecord_ == nullptr) {
261             return AbilityMsStatus::ProcessStatus("start app process fail");
262         }
263         appRecord_->SetPendingAbility(this);
264         return AbilityMsStatus::Ok();
265     }
266     return ActiveAbility();
267 }
268 
StartService()269 AbilityMsStatus PageAbilityRecord::StartService()
270 {
271     if (appRecord_ == nullptr) {
272         // If process is not exist, start process.
273         appRecord_ = AppManager::GetInstance().StartAppProcess(bundleInfo_);
274         if (appRecord_ == nullptr) {
275             return AbilityMsStatus::ProcessStatus("start app process fail");
276         }
277         appRecord_->SetPendingAbility(this);
278         return AbilityMsStatus::Ok();
279     }
280     return InactiveAbility();
281 }
282 
ActiveAbility()283 AbilityMsStatus PageAbilityRecord::ActiveAbility()
284 {
285     if (currentState_ == STATE_ACTIVE) {
286         return AbilityMsStatus::LifeCycleStatus("current state is already active when active");
287     }
288     if (appRecord_ == nullptr) {
289         return AbilityMsStatus::AppTransanctStatus("app record not exist");
290     }
291     TransactionState state = {token_, STATE_ACTIVE};
292     auto status = appRecord_->AbilityTransaction(state, want_, abilityInfo_.abilityType);
293     AdapterFree(want_.sid);
294     return status;
295 }
296 
InactiveAbility() const297 AbilityMsStatus PageAbilityRecord::InactiveAbility() const
298 {
299     if (currentState_ != STATE_ACTIVE && abilityInfo_.abilityType != AbilityType::SERVICE) {
300         return AbilityMsStatus::LifeCycleStatus("current state is not active when inactive");
301     }
302     if (appRecord_ == nullptr) {
303         return AbilityMsStatus::AppTransanctStatus("app record not exist");
304     }
305     TransactionState state = {token_, STATE_INACTIVE};
306     return appRecord_->AbilityTransaction(state, want_, abilityInfo_.abilityType);
307 }
308 
ToBackgroundAbility() const309 AbilityMsStatus PageAbilityRecord::ToBackgroundAbility() const
310 {
311     if (currentState_ != STATE_INACTIVE) {
312         return AbilityMsStatus::LifeCycleStatus("current state is not inactive when background");
313     }
314     if (appRecord_ == nullptr) {
315         return AbilityMsStatus::AppTransanctStatus("app record not exist");
316     }
317     TransactionState state = {token_, STATE_BACKGROUND};
318     return appRecord_->AbilityTransaction(state, want_, abilityInfo_.abilityType);
319 }
320 
StopAbility() const321 AbilityMsStatus PageAbilityRecord::StopAbility() const
322 {
323     if (currentState_ != STATE_INACTIVE) {
324         return AbilityMsStatus::LifeCycleStatus("current state is not inactive when stop");
325     }
326     if (appRecord_ == nullptr) {
327         return AbilityMsStatus::AppTransanctStatus("app record not exist");
328     }
329     TransactionState state = {token_, STATE_INITIAL};
330     return appRecord_->AbilityTransaction(state, want_, abilityInfo_.abilityType);
331 }
332 
ExitApp()333 AbilityMsStatus PageAbilityRecord::ExitApp()
334 {
335     if (appRecord_ == nullptr) {
336         return AbilityMsStatus::AppTransanctStatus("app record not exist");
337     }
338     AbilityMsStatus status = appRecord_->AppExitTransaction();
339     if (status.IsOk()) {
340         AppManager::GetInstance().RemoveAppRecord(*appRecord_);
341         appRecord_ = nullptr;
342     }
343     return status;
344 }
345 
ConnectAbility()346 AbilityMsStatus PageAbilityRecord::ConnectAbility()
347 {
348     if (appRecord_ == nullptr) {
349         return AbilityMsStatus::TaskStatus("connectAbility, ", "app record not exist");
350     }
351     return appRecord_->ConnectTransaction(want_, token_);
352 }
353 
DisconnectAbility(const SvcIdentity & connectSid)354 AbilityMsStatus PageAbilityRecord::DisconnectAbility(const SvcIdentity &connectSid)
355 {
356     if (appRecord_ == nullptr) {
357         return AbilityMsStatus::TaskStatus("disconnectAbility, ", "app record not exist");
358     }
359     RemoveConnectRecord(connectSid);
360 
361     if (connectStatus_ == ConnectStatus::DISCONNECT || connectStatus_ == ConnectStatus::DISCONNECTING) {
362         PRINTW("disconnectAbility", "service is disconnecting");
363         return AbilityMsStatus::Ok();
364     }
365     if (IsPerformStop()) {
366         PRINTW("disconnectAbility", "service is stopping");
367         return AbilityMsStatus::Ok();
368     }
369     if (connectRecords_.empty()) {
370         SetConnectStatus(ConnectStatus::DISCONNECTING);
371         return appRecord_->DisconnectTransaction(want_, token_);
372     }
373     return AbilityMsStatus::Ok();
374 }
375 
ConnectAbilityDone()376 AbilityMsStatus PageAbilityRecord::ConnectAbilityDone()
377 {
378     if (appRecord_ == nullptr) {
379         return AbilityMsStatus::TaskStatus("connectAbilityDone, ", "app record not exist");
380     }
381     for (auto record : connectRecords_) {
382         if (record != nullptr && record->GetStatus() == ConnectStatus::CONNECTING) {
383             record->SetStatus(ConnectStatus::CONNECTED);
384             appRecord_->ConnectDoneTransaction(want_, serviceSid_, record->GetConnectSid());
385         }
386     }
387     return AbilityMsStatus::Ok();
388 }
389 
DisconnectAbilityDone()390 AbilityMsStatus PageAbilityRecord::DisconnectAbilityDone()
391 {
392     if (appRecord_ == nullptr) {
393         return AbilityMsStatus::TaskStatus("disconnectAbilityDone, ", "app record not exist");
394     }
395     if (startDone_) {
396         SetConnectStatus(ConnectStatus::INIT);
397     } else {
398         SetConnectStatus(ConnectStatus::DISCONNECT);
399     }
400     if ((connectRecords_.empty() && !startDone_) || forceStop_) {
401         SetConnectStatus(ConnectStatus::STOPPING);
402         TransactionState state = {token_, STATE_INITIAL};
403         return appRecord_->AbilityTransaction(state, want_, abilityInfo_.abilityType);
404     }
405     return AbilityMsStatus::Ok();
406 }
407 
ForceStopServiceAbility()408 AbilityMsStatus PageAbilityRecord::ForceStopServiceAbility()
409 {
410     if (appRecord_ == nullptr) {
411         return AbilityMsStatus::TaskStatus("terminateService, ", "app record not exist");
412     }
413     forceStop_ = true;
414     if (IsPerformStop()) {
415         return AbilityMsStatus::TaskStatus("terminateService", "service is stopping");
416     }
417     if (connectStatus_ == ConnectStatus::DISCONNECTING) {
418         return AbilityMsStatus::TaskStatus("terminateService", "service is disconnecting");
419     }
420     if (connectStatus_ == ConnectStatus::DISCONNECT || connectRecords_.empty()) {
421         SetConnectStatus(ConnectStatus::STOPPING);
422         TransactionState state = {token_, STATE_INITIAL};
423         return appRecord_->AbilityTransaction(state, want_, abilityInfo_.abilityType);
424     } else {
425         SetConnectStatus(ConnectStatus::DISCONNECTING);
426         return appRecord_->DisconnectTransaction(want_, token_);
427     }
428 }
429 
StopAbilityDone()430 AbilityMsStatus PageAbilityRecord::StopAbilityDone()
431 {
432     if (appRecord_ == nullptr) {
433         return AbilityMsStatus::TaskStatus("disconnectAbilityDone, ", "app record not exist");
434     }
435     SetConnectStatus(ConnectStatus::STOPPED);
436     for (const auto record : connectRecords_) {
437         if (record != nullptr) {
438             appRecord_->DisconnectDoneTransaction(want_, record->GetConnectSid());
439         }
440     }
441     return AbilityMsStatus::Ok();
442 }
443 
444 #ifdef OHOS_DEBUG
DumpAbilityRecord() const445 AbilityMsStatus PageAbilityRecord::DumpAbilityRecord() const
446 {
447     std::string launcherMode = (abilityInfo_.launchMode == STANDARD) ? "standard" : "singleton";
448     std::string result = "\tAbilityRecord:" + std::to_string(token_) + "\n"
449         "\t    stat:" + AbilityMsHelper::AbilityStateToString(currentState_) + " launchMode:" + launcherMode + "\n"
450         "\t    bundleName:" + abilityInfo_.bundleName + " abilityName:" + abilityInfo_.name + "\n"
451         "\t    codePath:" + bundleInfo_.codePath + " dataPath:" + bundleInfo_.dataPath + "\n";
452     return AbilityMsStatus::DumpStatus(result.c_str());
453 }
454 #endif
455 
DumpAbilitySlice(const Want & want) const456 AbilityMsStatus PageAbilityRecord::DumpAbilitySlice(const Want &want) const
457 {
458     if (appRecord_ == nullptr) {
459         return AbilityMsStatus::TaskStatus("DumpAbility, ", "app record not exist");
460     }
461     return appRecord_->DumpAbilityTransaction(want, token_);
462 }
463 
RemoveConnectRecordByPageToken(uint64_t token)464 void PageAbilityRecord::RemoveConnectRecordByPageToken(uint64_t token)
465 {
466     if (connectRecords_.empty()) {
467         return;
468     }
469     for (auto iterator = connectRecords_.begin(); iterator != connectRecords_.end();) {
470         auto record = *iterator;
471         if (record != nullptr && record->GetAbilityToken() == token) {
472             iterator = connectRecords_.erase(iterator);
473             delete record;
474         } else {
475             ++iterator;
476         }
477     }
478     if (connectRecords_.empty() && !startDone_) {
479         StopAbility();
480     }
481 }
482 
GetConnectRecord(const SvcIdentity & serviceSid,uint64_t abilityToken) const483 AbilityConnectRecord *PageAbilityRecord::GetConnectRecord(const SvcIdentity &serviceSid, uint64_t abilityToken) const
484 {
485     for (const auto record : connectRecords_) {
486         if (record != nullptr && record->GetConnectSid().handle == serviceSid.handle &&
487             record->GetConnectSid().token == serviceSid.token && record->GetAbilityToken() == abilityToken) {
488             return record;
489         }
490     }
491     return nullptr;
492 }
493 }
494