summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes2017-11-10 12:22:07 -0600
committerElliott Hughes2017-11-10 15:18:10 -0600
commit8e9aeb9053695a14539653093937158d15385ca6 (patch)
treeb02f7ad2149812eea2cb2802b7f238856b66619c /libcutils/ashmem-dev.cpp
parent6707ef139d9786887649e3e3c2e3e251a95dc96d (diff)
downloadplatform-system-core-8e9aeb9053695a14539653093937158d15385ca6.tar.gz
platform-system-core-8e9aeb9053695a14539653093937158d15385ca6.tar.xz
platform-system-core-8e9aeb9053695a14539653093937158d15385ca6.zip
Move libcutils source to C++.
Just the minimial changes to get this to actually build, because otherwise we always bog down trying to rewrite everything (when the real answer is usually "stop using libcutils, it's awful"). This doesn't move a handful of files: two are basically just BSD libc source, a couple have outstanding code reviews, and one can be deleted (but I'll do that in a separate change). I'm also skipping the presubmit hooks because otherwise clang-format wants to reformat everything. I'll follow up with that... Bug: N/A Test: builds Change-Id: I06403f465b67c8e493bad466dd76b1151eed5993
Diffstat (limited to 'libcutils/ashmem-dev.cpp')
-rw-r--r--libcutils/ashmem-dev.cpp227
1 files changed, 227 insertions, 0 deletions
diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
new file mode 100644
index 000000000..15ace0e64
--- /dev/null
+++ b/libcutils/ashmem-dev.cpp
@@ -0,0 +1,227 @@
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <cutils/ashmem.h>
18
19/*
20 * Implementation of the user-space ashmem API for devices, which have our
21 * ashmem-enabled kernel. See ashmem-sim.c for the "fake" tmp-based version,
22 * used by the simulator.
23 */
24#define LOG_TAG "ashmem"
25
26#include <errno.h>
27#include <fcntl.h>
28#include <linux/ashmem.h>
29#include <pthread.h>
30#include <string.h>
31#include <sys/ioctl.h>
32#include <sys/stat.h>
33#include <sys/sysmacros.h>
34#include <sys/types.h>
35#include <unistd.h>
36#include <log/log.h>
37
38#define ASHMEM_DEVICE "/dev/ashmem"
39
40/* ashmem identity */
41static dev_t __ashmem_rdev;
42/*
43 * If we trigger a signal handler in the middle of locked activity and the
44 * signal handler calls ashmem, we could get into a deadlock state.
45 */
46static pthread_mutex_t __ashmem_lock = PTHREAD_MUTEX_INITIALIZER;
47
48/* logistics of getting file descriptor for ashmem */
49static int __ashmem_open_locked()
50{
51 int ret;
52 struct stat st;
53
54 int fd = TEMP_FAILURE_RETRY(open(ASHMEM_DEVICE, O_RDWR | O_CLOEXEC));
55 if (fd < 0) {
56 return fd;
57 }
58
59 ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
60 if (ret < 0) {
61 int save_errno = errno;
62 close(fd);
63 errno = save_errno;
64 return ret;
65 }
66 if (!S_ISCHR(st.st_mode) || !st.st_rdev) {
67 close(fd);
68 errno = ENOTTY;
69 return -1;
70 }
71
72 __ashmem_rdev = st.st_rdev;
73 return fd;
74}
75
76static int __ashmem_open()
77{
78 int fd;
79
80 pthread_mutex_lock(&__ashmem_lock);
81 fd = __ashmem_open_locked();
82 pthread_mutex_unlock(&__ashmem_lock);
83
84 return fd;
85}
86
87/* Make sure file descriptor references ashmem, negative number means false */
88static int __ashmem_is_ashmem(int fd, int fatal)
89{
90 dev_t rdev;
91 struct stat st;
92
93 if (TEMP_FAILURE_RETRY(fstat(fd, &st)) < 0) {
94 return -1;
95 }
96
97 rdev = 0; /* Too much complexity to sniff __ashmem_rdev */
98 if (S_ISCHR(st.st_mode) && st.st_rdev) {
99 pthread_mutex_lock(&__ashmem_lock);
100 rdev = __ashmem_rdev;
101 if (rdev) {
102 pthread_mutex_unlock(&__ashmem_lock);
103 } else {
104 int fd = __ashmem_open_locked();
105 if (fd < 0) {
106 pthread_mutex_unlock(&__ashmem_lock);
107 return -1;
108 }
109 rdev = __ashmem_rdev;
110 pthread_mutex_unlock(&__ashmem_lock);
111
112 close(fd);
113 }
114
115 if (st.st_rdev == rdev) {
116 return 0;
117 }
118 }
119
120 if (fatal) {
121 if (rdev) {
122 LOG_ALWAYS_FATAL("illegal fd=%d mode=0%o rdev=%d:%d expected 0%o %d:%d",
123 fd, st.st_mode, major(st.st_rdev), minor(st.st_rdev),
124 S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IRGRP,
125 major(rdev), minor(rdev));
126 } else {
127 LOG_ALWAYS_FATAL("illegal fd=%d mode=0%o rdev=%d:%d expected 0%o",
128 fd, st.st_mode, major(st.st_rdev), minor(st.st_rdev),
129 S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IRGRP);
130 }
131 /* NOTREACHED */
132 }
133
134 errno = ENOTTY;
135 return -1;
136}
137
138int ashmem_valid(int fd)
139{
140 return __ashmem_is_ashmem(fd, 0) >= 0;
141}
142
143/*
144 * ashmem_create_region - creates a new ashmem region and returns the file
145 * descriptor, or <0 on error
146 *
147 * `name' is an optional label to give the region (visible in /proc/pid/maps)
148 * `size' is the size of the region, in page-aligned bytes
149 */
150int ashmem_create_region(const char *name, size_t size)
151{
152 int ret, save_errno;
153
154 int fd = __ashmem_open();
155 if (fd < 0) {
156 return fd;
157 }
158
159 if (name) {
160 char buf[ASHMEM_NAME_LEN] = {0};
161
162 strlcpy(buf, name, sizeof(buf));
163 ret = TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_NAME, buf));
164 if (ret < 0) {
165 goto error;
166 }
167 }
168
169 ret = TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_SIZE, size));
170 if (ret < 0) {
171 goto error;
172 }
173
174 return fd;
175
176error:
177 save_errno = errno;
178 close(fd);
179 errno = save_errno;
180 return ret;
181}
182
183int ashmem_set_prot_region(int fd, int prot)
184{
185 int ret = __ashmem_is_ashmem(fd, 1);
186 if (ret < 0) {
187 return ret;
188 }
189
190 return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_PROT_MASK, prot));
191}
192
193int ashmem_pin_region(int fd, size_t offset, size_t len)
194{
195 // TODO: should LP64 reject too-large offset/len?
196 ashmem_pin pin = { static_cast<uint32_t>(offset), static_cast<uint32_t>(len) };
197
198 int ret = __ashmem_is_ashmem(fd, 1);
199 if (ret < 0) {
200 return ret;
201 }
202
203 return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_PIN, &pin));
204}
205
206int ashmem_unpin_region(int fd, size_t offset, size_t len)
207{
208 // TODO: should LP64 reject too-large offset/len?
209 ashmem_pin pin = { static_cast<uint32_t>(offset), static_cast<uint32_t>(len) };
210
211 int ret = __ashmem_is_ashmem(fd, 1);
212 if (ret < 0) {
213 return ret;
214 }
215
216 return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_UNPIN, &pin));
217}
218
219int ashmem_get_size_region(int fd)
220{
221 int ret = __ashmem_is_ashmem(fd, 1);
222 if (ret < 0) {
223 return ret;
224 }
225
226 return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL));
227}