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