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