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