1 /*
2 * Copyright (c) 2021 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 "ashmem.h"
17
18 #include <fcntl.h>
19 #include <pthread.h>
20 #include <sys/ioctl.h>
21 #include <sys/mman.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include "securec.h"
25 #include "utils_log.h"
26
27 namespace OHOS {
28 static pthread_mutex_t g_ashmemLock = PTHREAD_MUTEX_INITIALIZER;
29
30 #ifdef UTILS_CXX_RUST
CreateAshmemStd(const char * name,int32_t size)31 std::shared_ptr<Ashmem> CreateAshmemStd(const char *name, int32_t size)
32 {
33 if ((name == nullptr) || (size <= 0)) {
34 UTILS_LOGE("%{public}s: Parameter is invalid, size= %{public}d", __func__, size);
35 return std::shared_ptr<Ashmem>{};
36 }
37
38 int fd = AshmemCreate(name, size);
39 if (fd < 0) {
40 UTILS_LOGE("%{public}s: Failed to exec AshmemCreate, fd= %{public}d", __func__, size);
41 return std::shared_ptr<Ashmem>{};
42 }
43
44 return std::make_shared<Ashmem>(fd, size);
45 }
46
AsVoidPtr(const char * inPtr)47 const c_void* AsVoidPtr(const char* inPtr)
48 {
49 return static_cast<const c_void*>(inPtr);
50 }
51
AsCharPtr(const c_void * inPtr)52 const char* AsCharPtr(const c_void* inPtr)
53 {
54 return static_cast<const char*>(inPtr);
55 }
56 #endif
57
AshmemOpenLocked()58 static int AshmemOpenLocked()
59 {
60 int fd = TEMP_FAILURE_RETRY(open("/dev/ashmem", O_RDWR | O_CLOEXEC));
61 if (fd < 0) {
62 UTILS_LOGE("%{public}s: fd is invalid, fd = %{public}d, errno = %{public}d", __func__, fd, errno);
63 return fd;
64 }
65
66 struct stat st;
67 int ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
68 if (ret < 0) {
69 UTILS_LOGE("%{public}s: Failed to exec fstat, ret = %{public}d, errno = %{public}d", __func__, ret, errno);
70 close(fd);
71 return ret;
72 }
73
74 if (!S_ISCHR(st.st_mode) || !st.st_rdev) {
75 UTILS_LOGE("%{public}s: stat status is invalid, st_mode = %{public}u", __func__, st.st_mode);
76 close(fd);
77 return -1;
78 }
79 return fd;
80 }
81
AshmemOpen()82 static int AshmemOpen()
83 {
84 pthread_mutex_lock(&g_ashmemLock);
85 int fd = AshmemOpenLocked();
86 pthread_mutex_unlock(&g_ashmemLock);
87 return fd;
88 }
89
90 /*
91 * AshmemCreate - create a new ashmem region and returns the file descriptor
92 * fd < 0 means failed
93 *
94 */
AshmemCreate(const char * name,size_t size)95 int AshmemCreate(const char *name, size_t size)
96 {
97 int ret;
98 int fd = AshmemOpen();
99 if (fd < 0) {
100 UTILS_LOGE("%{public}s: Failed to exec AshmemOpen fd = %{public}d", __func__, fd);
101 return fd;
102 }
103
104 if (name != nullptr) {
105 char buf[ASHMEM_NAME_LEN] = {0};
106 ret = strcpy_s(buf, sizeof(buf), name);
107 if (ret != EOK) {
108 UTILS_LOGE("%{public}s: Failed to exec strcpy_s, name= %{public}s, ret= %{public}d", __func__, name, ret);
109 close(fd);
110 return -1;
111 }
112 ret = TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_NAME, buf));
113 if (ret < 0) {
114 UTILS_LOGE("%{public}s: Failed to set name, name= %{public}s, ret= %{public}d, errno = %{public}d",
115 __func__, name, ret, errno);
116 close(fd);
117 return ret;
118 }
119 }
120
121 ret = TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_SIZE, size));
122 if (ret < 0) {
123 UTILS_LOGE("%{public}s: Failed to set size, size= %{public}zu, errno = %{public}d", __func__, size, errno);
124 close(fd);
125 return ret;
126 }
127 return fd;
128 }
129
AshmemSetProt(int fd,int prot)130 int AshmemSetProt(int fd, int prot)
131 {
132 return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_PROT_MASK, prot));
133 }
134
AshmemGetSize(int fd)135 int AshmemGetSize(int fd)
136 {
137 return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL));
138 }
139
Ashmem(int fd,int32_t size)140 Ashmem::Ashmem(int fd, int32_t size) : memoryFd_(fd), memorySize_(size), flag_(0), startAddr_(nullptr)
141 {
142 }
143
~Ashmem()144 Ashmem::~Ashmem()
145 {
146 UnmapAshmem();
147 CloseAshmem();
148 }
149
CreateAshmem(const char * name,int32_t size)150 sptr<Ashmem> Ashmem::CreateAshmem(const char *name, int32_t size)
151 {
152 if ((name == nullptr) || (size <= 0)) {
153 UTILS_LOGE("%{public}s: Parameter is invalid, size= %{public}d", __func__, size);
154 return nullptr;
155 }
156
157 int fd = AshmemCreate(name, size);
158 if (fd < 0) {
159 UTILS_LOGE("%{public}s: Failed to exec AshmemCreate, fd= %{public}d", __func__, size);
160 return nullptr;
161 }
162
163 return new Ashmem(fd, size);
164 }
165
SetProtection(int protectionType) const166 bool Ashmem::SetProtection(int protectionType) const
167 {
168 int result = AshmemSetProt(memoryFd_, protectionType);
169 return result >= 0;
170 }
171
GetProtection() const172 int Ashmem::GetProtection() const
173 {
174 return TEMP_FAILURE_RETRY(ioctl(memoryFd_, ASHMEM_GET_PROT_MASK));
175 }
176
GetAshmemSize() const177 int32_t Ashmem::GetAshmemSize() const
178 {
179 return AshmemGetSize(memoryFd_);
180 }
181
182 #ifdef UTILS_CXX_RUST
CloseAshmem() const183 void Ashmem::CloseAshmem() const
184 #else
185 void Ashmem::CloseAshmem()
186 #endif
187 {
188 if (memoryFd_ > 0) {
189 ::close(memoryFd_);
190 memoryFd_ = -1;
191 }
192 memorySize_ = 0;
193 flag_ = 0;
194 startAddr_ = nullptr;
195 }
196
197 #ifdef UTILS_CXX_RUST
MapAshmem(int mapType) const198 bool Ashmem::MapAshmem(int mapType) const
199 #else
200 bool Ashmem::MapAshmem(int mapType)
201 #endif
202 {
203 void *startAddr = ::mmap(nullptr, memorySize_, mapType, MAP_SHARED, memoryFd_, 0);
204 if (startAddr == MAP_FAILED) {
205 UTILS_LOGE("Failed to exec mmap, errno = %{public}d", errno);
206 return false;
207 }
208
209 startAddr_ = startAddr;
210 flag_ = mapType;
211
212 return true;
213 }
214
215 #ifdef UTILS_CXX_RUST
MapReadAndWriteAshmem() const216 bool Ashmem::MapReadAndWriteAshmem() const
217 #else
218 bool Ashmem::MapReadAndWriteAshmem()
219 #endif
220 {
221 return MapAshmem(PROT_READ | PROT_WRITE);
222 }
223
224 #ifdef UTILS_CXX_RUST
MapReadOnlyAshmem() const225 bool Ashmem::MapReadOnlyAshmem() const
226 #else
227 bool Ashmem::MapReadOnlyAshmem()
228 #endif
229 {
230 return MapAshmem(PROT_READ);
231 }
232
233 #ifdef UTILS_CXX_RUST
UnmapAshmem() const234 void Ashmem::UnmapAshmem() const
235 #else
236 void Ashmem::UnmapAshmem()
237 #endif
238 {
239 if (startAddr_ != nullptr) {
240 ::munmap(startAddr_, memorySize_);
241 startAddr_ = nullptr;
242 }
243 flag_ = 0;
244 }
245
246 #ifdef UTILS_CXX_RUST
WriteToAshmem(const void * data,int32_t size,int32_t offset) const247 bool Ashmem::WriteToAshmem(const void *data, int32_t size, int32_t offset) const
248 #else
249 bool Ashmem::WriteToAshmem(const void *data, int32_t size, int32_t offset)
250 #endif
251 {
252 if (data == nullptr) {
253 return false;
254 }
255
256 if (!CheckValid(size, offset, PROT_WRITE)) {
257 UTILS_LOGE("%{public}s: invalid input or not map", __func__);
258 return false;
259 }
260
261 auto tmpData = reinterpret_cast<char *>(startAddr_);
262 int ret = memcpy_s(tmpData + offset, memorySize_ - offset, reinterpret_cast<const char *>(data), size);
263 if (ret != EOK) {
264 UTILS_LOGE("%{public}s: Failed to memcpy, ret = %{public}d", __func__, ret);
265 return false;
266 }
267
268 return true;
269 }
270
271 #ifdef UTILS_CXX_RUST
ReadFromAshmem(int32_t size,int32_t offset) const272 const void *Ashmem::ReadFromAshmem(int32_t size, int32_t offset) const
273 #else
274 const void *Ashmem::ReadFromAshmem(int32_t size, int32_t offset)
275 #endif
276 {
277 if (!CheckValid(size, offset, PROT_READ)) {
278 UTILS_LOGE("%{public}s: invalid input or not map", __func__);
279 return nullptr;
280 }
281
282 return reinterpret_cast<const char *>(startAddr_) + offset;
283 }
284
CheckValid(int32_t size,int32_t offset,int cmd) const285 bool Ashmem::CheckValid(int32_t size, int32_t offset, int cmd) const
286 {
287 if (startAddr_ == nullptr) {
288 return false;
289 }
290 if ((size < 0) || (size > memorySize_) || (offset < 0) || (offset > memorySize_)) {
291 UTILS_LOGE("%{public}s: , invalid parameter, size = %{public}d, memorySize_ = %{public}d, offset = %{public}d",
292 __func__, size, memorySize_, offset);
293 return false;
294 }
295 if (offset + size > memorySize_) {
296 UTILS_LOGE("%{public}s: , invalid parameter, size = %{public}d, memorySize_ = %{public}d, offset = %{public}d",
297 __func__, size, memorySize_, offset);
298 return false;
299 }
300 if (!(static_cast<uint32_t>(GetProtection()) & static_cast<uint32_t>(cmd)) ||
301 !(static_cast<uint32_t>(flag_) & static_cast<uint32_t>(cmd))) {
302 return false;
303 }
304
305 return true;
306 }
307 }
308