diff options
author | Jeff Brown <jeffbrown@google.com> | 2011-09-23 21:17:56 -0700 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2011-10-03 17:28:13 -0700 |
commit | 5707dbf15d0b44c88fbaa6dd271097f2d42932e0 (patch) | |
tree | 1948bba62a8ddd4ee448e29628ad4c0946b0f671 /libs/binder | |
parent | 16624bd4fec14e937ea2cc11a6ce45a5c494fa44 (diff) | |
download | frameworks_native-5707dbf15d0b44c88fbaa6dd271097f2d42932e0.zip frameworks_native-5707dbf15d0b44c88fbaa6dd271097f2d42932e0.tar.gz frameworks_native-5707dbf15d0b44c88fbaa6dd271097f2d42932e0.tar.bz2 |
Transfer large bitmaps using ashmem.
Bug: 5224703
Change-Id: If385a66adf4c6179a0bb49c0e6d09a9567e23808
Diffstat (limited to 'libs/binder')
-rw-r--r-- | libs/binder/Parcel.cpp | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 8eeab7a..9552c1c 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -30,12 +30,14 @@ #include <utils/TextOutput.h> #include <utils/misc.h> #include <utils/Flattenable.h> +#include <cutils/ashmem.h> #include <private/binder/binder_module.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> +#include <sys/mman.h> #ifndef INT32_MAX #define INT32_MAX ((int32_t)(2147483647)) @@ -54,6 +56,9 @@ // Note: must be kept in sync with android/os/Parcel.java's EX_HAS_REPLY_HEADER #define EX_HAS_REPLY_HEADER -128 +// Maximum size of a blob to transfer in-place. +static const size_t IN_PLACE_BLOB_LIMIT = 40 * 1024; + // XXX This can be made public if we want to provide // support for typed data. struct small_flat_data @@ -718,6 +723,54 @@ status_t Parcel::writeDupFileDescriptor(int fd) return writeObject(obj, true); } +status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob) +{ + status_t status; + + if (!mAllowFds || len <= IN_PLACE_BLOB_LIMIT) { + LOGV("writeBlob: write in place"); + status = writeInt32(0); + if (status) return status; + + void* ptr = writeInplace(len); + if (!ptr) return NO_MEMORY; + + outBlob->init(false /*mapped*/, ptr, len); + return NO_ERROR; + } + + LOGV("writeBlob: write to ashmem"); + int fd = ashmem_create_region("Parcel Blob", len); + if (fd < 0) return NO_MEMORY; + + int result = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE); + if (result < 0) { + status = -result; + } else { + void* ptr = ::mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + status = -errno; + } else { + result = ashmem_set_prot_region(fd, PROT_READ); + if (result < 0) { + status = -result; + } else { + status = writeInt32(1); + if (!status) { + status = writeFileDescriptor(fd); + if (!status) { + outBlob->init(true /*mapped*/, ptr, len); + return NO_ERROR; + } + } + } + } + ::munmap(ptr, len); + } + ::close(fd); + return status; +} + status_t Parcel::write(const Flattenable& val) { status_t err; @@ -1040,6 +1093,32 @@ int Parcel::readFileDescriptor() const return BAD_TYPE; } +status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const +{ + int32_t useAshmem; + status_t status = readInt32(&useAshmem); + if (status) return status; + + if (!useAshmem) { + LOGV("readBlob: read in place"); + const void* ptr = readInplace(len); + if (!ptr) return BAD_VALUE; + + outBlob->init(false /*mapped*/, const_cast<void*>(ptr), len); + return NO_ERROR; + } + + LOGV("readBlob: read from ashmem"); + int fd = readFileDescriptor(); + if (fd == int(BAD_TYPE)) return BAD_VALUE; + + void* ptr = ::mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + if (!ptr) return NO_MEMORY; + + outBlob->init(true /*mapped*/, ptr, len); + return NO_ERROR; +} + status_t Parcel::read(Flattenable& val) const { // size @@ -1469,4 +1548,33 @@ void Parcel::scanForFds() const mFdsKnown = true; } +// --- Parcel::Blob --- + +Parcel::Blob::Blob() : + mMapped(false), mData(NULL), mSize(0) { +} + +Parcel::Blob::~Blob() { + release(); +} + +void Parcel::Blob::release() { + if (mMapped && mData) { + ::munmap(mData, mSize); + } + clear(); +} + +void Parcel::Blob::init(bool mapped, void* data, size_t size) { + mMapped = mapped; + mData = data; + mSize = size; +} + +void Parcel::Blob::clear() { + mMapped = false; + mData = NULL; + mSize = 0; +} + }; // namespace android |