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