• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_ashmem.h"
25 
26 namespace OHOS {
27 namespace PurgeableMem {
28 #ifdef LOG_TAG
29 #undef LOG_TAG
30 #endif
31 #define LOG_TAG "PurgeableMem"
32 
RoundUp(size_t val,size_t align)33 static inline size_t RoundUp(size_t val, size_t align)
34 {
35     if (align == 0) {
36         return val;
37     }
38     return ((val + align - 1) / align) * align;
39 }
40 
PurgeableAshMem(std::unique_ptr<PurgeableMemBuilder> builder)41 PurgeableAshMem::PurgeableAshMem(std::unique_ptr<PurgeableMemBuilder> builder)
42 {
43     dataPtr_ = nullptr;
44     builder_ = nullptr;
45     ashmemFd_ = -1;
46     buildDataCount_ = 0;
47     isSupport_ = false;
48     isChange_ = false;
49     IF_NULL_LOG_ACTION(builder, "%{public}s: input builder nullptr", return);
50     builder_ = std::move(builder);
51     PM_HILOG_DEBUG(LOG_CORE, "%{public}s init succ. %{public}s", __func__, ToString().c_str());
52 }
53 
PurgeableAshMem(size_t dataSize,std::unique_ptr<PurgeableMemBuilder> builder)54 PurgeableAshMem::PurgeableAshMem(size_t dataSize, std::unique_ptr<PurgeableMemBuilder> builder)
55 {
56     dataPtr_ = nullptr;
57     builder_ = nullptr;
58     ashmemFd_ = -1;
59     buildDataCount_ = 0;
60     isSupport_ = false;
61     isChange_ = false;
62     if (dataSize == 0) {
63         return;
64     }
65     dataSizeInput_ = dataSize;
66     IF_NULL_LOG_ACTION(builder, "%{public}s: input builder nullptr", return);
67 
68     CreatePurgeableData_();
69     builder_ = std::move(builder);
70     PM_HILOG_DEBUG(LOG_CORE, "%{public}s init succ. %{public}s", __func__, ToString().c_str());
71 }
72 
~PurgeableAshMem()73 PurgeableAshMem::~PurgeableAshMem()
74 {
75     PM_HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString().c_str());
76     if (!isChange_ && dataPtr_) {
77         if (munmap(dataPtr_, RoundUp(dataSizeInput_, PAGE_SIZE)) != 0) {
78             PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr fail", __func__);
79         } else {
80             if (UxpteIsEnabled() && !IsPurged()) {
81                 PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr succ, but uxpte present", __func__);
82             }
83             dataPtr_ = nullptr;
84             close(ashmemFd_);
85         }
86     }
87     builder_.reset();
88 }
89 
GetAshmemFd()90 int PurgeableAshMem::GetAshmemFd()
91 {
92     return ashmemFd_;
93 }
94 
IsPurged()95 bool PurgeableAshMem::IsPurged()
96 {
97     if (!isSupport_) {
98         return false;
99     }
100     int ret = ioctl(ashmemFd_, PURGEABLE_ASHMEM_IS_PURGED);
101     PM_HILOG_DEBUG(LOG_CORE, "%{public}s: IsPurged %{public}d", __func__, ret);
102     return ret > 0 ? true : false;
103 }
104 
CreatePurgeableData_()105 bool PurgeableAshMem::CreatePurgeableData_()
106 {
107     PM_HILOG_DEBUG(LOG_CORE, "%{public}s", __func__);
108     if (dataSizeInput_ == 0) {
109         return false;
110     }
111     size_t size = RoundUp(dataSizeInput_, PAGE_SIZE);
112     int fd = AshmemCreate("PurgeableAshmem", size);
113     if (fd < 0) {
114         return false;
115     }
116     if (AshmemSetProt(fd, PROT_READ | PROT_WRITE) < 0) {
117         close(fd);
118         return false;
119     }
120     ashmemFd_ = fd;
121     pin_ = { static_cast<uint32_t>(0), static_cast<uint32_t>(0) };
122     dataPtr_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd_, 0);
123     if (dataPtr_ == MAP_FAILED) {
124         PM_HILOG_ERROR(LOG_CORE, "%{public}s: mmap fail", __func__);
125         dataPtr_ = nullptr;
126         close(ashmemFd_);
127         return false;
128     }
129     TEMP_FAILURE_RETRY(ioctl(ashmemFd_, ASHMEM_SET_PURGEABLE));
130     if (TEMP_FAILURE_RETRY(ioctl(ashmemFd_, ASHMEM_GET_PURGEABLE)) == 1) {
131         isSupport_ = true;
132     }
133     Unpin();
134     return true;
135 }
136 
Pin()137 bool PurgeableAshMem::Pin()
138 {
139     if (!isSupport_) {
140         return true;
141     }
142     if (ashmemFd_ > 0) {
143         TEMP_FAILURE_RETRY(ioctl(ashmemFd_, ASHMEM_PIN, &pin_));
144         PM_HILOG_DEBUG(LOG_CORE, "%{public}s: fd:%{pubilc}d PURGEABLE_GET_PIN_STATE: %{public}d",
145                        __func__, ashmemFd_, ioctl(ashmemFd_, ASHMEM_GET_PIN_STATUS, &pin_));
146     } else {
147         PM_HILOG_DEBUG(LOG_CORE, "ashmemFd_ not exist!!");
148         return false;
149     }
150     return true;
151 }
152 
Unpin()153 bool PurgeableAshMem::Unpin()
154 {
155     if (!isSupport_) {
156         return true;
157     }
158     if (ashmemFd_ > 0) {
159         TEMP_FAILURE_RETRY(ioctl(ashmemFd_, ASHMEM_UNPIN, &pin_));
160         PM_HILOG_DEBUG(LOG_CORE, "%{public}s: fd:%{pubilc}d PURGEABLE_GET_PIN_STATE: %{public}d",
161                        __func__, ashmemFd_, ioctl(ashmemFd_, ASHMEM_GET_PIN_STATUS, &pin_));
162     } else {
163         PM_HILOG_DEBUG(LOG_CORE, "ashmemFd_ not exist!!");
164         return false;
165     }
166     return true;
167 }
168 
GetPinStatus() const169 int PurgeableAshMem::GetPinStatus() const
170 {
171     int ret = 0;
172     if (!isSupport_) {
173         return ret;
174     }
175     ret = ioctl(ashmemFd_, ASHMEM_GET_PIN_STATUS, &pin_);
176     PM_HILOG_DEBUG(LOG_CORE, "%{public}s: GetPinStatus %{public}d", __func__, ret);
177     return ret;
178 }
179 
AfterRebuildSucc()180 void PurgeableAshMem::AfterRebuildSucc()
181 {
182     TEMP_FAILURE_RETRY(ioctl(ashmemFd_, PURGEABLE_ASHMEM_REBUILD_SUCCESS));
183 }
184 
ResizeData(size_t newSize)185 void PurgeableAshMem::ResizeData(size_t newSize)
186 {
187     if (newSize <= 0) {
188         return;
189     }
190     if (dataPtr_) {
191         if (munmap(dataPtr_, RoundUp(dataSizeInput_, PAGE_SIZE)) != 0) {
192             PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr fail", __func__);
193         } else {
194             dataPtr_ = nullptr;
195             if (ashmemFd_ > 0) {
196                 close(ashmemFd_);
197             }
198         }
199     }
200     dataSizeInput_ = newSize;
201     CreatePurgeableData_();
202 }
203 
ChangeAshmemData(size_t size,int fd,void * data)204 bool PurgeableAshMem::ChangeAshmemData(size_t size, int fd, void *data)
205 {
206     if (dataPtr_) {
207         if (munmap(dataPtr_, RoundUp(dataSizeInput_, PAGE_SIZE)) != 0) {
208             PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr fail", __func__);
209         } else {
210             dataPtr_ = nullptr;
211             if (ashmemFd_ > 0) {
212                 close(ashmemFd_);
213             }
214         }
215     }
216     dataSizeInput_ = size;
217     ashmemFd_ = fd;
218     dataPtr_ = data;
219     buildDataCount_++;
220     isChange_ = true;
221     TEMP_FAILURE_RETRY(ioctl(ashmemFd_, ASHMEM_SET_PURGEABLE));
222     if (TEMP_FAILURE_RETRY(ioctl(ashmemFd_, ASHMEM_GET_PURGEABLE)) == 1) {
223         isSupport_ = true;
224     }
225     Unpin();
226     return true;
227 }
228 
ToString() const229 inline std::string PurgeableAshMem::ToString() const
230 {
231     return "";
232 }
233 } /* namespace PurgeableMem */
234 } /* namespace OHOS */
235