1 /*
2 * Copyright (c) 2023 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 <sys/mman.h> /* mmap */
17
18 #include "securec.h"
19 #include "pm_util.h"
20 #include "pm_state_c.h"
21 #include "pm_smartptr_util.h"
22 #include "pm_log.h"
23
24 #include "purgeable_mem_base.h"
25
26 namespace OHOS {
27 namespace PurgeableMem {
28 #ifdef LOG_TAG
29 #undef LOG_TAG
30 #endif
31 #define LOG_TAG "PurgeableMem"
32 const int MAX_BUILD_TRYTIMES = 3;
33
RoundUp(size_t val, size_t align)34 static inline size_t RoundUp(size_t val, size_t align)
35 {
36 if (val + align < val || val + align < align) {
37 PM_HILOG_ERROR(LOG_CORE, "%{public}s: Addition overflow!", __func__);
38 return val;
39 }
40 if (align == 0) {
41 return val;
42 }
43 return ((val + align - 1) / align) * align;
44 }
45
PurgeableMemBase()46 PurgeableMemBase::PurgeableMemBase()
47 {
48 }
49
~PurgeableMemBase()50 PurgeableMemBase::~PurgeableMemBase()
51 {
52 }
53
BeginRead()54 bool PurgeableMemBase::BeginRead()
55 {
56 std::lock_guard<std::mutex> lock(dataLock_);
57 if (!isDataValid_) {
58 return false;
59 }
60
61 bool ret = false;
62 int tryTimes = 0;
63
64 PM_HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString().c_str());
65 IF_NULL_LOG_ACTION(dataPtr_, "dataPtr is nullptr in BeginRead", return false);
66 IF_NULL_LOG_ACTION(builder_, "builder_ is nullptr in BeginRead", return false);
67 Pin();
68 PMState err = PM_OK;
69 while (true) {
70 if (!IfNeedRebuild()) {
71 PM_HILOG_DEBUG(LOG_CORE, "%{public}s: not purged, return true. MAP_PUR=0x%{public}x",
72 __func__, MAP_PURGEABLE);
73 ret = true;
74 break;
75 }
76
77 bool succ = BuildContent();
78 if (succ) {
79 AfterRebuildSucc();
80 }
81 PM_HILOG_DEBUG(LOG_CORE, "%{public}s: purged, built %{public}s", __func__, succ ? "succ" : "fail");
82
83 tryTimes++;
84 if (!succ || tryTimes > MAX_BUILD_TRYTIMES) {
85 err = PMB_BUILD_ALL_FAIL;
86 break;
87 }
88 }
89
90 if (!ret) {
91 PM_HILOG_ERROR(LOG_CORE, "%{public}s: err %{public}s, UxptePut. tryTime:%{public}d",
92 __func__, GetPMStateName(err), tryTimes);
93 Unpin();
94 }
95 return ret;
96 }
97
EndRead()98 void PurgeableMemBase::EndRead()
99 {
100 std::lock_guard<std::mutex> lock(dataLock_);
101 if (isDataValid_) {
102 Unpin();
103 }
104
105 return;
106 }
107
BeginWrite()108 bool PurgeableMemBase::BeginWrite()
109 {
110 PM_HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString().c_str());
111 std::lock_guard<std::mutex> lock(dataLock_);
112 if (dataPtr_ == nullptr) {
113 return false;
114 }
115 IF_NULL_LOG_ACTION(dataPtr_, "dataPtr is nullptr in BeginWrite", return false);
116 IF_NULL_LOG_ACTION(builder_, "builder_ is nullptr in BeginWrite", return false);
117
118 Pin();
119 PMState err = PM_OK;
120 do {
121 if (!IfNeedRebuild()) {
122 /* data is not purged, return true */
123 break;
124 }
125 /* data purged, rebuild it */
126 if (BuildContent()) {
127 /* data rebuild succ, return true */
128 AfterRebuildSucc();
129 break;
130 }
131 err = PMB_BUILD_ALL_FAIL;
132 } while (0);
133
134 if (err == PM_OK) {
135 return true;
136 }
137
138 PM_HILOG_ERROR(LOG_CORE, "%{public}s: err %{public}s, UxptePut.", __func__, GetPMStateName(err));
139 Unpin();
140 return false;
141 }
142
EndWrite()143 void PurgeableMemBase::EndWrite()
144 {
145 std::lock_guard<std::mutex> lock(dataLock_);
146 PM_HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString().c_str());
147 Unpin();
148 }
149
ModifyContentByBuilder(std::unique_ptr<PurgeableMemBuilder> modifier)150 bool PurgeableMemBase::ModifyContentByBuilder(std::unique_ptr<PurgeableMemBuilder> modifier)
151 {
152 IF_NULL_LOG_ACTION(modifier, "input modifier is nullptr", return false);
153 std::lock_guard<std::mutex> lock(dataLock_);
154 if (!modifier->Build(dataPtr_, dataSizeInput_)) {
155 PM_HILOG_ERROR(LOG_CORE, "%{public}s: modify content by builder fail!!", __func__);
156 return false;
157 }
158 /* log modify */
159 if (builder_) {
160 builder_->AppendBuilder(std::move(modifier));
161 } else {
162 builder_ = std::move(modifier);
163 }
164 return true;
165 }
166
IfNeedRebuild()167 bool PurgeableMemBase::IfNeedRebuild()
168 {
169 if (buildDataCount_ == 0 || IsPurged()) {
170 return true;
171 }
172 return false;
173 }
174
AfterRebuildSucc()175 void PurgeableMemBase::AfterRebuildSucc()
176 {
177 }
178
GetContent()179 void *PurgeableMemBase::GetContent()
180 {
181 std::lock_guard<std::mutex> lock(dataLock_);
182 return dataPtr_;
183 }
184
GetContentSize()185 size_t PurgeableMemBase::GetContentSize()
186 {
187 std::lock_guard<std::mutex> lock(dataLock_);
188 return dataSizeInput_;
189 }
190
IsPurged()191 bool PurgeableMemBase::IsPurged()
192 {
193 return false;
194 }
195
BuildContent()196 bool PurgeableMemBase::BuildContent()
197 {
198 bool succ = false;
199 /* clear content before rebuild */
200 if (memset_s(dataPtr_, RoundUp(dataSizeInput_, PAGE_SIZE), 0, dataSizeInput_) != EOK) {
201 PM_HILOG_ERROR(LOG_CORE, "%{public}s, clear content fail", __func__);
202 return succ;
203 }
204 /* builder_ and dataPtr_ is never nullptr since it is checked by BeginAccess() before */
205 succ = builder_->BuildAll(dataPtr_, dataSizeInput_);
206 if (succ) {
207 buildDataCount_++;
208 }
209 return succ;
210 }
211
ResizeData(size_t newSize)212 void PurgeableMemBase::ResizeData(size_t newSize)
213 {
214 }
215
Pin()216 bool PurgeableMemBase::Pin()
217 {
218 return false;
219 }
220
Unpin()221 bool PurgeableMemBase::Unpin()
222 {
223 return false;
224 }
225
GetPinStatus() const226 int PurgeableMemBase::GetPinStatus() const
227 {
228 return 0;
229 }
230
ToString() const231 inline std::string PurgeableMemBase::ToString() const
232 {
233 return "";
234 }
235
SetRebuildSuccessCallback(std::function<void()> &callback)236 void PurgeableMemBase::SetRebuildSuccessCallback(std::function<void()> &callback)
237 {
238 std::lock_guard<std::mutex> lock(dataLock_);
239 if (builder_) {
240 builder_->SetRebuildSuccessCallback(callback);
241 }
242 }
243
IsDataValid()244 bool PurgeableMemBase::IsDataValid()
245 {
246 std::lock_guard<std::mutex> lock(dataLock_);
247 return isDataValid_;
248 }
249
SetDataValid(bool target)250 void PurgeableMemBase::SetDataValid(bool target)
251 {
252 std::lock_guard<std::mutex> lock(dataLock_);
253 isDataValid_ = target;
254 }
255 } /* namespace PurgeableMem */
256 } /* namespace OHOS */
257