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 #define LOG_TAG "MemoryHeapBase"
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <linux/memfd.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <sys/ioctl.h>
25 #include <sys/mman.h>
26 #include <sys/stat.h>
27 #include <sys/syscall.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30
31 #include <binder/MemoryHeapBase.h>
32 #include <cutils/ashmem.h>
33 #include <cutils/atomic.h>
34 #include <log/log.h>
35
36 namespace android {
37
38 // ---------------------------------------------------------------------------
39
40 #ifdef __BIONIC__
memfd_create_region(const char * name,size_t size)41 static int memfd_create_region(const char* name, size_t size) {
42 int fd = memfd_create(name, MFD_CLOEXEC | MFD_ALLOW_SEALING);
43 if (fd == -1) {
44 ALOGE("%s: memfd_create(%s, %zd) failed: %s\n", __func__, name, size, strerror(errno));
45 return -1;
46 }
47
48 if (ftruncate(fd, size) == -1) {
49 ALOGE("%s, ftruncate(%s, %zd) failed for memfd creation: %s\n", __func__, name, size,
50 strerror(errno));
51 close(fd);
52 return -1;
53 }
54 return fd;
55 }
56 #endif
57
MemoryHeapBase()58 MemoryHeapBase::MemoryHeapBase()
59 : mFD(-1), mSize(0), mBase(MAP_FAILED),
60 mDevice(nullptr), mNeedUnmap(false), mOffset(0)
61 {
62 }
63
MemoryHeapBase(size_t size,uint32_t flags,char const * name)64 MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
65 : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
66 mDevice(nullptr), mNeedUnmap(false), mOffset(0)
67 {
68 const size_t pagesize = getpagesize();
69 size = ((size + pagesize - 1) & ~(pagesize - 1));
70 int fd = -1;
71 if (mFlags & FORCE_MEMFD) {
72 #ifdef __BIONIC__
73 ALOGV("MemoryHeapBase: Attempting to force MemFD");
74 fd = memfd_create_region(name ? name : "MemoryHeapBase", size);
75 if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
76 const int SEAL_FLAGS = ((mFlags & READ_ONLY) ? F_SEAL_FUTURE_WRITE : 0) | F_SEAL_GROW |
77 F_SEAL_SHRINK | ((mFlags & MEMFD_ALLOW_SEALING_FLAG) ? 0 : F_SEAL_SEAL);
78 if (SEAL_FLAGS && (fcntl(fd, F_ADD_SEALS, SEAL_FLAGS) == -1)) {
79 ALOGE("MemoryHeapBase: MemFD %s sealing with flags %x failed with error %s", name,
80 SEAL_FLAGS, strerror(errno));
81 if (mNeedUnmap) munmap(mBase, mSize);
82 mBase = nullptr;
83 mSize = 0;
84 close(fd);
85 }
86 return;
87 #else
88 mFlags &= ~(FORCE_MEMFD | MEMFD_ALLOW_SEALING_FLAG);
89 #endif
90 }
91 fd = ashmem_create_region(name ? name : "MemoryHeapBase", size);
92 ALOGE_IF(fd < 0, "MemoryHeapBase: error creating ashmem region: %s", strerror(errno));
93 if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
94 if (mFlags & READ_ONLY) {
95 ashmem_set_prot_region(fd, PROT_READ);
96 }
97 }
98
MemoryHeapBase(const char * device,size_t size,uint32_t flags)99 MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
100 : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
101 mDevice(nullptr), mNeedUnmap(false), mOffset(0)
102 {
103 if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING_FLAG)) {
104 LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
105 }
106 int open_flags = O_RDWR;
107 if (flags & NO_CACHING)
108 open_flags |= O_SYNC;
109
110 int fd = open(device, open_flags);
111 ALOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno));
112 if (fd >= 0) {
113 const size_t pagesize = getpagesize();
114 size = ((size + pagesize-1) & ~(pagesize-1));
115 if (mapfd(fd, false, size) == NO_ERROR) {
116 mDevice = device;
117 }
118 }
119 }
120
MemoryHeapBase(int fd,size_t size,uint32_t flags,off_t offset)121 MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, off_t offset)
122 : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
123 mDevice(nullptr), mNeedUnmap(false), mOffset(0)
124 {
125 if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING_FLAG)) {
126 LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
127 }
128 const size_t pagesize = getpagesize();
129 size = ((size + pagesize-1) & ~(pagesize-1));
130 mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), false, size, offset);
131 }
132
init(int fd,void * base,size_t size,int flags,const char * device)133 status_t MemoryHeapBase::init(int fd, void *base, size_t size, int flags, const char* device)
134 {
135 if (mFD != -1) {
136 return INVALID_OPERATION;
137 }
138 mFD = fd;
139 mBase = base;
140 mSize = size;
141 mFlags = flags;
142 mDevice = device;
143 return NO_ERROR;
144 }
145
mapfd(int fd,bool writeableByCaller,size_t size,off_t offset)146 status_t MemoryHeapBase::mapfd(int fd, bool writeableByCaller, size_t size, off_t offset)
147 {
148 if (size == 0) {
149 // try to figure out the size automatically
150 struct stat sb;
151 if (fstat(fd, &sb) == 0) {
152 size = (size_t)sb.st_size;
153 // sb.st_size is off_t which on ILP32 may be 64 bits while size_t is 32 bits.
154 if ((off_t)size != sb.st_size) {
155 ALOGE("%s: size of file %lld cannot fit in memory",
156 __func__, (long long)sb.st_size);
157 return INVALID_OPERATION;
158 }
159 }
160 // if it didn't work, let mmap() fail.
161 }
162
163 if ((mFlags & DONT_MAP_LOCALLY) == 0) {
164 int prot = PROT_READ;
165 if (writeableByCaller || (mFlags & READ_ONLY) == 0) {
166 prot |= PROT_WRITE;
167 }
168 void* base = (uint8_t*)mmap(nullptr, size,
169 prot, MAP_SHARED, fd, offset);
170 if (base == MAP_FAILED) {
171 ALOGE("mmap(fd=%d, size=%zu) failed (%s)",
172 fd, size, strerror(errno));
173 close(fd);
174 return -errno;
175 }
176 //ALOGD("mmap(fd=%d, base=%p, size=%zu)", fd, base, size);
177 mBase = base;
178 mNeedUnmap = true;
179 } else {
180 mBase = nullptr; // not MAP_FAILED
181 mNeedUnmap = false;
182 }
183 mFD = fd;
184 mSize = size;
185 mOffset = offset;
186 return NO_ERROR;
187 }
188
~MemoryHeapBase()189 MemoryHeapBase::~MemoryHeapBase()
190 {
191 dispose();
192 }
193
dispose()194 void MemoryHeapBase::dispose()
195 {
196 int fd = android_atomic_or(-1, &mFD);
197 if (fd >= 0) {
198 if (mNeedUnmap) {
199 //ALOGD("munmap(fd=%d, base=%p, size=%zu)", fd, mBase, mSize);
200 munmap(mBase, mSize);
201 }
202 mBase = nullptr;
203 mSize = 0;
204 close(fd);
205 }
206 }
207
getHeapID() const208 int MemoryHeapBase::getHeapID() const {
209 return mFD;
210 }
211
getBase() const212 void* MemoryHeapBase::getBase() const {
213 return mBase;
214 }
215
getSize() const216 size_t MemoryHeapBase::getSize() const {
217 return mSize;
218 }
219
getFlags() const220 uint32_t MemoryHeapBase::getFlags() const {
221 return mFlags;
222 }
223
getDevice() const224 const char* MemoryHeapBase::getDevice() const {
225 return mDevice;
226 }
227
getOffset() const228 off_t MemoryHeapBase::getOffset() const {
229 return mOffset;
230 }
231
232 // ---------------------------------------------------------------------------
233 } // namespace android
234