• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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