1 /*
2 * Copyright (c) 2021-2022 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 "connection_state_manager.h"
23 #include "hilog_wrapper.h"
24
25 namespace OHOS {
26 namespace AAFwk {
DataAbilityRecord(const AbilityRequest & req)27 DataAbilityRecord::DataAbilityRecord(const AbilityRequest &req) : request_(req)
28 {
29 HILOG_DEBUG("%{public}s(%{public}d)", __PRETTY_FUNCTION__, __LINE__);
30
31 if (request_.abilityInfo.type != AppExecFwk::AbilityType::DATA) {
32 HILOG_ERROR("BUG: Construct a data ability with wrong ability type.");
33 }
34 }
35
~DataAbilityRecord()36 DataAbilityRecord::~DataAbilityRecord()
37 {
38 HILOG_DEBUG("%{public}s(%{public}d)", __PRETTY_FUNCTION__, __LINE__);
39 }
40
StartLoading()41 int DataAbilityRecord::StartLoading()
42 {
43 HILOG_INFO("Start data ability loading...");
44
45 if (ability_ || scheduler_) {
46 HILOG_ERROR("Data ability already started.");
47 return ERR_ALREADY_EXISTS;
48 }
49
50 if (request_.abilityInfo.type != AppExecFwk::AbilityType::DATA) {
51 HILOG_ERROR("Start a data ability with wrong ability type.");
52 return ERR_INVALID_VALUE;
53 }
54
55 auto ability = AbilityRecord::CreateAbilityRecord(request_);
56 if (!ability) {
57 HILOG_ERROR("Failed to allocate ability for DataAbilityRecord.");
58 return ERR_NO_MEMORY;
59 }
60
61 int ret = ability->LoadAbility();
62 if (ret != ERR_OK) {
63 HILOG_ERROR("Failed to start data ability loading.");
64 return ret;
65 }
66
67 ability_ = ability;
68
69 // Ability state is 'INITIAL' now.
70
71 return ERR_OK;
72 }
73
WaitForLoaded(std::mutex & mutex,const std::chrono::system_clock::duration & timeout)74 int DataAbilityRecord::WaitForLoaded(std::mutex &mutex, const std::chrono::system_clock::duration &timeout)
75 {
76 CHECK_POINTER_AND_RETURN(ability_, ERR_INVALID_STATE);
77
78 // Data ability uses 'ACTIVATE' as loaded state.
79 if (ability_->GetAbilityState() == ACTIVE) {
80 return ERR_OK;
81 }
82
83 auto ret = loadedCond_.wait_for(mutex, timeout, [this] { return ability_->GetAbilityState() == ACTIVE; });
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 isNotHap)183 int DataAbilityRecord::AddClient(const sptr<IRemoteObject> &client, bool tryBind, bool isNotHap)
184 {
185 if (!client) {
186 HILOG_ERROR("Data ability add client: invalid param.");
187 return ERR_INVALID_STATE;
188 }
189
190 if (!ability_ || !scheduler_) {
191 HILOG_ERROR("Data ability add client: not attached.");
192 return ERR_INVALID_STATE;
193 }
194
195 if (ability_->GetAbilityState() != ACTIVE) {
196 HILOG_ERROR("Data ability add client: not loaded.");
197 return ERR_INVALID_STATE;
198 }
199
200 auto appScheduler = DelayedSingleton<AppScheduler>::GetInstance();
201 if (!appScheduler) {
202 HILOG_ERROR("Data ability add client: failed to get app scheduler.");
203 return ERR_NULL_OBJECT;
204 }
205
206 HILOG_INFO("add death monitoring for data ability caller.");
207 if (client != nullptr && callerDeathRecipient_ != nullptr) {
208 client->RemoveDeathRecipient(callerDeathRecipient_);
209 }
210 if (callerDeathRecipient_ == nullptr) {
211 std::weak_ptr<DataAbilityRecord> thisWeakPtr(weak_from_this());
212 callerDeathRecipient_ = new DataAbilityCallerRecipient([thisWeakPtr](const wptr<IRemoteObject> &remote) {
213 auto dataAbilityRecord = thisWeakPtr.lock();
214 if (dataAbilityRecord) {
215 dataAbilityRecord->OnSchedulerDied(remote);
216 }
217 });
218 }
219 if (client != nullptr) {
220 client->AddDeathRecipient(callerDeathRecipient_);
221 }
222
223 // One client can be added multi-times, so 'RemoveClient()' must be called in corresponding times.
224 auto &clientInfo = clients_.emplace_back();
225 clientInfo.client = client;
226 clientInfo.tryBind = tryBind;
227 clientInfo.isNotHap = isNotHap;
228 clientInfo.clientPid = IPCSkeleton::GetCallingPid();
229 if (!isNotHap) {
230 auto clientAbilityRecord = Token::GetAbilityRecordByToken(client);
231 CHECK_POINTER_AND_RETURN(clientAbilityRecord, ERR_UNKNOWN_OBJECT);
232 appScheduler->AbilityBehaviorAnalysis(ability_->GetToken(), clientAbilityRecord->GetToken(), 0, 0, 1);
233 HILOG_INFO("Ability '%{public}s|%{public}s'.", clientAbilityRecord->GetApplicationInfo().bundleName.c_str(),
234 clientAbilityRecord->GetAbilityInfo().name.c_str());
235 }
236
237 HILOG_INFO("Data ability '%{public}s|%{public}s'.", ability_->GetApplicationInfo().bundleName.c_str(),
238 ability_->GetAbilityInfo().name.c_str());
239
240 return ERR_OK;
241 }
242
RemoveClient(const sptr<IRemoteObject> & client,bool isNotHap)243 int DataAbilityRecord::RemoveClient(const sptr<IRemoteObject> &client, bool isNotHap)
244 {
245 HILOG_INFO("Removing data ability client...");
246
247 if (!client) {
248 HILOG_ERROR("Data ability remove client: invalid client.");
249 return ERR_INVALID_STATE;
250 }
251
252 if (!ability_ || !scheduler_) {
253 HILOG_ERROR("Data ability remove clients: not attached.");
254 return ERR_INVALID_STATE;
255 }
256
257 if (ability_->GetAbilityState() != ACTIVE) {
258 HILOG_ERROR("Data ability remove client: not loaded.");
259 return ERR_INVALID_STATE;
260 }
261
262 if (clients_.empty()) {
263 HILOG_DEBUG("BUG: Data ability record has no clients.");
264 return ERR_OK;
265 }
266
267 auto appScheduler = DelayedSingleton<AppScheduler>::GetInstance();
268 if (!appScheduler) {
269 HILOG_ERROR("Data ability record remove client: invalid app scheduler.");
270 return ERR_NULL_OBJECT;
271 }
272
273 for (auto it(clients_.begin()); it != clients_.end(); ++it) {
274 if (it->client == client) {
275 if (!isNotHap) {
276 auto clientAbilityRecord = Token::GetAbilityRecordByToken(client);
277 CHECK_POINTER_AND_RETURN(clientAbilityRecord, ERR_UNKNOWN_OBJECT);
278 appScheduler->AbilityBehaviorAnalysis(ability_->GetToken(), clientAbilityRecord->GetToken(), 0, 0, 0);
279 HILOG_INFO("Ability ability '%{public}s|%{public}s'.",
280 clientAbilityRecord->GetApplicationInfo().bundleName.c_str(),
281 clientAbilityRecord->GetAbilityInfo().name.c_str());
282 }
283 clients_.erase(it);
284 HILOG_INFO("Data ability '%{public}s|%{public}s'.",
285 ability_->GetApplicationInfo().bundleName.c_str(),
286 ability_->GetAbilityInfo().name.c_str());
287 break;
288 }
289 }
290
291 return ERR_OK;
292 }
293
RemoveClients(const std::shared_ptr<AbilityRecord> & client)294 int DataAbilityRecord::RemoveClients(const std::shared_ptr<AbilityRecord> &client)
295 {
296 HILOG_DEBUG("%{public}s(%{public}d)", __PRETTY_FUNCTION__, __LINE__);
297
298 if (!ability_ || !scheduler_) {
299 HILOG_ERROR("Data ability remove clients: not attached.");
300 return ERR_INVALID_STATE;
301 }
302
303 if (ability_->GetAbilityState() != ACTIVE) {
304 HILOG_ERROR("Data ability remove clients: not loaded.");
305 return ERR_INVALID_STATE;
306 }
307
308 if (clients_.empty()) {
309 HILOG_DEBUG("Data ability remove clients: no clients.");
310 return ERR_OK;
311 }
312
313 auto appScheduler = DelayedSingleton<AppScheduler>::GetInstance();
314 if (!appScheduler) {
315 HILOG_ERROR("Data ability remove clients: invalid app scheduler.");
316 return ERR_NULL_OBJECT;
317 }
318
319 if (client) {
320 HILOG_DEBUG("Removing data ability clients with filter...");
321 auto it = clients_.begin();
322 while (it != clients_.end()) {
323 if (!it->isNotHap) {
324 auto clientAbilityRecord = Token::GetAbilityRecordByToken(it->client);
325 if (!clientAbilityRecord) {
326 HILOG_ERROR("clientAbilityRecord is nullptr, continue.");
327 ++it;
328 continue;
329 }
330 if (clientAbilityRecord == client) {
331 appScheduler->AbilityBehaviorAnalysis(
332 ability_->GetToken(), clientAbilityRecord->GetToken(), 0, 0, 0);
333 it = clients_.erase(it);
334 HILOG_INFO("Ability '%{public}s|%{public}s' --X-> Data ability '%{public}s|%{public}s'.",
335 client->GetApplicationInfo().bundleName.c_str(),
336 client->GetAbilityInfo().name.c_str(),
337 ability_->GetApplicationInfo().bundleName.c_str(),
338 ability_->GetAbilityInfo().name.c_str());
339 } else {
340 ++it;
341 }
342 } else {
343 ++it;
344 }
345 }
346 } else {
347 HILOG_DEBUG("Removing data ability clients...");
348 auto it = clients_.begin();
349 while (it != clients_.end()) {
350 if (!it->isNotHap) {
351 auto clientAbilityRecord = Token::GetAbilityRecordByToken(it->client);
352 if (!clientAbilityRecord) {
353 HILOG_DEBUG("clientAbilityRecord is null,clear record");
354 it = clients_.erase(it);
355 continue;
356 }
357 appScheduler->AbilityBehaviorAnalysis(ability_->GetToken(), clientAbilityRecord->GetToken(), 0, 0, 0);
358 it = clients_.erase(it);
359 } else {
360 ++it;
361 }
362 }
363 }
364
365 return ERR_OK;
366 }
367
GetClientCount(const sptr<IRemoteObject> & client) const368 size_t DataAbilityRecord::GetClientCount(const sptr<IRemoteObject> &client) const
369 {
370 CHECK_POINTER_AND_RETURN(ability_, 0);
371 CHECK_POINTER_AND_RETURN(scheduler_, 0);
372
373 if (ability_->GetAbilityState() != ACTIVE) {
374 HILOG_ERROR("Data ability get client count: not loaded.");
375 return 0;
376 }
377
378 if (client) {
379 return std::count_if(
380 clients_.begin(), clients_.end(), [client](const ClientInfo &ci) { return ci.client == client; });
381 }
382
383 return clients_.size();
384 }
385
KillBoundClientProcesses()386 int DataAbilityRecord::KillBoundClientProcesses()
387 {
388 CHECK_POINTER_AND_RETURN(ability_, ERR_INVALID_STATE);
389 CHECK_POINTER_AND_RETURN(scheduler_, ERR_INVALID_STATE);
390
391 if (ability_->GetAbilityState() != ACTIVE) {
392 HILOG_ERROR("Data ability kill bound clients: not loaded.");
393 return ERR_INVALID_STATE;
394 }
395
396 auto appScheduler = DelayedSingleton<AppScheduler>::GetInstance();
397 if (!appScheduler) {
398 HILOG_ERROR("Data ability kill bound clients: invalid app scheduler.");
399 return ERR_INVALID_STATE;
400 }
401
402 for (auto it = clients_.begin(); it != clients_.end(); ++it) {
403 if (it->tryBind && it->isNotHap == false) {
404 auto clientAbilityRecord = Token::GetAbilityRecordByToken(it->client);
405 CHECK_POINTER_CONTINUE(clientAbilityRecord);
406 HILOG_INFO("Killing bound client '%{public}s|%{public}s' of data ability '%{public}s|%{public}s'...",
407 clientAbilityRecord->GetApplicationInfo().bundleName.c_str(),
408 clientAbilityRecord->GetAbilityInfo().name.c_str(),
409 ability_->GetApplicationInfo().bundleName.c_str(),
410 ability_->GetAbilityInfo().name.c_str());
411 appScheduler->KillProcessByAbilityToken(clientAbilityRecord->GetToken());
412 }
413 }
414
415 return ERR_OK;
416 }
417
GetRequest() const418 const AbilityRequest &DataAbilityRecord::GetRequest() const
419 {
420 return request_;
421 }
422
GetAbilityRecord()423 std::shared_ptr<AbilityRecord> DataAbilityRecord::GetAbilityRecord()
424 {
425 return ability_;
426 }
427
GetToken()428 sptr<IRemoteObject> DataAbilityRecord::GetToken()
429 {
430 if (!ability_) {
431 return nullptr;
432 }
433
434 return ability_->GetToken();
435 }
436
Dump() const437 void DataAbilityRecord::Dump() const
438 {
439 CHECK_POINTER(ability_);
440
441 HILOG_INFO("attached: %{public}s, clients: %{public}zu, refcnt: %{public}d, state: %{public}s",
442 scheduler_ ? "true" : "false",
443 clients_.size(),
444 scheduler_ ? scheduler_->GetSptrRefCount() : 0,
445 AbilityRecord::ConvertAbilityState(ability_->GetAbilityState()).c_str());
446
447 int i = 0;
448
449 for (auto it = clients_.begin(); it != clients_.end(); ++it) {
450 if (it->isNotHap == false) {
451 auto clientAbilityRecord = Token::GetAbilityRecordByToken(it->client);
452 CHECK_POINTER_CONTINUE(clientAbilityRecord);
453 HILOG_INFO(" %{public}2d '%{public}s|%{public}s' - tryBind: %{public}s",
454 i++,
455 clientAbilityRecord->GetApplicationInfo().bundleName.c_str(),
456 clientAbilityRecord->GetAbilityInfo().name.c_str(),
457 it->tryBind ? "true" : "false");
458 } else {
459 HILOG_INFO(" %{public}2d '%{public}s' - tryBind: %{public}s",
460 i++,
461 "caller is system",
462 it->tryBind ? "true" : "false");
463 }
464 }
465 }
466
Dump(std::vector<std::string> & info) const467 void DataAbilityRecord::Dump(std::vector<std::string> &info) const
468 {
469 CHECK_POINTER(ability_);
470 info.emplace_back(" AbilityRecord ID #" + std::to_string(ability_->GetRecordId()) + " state #" +
471 AbilityRecord::ConvertAbilityState(ability_->GetAbilityState()) + " start time [" +
472 std::to_string(ability_->GetStartTime()) + "]");
473 info.emplace_back(" main name [" + ability_->GetAbilityInfo().name + "]");
474 info.emplace_back(" bundle name [" + ability_->GetAbilityInfo().bundleName + "]");
475 info.emplace_back(" ability type [DATA]");
476 info.emplace_back(" app state #" + AbilityRecord::ConvertAppState(ability_->GetAppState()));
477 info.emplace_back(" Clients: " + std::to_string(clients_.size()));
478
479 for (auto &&client : clients_) {
480 if (client.isNotHap == false) {
481 auto clientAbilityRecord = Token::GetAbilityRecordByToken(client.client);
482 CHECK_POINTER_CONTINUE(clientAbilityRecord);
483 info.emplace_back(" > " + clientAbilityRecord->GetAbilityInfo().bundleName + "/" +
484 clientAbilityRecord->GetAbilityInfo().name + " tryBind #" +
485 (client.tryBind ? "true" : "false") + " isNotHap # " +
486 (client.isNotHap ? "true" : "false"));
487 } else {
488 info.emplace_back(std::string(" > Caller is System / tryBind # ") +
489 (client.tryBind ? "true" : "false") + " isNotHap # " +
490 (client.isNotHap ? "true" : "false"));
491 }
492 }
493 }
494
OnSchedulerDied(const wptr<IRemoteObject> & remote)495 void DataAbilityRecord::OnSchedulerDied(const wptr<IRemoteObject> &remote)
496 {
497 HILOG_INFO("'%{public}s':", __func__);
498 auto object = remote.promote();
499 DelayedSingleton<ConnectionStateManager>::GetInstance()->HandleDataAbilityCallerDied(GetDiedCallerPid(object));
500
501 if (clients_.empty()) {
502 HILOG_DEBUG("BUG: Data ability record has no clients.");
503 return;
504 }
505
506 auto appScheduler = DelayedSingleton<AppScheduler>::GetInstance();
507 if (!appScheduler) {
508 HILOG_ERROR("Data ability remove clients: invalid app scheduler.");
509 return;
510 }
511
512 if (object) {
513 auto it = clients_.begin();
514 while (it != clients_.end()) {
515 if (it->client == object) {
516 HILOG_DEBUG("remove system caller record with filter...");
517 it = clients_.erase(it);
518 HILOG_INFO("Data ability '%{public}s|%{public}s'.",
519 ability_->GetApplicationInfo().bundleName.c_str(),
520 ability_->GetAbilityInfo().name.c_str());
521 } else {
522 ++it;
523 }
524 }
525 } else {
526 auto it = clients_.begin();
527 while (it != clients_.end()) {
528 if (it->isNotHap) {
529 HILOG_DEBUG("remove system caller record...");
530 it = clients_.erase(it);
531 HILOG_INFO("Data ability '%{public}s|%{public}s'.",
532 ability_->GetApplicationInfo().bundleName.c_str(),
533 ability_->GetAbilityInfo().name.c_str());
534 } else {
535 ++it;
536 }
537 }
538 }
539 }
540
GetDiedCallerPid(const sptr<IRemoteObject> & remote)541 int32_t DataAbilityRecord::GetDiedCallerPid(const sptr<IRemoteObject> &remote)
542 {
543 if (!remote) {
544 return 0;
545 }
546
547 int32_t result = 0;
548 for (auto it = clients_.begin(); it != clients_.end(); it++) {
549 if (it->client == remote) {
550 result = it->clientPid;
551 break;
552 }
553 }
554
555 return result;
556 }
557 } // namespace AAFwk
558 } // namespace OHOS
559