SkSafeUnref(ctable);\r
\r
size_t size = bitmap->getSize();\r
+\r
+ android::Parcel::ReadableBlob blob;\r
+ android::status_t status = p->readBlob(size, &blob);\r
+ if (status) {\r
+ doThrowRE(env, "Could not read bitmap from parcel blob.");\r
+ delete bitmap;\r
+ return NULL;\r
+ }\r
+\r
bitmap->lockPixels();\r
- memcpy(bitmap->getPixels(), p->readInplace(size), size);\r
+ memcpy(bitmap->getPixels(), blob.data(), size);\r
bitmap->unlockPixels();\r
\r
+ blob.release();\r
return GraphicsJNI::createBitmap(env, bitmap, buffer, isMutable, NULL, density);\r
}\r
\r
}\r
\r
size_t size = bitmap->getSize();\r
- bitmap->lockPixels();\r
- void* pDst = p->writeInplace(size);\r
\r
- const void* pSrc = bitmap->getPixels();\r
+ android::Parcel::WritableBlob blob;\r
+ android::status_t status = p->writeBlob(size, &blob);\r
+ if (status) {\r
+ doThrowRE(env, "Could not write bitmap to parcel blob.");\r
+ return false;\r
+ }\r
\r
+ bitmap->lockPixels();\r
+ const void* pSrc = bitmap->getPixels();\r
if (pSrc == NULL) {\r
- memset(pDst, 0, size);\r
+ memset(blob.data(), 0, size);\r
} else {\r
- memcpy(pDst, pSrc, size);\r
+ memcpy(blob.data(), pSrc, size);\r
}\r
bitmap->unlockPixels();\r
+\r
+ blob.release();\r
return true;\r
}\r
\r
class Parcel
{
public:
+ class ReadableBlob;
+ class WritableBlob;
+
Parcel();
~Parcel();
// Place a file descriptor into the parcel. A dup of the fd is made, which
// will be closed once the parcel is destroyed.
status_t writeDupFileDescriptor(int fd);
-
+
+ // Writes a blob to the parcel.
+ // If the blob is small, then it is stored in-place, otherwise it is
+ // transferred by way of an anonymous shared memory region.
+ // The caller should call release() on the blob after writing its contents.
+ status_t writeBlob(size_t len, WritableBlob* outBlob);
+
status_t writeObject(const flat_binder_object& val, bool nullMetaData);
// Like Parcel.java's writeNoException(). Just writes a zero int32.
// Retrieve a file descriptor from the parcel. This returns the raw fd
// in the parcel, which you do not own -- use dup() to get your own copy.
int readFileDescriptor() const;
-
+
+ // Reads a blob from the parcel.
+ // The caller should call release() on the blob after reading its contents.
+ status_t readBlob(size_t len, ReadableBlob* outBlob) const;
+
const flat_binder_object* readObject(bool nullMetaData) const;
// Explicitly close all file descriptors in the parcel.
release_func relFunc, void* relCookie);
void print(TextOutput& to, uint32_t flags = 0) const;
-
+
private:
Parcel(const Parcel& o);
Parcel& operator=(const Parcel& o);
release_func mOwner;
void* mOwnerCookie;
+
+ class Blob {
+ public:
+ Blob();
+ ~Blob();
+
+ void release();
+ inline size_t size() const { return mSize; }
+
+ protected:
+ void init(bool mapped, void* data, size_t size);
+ void clear();
+
+ bool mMapped;
+ void* mData;
+ size_t mSize;
+ };
+
+public:
+ class ReadableBlob : public Blob {
+ friend class Parcel;
+ public:
+ inline const void* data() const { return mData; }
+ };
+
+ class WritableBlob : public Blob {
+ friend class Parcel;
+ public:
+ inline void* data() { return mData; }
+ };
};
// ---------------------------------------------------------------------------
#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))
// 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
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;
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
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