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