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

Commit ec4e0063 authored by Jeff Brown's avatar Jeff Brown
Browse files

Use ashmem for CursorWindows.

Bug: 5332296

The memory dealer introduces additional delays for reclaiming
the memory owned by CursorWindows because the Binder object must
be finalized.  Using ashmem instead gives CursorWindow more
direct control over the lifetime of the shared memory region.

The provider now allocates the CursorWindows and returns them
to clients with a read-only protection bit set on the ashmem
region.

Improved the encapsulation of CursorWindow.  Callers shouldn't
need to care about details like how string fields are allocated.

Removed the compile-time configuration of string and numeric
storage modes to remove some dead weight.

Change-Id: I07c2bc2a9c573d7e435dcaecd269d25ea9807acd
parent 3829bc3c
Loading
Loading
Loading
Loading
+131 −160
Original line number Original line Diff line number Diff line
@@ -21,18 +21,8 @@
#include <stddef.h>
#include <stddef.h>
#include <stdint.h>
#include <stdint.h>


#include <binder/IMemory.h>
#include <binder/Parcel.h>
#include <utils/RefBase.h>
#include <utils/String8.h>

#define DEFAULT_WINDOW_SIZE 4096
#define WINDOW_ALLOCATION_SIZE 4096

#define ROW_SLOT_CHUNK_NUM_ROWS 16

// Row slots are allocated in chunks of ROW_SLOT_CHUNK_NUM_ROWS,
// with an offset after the rows that points to the next chunk
#define ROW_SLOT_CHUNK_SIZE ((ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t)) + sizeof(uint32_t))



#if LOG_NDEBUG
#if LOG_NDEBUG


@@ -46,29 +36,36 @@


#endif
#endif



// When defined to true strings are stored as UTF8, otherwise they're UTF16
#define WINDOW_STORAGE_UTF8 1

// When defined to true numberic values are stored inline in the field_slot_t, otherwise they're allocated in the window
#define WINDOW_STORAGE_INLINE_NUMERICS 1

namespace android {
namespace android {


typedef struct
/**
{
 * This class stores a set of rows from a database in a buffer. The begining of the
    uint32_t numRows;
 * window has first chunk of RowSlots, which are offsets to the row directory, followed by
    uint32_t numColumns;
 * an offset to the next chunk in a linked-list of additional chunk of RowSlots in case
} window_header_t;
 * the pre-allocated chunk isn't big enough to refer to all rows. Each row directory has a
 * FieldSlot per column, which has the size, offset, and type of the data for that field.
 * Note that the data types come from sqlite3.h.
 *
 * Strings are stored in UTF-8.
 */
class CursorWindow {
    CursorWindow(const String8& name, int ashmemFd,
            void* data, size_t size, bool readOnly);


typedef struct
public:
{
    /* Field types. */
    uint32_t offset;
    enum {
} row_slot_t;
        FIELD_TYPE_NULL = 0,
        FIELD_TYPE_INTEGER = 1,
        FIELD_TYPE_FLOAT = 2,
        FIELD_TYPE_STRING = 3,
        FIELD_TYPE_BLOB = 4,
    };


typedef struct
    /* Opaque type that describes a field slot. */
{
    struct FieldSlot {
    uint8_t type;
    private:
        int32_t type;
        union {
        union {
            double d;
            double d;
            int64_t l;
            int64_t l;
@@ -77,145 +74,119 @@ typedef struct
                uint32_t size;
                uint32_t size;
            } buffer;
            } buffer;
        } data;
        } data;
} __attribute__((packed)) field_slot_t;


#define FIELD_TYPE_NULL 0
        friend class CursorWindow;
#define FIELD_TYPE_INTEGER 1
    } __attribute((packed));
#define FIELD_TYPE_FLOAT 2
#define FIELD_TYPE_STRING 3
#define FIELD_TYPE_BLOB 4


/**
 * This class stores a set of rows from a database in a buffer. The begining of the
 * window has first chunk of row_slot_ts, which are offsets to the row directory, followed by
 * an offset to the next chunk in a linked-list of additional chunk of row_slot_ts in case
 * the pre-allocated chunk isn't big enough to refer to all rows. Each row directory has a
 * field_slot_t per column, which has the size, offset, and type of the data for that field.
 * Note that the data types come from sqlite3.h.
 */
class CursorWindow
{
public:
                        CursorWindow(size_t maxSize);
                        CursorWindow(){}
    bool                setMemory(const sp<IMemory>&);
    ~CursorWindow();
    ~CursorWindow();


    bool                initBuffer(bool localOnly);
    static status_t create(const String8& name, size_t size, bool localOnly,
    sp<IMemory>         getMemory() {return mMemory;}
            CursorWindow** outCursorWindow);
    static status_t createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow);


    size_t              size() {return mSize;}
    status_t writeToParcel(Parcel* parcel);
    uint8_t *           data() {return mData;}
    uint32_t            getNumRows() {return mHeader->numRows;}
    uint32_t            getNumColumns() {return mHeader->numColumns;}
    void                freeLastRow() {
                            if (mHeader->numRows > 0) {
                                mHeader->numRows--;
                            }
                        }
    bool                setNumColumns(uint32_t numColumns)
                            {
                                uint32_t cur = mHeader->numColumns;
                                if (cur > 0 && cur != numColumns) {
                                    LOGE("Trying to go from %d columns to %d", cur, numColumns);
                                    return false;
                                }
                                mHeader->numColumns = numColumns;
                                return true;
                            }


    int32_t             freeSpace();
    inline String8 name() { return mName; }
    inline size_t size() { return mSize; }
    inline size_t freeSpace() { return mSize - mHeader->freeOffset; }
    inline uint32_t getNumRows() { return mHeader->numRows; }
    inline uint32_t getNumColumns() { return mHeader->numColumns; }


    void                clear();
    status_t clear();
    status_t setNumColumns(uint32_t numColumns);


    /**
    /**
                         * Allocate a row slot and its directory. The returned
     * Allocate a row slot and its directory.
                         * pointer points to the begining of the row's directory
     * The row is initialized will null entries for each field.
                         * or NULL if there wasn't room. The directory is
                         * initialied with NULL entries for each field.
     */
     */
    field_slot_t *      allocRow();
    status_t allocRow();
    status_t freeLastRow();


                        /**
    status_t putBlob(uint32_t row, uint32_t column, const void* value, size_t size);
                         * Allocate a portion of the window. Returns the offset
    status_t putString(uint32_t row, uint32_t column, const char* value, size_t sizeIncludingNull);
                         * of the allocation, or 0 if there isn't enough space.
    status_t putLong(uint32_t row, uint32_t column, int64_t value);
                         * If aligned is true, the allocation gets 4 byte alignment.
    status_t putDouble(uint32_t row, uint32_t column, double value);
                         */
    status_t putNull(uint32_t row, uint32_t column);
    uint32_t            alloc(size_t size, bool aligned = false);


    /**
    /**
                         * Copy data into the window at the given offset.
     * Gets the field slot at the specified row and column.
     * Returns null if the requested row or column is not in the window.
     */
     */
    void                copyIn(uint32_t offset, uint8_t const * data, size_t size);
    FieldSlot* getFieldSlot(uint32_t row, uint32_t column);
    void                copyIn(uint32_t offset, int64_t data);
    void                copyIn(uint32_t offset, double data);

    void                copyOut(uint32_t offset, uint8_t * data, size_t size);
    int64_t             copyOutLong(uint32_t offset);
    double              copyOutDouble(uint32_t offset);


    bool                putLong(unsigned int row, unsigned int col, int64_t value);
    inline int32_t getFieldSlotType(FieldSlot* fieldSlot) {
    bool                putDouble(unsigned int row, unsigned int col, double value);
        return fieldSlot->type;
    bool                putNull(unsigned int row, unsigned int col);

    bool                getLong(unsigned int row, unsigned int col, int64_t * valueOut);
    bool                getDouble(unsigned int row, unsigned int col, double * valueOut);
    bool                getNull(unsigned int row, unsigned int col, bool * valueOut);

    uint8_t *           offsetToPtr(uint32_t offset) {return mData + offset;}

    row_slot_t *        allocRowSlot();

    row_slot_t *        getRowSlot(int row);

                        /**
                         * return NULL if Failed to find rowSlot or
                         * Invalid rowSlot
                         */
    field_slot_t *      getFieldSlotWithCheck(int row, int column);
    field_slot_t *      getFieldSlot(int row, int column)
                            {
                                int fieldDirOffset = getRowSlot(row)->offset;
                                return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column;
    }
    }


    int64_t getFieldSlotValueLong(field_slot_t* fieldSlot) {
    inline int64_t getFieldSlotValueLong(FieldSlot* fieldSlot) {
#if WINDOW_STORAGE_INLINE_NUMERICS
        return fieldSlot->data.l;
        return fieldSlot->data.l;
#else
        return copyOutLong(fieldSlot->data.buffer.offset);
#endif
    }
    }


    double getFieldSlotValueDouble(field_slot_t* fieldSlot) {
    inline double getFieldSlotValueDouble(FieldSlot* fieldSlot) {
#if WINDOW_STORAGE_INLINE_NUMERICS
        return fieldSlot->data.d;
        return fieldSlot->data.d;
#else
        return copyOutDouble(fieldSlot->data.buffer.offset);
#endif
    }
    }


#if WINDOW_STORAGE_UTF8
    inline const char* getFieldSlotValueString(FieldSlot* fieldSlot,
    char* getFieldSlotValueString(field_slot_t* fieldSlot) {
            size_t* outSizeIncludingNull) {
        return reinterpret_cast<char*>(offsetToPtr(fieldSlot->data.buffer.offset));
        *outSizeIncludingNull = fieldSlot->data.buffer.size;
        return static_cast<char*>(offsetToPtr(fieldSlot->data.buffer.offset));
    }
    }
#else

    char16_t* getFieldSlotValueString(field_slot_t* fieldSlot) {
    inline const void* getFieldSlotValueBlob(FieldSlot* fieldSlot, size_t* outSize) {
        return reinterpret_cast<char16_t*>(offsetToPtr(fieldSlot->data.buffer.offset));
        *outSize = fieldSlot->data.buffer.size;
        return offsetToPtr(fieldSlot->data.buffer.offset);
    }
    }
#endif


private:
private:
    uint8_t * mData;
    static const size_t ROW_SLOT_CHUNK_NUM_ROWS = 100;

    struct Header {
        // Offset of the lowest unused byte in the window.
        uint32_t freeOffset;

        // Offset of the first row slot chunk.
        uint32_t firstChunkOffset;

        uint32_t numRows;
        uint32_t numColumns;
    };

    struct RowSlot {
        uint32_t offset;
    };

    struct RowSlotChunk {
        RowSlot slots[ROW_SLOT_CHUNK_NUM_ROWS];
        uint32_t nextChunkOffset;
    };

    String8 mName;
    int mAshmemFd;
    void* mData;
    size_t mSize;
    size_t mSize;
    size_t mMaxSize;
    bool mReadOnly;
    window_header_t * mHeader;
    Header* mHeader;
    sp<IMemory> mMemory;

    inline void* offsetToPtr(uint32_t offset) {
        return static_cast<uint8_t*>(mData) + offset;
    }

    inline uint32_t offsetFromPtr(void* ptr) {
        return static_cast<uint8_t*>(ptr) - static_cast<uint8_t*>(mData);
    }


    /**
    /**
     * Offset of the lowest unused data byte in the array.
     * Allocate a portion of the window. Returns the offset
     * of the allocation, or 0 if there isn't enough space.
     * If aligned is true, the allocation gets 4 byte alignment.
     */
     */
    uint32_t mFreeOffset;
    uint32_t alloc(size_t size, bool aligned = false);

    RowSlot* getRowSlot(uint32_t row);
    RowSlot* allocRowSlot();

    status_t putBlobOrString(uint32_t row, uint32_t column,
            const void* value, size_t size, int32_t type);
};
};


}; // namespace android
}; // namespace android
+237 −261

File changed.

Preview size limit exceeded, changes collapsed.

+2 −2
Original line number Original line Diff line number Diff line
@@ -752,7 +752,7 @@ status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob)


    int result = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
    int result = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
    if (result < 0) {
    if (result < 0) {
        status = -result;
        status = result;
    } else {
    } else {
        void* ptr = ::mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        void* ptr = ::mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        if (ptr == MAP_FAILED) {
        if (ptr == MAP_FAILED) {
@@ -760,7 +760,7 @@ status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob)
        } else {
        } else {
            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(1);
                if (!status) {
                if (!status) {