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 <stdint.h>
22 #include <stdlib.h>
23 #include <sys/ioctl.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27
28 #include <binder/MemoryHeapBase.h>
29 #include <cutils/ashmem.h>
30 #include <cutils/atomic.h>
31 #include <log/log.h>
32
33 namespace android {
34
35 // ---------------------------------------------------------------------------
36
MemoryHeapBase()37 MemoryHeapBase::MemoryHeapBase()
38 : mFD(-1), mSize(0), mBase(MAP_FAILED),
39 mDevice(nullptr), mNeedUnmap(false), mOffset(0)
40 {
41 }
42
MemoryHeapBase(size_t size,uint32_t flags,char const * name)43 MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
44 : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
45 mDevice(nullptr), mNeedUnmap(false), mOffset(0)
46 {
47 const size_t pagesize = getpagesize();
48 size = ((size + pagesize-1) & ~(pagesize-1));
49 int fd = ashmem_create_region(name == nullptr ? "MemoryHeapBase" : name, size);
50 ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
51 if (fd >= 0) {
52 if (mapfd(fd, size) == NO_ERROR) {
53 if (flags & READ_ONLY) {
54 ashmem_set_prot_region(fd, PROT_READ);
55 }
56 }
57 }
58 }
59
MemoryHeapBase(const char * device,size_t size,uint32_t flags)60 MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
61 : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
62 mDevice(nullptr), mNeedUnmap(false), mOffset(0)
63 {
64 int open_flags = O_RDWR;
65 if (flags & NO_CACHING)
66 open_flags |= O_SYNC;
67
68 int fd = open(device, open_flags);
69 ALOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno));
70 if (fd >= 0) {
71 const size_t pagesize = getpagesize();
72 size = ((size + pagesize-1) & ~(pagesize-1));
73 if (mapfd(fd, size) == NO_ERROR) {
74 mDevice = device;
75 }
76 }
77 }
78
MemoryHeapBase(int fd,size_t size,uint32_t flags,off_t offset)79 MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, off_t offset)
80 : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
81 mDevice(nullptr), mNeedUnmap(false), mOffset(0)
82 {
83 const size_t pagesize = getpagesize();
84 size = ((size + pagesize-1) & ~(pagesize-1));
85 mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), size, offset);
86 }
87
init(int fd,void * base,size_t size,int flags,const char * device)88 status_t MemoryHeapBase::init(int fd, void *base, size_t size, int flags, const char* device)
89 {
90 if (mFD != -1) {
91 return INVALID_OPERATION;
92 }
93 mFD = fd;
94 mBase = base;
95 mSize = size;
96 mFlags = flags;
97 mDevice = device;
98 return NO_ERROR;
99 }
100
mapfd(int fd,size_t size,off_t offset)101 status_t MemoryHeapBase::mapfd(int fd, size_t size, off_t offset)
102 {
103 if (size == 0) {
104 // try to figure out the size automatically
105 struct stat sb;
106 if (fstat(fd, &sb) == 0) {
107 size = (size_t)sb.st_size;
108 // sb.st_size is off_t which on ILP32 may be 64 bits while size_t is 32 bits.
109 if ((off_t)size != sb.st_size) {
110 ALOGE("%s: size of file %lld cannot fit in memory",
111 __func__, (long long)sb.st_size);
112 return INVALID_OPERATION;
113 }
114 }
115 // if it didn't work, let mmap() fail.
116 }
117
118 if ((mFlags & DONT_MAP_LOCALLY) == 0) {
119 void* base = (uint8_t*)mmap(nullptr, size,
120 PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
121 if (base == MAP_FAILED) {
122 ALOGE("mmap(fd=%d, size=%zu) failed (%s)",
123 fd, size, strerror(errno));
124 close(fd);
125 return -errno;
126 }
127 //ALOGD("mmap(fd=%d, base=%p, size=%zu)", fd, base, size);
128 mBase = base;
129 mNeedUnmap = true;
130 } else {
131 mBase = nullptr; // not MAP_FAILED
132 mNeedUnmap = false;
133 }
134 mFD = fd;
135 mSize = size;
136 mOffset = offset;
137 return NO_ERROR;
138 }
139
~MemoryHeapBase()140 MemoryHeapBase::~MemoryHeapBase()
141 {
142 dispose();
143 }
144
dispose()145 void MemoryHeapBase::dispose()
146 {
147 int fd = android_atomic_or(-1, &mFD);
148 if (fd >= 0) {
149 if (mNeedUnmap) {
150 //ALOGD("munmap(fd=%d, base=%p, size=%zu)", fd, mBase, mSize);
151 munmap(mBase, mSize);
152 }
153 mBase = nullptr;
154 mSize = 0;
155 close(fd);
156 }
157 }
158
getHeapID() const159 int MemoryHeapBase::getHeapID() const {
160 return mFD;
161 }
162
getBase() const163 void* MemoryHeapBase::getBase() const {
164 return mBase;
165 }
166
getSize() const167 size_t MemoryHeapBase::getSize() const {
168 return mSize;
169 }
170
getFlags() const171 uint32_t MemoryHeapBase::getFlags() const {
172 return mFlags;
173 }
174
getDevice() const175 const char* MemoryHeapBase::getDevice() const {
176 return mDevice;
177 }
178
getOffset() const179 off_t MemoryHeapBase::getOffset() const {
180 return mOffset;
181 }
182
183 // ---------------------------------------------------------------------------
184 }; // namespace android
185