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