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