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 if (isDataValid_) {
101 Unpin();
102 }
103
104 return;
105 }
106
BeginWrite()107 bool PurgeableMemBase::BeginWrite()
108 {
109 PM_HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString().c_str());
110 std::lock_guard<std::mutex> lock(dataLock_);
111 if (dataPtr_ == nullptr) {
112 return false;
113 }
114 IF_NULL_LOG_ACTION(dataPtr_, "dataPtr is nullptr in BeginWrite", return false);
115 IF_NULL_LOG_ACTION(builder_, "builder_ is nullptr in BeginWrite", return false);
116
117 Pin();
118 PMState err = PM_OK;
119 do {
120 if (!IfNeedRebuild()) {
121 /* data is not purged, return true */
122 break;
123 }
124 /* data purged, rebuild it */
125 if (BuildContent()) {
126 /* data rebuild succ, return true */
127 AfterRebuildSucc();
128 break;
129 }
130 err = PMB_BUILD_ALL_FAIL;
131 } while (0);
132
133 if (err == PM_OK) {
134 return true;
135 }
136
137 PM_HILOG_ERROR(LOG_CORE, "%{public}s: err %{public}s, UxptePut.", __func__, GetPMStateName(err));
138 Unpin();
139 return false;
140 }
141
EndWrite()142 void PurgeableMemBase::EndWrite()
143 {
144 PM_HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString().c_str());
145 Unpin();
146 }
147
ModifyContentByBuilder(std::unique_ptr<PurgeableMemBuilder> modifier)148 bool PurgeableMemBase::ModifyContentByBuilder(std::unique_ptr<PurgeableMemBuilder> modifier)
149 {
150 IF_NULL_LOG_ACTION(modifier, "input modifier is nullptr", return false);
151 std::lock_guard<std::mutex> lock(dataLock_);
152 if (!modifier->Build(dataPtr_, dataSizeInput_)) {
153 PM_HILOG_ERROR(LOG_CORE, "%{public}s: modify content by builder fail!!", __func__);
154 return false;
155 }
156 /* log modify */
157 if (builder_) {
158 builder_->AppendBuilder(std::move(modifier));
159 } else {
160 builder_ = std::move(modifier);
161 }
162 return true;
163 }
164
IfNeedRebuild()165 bool PurgeableMemBase::IfNeedRebuild()
166 {
167 if (buildDataCount_ == 0 || IsPurged()) {
168 return true;
169 }
170 return false;
171 }
172
AfterRebuildSucc()173 void PurgeableMemBase::AfterRebuildSucc()
174 {
175 }
176
GetContent()177 void *PurgeableMemBase::GetContent()
178 {
179 std::lock_guard<std::mutex> lock(dataLock_);
180 return dataPtr_;
181 }
182
GetContentSize()183 size_t PurgeableMemBase::GetContentSize()
184 {
185 std::lock_guard<std::mutex> lock(dataLock_);
186 return dataSizeInput_;
187 }
188
IsPurged()189 bool PurgeableMemBase::IsPurged()
190 {
191 return false;
192 }
193
BuildContent()194 bool PurgeableMemBase::BuildContent()
195 {
196 bool succ = false;
197 /* clear content before rebuild */
198 if (memset_s(dataPtr_, RoundUp(dataSizeInput_, PAGE_SIZE), 0, dataSizeInput_) != EOK) {
199 PM_HILOG_ERROR(LOG_CORE, "%{public}s, clear content fail", __func__);
200 return succ;
201 }
202 /* builder_ and dataPtr_ is never nullptr since it is checked by BeginAccess() before */
203 succ = builder_->BuildAll(dataPtr_, dataSizeInput_);
204 if (succ) {
205 buildDataCount_++;
206 }
207 return succ;
208 }
209
ResizeData(size_t newSize)210 void PurgeableMemBase::ResizeData(size_t newSize)
211 {
212 }
213
Pin()214 bool PurgeableMemBase::Pin()
215 {
216 return false;
217 }
218
Unpin()219 bool PurgeableMemBase::Unpin()
220 {
221 return false;
222 }
223
GetPinStatus() const224 int PurgeableMemBase::GetPinStatus() const
225 {
226 return 0;
227 }
228
ToString() const229 inline std::string PurgeableMemBase::ToString() const
230 {
231 return "";
232 }
233
SetRebuildSuccessCallback(std::function<void ()> & callback)234 void PurgeableMemBase::SetRebuildSuccessCallback(std::function<void()> &callback)
235 {
236 if (builder_) {
237 builder_->SetRebuildSuccessCallback(callback);
238 }
239 }
240
IsDataValid()241 bool PurgeableMemBase::IsDataValid()
242 {
243 return isDataValid_;
244 }
245
SetDataValid(bool target)246 void PurgeableMemBase::SetDataValid(bool target)
247 {
248 isDataValid_ = target;
249 }
250 } /* namespace PurgeableMem */
251 } /* namespace OHOS */
252