1/*
2 * Copyright (c) 2022-2024 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 "connection_state_item.h"
17
18#include "hilog_tag_wrapper.h"
19
20namespace OHOS {
21namespace AAFwk {
22/**
23 * @class ConnectedExtension
24 * ConnectedExtension,This class is used to record a connected extension.
25 */
26class ConnectedExtension : public std::enable_shared_from_this<ConnectedExtension> {
27public:
28    static std::shared_ptr<ConnectedExtension> CreateConnectedExtension(std::shared_ptr<ConnectionRecord> record)
29    {
30        if (!record) {
31            return nullptr;
32        }
33
34        auto targetExtension = record->GetAbilityRecord();
35        if (!targetExtension) {
36            return nullptr;
37        }
38
39        return std::make_shared<ConnectedExtension>(targetExtension);
40    }
41
42    ConnectedExtension()
43    {
44        extensionType_ = AppExecFwk::ExtensionAbilityType::UNSPECIFIED;
45    }
46
47    explicit ConnectedExtension(std::shared_ptr<AbilityRecord> target)
48    {
49        if (!target) {
50            return;
51        }
52        extensionPid_ = target->GetPid();
53        extensionUid_ = target->GetUid();
54        extensionBundleName_ = target->GetAbilityInfo().bundleName;
55        extensionModuleName_ = target->GetAbilityInfo().moduleName;
56        extensionName_ = target->GetAbilityInfo().name;
57        extensionType_ = target->GetAbilityInfo().extensionAbilityType;
58        if (target->GetAbilityInfo().type == AppExecFwk::AbilityType::SERVICE) {
59            extensionType_ = AppExecFwk::ExtensionAbilityType::SERVICE;
60        } else if (target->GetAbilityInfo().type == AppExecFwk::AbilityType::DATA) {
61            extensionType_ = AppExecFwk::ExtensionAbilityType::DATASHARE;
62        }
63    }
64
65    virtual ~ConnectedExtension() = default;
66
67    bool AddConnection(sptr<IRemoteObject> connection)
68    {
69        if (!connection) {
70            return false;
71        }
72
73        std::lock_guard guard(connectionsMutex_);
74        bool needNotify = connections_.empty();
75        connections_.emplace(connection);
76
77        return needNotify;
78    }
79
80    bool RemoveConnection(sptr<IRemoteObject> connection)
81    {
82        if (!connection) {
83            return false;
84        }
85        std::lock_guard guard(connectionsMutex_);
86        connections_.erase(connection);
87        return connections_.empty();
88    }
89
90    void GenerateExtensionInfo(AbilityRuntime::ConnectionData &data)
91    {
92        data.extensionPid = extensionPid_;
93        data.extensionUid = extensionUid_;
94        data.extensionBundleName = extensionBundleName_;
95        data.extensionModuleName = extensionModuleName_;
96        data.extensionName = extensionName_;
97        data.extensionType = extensionType_;
98    }
99
100private:
101    int32_t extensionPid_ = 0;
102    int32_t extensionUid_ = 0;
103    std::string extensionBundleName_;
104    std::string extensionModuleName_;
105    std::string extensionName_;
106    AppExecFwk::ExtensionAbilityType extensionType_;
107
108    std::mutex connectionsMutex_;
109    std::set<sptr<IRemoteObject>> connections_; // remote object of IAbilityConnection
110};
111
112/**
113 * @class ConnectedDataAbility
114 * ConnectedDataAbility,This class is used to record a connected data ability.
115 */
116class ConnectedDataAbility : public std::enable_shared_from_this<ConnectedDataAbility> {
117public:
118    static std::shared_ptr<ConnectedDataAbility> CreateConnectedDataAbility(
119        const std::shared_ptr<DataAbilityRecord> &record)
120    {
121        if (!record) {
122            return nullptr;
123        }
124
125        auto targetAbility = record->GetAbilityRecord();
126        if (!targetAbility) {
127            return nullptr;
128        }
129
130        return std::make_shared<ConnectedDataAbility>(targetAbility);
131    }
132
133    ConnectedDataAbility() {}
134
135    explicit ConnectedDataAbility(const std::shared_ptr<AbilityRecord> &target)
136    {
137        if (!target) {
138            return;
139        }
140
141        dataAbilityPid_ = target->GetPid();
142        dataAbilityUid_ = target->GetUid();
143        bundleName_ = target->GetAbilityInfo().bundleName;
144        moduleName_ = target->GetAbilityInfo().moduleName;
145        abilityName_ = target->GetAbilityInfo().name;
146    }
147
148    virtual ~ConnectedDataAbility() = default;
149
150    bool AddCaller(const DataAbilityCaller &caller)
151    {
152        if (!caller.isNotHap && !caller.callerToken) {
153            return false;
154        }
155
156        bool needNotify = callers_.empty();
157        auto it = find_if(callers_.begin(), callers_.end(), [&caller](const std::shared_ptr<CallerInfo> &info) {
158            if (caller.isNotHap) {
159                return info && info->IsNotHap() && info->GetCallerPid() == caller.callerPid;
160            } else {
161                return info && info->GetCallerToken() == caller.callerToken;
162            }
163        });
164        if (it == callers_.end()) {
165            callers_.emplace_back(std::make_shared<CallerInfo>(caller.isNotHap, caller.callerPid, caller.callerToken));
166        }
167
168        return needNotify;
169    }
170
171    bool RemoveCaller(const DataAbilityCaller &caller)
172    {
173        if (!caller.isNotHap && !caller.callerToken) {
174            return false;
175        }
176
177        auto it = find_if(callers_.begin(), callers_.end(), [&caller](const std::shared_ptr<CallerInfo> &info) {
178            if (caller.isNotHap) {
179                return info && info->IsNotHap() && info->GetCallerPid() == caller.callerPid;
180            } else {
181                return info && info->GetCallerToken() == caller.callerToken;
182            }
183        });
184        if (it != callers_.end()) {
185            callers_.erase(it);
186        }
187
188        return callers_.empty();
189    }
190
191    void GenerateExtensionInfo(AbilityRuntime::ConnectionData &data)
192    {
193        data.extensionPid = dataAbilityPid_;
194        data.extensionUid = dataAbilityUid_;
195        data.extensionBundleName = bundleName_;
196        data.extensionModuleName = moduleName_;
197        data.extensionName = abilityName_;
198        data.extensionType = AppExecFwk::ExtensionAbilityType::DATASHARE;
199    }
200
201private:
202    class CallerInfo : public std::enable_shared_from_this<CallerInfo> {
203    public:
204        CallerInfo(bool isNotHap, int32_t callerPid, const sptr<IRemoteObject> &callerToken)
205            : isNotHap_(isNotHap), callerPid_(callerPid), callerToken_(callerToken) {}
206
207        bool IsNotHap() const
208        {
209            return isNotHap_;
210        }
211
212        int32_t GetCallerPid() const
213        {
214            return callerPid_;
215        }
216
217        sptr<IRemoteObject> GetCallerToken() const
218        {
219            return callerToken_;
220        }
221
222    private:
223        bool isNotHap_ = false;
224        int32_t callerPid_ = 0;
225        sptr<IRemoteObject> callerToken_ = nullptr;
226    };
227
228    int32_t dataAbilityPid_ = 0;
229    int32_t dataAbilityUid_ = 0;
230    std::string bundleName_;
231    std::string moduleName_;
232    std::string abilityName_;
233    std::list<std::shared_ptr<CallerInfo>> callers_; // caller infos of this data ability.
234};
235
236ConnectionStateItem::ConnectionStateItem(int32_t callerUid, int32_t callerPid, const std::string &callerName)
237    : callerUid_(callerUid), callerPid_(callerPid), callerName_(callerName)
238{
239}
240
241ConnectionStateItem::~ConnectionStateItem()
242{}
243
244std::shared_ptr<ConnectionStateItem> ConnectionStateItem::CreateConnectionStateItem(
245    const std::shared_ptr<ConnectionRecord> &record)
246{
247    if (!record) {
248        return nullptr;
249    }
250
251    return std::make_shared<ConnectionStateItem>(record->GetCallerUid(),
252        record->GetCallerPid(), record->GetCallerName());
253}
254
255std::shared_ptr<ConnectionStateItem> ConnectionStateItem::CreateConnectionStateItem(
256    const DataAbilityCaller &dataCaller)
257{
258    return std::make_shared<ConnectionStateItem>(dataCaller.callerUid,
259        dataCaller.callerPid, dataCaller.callerName);
260}
261
262bool ConnectionStateItem::AddConnection(std::shared_ptr<ConnectionRecord> record,
263    AbilityRuntime::ConnectionData &data)
264{
265    if (!record) {
266        TAG_LOGE(AAFwkTag::CONNECTION, "invalid connection record");
267        return false;
268    }
269
270    auto token = record->GetTargetToken();
271    if (!token) {
272        TAG_LOGE(AAFwkTag::CONNECTION, "invalid token");
273        return false;
274    }
275
276    sptr<IRemoteObject> connectionObj = record->GetConnection();
277    if (!connectionObj) {
278        TAG_LOGE(AAFwkTag::CONNECTION, "no connection callback");
279        return false;
280    }
281
282    std::shared_ptr<ConnectedExtension> connectedExtension = nullptr;
283    auto it = connectionMap_.find(token);
284    if (it == connectionMap_.end()) {
285        connectedExtension = ConnectedExtension::CreateConnectedExtension(record);
286        if (connectedExtension) {
287            connectionMap_[token] = connectedExtension;
288        }
289    } else {
290        connectedExtension = it->second;
291    }
292
293    if (!connectedExtension) {
294        TAG_LOGE(AAFwkTag::CONNECTION, "invalid connectedExtension");
295        return false;
296    }
297
298    bool needNotify = connectedExtension->AddConnection(connectionObj);
299    if (needNotify) {
300        GenerateConnectionData(connectedExtension, data);
301    }
302
303    return needNotify;
304}
305
306bool ConnectionStateItem::RemoveConnection(std::shared_ptr<ConnectionRecord> record,
307    AbilityRuntime::ConnectionData &data)
308{
309    if (!record) {
310        TAG_LOGE(AAFwkTag::CONNECTION, "invalid connection record");
311        return false;
312    }
313
314    auto token = record->GetTargetToken();
315    if (!token) {
316        TAG_LOGE(AAFwkTag::CONNECTION, "invalid token");
317        return false;
318    }
319
320    sptr<IRemoteObject> connectionObj = record->GetConnection();
321    if (!connectionObj) {
322        TAG_LOGE(AAFwkTag::CONNECTION, "no connection callback");
323        return false;
324    }
325
326    auto it = connectionMap_.find(token);
327    if (it == connectionMap_.end()) {
328        TAG_LOGE(AAFwkTag::CONNECTION, "no such connectedExtension");
329        return false;
330    }
331
332    auto connectedExtension = it->second;
333    if (!connectedExtension) {
334        TAG_LOGE(AAFwkTag::CONNECTION, "no such connectedExtension");
335        return false;
336    }
337
338    bool needNotify = connectedExtension->RemoveConnection(connectionObj);
339    if (needNotify) {
340        connectionMap_.erase(it);
341        GenerateConnectionData(connectedExtension, data);
342    }
343
344    return needNotify;
345}
346
347bool ConnectionStateItem::AddDataAbilityConnection(const DataAbilityCaller &caller,
348    const std::shared_ptr<DataAbilityRecord> &dataAbility, AbilityRuntime::ConnectionData &data)
349{
350    if (!dataAbility) {
351        TAG_LOGE(AAFwkTag::CONNECTION, "invalid dataAbility");
352        return false;
353    }
354
355    auto token = dataAbility->GetToken();
356    if (!token) {
357        TAG_LOGE(AAFwkTag::CONNECTION, "invalid dataAbility token");
358        return false;
359    }
360
361    std::shared_ptr<ConnectedDataAbility> connectedAbility = nullptr;
362    auto it = dataAbilityMap_.find(token);
363    if (it == dataAbilityMap_.end()) {
364        connectedAbility = ConnectedDataAbility::CreateConnectedDataAbility(dataAbility);
365        if (connectedAbility) {
366            dataAbilityMap_[token] = connectedAbility;
367        }
368    } else {
369        connectedAbility = it->second;
370    }
371
372    if (!connectedAbility) {
373        TAG_LOGE(AAFwkTag::CONNECTION, "invalid connectedAbility");
374        return false;
375    }
376
377    bool needNotify = connectedAbility->AddCaller(caller);
378    if (needNotify) {
379        GenerateConnectionData(connectedAbility, data);
380    }
381
382    return needNotify;
383}
384
385bool ConnectionStateItem::RemoveDataAbilityConnection(const DataAbilityCaller &caller,
386    const std::shared_ptr<DataAbilityRecord> &dataAbility, AbilityRuntime::ConnectionData &data)
387{
388    if (!dataAbility) {
389        TAG_LOGE(AAFwkTag::CONNECTION, "invalid data ability record");
390        return false;
391    }
392
393    auto token = dataAbility->GetToken();
394    if (!token) {
395        TAG_LOGE(AAFwkTag::CONNECTION, "invalid data ability token");
396        return false;
397    }
398
399    auto it = dataAbilityMap_.find(token);
400    if (it == dataAbilityMap_.end()) {
401        TAG_LOGE(AAFwkTag::CONNECTION, "no such connected data ability");
402        return false;
403    }
404
405    auto connectedDataAbility = it->second;
406    if (!connectedDataAbility) {
407        TAG_LOGE(AAFwkTag::CONNECTION, "no such connectedDataAbility");
408        return false;
409    }
410
411    bool needNotify = connectedDataAbility->RemoveCaller(caller);
412    if (needNotify) {
413        dataAbilityMap_.erase(it);
414        GenerateConnectionData(connectedDataAbility, data);
415    }
416
417    return needNotify;
418}
419
420bool ConnectionStateItem::HandleDataAbilityDied(const sptr<IRemoteObject> &token,
421    AbilityRuntime::ConnectionData &data)
422{
423    if (!token) {
424        return false;
425    }
426
427    auto it = dataAbilityMap_.find(token);
428    if (it == dataAbilityMap_.end()) {
429        TAG_LOGE(AAFwkTag::CONNECTION, "no such data ability");
430        return false;
431    }
432
433    auto connectedDataAbility = it->second;
434    if (!connectedDataAbility) {
435        TAG_LOGE(AAFwkTag::CONNECTION, "no connectedDataAbility");
436        return false;
437    }
438
439    dataAbilityMap_.erase(it);
440    GenerateConnectionData(connectedDataAbility, data);
441    return true;
442}
443
444bool ConnectionStateItem::IsEmpty() const
445{
446    return connectionMap_.empty() && dataAbilityMap_.empty();
447}
448
449void ConnectionStateItem::GenerateAllConnectionData(std::vector<AbilityRuntime::ConnectionData> &datas)
450{
451    AbilityRuntime::ConnectionData data;
452    for (auto it = connectionMap_.begin(); it != connectionMap_.end(); ++it) {
453        GenerateConnectionData(it->second, data);
454        datas.emplace_back(data);
455    }
456
457    for (auto it = dataAbilityMap_.begin(); it != dataAbilityMap_.end(); ++it) {
458        GenerateConnectionData(it->second, data);
459        datas.emplace_back(data);
460    }
461}
462
463void ConnectionStateItem::GenerateConnectionData(
464    const std::shared_ptr<ConnectedExtension> &connectedExtension, AbilityRuntime::ConnectionData &data)
465{
466    if (connectedExtension) {
467        connectedExtension->GenerateExtensionInfo(data);
468    }
469    data.callerUid = callerUid_;
470    data.callerPid = callerPid_;
471    data.callerName = callerName_;
472}
473
474void ConnectionStateItem::GenerateConnectionData(const std::shared_ptr<ConnectedDataAbility> &connectedDataAbility,
475    AbilityRuntime::ConnectionData &data)
476{
477    if (connectedDataAbility) {
478        connectedDataAbility->GenerateExtensionInfo(data);
479    }
480    data.callerUid = callerUid_;
481    data.callerPid = callerPid_;
482    data.callerName = callerName_;
483}
484}  // namespace AAFwk
485}  // namespace OHOS
486