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 #include "ffi_remote_data.h"
17
18 #include <cinttypes>
19
20 #include "hilog/log_cpp.h"
21
22 using namespace OHOS::FFI;
23 using namespace OHOS;
24 using namespace OHOS::HiviewDFX;
25
26 namespace {
27 constexpr HiLogLabel LABEL = { LOG_CORE, 0xD003901, "CJ-FFIBindNative" };
28 } // namespace
29
30 FFIDataManager* FFIDataManager::instance_ = nullptr;
31
GetInstance()32 FFIDataManager* FFIDataManager::GetInstance()
33 {
34 if (instance_ == nullptr) {
35 instance_ = new FFIDataManager();
36 }
37 return instance_;
38 }
39
StoreFFIData(const sptr<FFIData> & data)40 void FFIDataManager::StoreFFIData(const sptr<FFIData>& data)
41 {
42 std::lock_guard<std::mutex> lock(mtx);
43 int64_t id = data->GetID();
44 // 0 represents invalid status
45 if (id == 0) {
46 HiLog::Fatal(LABEL, "FFIData store invalid key");
47 return;
48 }
49 HiLog::Info(LABEL, "FFIData store_ key put in: %{public}" PRId64, id);
50 ffiDataStore_[id] = data;
51 }
52
StoreRemoteData(const sptr<RemoteData> & data)53 void FFIDataManager::StoreRemoteData(const sptr<RemoteData>& data)
54 {
55 std::lock_guard<std::mutex> lock(mtx);
56 remoteDataStore_[data->GetID()] = data;
57 }
58
NewFFIDataId()59 int64_t FFIDataManager::NewFFIDataId()
60 {
61 std::lock_guard<std::mutex> lock(mtx);
62 if (static_cast<int64_t>(ffiDataStore_.size()) >= maxCapacity) {
63 HiLog::Fatal(LABEL, "FFIData store_ over max capacity: %{public}" PRId64, maxCapacity);
64 // 0 represents invalid status in CJ RemoteData, will be handled by CJ Exception
65 return 0;
66 }
67 // When ffiDataId over uint64 max value, resetTime will be increased with 1.
68 auto resetTimes = FFIDataIdSafeIncrease();
69 auto resetTimeUpperBound = 2;
70 while ((ffiDataStore_.find(curFFIDataId_) != ffiDataStore_.end()) && resetTimes < resetTimeUpperBound) {
71 resetTimes += FFIDataIdSafeIncrease();
72 }
73 // It means there is no one available id, When resetTimes come to UpperBound 2.
74 if (resetTimes >= resetTimeUpperBound) {
75 HiLog::Fatal(LABEL, "FFIData id run out");
76 // 0 represents invalid status in CJ RemoteData, will be handled by CJ Exception
77 return 0;
78 }
79 HiLog::Info(LABEL, "FFIDataManager new ID : %{public}" PRId64 ", cache size: %{public}zu", curFFIDataId_,
80 ffiDataStore_.size());
81 return curFFIDataId_;
82 }
83
FFIDataIdSafeIncrease()84 int FFIDataManager::FFIDataIdSafeIncrease()
85 {
86 curFFIDataId_++;
87 if (curFFIDataId_ >= static_cast<uint64_t>(maxId)) {
88 HiLog::Warn(LABEL, "FFIData id: %{public}" PRId64 " over max %{public}" PRId64 ", reset to 0", curFFIDataId_,
89 maxCapacity);
90 curFFIDataId_ = 1;
91 return 1;
92 }
93 return 0;
94 }
95
RemoteData(int64_t id)96 RemoteData::RemoteData(int64_t id) : id_(id), isValid_(id != 0)
97 {
98 HiLog::Debug(LABEL, "RemoteData constructed: %{public}" PRId64 ".", id_);
99 }
100
~RemoteData()101 RemoteData::~RemoteData()
102 {
103 HiLog::Debug(LABEL, "RemoteData destructed: %{public}" PRId64 ".", id_);
104 auto cjFunc = CJFFIFnInvoker::GetInstance()->GetCJFuncs().atCOHOSFFIReleaseFFIData;
105 if (!cjFunc) {
106 HiLog::Error(LABEL, "Failed to invoke CJ function: FFIReleaseFFIData!");
107 return;
108 }
109 cjFunc(GetID());
110 isValid_ = false;
111 }
112
~CJLambdaRemoteData()113 CJLambdaRemoteData::~CJLambdaRemoteData()
114 {
115 auto manager = FFIDataManager::GetInstance();
116 manager->RemoveRemoteData(GetID());
117 }
118
GetID() const119 int64_t RemoteData::GetID() const
120 {
121 if (!isValid_) {
122 HiLog::Error(LABEL, "RemoteData::GetID error, remote data invalid: %{public}" PRId64 ".", id_);
123 }
124 return id_;
125 }
126
~FFIData()127 FFIData::~FFIData()
128 {
129 auto cjFunc = CJFFIFnInvoker::GetInstance()->GetCJFuncs().atCOHOSFFIReleaseRemoteData;
130 if (!cjFunc) {
131 HiLog::Error(LABEL, "Failed to invoke CJ function: FFIReleaseRemoteData!");
132 return;
133 }
134 cjFunc(GetID());
135 }
136