xref: /aosp_15_r20/frameworks/native/libs/binder/MemoryHeapBase.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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