| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 19 | #include <errno.h> | 
| Mark Salyzyn | a5e161b | 2016-09-29 08:08:05 -0700 | [diff] [blame] | 20 | #include <fcntl.h> | 
 | 21 | #include <stdint.h> | 
 | 22 | #include <stdlib.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 23 | #include <sys/ioctl.h> | 
| Mark Salyzyn | a5e161b | 2016-09-29 08:08:05 -0700 | [diff] [blame] | 24 | #include <sys/stat.h> | 
 | 25 | #include <sys/types.h> | 
 | 26 | #include <unistd.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 27 |  | 
| Mark Salyzyn | 7823e12 | 2016-09-29 08:08:05 -0700 | [diff] [blame] | 28 | #include <binder/MemoryHeapBase.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 29 | #include <cutils/ashmem.h> | 
 | 30 | #include <cutils/atomic.h> | 
| Mark Salyzyn | 4dad9ce | 2016-09-29 08:08:05 -0700 | [diff] [blame] | 31 | #include <log/log.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 32 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 33 | namespace android { | 
 | 34 |  | 
 | 35 | // --------------------------------------------------------------------------- | 
 | 36 |  | 
| Anu Sundararajan | 5728a92 | 2011-06-22 15:58:59 -0500 | [diff] [blame] | 37 | MemoryHeapBase::MemoryHeapBase() | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 38 |     : mFD(-1), mSize(0), mBase(MAP_FAILED), | 
| Yi Kong | 9163556 | 2018-06-07 14:38:36 -0700 | [diff] [blame] | 39 |       mDevice(nullptr), mNeedUnmap(false), mOffset(0) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 40 | { | 
 | 41 | } | 
 | 42 |  | 
 | 43 | MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name) | 
 | 44 |     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), | 
| Yi Kong | 9163556 | 2018-06-07 14:38:36 -0700 | [diff] [blame] | 45 |       mDevice(nullptr), mNeedUnmap(false), mOffset(0) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 46 | { | 
 | 47 |     const size_t pagesize = getpagesize(); | 
 | 48 |     size = ((size + pagesize-1) & ~(pagesize-1)); | 
| Yi Kong | 9163556 | 2018-06-07 14:38:36 -0700 | [diff] [blame] | 49 |     int fd = ashmem_create_region(name == nullptr ? "MemoryHeapBase" : name, size); | 
| Steve Block | e6f43dd | 2012-01-06 19:20:56 +0000 | [diff] [blame] | 50 |     ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno)); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 51 |     if (fd >= 0) { | 
| Ytai Ben-Tsvi | dacdbd1 | 2020-10-22 15:40:45 -0700 | [diff] [blame] | 52 |         if (mapfd(fd, true, size) == NO_ERROR) { | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 53 |             if (flags & READ_ONLY) { | 
 | 54 |                 ashmem_set_prot_region(fd, PROT_READ); | 
 | 55 |             } | 
 | 56 |         } | 
 | 57 |     } | 
 | 58 | } | 
 | 59 |  | 
 | 60 | MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags) | 
 | 61 |     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), | 
| Yi Kong | 9163556 | 2018-06-07 14:38:36 -0700 | [diff] [blame] | 62 |       mDevice(nullptr), mNeedUnmap(false), mOffset(0) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 63 | { | 
| Iliyan Malchev | 0db1a89 | 2009-10-29 22:55:00 -0700 | [diff] [blame] | 64 |     int open_flags = O_RDWR; | 
 | 65 |     if (flags & NO_CACHING) | 
 | 66 |         open_flags |= O_SYNC; | 
 | 67 |  | 
 | 68 |     int fd = open(device, open_flags); | 
| Steve Block | e6f43dd | 2012-01-06 19:20:56 +0000 | [diff] [blame] | 69 |     ALOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno)); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 70 |     if (fd >= 0) { | 
 | 71 |         const size_t pagesize = getpagesize(); | 
 | 72 |         size = ((size + pagesize-1) & ~(pagesize-1)); | 
| Ytai Ben-Tsvi | dacdbd1 | 2020-10-22 15:40:45 -0700 | [diff] [blame] | 73 |         if (mapfd(fd, false, size) == NO_ERROR) { | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 74 |             mDevice = device; | 
 | 75 |         } | 
 | 76 |     } | 
 | 77 | } | 
 | 78 |  | 
| Andy Hung | 5b02852 | 2018-10-22 15:29:49 -0700 | [diff] [blame] | 79 | MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, off_t offset) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 80 |     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), | 
| Yi Kong | 9163556 | 2018-06-07 14:38:36 -0700 | [diff] [blame] | 81 |       mDevice(nullptr), mNeedUnmap(false), mOffset(0) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 82 | { | 
 | 83 |     const size_t pagesize = getpagesize(); | 
 | 84 |     size = ((size + pagesize-1) & ~(pagesize-1)); | 
| Ytai Ben-Tsvi | dacdbd1 | 2020-10-22 15:40:45 -0700 | [diff] [blame] | 85 |     mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), false, size, offset); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 86 | } | 
 | 87 |  | 
| Andy Hung | 5b02852 | 2018-10-22 15:29:49 -0700 | [diff] [blame] | 88 | status_t MemoryHeapBase::init(int fd, void *base, size_t size, int flags, const char* device) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |  | 
| Ytai Ben-Tsvi | dacdbd1 | 2020-10-22 15:40:45 -0700 | [diff] [blame] | 101 | status_t MemoryHeapBase::mapfd(int fd, bool writeableByCaller, size_t size, off_t offset) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 102 | { | 
 | 103 |     if (size == 0) { | 
 | 104 |         // try to figure out the size automatically | 
| Elliott Hughes | a5a13a3 | 2013-11-21 12:22:39 -0800 | [diff] [blame] | 105 |         struct stat sb; | 
| Andy Hung | 5b02852 | 2018-10-22 15:29:49 -0700 | [diff] [blame] | 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 |         } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 115 |         // if it didn't work, let mmap() fail. | 
 | 116 |     } | 
 | 117 |  | 
 | 118 |     if ((mFlags & DONT_MAP_LOCALLY) == 0) { | 
| Ytai Ben-Tsvi | dacdbd1 | 2020-10-22 15:40:45 -0700 | [diff] [blame] | 119 |         int prot = PROT_READ; | 
 | 120 |         if (writeableByCaller || (mFlags & READ_ONLY) == 0) { | 
 | 121 |             prot |= PROT_WRITE; | 
 | 122 |         } | 
| Yi Kong | 9163556 | 2018-06-07 14:38:36 -0700 | [diff] [blame] | 123 |         void* base = (uint8_t*)mmap(nullptr, size, | 
| Ytai Ben-Tsvi | dacdbd1 | 2020-10-22 15:40:45 -0700 | [diff] [blame] | 124 |                 prot, MAP_SHARED, fd, offset); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 125 |         if (base == MAP_FAILED) { | 
| Andy Hung | 5b02852 | 2018-10-22 15:29:49 -0700 | [diff] [blame] | 126 |             ALOGE("mmap(fd=%d, size=%zu) failed (%s)", | 
 | 127 |                     fd, size, strerror(errno)); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 128 |             close(fd); | 
 | 129 |             return -errno; | 
 | 130 |         } | 
| Andy Hung | 5b02852 | 2018-10-22 15:29:49 -0700 | [diff] [blame] | 131 |         //ALOGD("mmap(fd=%d, base=%p, size=%zu)", fd, base, size); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 132 |         mBase = base; | 
 | 133 |         mNeedUnmap = true; | 
 | 134 |     } else  { | 
| Yi Kong | 9163556 | 2018-06-07 14:38:36 -0700 | [diff] [blame] | 135 |         mBase = nullptr; // not MAP_FAILED | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 136 |         mNeedUnmap = false; | 
 | 137 |     } | 
 | 138 |     mFD = fd; | 
 | 139 |     mSize = size; | 
| Anu Sundararajan | 5728a92 | 2011-06-22 15:58:59 -0500 | [diff] [blame] | 140 |     mOffset = offset; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 141 |     return NO_ERROR; | 
 | 142 | } | 
 | 143 |  | 
 | 144 | MemoryHeapBase::~MemoryHeapBase() | 
 | 145 | { | 
 | 146 |     dispose(); | 
 | 147 | } | 
 | 148 |  | 
 | 149 | void MemoryHeapBase::dispose() | 
 | 150 | { | 
 | 151 |     int fd = android_atomic_or(-1, &mFD); | 
 | 152 |     if (fd >= 0) { | 
 | 153 |         if (mNeedUnmap) { | 
| Andy Hung | 5b02852 | 2018-10-22 15:29:49 -0700 | [diff] [blame] | 154 |             //ALOGD("munmap(fd=%d, base=%p, size=%zu)", fd, mBase, mSize); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 155 |             munmap(mBase, mSize); | 
 | 156 |         } | 
| Yi Kong | 9163556 | 2018-06-07 14:38:36 -0700 | [diff] [blame] | 157 |         mBase = nullptr; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 158 |         mSize = 0; | 
 | 159 |         close(fd); | 
 | 160 |     } | 
 | 161 | } | 
 | 162 |  | 
 | 163 | int MemoryHeapBase::getHeapID() const { | 
 | 164 |     return mFD; | 
 | 165 | } | 
 | 166 |  | 
 | 167 | void* MemoryHeapBase::getBase() const { | 
 | 168 |     return mBase; | 
 | 169 | } | 
 | 170 |  | 
 | 171 | size_t MemoryHeapBase::getSize() const { | 
 | 172 |     return mSize; | 
 | 173 | } | 
 | 174 |  | 
 | 175 | uint32_t MemoryHeapBase::getFlags() const { | 
 | 176 |     return mFlags; | 
 | 177 | } | 
 | 178 |  | 
 | 179 | const char* MemoryHeapBase::getDevice() const { | 
 | 180 |     return mDevice; | 
 | 181 | } | 
 | 182 |  | 
| Andy Hung | 5b02852 | 2018-10-22 15:29:49 -0700 | [diff] [blame] | 183 | off_t MemoryHeapBase::getOffset() const { | 
| Anu Sundararajan | 5728a92 | 2011-06-22 15:58:59 -0500 | [diff] [blame] | 184 |     return mOffset; | 
 | 185 | } | 
 | 186 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 187 | // --------------------------------------------------------------------------- | 
| Steven Moreland | 61ff849 | 2019-09-26 16:05:45 -0700 | [diff] [blame] | 188 | } // namespace android |