• 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         return nullptr;
46     }
47     openFdFunction func = reinterpret_cast<openFdFunction>(dlsym(handle, "openAshmemdFd"));
48     if (!func) {
49         dlclose(handle);
50     }
51     return func;
52 }
53 
TrimFromStart(std::string & s)54 static inline void TrimFromStart(std::string &s)
55 {
56     s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {return !std::isspace(ch);}));
57 }
58 
TrimFromEnd(std::string & s)59 static inline void TrimFromEnd(std::string &s)
60 {
61     s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {return !std::isspace(ch);}).base(), s.end());
62 }
63 
Trim(std::string & s)64 static void Trim(std::string &s)
65 {
66     TrimFromStart(s);
67     TrimFromEnd(s);
68 }
69 
GetAshmemDeviceFd()70 static int GetAshmemDeviceFd()
71 {
72     static const std::string boot_id_path = "/proc/sys/kernel/random/boot_id";
73     std::string boot_id;
74     char buf[BUFSIZ];
75     ssize_t n;
76     int fdBoot = -1;
77     int fdAshmem = -1;
78 
79     fdBoot = TEMP_FAILURE_RETRY(open(boot_id_path.c_str(), O_RDONLY | O_CLOEXEC));
80     if (fdBoot < 0) {
81         return -1;
82     }
83 
84     if ((n = TEMP_FAILURE_RETRY(read(fdBoot, &buf[0], sizeof(buf)))) > 0) {
85         boot_id.append(buf, n);
86     } else {
87         close(fdBoot);
88         return -1;
89     }
90     close(fdBoot);
91 
92     Trim(boot_id);
93 
94     fdAshmem = TEMP_FAILURE_RETRY(open(("/dev/ashmem" + boot_id).c_str(), O_RDWR | O_CLOEXEC));
95     return fdAshmem;
96 }
97 
98 
AshmemOpenLocked()99 static int AshmemOpenLocked()
100 {
101     int fd = -1;
102 
103     if (g_openFdApi == nullptr) {
104         g_openFdApi = ProbeAshmemFdFunction();
105     }
106 
107     if (g_openFdApi != nullptr) {
108         fd = g_openFdApi();
109     } else {
110         fd = GetAshmemDeviceFd();
111     }
112 
113     if (fd < 0) {
114         fd = TEMP_FAILURE_RETRY(open("/dev/ashmem", O_RDWR | O_CLOEXEC));
115     }
116 
117     if (fd < 0) {
118         UTILS_LOGE("%{public}s: fd is invalid, fd = %{public}d", __func__, fd);
119         return fd;
120     }
121 
122     struct stat st;
123     int ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
124     if (ret < 0) {
125         UTILS_LOGE("%{public}s: Failed to exec fstat, ret = %{public}d", __func__, ret);
126         close(fd);
127         return ret;
128     }
129 
130     if (!S_ISCHR(st.st_mode) || !st.st_rdev) {
131         UTILS_LOGE("%{public}s: stat status is invalid, st_mode = %{public}u", __func__, st.st_mode);
132         close(fd);
133         return -1;
134     }
135     return fd;
136 }
137 
AshmemOpen()138 static int AshmemOpen()
139 {
140     pthread_mutex_lock(&g_ashmemLock);
141     int fd = AshmemOpenLocked();
142     pthread_mutex_unlock(&g_ashmemLock);
143     return fd;
144 }
145 
146 /*
147  * AshmemCreate - create a new ashmem region and returns the file descriptor
148  * fd < 0 means failed
149  *
150  */
AshmemCreate(const char * name,size_t size)151 int AshmemCreate(const char *name, size_t size)
152 {
153     int ret;
154     int fd = AshmemOpen();
155     if (fd < 0) {
156         UTILS_LOGE("%{public}s: Failed to exec AshmemOpen fd = %{public}d", __func__, fd);
157         return fd;
158     }
159 
160     if (name != nullptr) {
161         char buf[ASHMEM_NAME_LEN] = {0};
162         ret = strcpy_s(buf, sizeof(buf), name);
163         if (ret != EOK) {
164             UTILS_LOGE("%{public}s: Failed to exec strcpy_s, name= %{public}s, ret= %{public}d", __func__, name, ret);
165             close(fd);
166             return -1;
167         }
168         ret = TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_NAME, buf));
169         if (ret < 0) {
170             UTILS_LOGE("%{public}s: Failed to set name, name= %{public}s, ret= %{public}d", __func__, name, ret);
171             close(fd);
172             return ret;
173         }
174     }
175 
176     ret = TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_SIZE, size));
177     if (ret < 0) {
178         UTILS_LOGE("%{public}s: Failed to set size, size= %{public}zu", __func__, size);
179         close(fd);
180         return ret;
181     }
182     return fd;
183 }
184 
AshmemSetProt(int fd,int prot)185 int AshmemSetProt(int fd, int prot)
186 {
187     return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_PROT_MASK, prot));
188 }
189 
AshmemGetSize(int fd)190 int AshmemGetSize(int fd)
191 {
192     return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL));
193 }
194 
Ashmem(int fd,int size)195 Ashmem::Ashmem(int fd, int size) : memoryFd_(fd), memorySize_(size), flag_(0), startAddr_(nullptr)
196 {
197 }
198 
~Ashmem()199 Ashmem::~Ashmem()
200 {
201 }
202 
CreateAshmem(const char * name,int32_t size)203 sptr<Ashmem> Ashmem::CreateAshmem(const char *name, int32_t size)
204 {
205     if ((name == nullptr) || (size <= 0)) {
206         UTILS_LOGE("%{public}s: Parameter is invalid, size= %{public}d", __func__, size);
207         return nullptr;
208     }
209 
210     int fd = AshmemCreate(name, size);
211     if (fd < 0) {
212         UTILS_LOGE("%{public}s: Failed to exec AshmemCreate, fd= %{public}d", __func__, size);
213         return nullptr;
214     }
215 
216     return new Ashmem(fd, size);
217 }
218 
CloseAshmem()219 void Ashmem::CloseAshmem()
220 {
221     if (memoryFd_ > 0) {
222         ::close(memoryFd_);
223         memoryFd_ = -1;
224     }
225     memorySize_ = 0;
226     flag_ = 0;
227     startAddr_ = nullptr;
228 }
229 
MapAshmem(int mapType)230 bool Ashmem::MapAshmem(int mapType)
231 {
232     void *startAddr = ::mmap(nullptr, memorySize_, mapType, MAP_SHARED, memoryFd_, 0);
233     if (startAddr == MAP_FAILED) {
234         UTILS_LOGE("Failed to exec mmap");
235         return false;
236     }
237 
238     startAddr_ = startAddr;
239     flag_ = mapType;
240 
241     return true;
242 }
243 
MapReadAndWriteAshmem()244 bool Ashmem::MapReadAndWriteAshmem()
245 {
246     return MapAshmem(PROT_READ | PROT_WRITE);
247 }
248 
MapReadOnlyAshmem()249 bool Ashmem::MapReadOnlyAshmem()
250 {
251     return MapAshmem(PROT_READ);
252 }
253 
UnmapAshmem()254 void Ashmem::UnmapAshmem()
255 {
256     if (startAddr_ != nullptr) {
257         ::munmap(startAddr_, memorySize_);
258         startAddr_ = nullptr;
259     }
260     flag_ = 0;
261 }
262 
SetProtection(int protectionType)263 bool Ashmem::SetProtection(int protectionType)
264 {
265     int result = AshmemSetProt(memoryFd_, protectionType);
266     return result >= 0;
267 }
268 
GetProtection()269 int Ashmem::GetProtection()
270 {
271     return TEMP_FAILURE_RETRY(ioctl(memoryFd_, ASHMEM_GET_PROT_MASK));
272 }
273 
GetAshmemSize()274 int32_t Ashmem::GetAshmemSize()
275 {
276     return AshmemGetSize(memoryFd_);
277 }
278 
WriteToAshmem(const void * data,int32_t size,int32_t offset)279 bool Ashmem::WriteToAshmem(const void *data, int32_t size, int32_t offset)
280 {
281     if (data == nullptr) {
282         return false;
283     }
284 
285     if (!CheckValid(size, offset, PROT_WRITE)) {
286         UTILS_LOGE("%{public}s: invalid input or not map", __func__);
287         return false;
288     }
289 
290     auto tmpData = reinterpret_cast<char *>(startAddr_);
291     int ret = memcpy_s(tmpData + offset, memorySize_ - offset, reinterpret_cast<const char *>(data), size);
292     if (ret != EOK) {
293         UTILS_LOGE("%{public}s: Failed to memcpy, ret = %{public}d", __func__, ret);
294         return false;
295     }
296 
297     return true;
298 }
299 
ReadFromAshmem(int32_t size,int32_t offset)300 const void *Ashmem::ReadFromAshmem(int32_t size, int32_t offset)
301 {
302     if (!CheckValid(size, offset, PROT_READ)) {
303         UTILS_LOGE("%{public}s: invalid input or not map", __func__);
304         return nullptr;
305     }
306 
307     return reinterpret_cast<const char *>(startAddr_) + offset;
308 }
309 
CheckValid(int32_t size,int32_t offset,int cmd)310 bool Ashmem::CheckValid(int32_t size, int32_t offset, int cmd)
311 {
312     if (startAddr_ == nullptr) {
313         return false;
314     }
315     if ((size < 0) || (size > memorySize_) || (offset < 0) || (offset > memorySize_)) {
316         UTILS_LOGE("%{public}s: , invalid parameter, size = %{public}d, memorySize_ = %{public}d, offset = %{public}d",
317             __func__, size, memorySize_, offset);
318         return false;
319     }
320     if (offset + size > memorySize_) {
321         UTILS_LOGE("%{public}s: , invalid parameter, size = %{public}d, memorySize_ = %{public}d, offset = %{public}d",
322             __func__, size, memorySize_, offset);
323         return false;
324     }
325     if (!(static_cast<uint32_t>(GetProtection()) & static_cast<uint32_t>(cmd)) ||
326         !(static_cast<uint32_t>(flag_) & static_cast<uint32_t>(cmd))) {
327         return false;
328     }
329 
330     return true;
331 }
332 }
333