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