/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ffi_remote_data.h" #include <cinttypes> #include "hilog/log_cpp.h" using namespace OHOS::FFI; using namespace OHOS; using namespace OHOS::HiviewDFX; namespace { constexpr HiLogLabel LABEL = { LOG_CORE, 0xD003901, "CJ-FFIBindNative" }; } // namespace FFIDataManager* FFIDataManager::instance_ = nullptr; FFIDataManager* FFIDataManager::GetInstance() { if (instance_ == nullptr) { instance_ = new FFIDataManager(); } return instance_; } void FFIDataManager::StoreFFIData(const sptr<FFIData>& data) { std::lock_guard<std::mutex> lock(mtx); int64_t id = data->GetID(); // 0 represents invalid status if (id == 0) { HiLog::Fatal(LABEL, "FFIData store invalid key"); return; } HiLog::Info(LABEL, "FFIData store_ key put in: %{public}" PRId64, id); ffiDataStore_[id] = data; } void FFIDataManager::StoreRemoteData(const sptr<RemoteData>& data) { std::lock_guard<std::mutex> lock(mtx); remoteDataStore_[data->GetID()] = data; } int64_t FFIDataManager::NewFFIDataId() { std::lock_guard<std::mutex> lock(mtx); if (static_cast<int64_t>(ffiDataStore_.size()) >= maxCapacity) { HiLog::Fatal(LABEL, "FFIData store_ over max capacity: %{public}" PRId64, maxCapacity); // 0 represents invalid status in CJ RemoteData, will be handled by CJ Exception return 0; } // When ffiDataId over uint64 max value, resetTime will be increased with 1. auto resetTimes = FFIDataIdSafeIncrease(); auto resetTimeUpperBound = 2; while ((ffiDataStore_.find(curFFIDataId_) != ffiDataStore_.end()) && resetTimes < resetTimeUpperBound) { resetTimes += FFIDataIdSafeIncrease(); } // It means there is no one available id, When resetTimes come to UpperBound 2. if (resetTimes >= resetTimeUpperBound) { HiLog::Fatal(LABEL, "FFIData id run out"); // 0 represents invalid status in CJ RemoteData, will be handled by CJ Exception return 0; } HiLog::Info(LABEL, "FFIDataManager new ID : %{public}" PRId64 ", cache size: %{public}zu", curFFIDataId_, ffiDataStore_.size()); return curFFIDataId_; } int FFIDataManager::FFIDataIdSafeIncrease() { curFFIDataId_++; if (curFFIDataId_ >= static_cast<uint64_t>(maxId)) { HiLog::Warn(LABEL, "FFIData id: %{public}" PRId64 " over max %{public}" PRId64 ", reset to 0", curFFIDataId_, maxCapacity); curFFIDataId_ = 1; return 1; } return 0; } RemoteData::RemoteData(int64_t id) : id_(id), isValid_(id != 0) { HiLog::Debug(LABEL, "RemoteData constructed: %{public}" PRId64 ".", id_); } RemoteData::~RemoteData() { HiLog::Debug(LABEL, "RemoteData destructed: %{public}" PRId64 ".", id_); auto cjFunc = CJFFIFnInvoker::GetInstance()->GetCJFuncs().atCOHOSFFIReleaseFFIData; if (!cjFunc) { HiLog::Error(LABEL, "Failed to invoke CJ function: FFIReleaseFFIData!"); return; } cjFunc(GetID()); isValid_ = false; } CJLambdaRemoteData::~CJLambdaRemoteData() { auto manager = FFIDataManager::GetInstance(); manager->RemoveRemoteData(GetID()); } int64_t RemoteData::GetID() const { if (!isValid_) { HiLog::Error(LABEL, "RemoteData::GetID error, remote data invalid: %{public}" PRId64 ".", id_); } return id_; } FFIData::~FFIData() { auto cjFunc = CJFFIFnInvoker::GetInstance()->GetCJFuncs().atCOHOSFFIReleaseRemoteData; if (!cjFunc) { HiLog::Error(LABEL, "Failed to invoke CJ function: FFIReleaseRemoteData!"); return; } cjFunc(GetID()); }