• 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 
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