| /* | 
 |  * Copyright (C) 2008 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #define LOG_TAG "MemoryHeapBase" | 
 |  | 
 | #include <errno.h> | 
 | #include <fcntl.h> | 
 | #include <stdint.h> | 
 | #include <stdlib.h> | 
 | #include <sys/ioctl.h> | 
 | #include <sys/stat.h> | 
 | #include <sys/types.h> | 
 | #include <unistd.h> | 
 |  | 
 | #include <binder/MemoryHeapBase.h> | 
 | #include <cutils/ashmem.h> | 
 | #include <cutils/atomic.h> | 
 | #include <log/log.h> | 
 |  | 
 | namespace android { | 
 |  | 
 | // --------------------------------------------------------------------------- | 
 |  | 
 | MemoryHeapBase::MemoryHeapBase() | 
 |     : mFD(-1), mSize(0), mBase(MAP_FAILED), | 
 |       mDevice(NULL), mNeedUnmap(false), mOffset(0) | 
 | { | 
 | } | 
 |  | 
 | MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name) | 
 |     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), | 
 |       mDevice(0), mNeedUnmap(false), mOffset(0) | 
 | { | 
 |     const size_t pagesize = getpagesize(); | 
 |     size = ((size + pagesize-1) & ~(pagesize-1)); | 
 |     int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size); | 
 |     ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno)); | 
 |     if (fd >= 0) { | 
 |         if (mapfd(fd, size) == NO_ERROR) { | 
 |             if (flags & READ_ONLY) { | 
 |                 ashmem_set_prot_region(fd, PROT_READ); | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags) | 
 |     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), | 
 |       mDevice(0), mNeedUnmap(false), mOffset(0) | 
 | { | 
 |     int open_flags = O_RDWR; | 
 |     if (flags & NO_CACHING) | 
 |         open_flags |= O_SYNC; | 
 |  | 
 |     int fd = open(device, open_flags); | 
 |     ALOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno)); | 
 |     if (fd >= 0) { | 
 |         const size_t pagesize = getpagesize(); | 
 |         size = ((size + pagesize-1) & ~(pagesize-1)); | 
 |         if (mapfd(fd, size) == NO_ERROR) { | 
 |             mDevice = device; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, uint32_t offset) | 
 |     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), | 
 |       mDevice(0), mNeedUnmap(false), mOffset(0) | 
 | { | 
 |     const size_t pagesize = getpagesize(); | 
 |     size = ((size + pagesize-1) & ~(pagesize-1)); | 
 |     mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), size, offset); | 
 | } | 
 |  | 
 | status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device) | 
 | { | 
 |     if (mFD != -1) { | 
 |         return INVALID_OPERATION; | 
 |     } | 
 |     mFD = fd; | 
 |     mBase = base; | 
 |     mSize = size; | 
 |     mFlags = flags; | 
 |     mDevice = device; | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset) | 
 | { | 
 |     if (size == 0) { | 
 |         // try to figure out the size automatically | 
 |         struct stat sb; | 
 |         if (fstat(fd, &sb) == 0) | 
 |             size = sb.st_size; | 
 |         // if it didn't work, let mmap() fail. | 
 |     } | 
 |  | 
 |     if ((mFlags & DONT_MAP_LOCALLY) == 0) { | 
 |         void* base = (uint8_t*)mmap(0, size, | 
 |                 PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset); | 
 |         if (base == MAP_FAILED) { | 
 |             ALOGE("mmap(fd=%d, size=%u) failed (%s)", | 
 |                     fd, uint32_t(size), strerror(errno)); | 
 |             close(fd); | 
 |             return -errno; | 
 |         } | 
 |         //ALOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size); | 
 |         mBase = base; | 
 |         mNeedUnmap = true; | 
 |     } else  { | 
 |         mBase = 0; // not MAP_FAILED | 
 |         mNeedUnmap = false; | 
 |     } | 
 |     mFD = fd; | 
 |     mSize = size; | 
 |     mOffset = offset; | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | MemoryHeapBase::~MemoryHeapBase() | 
 | { | 
 |     dispose(); | 
 | } | 
 |  | 
 | void MemoryHeapBase::dispose() | 
 | { | 
 |     int fd = android_atomic_or(-1, &mFD); | 
 |     if (fd >= 0) { | 
 |         if (mNeedUnmap) { | 
 |             //ALOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize); | 
 |             munmap(mBase, mSize); | 
 |         } | 
 |         mBase = 0; | 
 |         mSize = 0; | 
 |         close(fd); | 
 |     } | 
 | } | 
 |  | 
 | int MemoryHeapBase::getHeapID() const { | 
 |     return mFD; | 
 | } | 
 |  | 
 | void* MemoryHeapBase::getBase() const { | 
 |     return mBase; | 
 | } | 
 |  | 
 | size_t MemoryHeapBase::getSize() const { | 
 |     return mSize; | 
 | } | 
 |  | 
 | uint32_t MemoryHeapBase::getFlags() const { | 
 |     return mFlags; | 
 | } | 
 |  | 
 | const char* MemoryHeapBase::getDevice() const { | 
 |     return mDevice; | 
 | } | 
 |  | 
 | uint32_t MemoryHeapBase::getOffset() const { | 
 |     return mOffset; | 
 | } | 
 |  | 
 | // --------------------------------------------------------------------------- | 
 | }; // namespace android |