1 /*
2 * Copyright (c) 2021 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 "data_ability_record.h"
17
18 #include <algorithm>
19 #include "hilog_wrapper.h"
20 #include "ability_util.h"
21 #include "app_scheduler.h"
22
23 namespace OHOS {
24 namespace AAFwk {
DataAbilityRecord(const AbilityRequest & req)25 DataAbilityRecord::DataAbilityRecord(const AbilityRequest &req) : request_(req)
26 {
27 HILOG_DEBUG("%{public}s(%{public}d)", __PRETTY_FUNCTION__, __LINE__);
28
29 if (request_.abilityInfo.type != AppExecFwk::AbilityType::DATA) {
30 HILOG_ERROR("BUG: Construct a data ability with wrong ability type.");
31 }
32 }
33
~DataAbilityRecord()34 DataAbilityRecord::~DataAbilityRecord()
35 {
36 HILOG_DEBUG("%{public}s(%{public}d)", __PRETTY_FUNCTION__, __LINE__);
37 }
38
StartLoading()39 int DataAbilityRecord::StartLoading()
40 {
41 HILOG_INFO("Start data ability loading...");
42
43 if (ability_ || scheduler_) {
44 HILOG_ERROR("Data ability already started.");
45 return ERR_ALREADY_EXISTS;
46 }
47
48 if (request_.abilityInfo.type != AppExecFwk::AbilityType::DATA) {
49 HILOG_ERROR("Start a data ability with wrong ability type.");
50 return ERR_INVALID_VALUE;
51 }
52
53 auto ability = AbilityRecord::CreateAbilityRecord(request_);
54 if (!ability) {
55 HILOG_ERROR("Failed to allocate ability for DataAbilityRecord.");
56 return ERR_NO_MEMORY;
57 }
58
59 int ret = ability->LoadAbility();
60 if (ret != ERR_OK) {
61 HILOG_ERROR("Failed to start data ability loading.");
62 return ret;
63 }
64
65 ability_ = ability;
66
67 // Ability state is 'INITIAL' now.
68
69 return ERR_OK;
70 }
71
WaitForLoaded(std::mutex & mutex,const std::chrono::system_clock::duration & timeout)72 int DataAbilityRecord::WaitForLoaded(std::mutex &mutex, const std::chrono::system_clock::duration &timeout)
73 {
74 CHECK_POINTER_AND_RETURN(ability_, ERR_INVALID_STATE);
75
76 // Data ability uses 'ACTIVATE' as loaded state.
77 if (ability_->GetAbilityState() == ACTIVE) {
78 return ERR_OK;
79 }
80
81 auto ret = loadedCond_.wait_for(mutex, timeout, [this] { return ability_->GetAbilityState() == ACTIVE; });
82
83 if (!ret) {
84 return ERR_TIMED_OUT;
85 }
86
87 if (!scheduler_ || ability_->GetAbilityState() != ACTIVE) {
88 return ERR_INVALID_STATE;
89 }
90
91 return ERR_OK;
92 }
93
GetScheduler()94 sptr<IAbilityScheduler> DataAbilityRecord::GetScheduler()
95 {
96 // Check if data ability is attached.
97 CHECK_POINTER_AND_RETURN(ability_, nullptr);
98 CHECK_POINTER_AND_RETURN(scheduler_, nullptr);
99
100 // Check if data ability is loaded.
101 if (ability_->GetAbilityState() != ACTIVE) {
102 return nullptr;
103 }
104
105 return scheduler_;
106 }
107
Attach(const sptr<IAbilityScheduler> & scheduler)108 int DataAbilityRecord::Attach(const sptr<IAbilityScheduler> &scheduler)
109 {
110 HILOG_DEBUG("%{public}s(%{public}d)", __PRETTY_FUNCTION__, __LINE__);
111
112 if (!scheduler) {
113 HILOG_ERROR("Attach data ability: invalid scheduler.");
114 return ERR_INVALID_DATA;
115 }
116
117 if (!ability_) {
118 HILOG_ERROR("Data ability attach: not startloading.");
119 return ERR_INVALID_STATE;
120 }
121
122 if (scheduler_) {
123 HILOG_ERROR("Attach data ability: already attached.");
124 return ERR_INVALID_STATE;
125 }
126
127 // INITIAL => ACTIVATING
128
129 if (ability_->GetAbilityState() != INITIAL) {
130 HILOG_ERROR("Attaching data ability: not in 'INITIAL' state.");
131 return ERR_INVALID_STATE;
132 }
133
134 HILOG_DEBUG("Attaching data ability...");
135 ability_->SetScheduler(scheduler);
136 scheduler_ = scheduler;
137
138 HILOG_INFO("Scheduling 'OnStart' for data ability '%{public}s|%{public}s'...",
139 ability_->GetApplicationInfo().bundleName.c_str(),
140 ability_->GetAbilityInfo().name.c_str());
141
142 ability_->SetAbilityState(ACTIVATING);
143
144 LifeCycleStateInfo state;
145 state.state = AbilityLifeCycleState::ABILITY_STATE_ACTIVE;
146
147 scheduler->ScheduleAbilityTransaction(ability_->GetWant(), state);
148
149 return ERR_OK;
150 }
151
OnTransitionDone(int state)152 int DataAbilityRecord::OnTransitionDone(int state)
153 {
154 CHECK_POINTER_AND_RETURN(ability_, ERR_INVALID_STATE);
155 CHECK_POINTER_AND_RETURN(scheduler_, ERR_INVALID_STATE);
156
157 if (ability_->GetAbilityState() != ACTIVATING) {
158 HILOG_ERROR("Data ability on transition done: not in 'ACTIVATING' state.");
159 return ERR_INVALID_STATE;
160 }
161
162 if (state != AbilityLifeCycleState::ABILITY_STATE_ACTIVE) {
163 HILOG_ERROR("Data ability on transition done: not ACTIVE.");
164 ability_->SetAbilityState(INITIAL);
165 loadedCond_.notify_all();
166 return ERR_INVALID_STATE;
167 }
168
169 // ACTIVATING => ACTIVE(loaded):
170 // Set loaded state, data ability uses 'ACTIVE' as loaded state.
171
172 ability_->SetAbilityState(ACTIVE);
173 loadedCond_.notify_all();
174
175 HILOG_INFO("Data ability '%{public}s|%{public}s' is loaded.",
176 ability_->GetApplicationInfo().bundleName.c_str(),
177 ability_->GetAbilityInfo().name.c_str());
178
179 return ERR_OK;
180 }
181
AddClient(const sptr<IRemoteObject> & client,bool tryBind,bool isSystem)182 int DataAbilityRecord::AddClient(const sptr<IRemoteObject> &client, bool tryBind, bool isSystem)
183 {
184 HILOG_INFO("Adding data ability client...");
185
186 if (!client) {
187 HILOG_ERROR("Data ability add client: invalid param.");
188 return ERR_INVALID_STATE;
189 }
190
191 if (!ability_ || !scheduler_) {
192 HILOG_ERROR("Data ability add client: not attached.");
193 return ERR_INVALID_STATE;
194 }
195
196 if (ability_->GetAbilityState() != ACTIVE) {
197 HILOG_ERROR("Data ability add client: not loaded.");
198 return ERR_INVALID_STATE;
199 }
200
201 auto appScheduler = DelayedSingleton<AppScheduler>::GetInstance();
202 if (!appScheduler) {
203 HILOG_ERROR("Data ability add client: failed to get app scheduler.");
204 return ERR_NULL_OBJECT;
205 }
206
207 if (isSystem) {
208 HILOG_ERROR("When the caller is system,add death monitoring");
209 if (client != nullptr && callerDeathRecipient_ != nullptr) {
210 client->RemoveDeathRecipient(callerDeathRecipient_);
211 }
212 if (callerDeathRecipient_ == nullptr) {
213 callerDeathRecipient_ = new DataAbilityCallerRecipient(
214 std::bind(&DataAbilityRecord::OnSchedulerDied, this, std::placeholders::_1));
215 }
216 if (client != nullptr) {
217 client->AddDeathRecipient(callerDeathRecipient_);
218 }
219 }
220
221 // One client can be added multi-times, so 'RemoveClient()' must be called in corresponding times.
222 auto &clientInfo = clients_.emplace_back();
223 clientInfo.client = client;
224 clientInfo.tryBind = tryBind;
225 clientInfo.isSystem = isSystem;
226 if (!isSystem) {
227 auto clientAbilityRecord = Token::GetAbilityRecordByToken(client);
228 CHECK_POINTER_AND_RETURN(clientAbilityRecord, ERR_UNKNOWN_OBJECT);
229 appScheduler->AbilityBehaviorAnalysis(ability_->GetToken(), clientAbilityRecord->GetToken(), 0, 0, 1);
230 HILOG_INFO("Ability ability '%{public}s|%{public}s'.",
231 clientAbilityRecord->GetApplicationInfo().bundleName.c_str(),
232 clientAbilityRecord->GetAbilityInfo().name.c_str());
233 }
234
235 if (clients_.size() == 1) {
236 HILOG_INFO("Moving data ability app to foreground...");
237 appScheduler->MoveToForground(ability_->GetToken());
238 }
239
240 HILOG_INFO("Data ability '%{public}s|%{public}s'.",
241 ability_->GetApplicationInfo().bundleName.c_str(),
242 ability_->GetAbilityInfo().name.c_str());
243
244 return ERR_OK;
245 }
246
RemoveClient(const sptr<IRemoteObject> & client,bool isSystem)247 int DataAbilityRecord::RemoveClient(const sptr<IRemoteObject> &client, bool isSystem)
248 {
249 HILOG_INFO("Removing data ability client...");
250
251 if (!client) {
252 HILOG_ERROR("Data ability remove client: invalid client.");
253 return ERR_INVALID_STATE;
254 }
255
256 if (!ability_ || !scheduler_) {
257 HILOG_ERROR("Data ability remove clients: not attached.");
258 return ERR_INVALID_STATE;
259 }
260
261 if (ability_->GetAbilityState() != ACTIVE) {
262 HILOG_ERROR("Data ability remove client: not loaded.");
263 return ERR_INVALID_STATE;
264 }
265
266 if (clients_.empty()) {
267 HILOG_DEBUG("BUG: Data ability record has no clients.");
268 return ERR_OK;
269 }
270
271 auto appScheduler = DelayedSingleton<AppScheduler>::GetInstance();
272 if (!appScheduler) {
273 HILOG_ERROR("Data ability record remove client: invalid app scheduler.");
274 return ERR_NULL_OBJECT;
275 }
276
277 for (auto it(clients_.begin()); it != clients_.end(); ++it) {
278 if (it->client == client) {
279 if (!isSystem) {
280 auto clientAbilityRecord = Token::GetAbilityRecordByToken(client);
281 CHECK_POINTER_AND_RETURN(clientAbilityRecord, ERR_UNKNOWN_OBJECT);
282 appScheduler->AbilityBehaviorAnalysis(ability_->GetToken(), clientAbilityRecord->GetToken(), 0, 0, 0);
283 HILOG_INFO("Ability ability '%{public}s|%{public}s'.",
284 clientAbilityRecord->GetApplicationInfo().bundleName.c_str(),
285 clientAbilityRecord->GetAbilityInfo().name.c_str());
286 }
287 clients_.erase(it);
288 HILOG_INFO("Data ability '%{public}s|%{public}s'.",
289 ability_->GetApplicationInfo().bundleName.c_str(),
290 ability_->GetAbilityInfo().name.c_str());
291 break;
292 }
293 }
294
295 if (clients_.empty()) {
296 HILOG_INFO("Moving data ability to background...");
297 appScheduler->MoveToBackground(ability_->GetToken());
298 }
299
300 return ERR_OK;
301 }
302
RemoveClients(const std::shared_ptr<AbilityRecord> & client)303 int DataAbilityRecord::RemoveClients(const std::shared_ptr<AbilityRecord> &client)
304 {
305 HILOG_DEBUG("%{public}s(%{public}d)", __PRETTY_FUNCTION__, __LINE__);
306
307 if (!ability_ || !scheduler_) {
308 HILOG_ERROR("Data ability remove clients: not attached.");
309 return ERR_INVALID_STATE;
310 }
311
312 if (ability_->GetAbilityState() != ACTIVE) {
313 HILOG_ERROR("Data ability remove clients: not loaded.");
314 return ERR_INVALID_STATE;
315 }
316
317 if (clients_.empty()) {
318 HILOG_DEBUG("Data ability remove clients: no clients.");
319 return ERR_OK;
320 }
321
322 auto appScheduler = DelayedSingleton<AppScheduler>::GetInstance();
323 if (!appScheduler) {
324 HILOG_ERROR("Data ability remove clients: invalid app scheduler.");
325 return ERR_NULL_OBJECT;
326 }
327
328 if (client) {
329 HILOG_DEBUG("Removing data ability clients with filter...");
330 auto it = clients_.begin();
331 while (it != clients_.end()) {
332 if (!it->isSystem) {
333 auto clientAbilityRecord = Token::GetAbilityRecordByToken(it->client);
334 CHECK_POINTER_CONTINUE(clientAbilityRecord);
335 if (clientAbilityRecord == client) {
336 appScheduler->AbilityBehaviorAnalysis(
337 ability_->GetToken(), clientAbilityRecord->GetToken(), 0, 0, 0);
338 it = clients_.erase(it);
339 HILOG_INFO("Ability '%{public}s|%{public}s' --X-> Data ability '%{public}s|%{public}s'.",
340 client->GetApplicationInfo().bundleName.c_str(),
341 client->GetAbilityInfo().name.c_str(),
342 ability_->GetApplicationInfo().bundleName.c_str(),
343 ability_->GetAbilityInfo().name.c_str());
344 } else {
345 ++it;
346 }
347 } else {
348 ++it;
349 }
350 }
351 } else {
352 HILOG_DEBUG("Removing data ability clients...");
353 auto it = clients_.begin();
354 while (it != clients_.end()) {
355 if (!it->isSystem) {
356 auto clientAbilityRecord = Token::GetAbilityRecordByToken(it->client);
357 if (!clientAbilityRecord) {
358 HILOG_DEBUG("clientAbilityRecord is null,clear record");
359 it = clients_.erase(it);
360 continue;
361 }
362 appScheduler->AbilityBehaviorAnalysis(ability_->GetToken(), clientAbilityRecord->GetToken(), 0, 0, 0);
363 it = clients_.erase(it);
364 HILOG_INFO("Ability '%{public}s|%{public}s' --X-> Data ability '%{public}s|%{public}s'.",
365 client->GetApplicationInfo().bundleName.c_str(),
366 client->GetAbilityInfo().name.c_str(),
367 ability_->GetApplicationInfo().bundleName.c_str(),
368 ability_->GetAbilityInfo().name.c_str());
369 } else {
370 ++it;
371 }
372 }
373 }
374
375 if (clients_.empty()) {
376 HILOG_INFO("Moving data ability to background...");
377 appScheduler->MoveToBackground(ability_->GetToken());
378 }
379
380 return ERR_OK;
381 }
382
GetClientCount(const sptr<IRemoteObject> & client) const383 size_t DataAbilityRecord::GetClientCount(const sptr<IRemoteObject> &client) const
384 {
385 CHECK_POINTER_AND_RETURN(ability_, 0);
386 CHECK_POINTER_AND_RETURN(scheduler_, 0);
387
388 if (ability_->GetAbilityState() != ACTIVE) {
389 HILOG_ERROR("Data ability get client count: not loaded.");
390 return 0;
391 }
392
393 if (client) {
394 return std::count_if(
395 clients_.begin(), clients_.end(), [client](const ClientInfo &ci) { return ci.client == client; });
396 }
397
398 return clients_.size();
399 }
400
KillBoundClientProcesses()401 int DataAbilityRecord::KillBoundClientProcesses()
402 {
403 CHECK_POINTER_AND_RETURN(ability_, ERR_INVALID_STATE);
404 CHECK_POINTER_AND_RETURN(scheduler_, ERR_INVALID_STATE);
405
406 if (ability_->GetAbilityState() != ACTIVE) {
407 HILOG_ERROR("Data ability kill bound clients: not loaded.");
408 return ERR_INVALID_STATE;
409 }
410
411 auto appScheduler = DelayedSingleton<AppScheduler>::GetInstance();
412 if (!appScheduler) {
413 HILOG_ERROR("Data ability kill bound clients: invalid app scheduler.");
414 return ERR_INVALID_STATE;
415 }
416
417 for (auto it = clients_.begin(); it != clients_.end(); ++it) {
418 if (it->tryBind && false == it->isSystem) {
419 auto clientAbilityRecord = Token::GetAbilityRecordByToken(it->client);
420 CHECK_POINTER_CONTINUE(clientAbilityRecord);
421 HILOG_INFO("Killing bound client '%{public}s|%{public}s' of data ability '%{public}s|%{public}s'...",
422 clientAbilityRecord->GetApplicationInfo().bundleName.c_str(),
423 clientAbilityRecord->GetAbilityInfo().name.c_str(),
424 ability_->GetApplicationInfo().bundleName.c_str(),
425 ability_->GetAbilityInfo().name.c_str());
426 appScheduler->KillProcessByAbilityToken(clientAbilityRecord->GetToken());
427 }
428 }
429
430 return ERR_OK;
431 }
432
GetRequest() const433 const AbilityRequest &DataAbilityRecord::GetRequest() const
434 {
435 return request_;
436 }
437
GetAbilityRecord()438 std::shared_ptr<AbilityRecord> DataAbilityRecord::GetAbilityRecord()
439 {
440 return ability_;
441 }
442
GetToken()443 sptr<IRemoteObject> DataAbilityRecord::GetToken()
444 {
445 if (!ability_) {
446 return nullptr;
447 }
448
449 return ability_->GetToken();
450 }
451
Dump() const452 void DataAbilityRecord::Dump() const
453 {
454 CHECK_POINTER(ability_);
455
456 HILOG_INFO("attached: %{public}s, clients: %{public}zu, refcnt: %{public}d, state: %{public}s",
457 scheduler_ ? "true" : "false",
458 clients_.size(),
459 scheduler_ ? scheduler_->GetSptrRefCount() : 0,
460 AbilityRecord::ConvertAbilityState(ability_->GetAbilityState()).c_str());
461
462 int i = 0;
463
464 for (auto it = clients_.begin(); it != clients_.end(); ++it) {
465 if (false == it->isSystem) {
466 auto clientAbilityRecord = Token::GetAbilityRecordByToken(it->client);
467 CHECK_POINTER_CONTINUE(clientAbilityRecord);
468 HILOG_INFO(" %{public}2d '%{public}s|%{public}s' - tryBind: %{public}s",
469 i++,
470 clientAbilityRecord->GetApplicationInfo().bundleName.c_str(),
471 clientAbilityRecord->GetAbilityInfo().name.c_str(),
472 it->tryBind ? "true" : "false");
473 } else {
474 HILOG_INFO(" %{public}2d '%{public}s' - tryBind: %{public}s",
475 i++,
476 "caller is system",
477 it->tryBind ? "true" : "false");
478 }
479 }
480 }
481
Dump(std::vector<std::string> & info) const482 void DataAbilityRecord::Dump(std::vector<std::string> &info) const
483 {
484 CHECK_POINTER(ability_);
485 info.emplace_back(" AbilityRecord ID #" + std::to_string(ability_->GetRecordId()) + " state #" +
486 AbilityRecord::ConvertAbilityState(ability_->GetAbilityState()) + " start time [" +
487 std::to_string(ability_->GetStartTime()) + "]");
488 info.emplace_back(" main name [" + ability_->GetAbilityInfo().name + "]");
489 info.emplace_back(" bundle name [" + ability_->GetAbilityInfo().bundleName + "]");
490 info.emplace_back(" ability type [DATA]");
491 info.emplace_back(" app state #" + AbilityRecord::ConvertAppState(ability_->GetAppState()));
492 info.emplace_back(" Clients: " + std::to_string(clients_.size()));
493
494 for (auto &&client : clients_) {
495 if (false == client.isSystem) {
496 auto clientAbilityRecord = Token::GetAbilityRecordByToken(client.client);
497 CHECK_POINTER_CONTINUE(clientAbilityRecord);
498 info.emplace_back(" > " + clientAbilityRecord->GetAbilityInfo().bundleName + "/" +
499 clientAbilityRecord->GetAbilityInfo().name + " tryBind #" +
500 (client.tryBind ? "true" : "false") + " isSystem # " +
501 (client.isSystem ? "true" : "false"));
502 } else {
503 info.emplace_back(std::string(" > Caller is System / tryBind # ") +
504 (client.tryBind ? "true" : "false") + " isSystem # " +
505 (client.isSystem ? "true" : "false"));
506 }
507 }
508 }
509
OnSchedulerDied(const wptr<IRemoteObject> & remote)510 void DataAbilityRecord::OnSchedulerDied(const wptr<IRemoteObject> &remote)
511 {
512 HILOG_INFO("'%{public}s':", __func__);
513 auto object = remote.promote();
514
515 if (clients_.empty()) {
516 HILOG_DEBUG("BUG: Data ability record has no clients.");
517 return;
518 }
519
520 auto appScheduler = DelayedSingleton<AppScheduler>::GetInstance();
521 if (!appScheduler) {
522 HILOG_ERROR("Data ability remove clients: invalid app scheduler.");
523 return;
524 }
525
526 if (object) {
527 auto it = clients_.begin();
528 while (it != clients_.end()) {
529 if (it->client == object) {
530 HILOG_DEBUG("remove system caller record with filter...");
531 it = clients_.erase(it);
532 HILOG_INFO("Data ability '%{public}s|%{public}s'.",
533 ability_->GetApplicationInfo().bundleName.c_str(),
534 ability_->GetAbilityInfo().name.c_str());
535 } else {
536 ++it;
537 }
538 }
539 } else {
540 auto it = clients_.begin();
541 while (it != clients_.end()) {
542 if (it->isSystem) {
543 HILOG_DEBUG("remove system caller record...");
544 it = clients_.erase(it);
545 HILOG_INFO("Data ability '%{public}s|%{public}s'.",
546 ability_->GetApplicationInfo().bundleName.c_str(),
547 ability_->GetAbilityInfo().name.c_str());
548 } else {
549 ++it;
550 }
551 }
552 }
553
554 if (clients_.empty()) {
555 HILOG_INFO("Moving data ability to background...");
556 appScheduler->MoveToBackground(ability_->GetToken());
557 }
558 }
559 } // namespace AAFwk
560 } // namespace OHOS
561