am 13b16040: Enable more flexible usage of blobs in parcels.

* commit '13b1604018968408bcc5553e1fa5ea9df3e4e009':
  Enable more flexible usage of blobs in parcels.
This commit is contained in:
Jeff Brown 2015-06-06 04:47:56 +00:00 committed by Android Git Automerger
commit 6f33fbc82b
2 changed files with 65 additions and 28 deletions

View File

@ -60,6 +60,7 @@ public:
status_t appendFrom(const Parcel *parcel, status_t appendFrom(const Parcel *parcel,
size_t start, size_t len); size_t start, size_t len);
bool allowFds() const;
bool pushAllowFds(bool allowFds); bool pushAllowFds(bool allowFds);
void restoreAllowFds(bool lastValue); void restoreAllowFds(bool lastValue);
@ -132,9 +133,16 @@ public:
// Writes a blob to the parcel. // Writes a blob to the parcel.
// If the blob is small, then it is stored in-place, otherwise it is // If the blob is small, then it is stored in-place, otherwise it is
// transferred by way of an anonymous shared memory region. // transferred by way of an anonymous shared memory region. Prefer sending
// immutable blobs if possible since they may be subsequently transferred between
// processes without further copying whereas mutable blobs always need to be copied.
// The caller should call release() on the blob after writing its contents. // The caller should call release() on the blob after writing its contents.
status_t writeBlob(size_t len, WritableBlob* outBlob); status_t writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob);
// Write an existing immutable blob file descriptor to the parcel.
// This allows the client to send the same blob to multiple processes
// as long as it keeps a dup of the blob file descriptor handy for later.
status_t writeDupImmutableBlobFileDescriptor(int fd);
status_t writeObject(const flat_binder_object& val, bool nullMetaData); status_t writeObject(const flat_binder_object& val, bool nullMetaData);
@ -270,16 +278,19 @@ private:
Blob(); Blob();
~Blob(); ~Blob();
void clear();
void release(); void release();
inline size_t size() const { return mSize; } inline size_t size() const { return mSize; }
inline int fd() const { return mFd; };
inline bool isMutable() const { return mMutable; }
protected: protected:
void init(bool mapped, void* data, size_t size); void init(int fd, void* data, size_t size, bool isMutable);
void clear();
bool mMapped; int mFd; // owned by parcel so not closed when released
void* mData; void* mData;
size_t mSize; size_t mSize;
bool mMutable;
}; };
class FlattenableHelperInterface { class FlattenableHelperInterface {
@ -320,6 +331,7 @@ public:
friend class Parcel; friend class Parcel;
public: public:
inline const void* data() const { return mData; } inline const void* data() const { return mData; }
inline void* mutableData() { return isMutable() ? mData : NULL; }
}; };
class WritableBlob : public Blob { class WritableBlob : public Blob {

View File

@ -72,9 +72,6 @@ static size_t pad_size(size_t s) {
// Note: must be kept in sync with android/os/Parcel.java's EX_HAS_REPLY_HEADER // Note: must be kept in sync with android/os/Parcel.java's EX_HAS_REPLY_HEADER
#define EX_HAS_REPLY_HEADER -128 #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 // XXX This can be made public if we want to provide
// support for typed data. // support for typed data.
struct small_flat_data struct small_flat_data
@ -89,6 +86,15 @@ static pthread_mutex_t gParcelGlobalAllocSizeLock = PTHREAD_MUTEX_INITIALIZER;
static size_t gParcelGlobalAllocSize = 0; static size_t gParcelGlobalAllocSize = 0;
static size_t gParcelGlobalAllocCount = 0; static size_t gParcelGlobalAllocCount = 0;
// Maximum size of a blob to transfer in-place.
static const size_t BLOB_INPLACE_LIMIT = 16 * 1024;
enum {
BLOB_INPLACE = 0,
BLOB_ASHMEM_IMMUTABLE = 1,
BLOB_ASHMEM_MUTABLE = 2,
};
void acquire_object(const sp<ProcessState>& proc, void acquire_object(const sp<ProcessState>& proc,
const flat_binder_object& obj, const void* who) const flat_binder_object& obj, const void* who)
{ {
@ -516,6 +522,11 @@ status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len)
return err; return err;
} }
bool Parcel::allowFds() const
{
return mAllowFds;
}
bool Parcel::pushAllowFds(bool allowFds) bool Parcel::pushAllowFds(bool allowFds)
{ {
const bool origValue = mAllowFds; const bool origValue = mAllowFds;
@ -886,25 +897,24 @@ status_t Parcel::writeDupFileDescriptor(int fd)
return err; return err;
} }
status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob) status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob)
{ {
status_t status;
if (len > INT32_MAX) { if (len > INT32_MAX) {
// don't accept size_t values which may have come from an // don't accept size_t values which may have come from an
// inadvertent conversion from a negative int. // inadvertent conversion from a negative int.
return BAD_VALUE; return BAD_VALUE;
} }
if (!mAllowFds || len <= IN_PLACE_BLOB_LIMIT) { status_t status;
if (!mAllowFds || len <= BLOB_INPLACE_LIMIT) {
ALOGV("writeBlob: write in place"); ALOGV("writeBlob: write in place");
status = writeInt32(0); status = writeInt32(BLOB_INPLACE);
if (status) return status; if (status) return status;
void* ptr = writeInplace(len); void* ptr = writeInplace(len);
if (!ptr) return NO_MEMORY; if (!ptr) return NO_MEMORY;
outBlob->init(false /*mapped*/, ptr, len); outBlob->init(-1, ptr, len, false);
return NO_ERROR; return NO_ERROR;
} }
@ -922,15 +932,17 @@ status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob)
if (ptr == MAP_FAILED) { if (ptr == MAP_FAILED) {
status = -errno; status = -errno;
} else { } else {
result = ashmem_set_prot_region(fd, PROT_READ); if (!mutableCopy) {
result = ashmem_set_prot_region(fd, PROT_READ);
}
if (result < 0) { if (result < 0) {
status = result; status = result;
} else { } else {
status = writeInt32(1); status = writeInt32(mutableCopy ? BLOB_ASHMEM_MUTABLE : BLOB_ASHMEM_IMMUTABLE);
if (!status) { if (!status) {
status = writeFileDescriptor(fd, true /*takeOwnership*/); status = writeFileDescriptor(fd, true /*takeOwnership*/);
if (!status) { if (!status) {
outBlob->init(true /*mapped*/, ptr, len); outBlob->init(fd, ptr, len, mutableCopy);
return NO_ERROR; return NO_ERROR;
} }
} }
@ -942,6 +954,15 @@ status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob)
return status; return status;
} }
status_t Parcel::writeDupImmutableBlobFileDescriptor(int fd)
{
// Must match up with what's done in writeBlob.
if (!mAllowFds) return FDS_NOT_ALLOWED;
status_t status = writeInt32(BLOB_ASHMEM_IMMUTABLE);
if (status) return status;
return writeDupFileDescriptor(fd);
}
status_t Parcel::write(const FlattenableHelperInterface& val) status_t Parcel::write(const FlattenableHelperInterface& val)
{ {
status_t err; status_t err;
@ -1354,27 +1375,29 @@ int Parcel::readFileDescriptor() const
status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const
{ {
int32_t useAshmem; int32_t blobType;
status_t status = readInt32(&useAshmem); status_t status = readInt32(&blobType);
if (status) return status; if (status) return status;
if (!useAshmem) { if (blobType == BLOB_INPLACE) {
ALOGV("readBlob: read in place"); ALOGV("readBlob: read in place");
const void* ptr = readInplace(len); const void* ptr = readInplace(len);
if (!ptr) return BAD_VALUE; if (!ptr) return BAD_VALUE;
outBlob->init(false /*mapped*/, const_cast<void*>(ptr), len); outBlob->init(-1, const_cast<void*>(ptr), len, false);
return NO_ERROR; return NO_ERROR;
} }
ALOGV("readBlob: read from ashmem"); ALOGV("readBlob: read from ashmem");
bool isMutable = (blobType == BLOB_ASHMEM_MUTABLE);
int fd = readFileDescriptor(); int fd = readFileDescriptor();
if (fd == int(BAD_TYPE)) return BAD_VALUE; if (fd == int(BAD_TYPE)) return BAD_VALUE;
void* ptr = ::mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); void* ptr = ::mmap(NULL, len, isMutable ? PROT_READ | PROT_WRITE : PROT_READ,
MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) return NO_MEMORY; if (ptr == MAP_FAILED) return NO_MEMORY;
outBlob->init(true /*mapped*/, ptr, len); outBlob->init(fd, ptr, len, isMutable);
return NO_ERROR; return NO_ERROR;
} }
@ -1890,7 +1913,7 @@ size_t Parcel::getBlobAshmemSize() const
// --- Parcel::Blob --- // --- Parcel::Blob ---
Parcel::Blob::Blob() : Parcel::Blob::Blob() :
mMapped(false), mData(NULL), mSize(0) { mFd(-1), mData(NULL), mSize(0), mMutable(false) {
} }
Parcel::Blob::~Blob() { Parcel::Blob::~Blob() {
@ -1898,22 +1921,24 @@ Parcel::Blob::~Blob() {
} }
void Parcel::Blob::release() { void Parcel::Blob::release() {
if (mMapped && mData) { if (mFd != -1 && mData) {
::munmap(mData, mSize); ::munmap(mData, mSize);
} }
clear(); clear();
} }
void Parcel::Blob::init(bool mapped, void* data, size_t size) { void Parcel::Blob::init(int fd, void* data, size_t size, bool isMutable) {
mMapped = mapped; mFd = fd;
mData = data; mData = data;
mSize = size; mSize = size;
mMutable = isMutable;
} }
void Parcel::Blob::clear() { void Parcel::Blob::clear() {
mMapped = false; mFd = -1;
mData = NULL; mData = NULL;
mSize = 0; mSize = 0;
mMutable = false;
} }
}; // namespace android }; // namespace android