Enable more flexible usage of blobs in parcels.
Add functions to allow a client to take over the ashmem region that was transferred so that it can claim it for its own and reuse it. Add support for mutable ashmem regions too. Bug: 21428802 Change-Id: I16eca338cdb99b07d81fc43573d53ce86dbc60c8
This commit is contained in:
parent
9d2c5a7c67
commit
13b1604018
@ -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 {
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user