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