Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 13b16040 authored by Jeff Brown's avatar Jeff Brown
Browse files

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
parent 9d2c5a7c
Loading
Loading
Loading
Loading
+17 −5
Original line number Original line Diff line number Diff line
@@ -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 {
+48 −23
Original line number Original line Diff line number Diff line
@@ -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 {
            if (!mutableCopy) {
                result = ashmem_set_prot_region(fd, PROT_READ);
                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