1 /*
2 * Copyright (c) 2022-2023 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 "local_call_container.h"
17
18 #include "hilog_wrapper.h"
19 #include "ability_manager_client.h"
20 #include "os_account_manager_wrapper.h"
21
22 namespace OHOS {
23 namespace AbilityRuntime {
StartAbilityByCallInner(const Want & want,std::shared_ptr<CallerCallBack> callback,sptr<IRemoteObject> callerToken,int32_t accountId)24 int LocalCallContainer::StartAbilityByCallInner(const Want& want, std::shared_ptr<CallerCallBack> callback,
25 sptr<IRemoteObject> callerToken, int32_t accountId)
26 {
27 AppExecFwk::ElementName element = want.GetElement();
28 HILOG_DEBUG("start ability by call, element:%{public}s", element.GetURI().c_str());
29 if (callback == nullptr) {
30 HILOG_ERROR("callback is nullptr.");
31 return ERR_INVALID_VALUE;
32 }
33 if (element.GetBundleName().empty() || element.GetAbilityName().empty()) {
34 HILOG_ERROR("the element of want is empty.");
35 return ERR_INVALID_VALUE;
36 }
37 if (element.GetDeviceID().empty()) {
38 HILOG_DEBUG("start ability by call, element:DeviceID is empty");
39 }
40
41 int32_t oriValidUserId = GetValidUserId(accountId);
42 std::shared_ptr<LocalCallRecord> localCallRecord;
43 if (!GetCallLocalRecord(element, localCallRecord, oriValidUserId)) {
44 localCallRecord = std::make_shared<LocalCallRecord>(element);
45 localCallRecord->SetUserId(oriValidUserId);
46 HILOG_DEBUG("create local call record and set user id[%{public}d] to record", oriValidUserId);
47 }
48 localCallRecord->AddCaller(callback);
49 auto remote = localCallRecord->GetRemoteObject();
50 // already finish call request.
51 if (remote) {
52 HILOG_DEBUG("start ability by call, callback->InvokeCallBack(remote) begin");
53 callback->InvokeCallBack(remote);
54 HILOG_DEBUG("start ability by call, callback->InvokeCallBack(remote) end");
55 if (!want.GetBoolParam(Want::PARAM_RESV_CALL_TO_FOREGROUND, false)) {
56 return ERR_OK;
57 }
58 }
59 sptr<CallerConnection> connect = new (std::nothrow) CallerConnection();
60 if (connect == nullptr) {
61 HILOG_ERROR("StartAbilityByCallInner Create local call connection failed");
62 return ERR_INVALID_VALUE;
63 }
64 connections_.emplace(connect);
65 connect->SetRecordAndContainer(localCallRecord, shared_from_this());
66 HILOG_DEBUG("StartAbilityByCallInner connections_.size is %{public}zu", connections_.size());
67 auto retval = AAFwk::AbilityManagerClient::GetInstance()->StartAbilityByCall(want, connect,
68 callerToken, oriValidUserId);
69 if (retval != ERR_OK) {
70 ClearFailedCallConnection(callback);
71 }
72 return retval;
73 }
74
ReleaseCall(const std::shared_ptr<CallerCallBack> & callback)75 int LocalCallContainer::ReleaseCall(const std::shared_ptr<CallerCallBack>& callback)
76 {
77 HILOG_DEBUG("LocalCallContainer::ReleaseCall begin.");
78 if (callback == nullptr) {
79 HILOG_ERROR("LocalCallContainer::ReleaseCall input params is nullptr");
80 return ERR_INVALID_VALUE;
81 }
82 auto abilityClient = AAFwk::AbilityManagerClient::GetInstance();
83 if (abilityClient == nullptr) {
84 HILOG_ERROR("LocalCallContainer::ReleaseCall abilityClient is nullptr");
85 return ERR_INVALID_VALUE;
86 }
87 auto localCallRecord = callback->GetRecord();
88 if (localCallRecord == nullptr) {
89 HILOG_ERROR("LocalCallContainer::ReleaseCall localCallRecord is nullptr");
90 return ERR_INVALID_VALUE;
91 }
92 localCallRecord->RemoveCaller(callback);
93 if (localCallRecord->IsExistCallBack()) {
94 // just release callback.
95 HILOG_DEBUG("LocalCallContainer::ReleaseCall, The callee has onther callers, just release this callback.");
96 return ERR_OK;
97 }
98 auto connect = iface_cast<CallerConnection>(localCallRecord->GetConnection());
99 if (connect == nullptr) {
100 HILOG_ERROR("LocalCallContainer::ReleaseCall connection conversion failed.");
101 return ERR_INVALID_VALUE;
102 }
103 int32_t retval = ERR_OK;
104 if (localCallRecord->IsSingletonRemote()) {
105 retval = RemoveSingletonCallLocalRecord(localCallRecord);
106 } else {
107 retval = RemoveMultipleCallLocalRecord(localCallRecord);
108 }
109
110 if (retval != ERR_OK) {
111 HILOG_ERROR("Remove call local record failed");
112 return retval;
113 }
114
115 connections_.erase(connect);
116 if (abilityClient->ReleaseCall(connect, localCallRecord->GetElementName()) != ERR_OK) {
117 HILOG_ERROR("ReleaseCall failed.");
118 return ERR_INVALID_VALUE;
119 }
120 HILOG_DEBUG("LocalCallContainer::ReleaseCall end.");
121 return ERR_OK;
122 }
123
ClearFailedCallConnection(const std::shared_ptr<CallerCallBack> & callback)124 void LocalCallContainer::ClearFailedCallConnection(const std::shared_ptr<CallerCallBack> &callback)
125 {
126 HILOG_DEBUG("LocalCallContainer::ClearFailedCallConnection called");
127 if (callback == nullptr) {
128 HILOG_ERROR("LocalCallContainer::ClearFailedCallConnection callback is nullptr");
129 return;
130 }
131
132 auto localCallRecord = callback->GetRecord();
133 if (localCallRecord == nullptr) {
134 HILOG_ERROR("LocalCallContainer::ClearFailedCallConnection localCallRecord is nullptr");
135 return;
136 }
137
138 auto connect = iface_cast<CallerConnection>(localCallRecord->GetConnection());
139 if (connect == nullptr) {
140 HILOG_ERROR("LocalCallContainer::ClearFailedCallConnection connection conversion failed.");
141 return;
142 }
143
144 connections_.erase(connect);
145 }
146
RemoveSingletonCallLocalRecord(const std::shared_ptr<LocalCallRecord> & record)147 int32_t LocalCallContainer::RemoveSingletonCallLocalRecord(const std::shared_ptr<LocalCallRecord> &record)
148 {
149 std::lock_guard<std::mutex> lock(mutex_);
150 if (record == nullptr) {
151 HILOG_ERROR("input params invalid value");
152 return ERR_INVALID_VALUE;
153 }
154
155 auto iterRecord = callProxyRecords_.find(record->GetElementName().GetURI());
156 if (iterRecord == callProxyRecords_.end()) {
157 HILOG_ERROR("release record in singleton not found.");
158 return ERR_INVALID_VALUE;
159 }
160
161 iterRecord->second.erase(record);
162 if (iterRecord->second.empty()) {
163 callProxyRecords_.erase(iterRecord);
164 }
165
166 return ERR_OK;
167 }
168
RemoveMultipleCallLocalRecord(const std::shared_ptr<LocalCallRecord> & record)169 int32_t LocalCallContainer::RemoveMultipleCallLocalRecord(const std::shared_ptr<LocalCallRecord> &record)
170 {
171 if (record == nullptr) {
172 HILOG_ERROR("input params invalid value");
173 return ERR_INVALID_VALUE;
174 }
175
176 std::lock_guard<std::mutex> lock(multipleMutex_);
177 auto iterRecord = multipleCallProxyRecords_.find(record->GetElementName().GetURI());
178 if (iterRecord == multipleCallProxyRecords_.end()) {
179 HILOG_ERROR("release record in multiple not found.");
180 return ERR_INVALID_VALUE;
181 }
182
183 iterRecord->second.erase(record);
184 if (iterRecord->second.empty()) {
185 multipleCallProxyRecords_.erase(iterRecord);
186 }
187
188 return ERR_OK;
189 }
190
IsCallBackCalled(const std::vector<std::shared_ptr<CallerCallBack>> & callers) const191 bool LocalCallContainer::IsCallBackCalled(const std::vector<std::shared_ptr<CallerCallBack>> &callers) const
192 {
193 for (auto& callBack : callers) {
194 if (callBack != nullptr && !callBack->IsCallBack()) {
195 HILOG_INFO("%{public}s call back is not called.", __func__);
196 return false;
197 }
198 }
199
200 return true;
201 }
202
DumpCalls(std::vector<std::string> & info)203 void LocalCallContainer::DumpCalls(std::vector<std::string>& info)
204 {
205 HILOG_DEBUG("LocalCallContainer::DumpCalls called.");
206 info.emplace_back(" caller connections:");
207 std::lock_guard<std::mutex> lock(mutex_);
208 for (auto &item : callProxyRecords_) {
209 for (auto &itemCall : item.second) {
210 std::string tempstr = " LocalCallRecord";
211 tempstr += " ID #" + std::to_string(itemCall->GetRecordId()) + "\n";
212 tempstr += " callee";
213 tempstr += " uri[" + item.first + "]" + "\n";
214 tempstr += " callers #" + std::to_string(itemCall->GetCallers().size());
215 if (IsCallBackCalled(itemCall->GetCallers())) {
216 HILOG_INFO("%{public}s state is REQUESTEND.", __func__);
217 tempstr += " state #REQUESTEND";
218 } else {
219 HILOG_INFO("%{public}s state is REQUESTING.", __func__);
220 tempstr += " state #REQUESTING";
221 }
222 info.emplace_back(tempstr);
223 }
224 }
225 return;
226 }
227
GetCallLocalRecord(const AppExecFwk::ElementName & elementName,std::shared_ptr<LocalCallRecord> & localCallRecord,int32_t accountId)228 bool LocalCallContainer::GetCallLocalRecord(
229 const AppExecFwk::ElementName& elementName, std::shared_ptr<LocalCallRecord>& localCallRecord, int32_t accountId)
230 {
231 std::lock_guard<std::mutex> lock(mutex_);
232 HILOG_DEBUG("Get call local record by %{public}s and id %{public}d", elementName.GetURI().c_str(), accountId);
233 for (auto pair : callProxyRecords_) {
234 AppExecFwk::ElementName callElement;
235 if (!callElement.ParseURI(pair.first)) {
236 HILOG_ERROR("Parse uri to elementName failed, elementName uri: %{private}s", pair.first.c_str());
237 continue;
238 }
239 // elementName in callProxyRecords_ has moduleName (sometimes not empty),
240 // but the moduleName of input param elementName is usually empty.
241 callElement.SetModuleName("");
242 if ((pair.first != elementName.GetURI() && callElement.GetURI() != elementName.GetURI())) {
243 continue;
244 }
245
246 for (auto &itemCall : pair.second) {
247 if (itemCall != nullptr && itemCall->GetUserId() == accountId) {
248 localCallRecord = itemCall;
249 return true;
250 }
251 }
252 }
253 return false;
254 }
255
OnCallStubDied(const wptr<IRemoteObject> & remote)256 void LocalCallContainer::OnCallStubDied(const wptr<IRemoteObject>& remote)
257 {
258 auto diedRemote = remote.promote();
259 auto isExist = [&diedRemote](auto& record) {
260 return record->IsSameObject(diedRemote);
261 };
262
263 {
264 std::lock_guard<std::mutex> lock(mutex_);
265 for (auto &item : callProxyRecords_) {
266 auto iter = std::find_if(item.second.begin(), item.second.end(), isExist);
267 if (iter == item.second.end()) {
268 continue;
269 }
270 HILOG_DEBUG("LocalCallContainer::OnCallStubDied singleton key[%{public}s]. notify died event",
271 item.first.c_str());
272 (*iter)->OnCallStubDied(remote);
273 item.second.erase(iter);
274 if (item.second.empty()) {
275 HILOG_DEBUG("LocalCallContainer::OnCallStubDied singleton key[%{public}s] empty.", item.first.c_str());
276 callProxyRecords_.erase(item.first);
277 break;
278 }
279 }
280 }
281
282 std::lock_guard<std::mutex> lock(multipleMutex_);
283 for (auto &item : multipleCallProxyRecords_) {
284 HILOG_DEBUG("LocalCallContainer::OnCallStubDied multiple key[%{public}s].", item.first.c_str());
285 auto iterMultiple = find_if(item.second.begin(), item.second.end(), isExist);
286 if (iterMultiple == item.second.end()) {
287 continue;
288 }
289 HILOG_DEBUG("LocalCallContainer::OnCallStubDied multiple key[%{public}s]. notify died event",
290 item.first.c_str());
291 (*iterMultiple)->OnCallStubDied(remote);
292 item.second.erase(iterMultiple);
293 if (item.second.empty()) {
294 HILOG_DEBUG("LocalCallContainer::OnCallStubDied multiple key[%{public}s] empty.", item.first.c_str());
295 multipleCallProxyRecords_.erase(item.first);
296 break;
297 }
298 }
299 HILOG_DEBUG("LocalCallContainer::OnCallStubDied end.");
300 }
301
SetCallLocalRecord(const AppExecFwk::ElementName & element,const std::shared_ptr<LocalCallRecord> & localCallRecord)302 void LocalCallContainer::SetCallLocalRecord(
303 const AppExecFwk::ElementName& element, const std::shared_ptr<LocalCallRecord> &localCallRecord)
304 {
305 HILOG_DEBUG("LocalCallContainer::SetCallLocalRecord called uri is %{private}s.", element.GetURI().c_str());
306 const std::string strKey = element.GetURI();
307 std::lock_guard<std::mutex> lock(mutex_);
308 auto iter = callProxyRecords_.find(strKey);
309 if (iter == callProxyRecords_.end()) {
310 std::set<std::shared_ptr<LocalCallRecord>> records = { localCallRecord };
311 callProxyRecords_.emplace(strKey, records);
312 return;
313 }
314
315 iter->second.emplace(localCallRecord);
316 }
317
SetMultipleCallLocalRecord(const AppExecFwk::ElementName & element,const std::shared_ptr<LocalCallRecord> & localCallRecord)318 void LocalCallContainer::SetMultipleCallLocalRecord(
319 const AppExecFwk::ElementName& element, const std::shared_ptr<LocalCallRecord> &localCallRecord)
320 {
321 HILOG_DEBUG("LocalCallContainer::SetMultipleCallLocalRecord called uri is %{private}s.", element.GetURI().c_str());
322 const std::string strKey = element.GetURI();
323 std::lock_guard<std::mutex> lock(multipleMutex_);
324 auto iter = multipleCallProxyRecords_.find(strKey);
325 if (iter == multipleCallProxyRecords_.end()) {
326 std::set<std::shared_ptr<LocalCallRecord>> records = { localCallRecord };
327 multipleCallProxyRecords_.emplace(strKey, records);
328 return;
329 }
330
331 iter->second.emplace(localCallRecord);
332 }
333
SetRecordAndContainer(const std::shared_ptr<LocalCallRecord> & localCallRecord,const std::weak_ptr<LocalCallContainer> & container)334 void CallerConnection::SetRecordAndContainer(const std::shared_ptr<LocalCallRecord> &localCallRecord,
335 const std::weak_ptr<LocalCallContainer> &container)
336 {
337 if (localCallRecord == nullptr) {
338 HILOG_DEBUG("CallerConnection::SetRecordAndContainer input param is nullptr.");
339 return;
340 }
341 localCallRecord_ = localCallRecord;
342 container_ = container;
343 localCallRecord_->SetConnection(this->AsObject());
344 }
345
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int code)346 void CallerConnection::OnAbilityConnectDone(
347 const AppExecFwk::ElementName &element, const sptr<IRemoteObject> &remoteObject, int code)
348 {
349 HILOG_DEBUG("CallerConnection::OnAbilityConnectDone start %{public}s .", element.GetURI().c_str());
350 auto container = container_.lock();
351 if (container == nullptr || localCallRecord_ == nullptr) {
352 HILOG_ERROR("CallerConnection::OnAbilityConnectDone container or record is nullptr.");
353 return;
354 }
355
356 const bool isSingleton = (code == static_cast<int32_t>(AppExecFwk::LaunchMode::SINGLETON));
357 localCallRecord_->SetIsSingleton(isSingleton);
358
359 auto callRecipient = new (std::nothrow) CallRecipient(
360 std::bind(&LocalCallContainer::OnCallStubDied, container, std::placeholders::_1));
361 localCallRecord_->SetRemoteObject(remoteObject, callRecipient);
362
363 if (isSingleton) {
364 container->SetCallLocalRecord(element, localCallRecord_);
365 } else {
366 container->SetMultipleCallLocalRecord(element, localCallRecord_);
367 }
368
369 localCallRecord_->InvokeCallBack();
370 HILOG_DEBUG("CallerConnection::OnAbilityConnectDone end. code:%{public}d.", code);
371 return;
372 }
373
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int code)374 void CallerConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int code)
375 {
376 HILOG_DEBUG("CallerConnection::OnAbilityDisconnectDone start %{public}s %{public}d.",
377 element.GetURI().c_str(), code);
378 }
379
OnRemoteStateChanged(const AppExecFwk::ElementName & element,int32_t abilityState)380 void CallerConnection::OnRemoteStateChanged(const AppExecFwk::ElementName &element, int32_t abilityState)
381 {
382 HILOG_DEBUG("CallerConnection::OnRemoteStateChanged start %{public}s .", element.GetURI().c_str());
383 if (localCallRecord_ == nullptr) {
384 HILOG_DEBUG("local call record is nullptr.");
385 return;
386 }
387
388 localCallRecord_->NotifyRemoteStateChanged(abilityState);
389
390 HILOG_DEBUG("CallerConnection::OnRemoteStateChanged end. abilityState:%{public}d.", abilityState);
391 return;
392 }
393
GetCurrentUserId()394 int32_t LocalCallContainer::GetCurrentUserId()
395 {
396 if (currentUserId_ == DEFAULT_INVAL_VALUE) {
397 auto osAccount = DelayedSingleton<AppExecFwk::OsAccountManagerWrapper>::GetInstance();
398 if (osAccount == nullptr) {
399 HILOG_ERROR("LocalCallContainer::GetCurrentUserId get osAccount is nullptr.");
400 return DEFAULT_INVAL_VALUE;
401 }
402
403 osAccount->GetOsAccountLocalIdFromProcess(currentUserId_);
404 HILOG_DEBUG("LocalCallContainer::GetCurrentUserId called. %{public}d", currentUserId_);
405 }
406
407 return currentUserId_;
408 }
409
GetValidUserId(int32_t accountId)410 int32_t LocalCallContainer::GetValidUserId(int32_t accountId)
411 {
412 HILOG_DEBUG("LocalCallContainer::GetValidUserId is %{public}d", accountId);
413 if (accountId > 0 && accountId != GetCurrentUserId()) {
414 return accountId;
415 }
416
417 return DEFAULT_INVAL_VALUE;
418 }
419 } // namespace AbilityRuntime
420 } // namespace OHOS
421