diff options
Diffstat (limited to 'libs/binder/MemoryHeapBase.cpp')
-rw-r--r-- | libs/binder/MemoryHeapBase.cpp | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp new file mode 100644 index 0000000..ac38f51 --- /dev/null +++ b/libs/binder/MemoryHeapBase.cpp @@ -0,0 +1,183 @@ +/* + * 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 fd = open(device, O_RDWR); + 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) + : 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); +} + +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) +{ + 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, 0); + 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 |