• 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 <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 
AshmemOpenLocked()38 static int AshmemOpenLocked()
39 {
40     int fd = TEMP_FAILURE_RETRY(open("/dev/ashmem", O_RDWR | O_CLOEXEC));
41 
42     if (fd < 0) {
43         UTILS_LOGE("%{public}s: fd is invalid, fd = %{public}d", __func__, fd);
44         return fd;
45     }
46 
47     struct stat st;
48     int ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
49     if (ret < 0) {
50         UTILS_LOGE("%{public}s: Failed to exec fstat, ret = %{public}d", __func__, ret);
51         close(fd);
52         return ret;
53     }
54 
55     if (!S_ISCHR(st.st_mode) || !st.st_rdev) {
56         UTILS_LOGE("%{public}s: stat status is invalid, st_mode = %{public}u", __func__, st.st_mode);
57         close(fd);
58         return -1;
59     }
60     return fd;
61 }
62 
AshmemOpen()63 static int AshmemOpen()
64 {
65     pthread_mutex_lock(&g_ashmemLock);
66     int fd = AshmemOpenLocked();
67     pthread_mutex_unlock(&g_ashmemLock);
68     return fd;
69 }
70 
71 /*
72  * AshmemCreate - create a new ashmem region and returns the file descriptor
73  * fd < 0 means failed
74  *
75  */
AshmemCreate(const char * name,size_t size)76 int AshmemCreate(const char *name, size_t size)
77 {
78     int ret;
79     int fd = AshmemOpen();
80     if (fd < 0) {
81         UTILS_LOGE("%{public}s: Failed to exec AshmemOpen fd = %{public}d", __func__, fd);
82         return fd;
83     }
84 
85     if (name != nullptr) {
86         char buf[ASHMEM_NAME_LEN] = {0};
87         ret = strcpy_s(buf, sizeof(buf), name);
88         if (ret != EOK) {
89             UTILS_LOGE("%{public}s: Failed to exec strcpy_s, name= %{public}s, ret= %{public}d", __func__, name, ret);
90             close(fd);
91             return -1;
92         }
93         ret = TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_NAME, buf));
94         if (ret < 0) {
95             UTILS_LOGE("%{public}s: Failed to set name, name= %{public}s, ret= %{public}d", __func__, name, ret);
96             close(fd);
97             return ret;
98         }
99     }
100 
101     ret = TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_SIZE, size));
102     if (ret < 0) {
103         UTILS_LOGE("%{public}s: Failed to set size, size= %{public}zu", __func__, size);
104         close(fd);
105         return ret;
106     }
107     return fd;
108 }
109 
AshmemSetProt(int fd,int prot)110 int AshmemSetProt(int fd, int prot)
111 {
112     return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_PROT_MASK, prot));
113 }
114 
AshmemGetSize(int fd)115 int AshmemGetSize(int fd)
116 {
117     return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL));
118 }
119 
Ashmem(int fd,int size)120 Ashmem::Ashmem(int fd, int size) : memoryFd_(fd), memorySize_(size), flag_(0), startAddr_(nullptr)
121 {
122 }
123 
~Ashmem()124 Ashmem::~Ashmem()
125 {
126 }
127 
CreateAshmem(const char * name,int32_t size)128 sptr<Ashmem> Ashmem::CreateAshmem(const char *name, int32_t size)
129 {
130     if ((name == nullptr) || (size <= 0)) {
131         UTILS_LOGE("%{public}s: Parameter is invalid, size= %{public}d", __func__, size);
132         return nullptr;
133     }
134 
135     int fd = AshmemCreate(name, size);
136     if (fd < 0) {
137         UTILS_LOGE("%{public}s: Failed to exec AshmemCreate, fd= %{public}d", __func__, size);
138         return nullptr;
139     }
140 
141     return new Ashmem(fd, size);
142 }
143 
CloseAshmem()144 void Ashmem::CloseAshmem()
145 {
146     if (memoryFd_ > 0) {
147         ::close(memoryFd_);
148         memoryFd_ = -1;
149     }
150     memorySize_ = 0;
151     flag_ = 0;
152     startAddr_ = nullptr;
153 }
154 
MapAshmem(int mapType)155 bool Ashmem::MapAshmem(int mapType)
156 {
157     void *startAddr = ::mmap(nullptr, memorySize_, mapType, MAP_SHARED, memoryFd_, 0);
158     if (startAddr == MAP_FAILED) {
159         UTILS_LOGE("Failed to exec mmap");
160         return false;
161     }
162 
163     startAddr_ = startAddr;
164     flag_ = mapType;
165 
166     return true;
167 }
168 
MapReadAndWriteAshmem()169 bool Ashmem::MapReadAndWriteAshmem()
170 {
171     return MapAshmem(PROT_READ | PROT_WRITE);
172 }
173 
MapReadOnlyAshmem()174 bool Ashmem::MapReadOnlyAshmem()
175 {
176     return MapAshmem(PROT_READ);
177 }
178 
UnmapAshmem()179 void Ashmem::UnmapAshmem()
180 {
181     if (startAddr_ != nullptr) {
182         ::munmap(startAddr_, memorySize_);
183         startAddr_ = nullptr;
184     }
185     flag_ = 0;
186 }
187 
SetProtection(int protectionType)188 bool Ashmem::SetProtection(int protectionType)
189 {
190     int result = AshmemSetProt(memoryFd_, protectionType);
191     return result >= 0;
192 }
193 
GetProtection()194 int Ashmem::GetProtection()
195 {
196     return TEMP_FAILURE_RETRY(ioctl(memoryFd_, ASHMEM_GET_PROT_MASK));
197 }
198 
GetAshmemSize()199 int32_t Ashmem::GetAshmemSize()
200 {
201     return AshmemGetSize(memoryFd_);
202 }
203 
WriteToAshmem(const void * data,int32_t size,int32_t offset)204 bool Ashmem::WriteToAshmem(const void *data, int32_t size, int32_t offset)
205 {
206     if (data == nullptr) {
207         return false;
208     }
209 
210     if (!CheckValid(size, offset, PROT_WRITE)) {
211         UTILS_LOGE("%{public}s: invalid input or not map", __func__);
212         return false;
213     }
214 
215     auto tmpData = reinterpret_cast<char *>(startAddr_);
216     int ret = memcpy_s(tmpData + offset, memorySize_ - offset, reinterpret_cast<const char *>(data), size);
217     if (ret != EOK) {
218         UTILS_LOGE("%{public}s: Failed to memcpy, ret = %{public}d", __func__, ret);
219         return false;
220     }
221 
222     return true;
223 }
224 
ReadFromAshmem(int32_t size,int32_t offset)225 const void *Ashmem::ReadFromAshmem(int32_t size, int32_t offset)
226 {
227     if (!CheckValid(size, offset, PROT_READ)) {
228         UTILS_LOGE("%{public}s: invalid input or not map", __func__);
229         return nullptr;
230     }
231 
232     return reinterpret_cast<const char *>(startAddr_) + offset;
233 }
234 
CheckValid(int32_t size,int32_t offset,int cmd)235 bool Ashmem::CheckValid(int32_t size, int32_t offset, int cmd)
236 {
237     if (startAddr_ == nullptr) {
238         return false;
239     }
240     if ((size < 0) || (size > memorySize_) || (offset < 0) || (offset > memorySize_)) {
241         UTILS_LOGE("%{public}s: , invalid parameter, size = %{public}d, memorySize_ = %{public}d, offset = %{public}d",
242             __func__, size, memorySize_, offset);
243         return false;
244     }
245     if (offset + size > memorySize_) {
246         UTILS_LOGE("%{public}s: , invalid parameter, size = %{public}d, memorySize_ = %{public}d, offset = %{public}d",
247             __func__, size, memorySize_, offset);
248         return false;
249     }
250     if (!(static_cast<uint32_t>(GetProtection()) & static_cast<uint32_t>(cmd)) ||
251         !(static_cast<uint32_t>(flag_) & static_cast<uint32_t>(cmd))) {
252         return false;
253     }
254 
255     return true;
256 }
257 }
258