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