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