• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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