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