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

Commit d16d4f86 authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

Merge "Transfer large bitmaps using ashmem. Bug: 5224703"

parents dd570756 5707dbf1
Loading
Loading
Loading
Loading
+46 −3
Original line number Original line Diff line number Diff line
@@ -38,6 +38,9 @@ struct flat_binder_object; // defined in support_p/binder_module.h
class Parcel
class Parcel
{
{
public:
public:
    class ReadableBlob;
    class WritableBlob;

                        Parcel();
                        Parcel();
                        ~Parcel();
                        ~Parcel();
    
    
@@ -112,6 +115,12 @@ public:
    // will be closed once the parcel is destroyed.
    // will be closed once the parcel is destroyed.
    status_t            writeDupFileDescriptor(int fd);
    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);
    status_t            writeObject(const flat_binder_object& val, bool nullMetaData);


    // Like Parcel.java's writeNoException().  Just writes a zero int32.
    // Like Parcel.java's writeNoException().  Just writes a zero int32.
@@ -160,6 +169,10 @@ public:
    // in the parcel, which you do not own -- use dup() to get your own copy.
    // in the parcel, which you do not own -- use dup() to get your own copy.
    int                 readFileDescriptor() const;
    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;
    const flat_binder_object* readObject(bool nullMetaData) const;


    // Explicitly close all file descriptors in the parcel.
    // Explicitly close all file descriptors in the parcel.
@@ -218,6 +231,36 @@ private:
    
    
    release_func        mOwner;
    release_func        mOwner;
    void*               mOwnerCookie;
    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; }
    };
};
};


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
+108 −0
Original line number Original line Diff line number Diff line
@@ -30,12 +30,14 @@
#include <utils/TextOutput.h>
#include <utils/TextOutput.h>
#include <utils/misc.h>
#include <utils/misc.h>
#include <utils/Flattenable.h>
#include <utils/Flattenable.h>
#include <cutils/ashmem.h>


#include <private/binder/binder_module.h>
#include <private/binder/binder_module.h>


#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdint.h>
#include <sys/mman.h>


#ifndef INT32_MAX
#ifndef INT32_MAX
#define INT32_MAX ((int32_t)(2147483647))
#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
// 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
@@ -718,6 +723,54 @@ status_t Parcel::writeDupFileDescriptor(int fd)
    return writeObject(obj, true);
    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 Parcel::write(const Flattenable& val)
{
{
    status_t err;
    status_t err;
@@ -1040,6 +1093,32 @@ int Parcel::readFileDescriptor() const
    return BAD_TYPE;
    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
status_t Parcel::read(Flattenable& val) const
{
{
    // size
    // size
@@ -1469,4 +1548,33 @@ void Parcel::scanForFds() const
    mFdsKnown = true;
    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
}; // namespace android