/* * 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 <stdlib.h> #include <stdint.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <cutils/log.h> #include <cutils/ashmem.h> #include <cutils/atomic.h> #include <binder/MemoryHeapBase.h> #if HAVE_ANDROID_OS #include <linux/android_pmem.h> #endif namespace android { // --------------------------------------------------------------------------- MemoryHeapBase::MemoryHeapBase() : mFD(-1), mSize(0), mBase(MAP_FAILED), mDevice(NULL), mNeedUnmap(false) { } MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name) : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), mDevice(0), mNeedUnmap(false) { const size_t pagesize = getpagesize(); size = ((size + pagesize-1) & ~(pagesize-1)); int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size); LOGE_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) { int open_flags = O_RDWR; if (flags & NO_CACHING) open_flags |= O_SYNC; int fd = open(device, open_flags); LOGE_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) { const size_t pagesize = getpagesize(); size = ((size + pagesize-1) & ~(pagesize-1)); mapfd(dup(fd), 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 #if HAVE_ANDROID_OS // first try the PMEM ioctl pmem_region reg; int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, ®); if (err == 0) size = reg.len; #endif if (size == 0) { // try fstat 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) { LOGE("mmap(fd=%d, size=%u) failed (%s)", fd, uint32_t(size), strerror(errno)); close(fd); return -errno; } //LOGD("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; return NO_ERROR; } MemoryHeapBase::~MemoryHeapBase() { dispose(); } void MemoryHeapBase::dispose() { int fd = android_atomic_or(-1, &mFD); if (fd >= 0) { if (mNeedUnmap) { //LOGD("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; } // --------------------------------------------------------------------------- }; // namespace android