1 /*
2  * Copyright (c) 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 #ifndef OHOS_FFI_FFI_REMOTE_DATA_H
17 #define OHOS_FFI_FFI_REMOTE_DATA_H
18 
19 #include "nocopyable.h"
20 #include "refbase.h"
21 #include "unordered_map"
22 
23 #include <mutex>
24 
25 #include "cj_fn_invoker.h"
26 #include "runtimetype.h"
27 
28 namespace OHOS::FFI {
29 
30 constexpr int64_t MAX_INT64 = 0x7fffffffffffffff;
31 
32 class RemoteData;
33 class FFIData;
34 
35 class FFI_EXPORT FFIDataManager {
36 public:
37     static FFIDataManager* GetInstance();
38 
39     DISALLOW_COPY_AND_MOVE(FFIDataManager);
40     FFIDataManager() = default;
41 
GetFFIData(int64_t id)42     sptr<FFIData> GetFFIData(int64_t id)
43     {
44         std::lock_guard<std::mutex> lock(mtx);
45         return ffiDataStore_[id];
46     }
47 
GetRemoteData(int64_t id)48     sptr<RemoteData> GetRemoteData(int64_t id)
49     {
50         std::lock_guard<std::mutex> lock(mtx);
51         auto existP = remoteDataStore_[id];
52         return existP.promote();
53     }
54     void StoreFFIData(const sptr<FFIData>& data);
55     void StoreRemoteData(const sptr<RemoteData>& data);
RemoveFFIData(int64_t id)56     void RemoveFFIData(int64_t id)
57     {
58         std::lock_guard<std::mutex> lock(mtx);
59         ffiDataStore_.erase(id);
60     }
RemoveRemoteData(int64_t id)61     void RemoveRemoteData(int64_t id)
62     {
63         std::lock_guard<std::mutex> lock(mtx);
64         remoteDataStore_.erase(id);
65     }
66 
67     int64_t NewFFIDataId();
68 
69 private:
70     friend class FFIData;
71     uint64_t curFFIDataId_ = 0;
72     const int64_t maxId = MAX_INT64;
73     // maxCapacity can be set to a larger number if needed, make sure maxCapacity is not larger than maxId
74     const int64_t maxCapacity = MAX_INT64;
75     static FFIDataManager* instance_;
76     std::mutex mtx;
77 
78     std::unordered_map<int64_t, sptr<FFIData>> ffiDataStore_;
79     std::unordered_map<int64_t, wptr<RemoteData>> remoteDataStore_;
80 
FFIDataExist(int64_t id)81     bool FFIDataExist(int64_t id) const
82     {
83         return ffiDataStore_.find(id) != ffiDataStore_.end();
84     }
85 
86     int FFIDataIdSafeIncrease();
87 };
88 
89 #define CJ_REMOTE_CLASS(className)                               \
90     DECL_TYPE(className, RemoteData)                           \
91 public:                                                        \
92     friend class RefBase;                                      \
93     friend class RemoteData;                                   \
94     DISALLOW_COPY_AND_MOVE(className);                         \
95     className() = delete;                                      \
96                                                                \
97 protected:                                                     \
98     explicit className(int64_t id) : OHOS::FFI::RemoteData(id) \
99     {}
100 
101 /**
102  * a reference of cj FFIData object.
103  *  standard create procedure:
104  *      1. cj: create FFIData
105  *      2. cj: register to FFIDataManager
106  *      3. cj: pass id to native
107  *      4. native: RemoteData::Create
108  *  standard destroy procedure:
109  *      1. native: ~RemoteData
110  *      2. cj: remove from FFIDataManager
111  *      3. cj: FFIData::onDestroyed
112  */
113 class FFI_EXPORT RemoteData : public TypeBase, public virtual RefBase {
114     DECL_TYPE(RemoteData, TypeBase)
115 public:
116     DISALLOW_COPY_AND_MOVE(RemoteData);
117 
118     template<class T>
Create(int64_t id)119     static sptr<T> Create(int64_t id)
120     {
121         auto manager = FFIDataManager::GetInstance();
122         auto existed = manager->GetRemoteData(id);
123         if (existed != nullptr) {
124             return sptr<T>(existed.GetRefPtr()->template DynamicCast<T>());
125         }
126         auto ref = sptr<T>(new (std::nothrow) T(id));
127         if (ref) {
128             manager->StoreRemoteData(ref);
129         }
130         return ref;
131     }
132 
133     ~RemoteData() override;
134 
135 protected:
136     explicit RemoteData(int64_t id);
137 
138 private:
139     friend class RefBase;
140 
141 public:
142     int64_t GetID() const;
143 
144 private:
145     int64_t id_;
146     bool isValid_;
147 };
148 
149 class FFI_EXPORT CJLambdaRemoteData : public RemoteData {
DECL_TYPE(CJLambdaRemoteData,RemoteData)150     DECL_TYPE(CJLambdaRemoteData, RemoteData)
151 public:
152     explicit CJLambdaRemoteData(int64_t id): RemoteData(id) {}
153 
154     ~CJLambdaRemoteData() override;
155 };
156 
157 /**
158  * object to referenced by cj.
159  *  standard create procedure:
160  *      0. native: Define class derived from FFIData with macro DECL_TYPE to support safe dynamic cast
161  *      1. native: FFIData::Create
162  *      2. native: register to FFIDataManager
163  *      3. native: pass to cj side
164  *      4. cj: create RemoteData
165  *      5. cj: register to RemoteDataManager
166  *  standard destroy procedure:
167  *      1. cj: RemoteData.release
168  *      2. native: remove from FFIDataManager
169  *      3. native: ~FFIData
170  *      4. cj: RemoteData.onDestroyed
171  */
172 class FFI_EXPORT FFIData : public TypeBase, public RefBase {
173     DECL_TYPE(FFIData, TypeBase)
174 public:
175     DISALLOW_COPY_AND_MOVE(FFIData);
FFIData()176     FFIData() : id_(FFIDataManager::GetInstance()->NewFFIDataId()) {}
177     ~FFIData() override;
178 
179     template<class T, class... Args>
Create(Args...args)180     static sptr<T> Create(Args... args)
181     {
182         auto ref = sptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
183         if (ref) {
184             FFIDataManager::GetInstance()->StoreFFIData(ref);
185         }
186         return ref;
187     }
188 
189     template<class T>
GetData(int64_t id)190     static sptr<T> GetData(int64_t id)
191     {
192         auto data = FFIDataManager::GetInstance()->GetFFIData(id);
193         if (data != nullptr) {
194             return sptr<T>(data.GetRefPtr()->template DynamicCast<T>());
195         }
196         return nullptr;
197     }
198 
Release(int64_t id)199     static void Release(int64_t id)
200     {
201         FFIDataManager::GetInstance()->RemoveFFIData(id);
202     }
Exist(int64_t id)203     static bool Exist(int64_t id)
204     {
205         auto& store_ = FFIDataManager::GetInstance()->ffiDataStore_;
206         return store_.find(id) != store_.end();
207     }
208 
GetID()209     int64_t GetID() const
210     {
211         return id_;
212     }
213 
214 private:
215     int64_t id_;
216 };
217 
218 } // namespace OHOS::FFI
219 
220 #endif // OHOS_FFI_FFI_REMOTE_DATA_H
221