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

Commit a962f6d1 authored by Vasu Nori's avatar Vasu Nori Committed by Android (Google) Code Review
Browse files

Merge "(do not merge)hide videochat changes in gingerbread. bug:3001483" into gingerbread

parents ab7a8ac2 15ea66db
Loading
Loading
Loading
Loading
+200 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _ANDROID__DATABASE_WINDOW_H
#define _ANDROID__DATABASE_WINDOW_H

#include <cutils/log.h>
#include <stddef.h>
#include <stdint.h>

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

#define DEFAULT_WINDOW_SIZE 4096
#define MAX_WINDOW_SIZE (1024 * 1024)
#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

#define IF_LOG_WINDOW() if (false)
#define LOG_WINDOW(...)

#else

#define IF_LOG_WINDOW() IF_LOG(LOG_DEBUG, "CursorWindow")
#define LOG_WINDOW(...) LOG(LOG_DEBUG, "CursorWindow", __VA_ARGS__)

#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 {

typedef struct
{
    uint32_t numRows;
    uint32_t numColumns;
} window_header_t;

typedef struct
{
    uint32_t offset;
} row_slot_t;

typedef struct
{
    uint8_t type;
    union {
        double d;
        int64_t l;
        struct {
            uint32_t offset;
            uint32_t size;
        } buffer;
    } data;
} __attribute__((packed)) field_slot_t;

#define FIELD_TYPE_NULL 0
#define FIELD_TYPE_INTEGER 1
#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();

    bool                initBuffer(bool localOnly);
    sp<IMemory>         getMemory() {return mMemory;}

    size_t              size() {return mSize;}
    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();

    void                clear();

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

                        /**
                         * 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            alloc(size_t size, bool aligned = false);

    uint32_t            read_field_slot(int row, int column, field_slot_t * slot);

                        /**
                         * Copy data into the window at the given offset.
                         */
    void                copyIn(uint32_t offset, uint8_t const * data, size_t size);
    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);
    bool                putDouble(unsigned int row, unsigned int col, double value);
    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;
                            }

private:
    uint8_t * mData;
    size_t mSize;
    size_t mMaxSize;
    window_header_t * mHeader;
    sp<IMemory> mMemory;

    /**
     * Offset of the lowest unused data byte in the array.
     */
    uint32_t mFreeOffset;
};

}; // namespace android

#endif
+3 −3
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ private:
    friend class SurfaceComposerClient;

    // camera and camcorder need access to the ISurface binder interface for preview
    friend class Camera;
    friend class CameraService;
    friend class MediaRecorder;
    // mediaplayer needs access to ISurface for display
    friend class MediaPlayer;
@@ -173,11 +173,12 @@ private:
     * (eventually this should go away and be replaced by proper APIs)
     */
    // camera and camcorder need access to the ISurface binder interface for preview
    friend class Camera;
    friend class CameraService;
    friend class MediaRecorder;
    // MediaPlayer needs access to ISurface for display
    friend class MediaPlayer;
    friend class IOMX;
    friend class SoftwareRenderer;
    // this is just to be able to write some unit tests
    friend class Test;

@@ -312,4 +313,3 @@ private:
}; // namespace android

#endif // ANDROID_SF_SURFACE_H
+5 −0
Original line number Diff line number Diff line
@@ -38,6 +38,11 @@ public:
        return *instance;
    }

    static bool hasInstance() {
        Mutex::Autolock _l(sLock);
        return sInstance != 0;
    }
    
protected:
    ~Singleton() { };
    Singleton() { };
+1 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
sources := \
    Binder.cpp \
    BpBinder.cpp \
    CursorWindow.cpp \
    IInterface.cpp \
    IMemory.cpp \
    IPCThreadState.cpp \
+408 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2006-2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 *
 *      http://www.apache.org/licenses/LICENSE-2.0 
 *
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */

#undef LOG_TAG
#define LOG_TAG "CursorWindow"

#include <utils/Log.h>
#include <binder/CursorWindow.h>
#include <binder/MemoryHeapBase.h>
#include <binder/MemoryBase.h>

#include <assert.h>
#include <string.h>
#include <stdlib.h>

namespace android {

CursorWindow::CursorWindow(size_t maxSize) :
    mMaxSize(maxSize)
{
}

bool CursorWindow::setMemory(const sp<IMemory>& memory)
{
    mMemory = memory;
    mData = (uint8_t *) memory->pointer();
    if (mData == NULL) {
        return false;
    }
    mHeader = (window_header_t *) mData;

    // Make the window read-only
    ssize_t size = memory->size();
    mSize = size;
    mMaxSize = size;
    mFreeOffset = size;
LOG_WINDOW("Created CursorWindow from existing IMemory: mFreeOffset = %d, numRows = %d, numColumns = %d, mSize = %d, mMaxSize = %d, mData = %p", mFreeOffset, mHeader->numRows, mHeader->numColumns, mSize, mMaxSize, mData);
    return true;
}

bool CursorWindow::initBuffer(bool localOnly)
{
    //TODO Use a non-memory dealer mmap region for localOnly

    sp<MemoryHeapBase> heap;
    heap = new MemoryHeapBase(mMaxSize, 0, "CursorWindow");
    if (heap != NULL) {
        mMemory = new MemoryBase(heap, 0, mMaxSize);
        if (mMemory != NULL) {
            mData = (uint8_t *) mMemory->pointer();
            if (mData) {
                mHeader = (window_header_t *) mData;
                mSize = mMaxSize;

                // Put the window into a clean state
                clear();
            LOG_WINDOW("Created CursorWindow with new MemoryDealer: mFreeOffset = %d, mSize = %d, mMaxSize = %d, mData = %p", mFreeOffset, mSize, mMaxSize, mData);
                return true;                
            }
        } 
        LOGE("CursorWindow heap allocation failed");
        return false;
    } else {
        LOGE("failed to create the CursorWindow heap");
        return false;
    }
}

CursorWindow::~CursorWindow()
{
    // Everything that matters is a smart pointer
}

void CursorWindow::clear()
{
    mHeader->numRows = 0;
    mHeader->numColumns = 0;
    mFreeOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE;
    // Mark the first chunk's next 'pointer' as null
    *((uint32_t *)(mData + mFreeOffset - sizeof(uint32_t))) = 0;
}

int32_t CursorWindow::freeSpace()
{
    int32_t freeSpace = mSize - mFreeOffset;
    if (freeSpace < 0) {
        freeSpace = 0;
    }
    return freeSpace;
}

field_slot_t * CursorWindow::allocRow()
{
    // Fill in the row slot
    row_slot_t * rowSlot = allocRowSlot();
    if (rowSlot == NULL) {
        return NULL;
    }

    // Allocate the slots for the field directory
    size_t fieldDirSize = mHeader->numColumns * sizeof(field_slot_t);
    uint32_t fieldDirOffset = alloc(fieldDirSize);
    if (!fieldDirOffset) {
        mHeader->numRows--;
        LOGE("The row failed, so back out the new row accounting from allocRowSlot %d", mHeader->numRows);
        return NULL;
    }
    field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(fieldDirOffset);
    memset(fieldDir, 0x0, fieldDirSize);

LOG_WINDOW("Allocated row %u, rowSlot is at offset %u, fieldDir is %d bytes at offset %u\n", (mHeader->numRows - 1), ((uint8_t *)rowSlot) - mData, fieldDirSize, fieldDirOffset);
    rowSlot->offset = fieldDirOffset;

    return fieldDir;
}

uint32_t CursorWindow::alloc(size_t requestedSize, bool aligned)
{
    int32_t size;
    uint32_t padding;
    if (aligned) {
        // 4 byte alignment
        padding = 4 - (mFreeOffset & 0x3);
    } else {
        padding = 0;
    }

    size = requestedSize + padding;

    if (size > freeSpace()) {
        LOGE("need to grow: mSize = %d, size = %d, freeSpace() = %d, numRows = %d", mSize, size, freeSpace(), mHeader->numRows);
        // Only grow the window if the first row doesn't fit
        if (mHeader->numRows > 1) {
LOGE("not growing since there are already %d row(s), max size %d", mHeader->numRows, mMaxSize);
            return 0;
        }

        // Find a new size that will fit the allocation
        int allocated = mSize - freeSpace();
        int newSize = mSize + WINDOW_ALLOCATION_SIZE;
        while (size > (newSize - allocated)) {
            newSize += WINDOW_ALLOCATION_SIZE;
            if (newSize > mMaxSize) {
                LOGE("Attempting to grow window beyond max size (%d)", mMaxSize);
                return 0;
            }
        }
LOG_WINDOW("found size %d", newSize);
        mSize = newSize;
    }

    uint32_t offset = mFreeOffset + padding;
    mFreeOffset += size;
    return offset;
}

row_slot_t * CursorWindow::getRowSlot(int row)
{
    LOG_WINDOW("enter getRowSlot current row num %d, this row %d", mHeader->numRows, row);
    int chunkNum = row / ROW_SLOT_CHUNK_NUM_ROWS;
    int chunkPos = row % ROW_SLOT_CHUNK_NUM_ROWS;
    int chunkPtrOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t);
    uint8_t * rowChunk = mData + sizeof(window_header_t);
    for (int i = 0; i < chunkNum; i++) {
        rowChunk = offsetToPtr(*((uint32_t *)(mData + chunkPtrOffset)));
        chunkPtrOffset = rowChunk - mData + (ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t));
    }
    return (row_slot_t *)(rowChunk + (chunkPos * sizeof(row_slot_t)));
    LOG_WINDOW("exit getRowSlot current row num %d, this row %d", mHeader->numRows, row);    
}

row_slot_t * CursorWindow::allocRowSlot()
{
    int chunkNum = mHeader->numRows / ROW_SLOT_CHUNK_NUM_ROWS;
    int chunkPos = mHeader->numRows % ROW_SLOT_CHUNK_NUM_ROWS;
    int chunkPtrOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t);
    uint8_t * rowChunk = mData + sizeof(window_header_t);
LOG_WINDOW("Allocating row slot, mHeader->numRows is %d, chunkNum is %d, chunkPos is %d", mHeader->numRows, chunkNum, chunkPos);
    for (int i = 0; i < chunkNum; i++) {
        uint32_t nextChunkOffset = *((uint32_t *)(mData + chunkPtrOffset));
LOG_WINDOW("nextChunkOffset is %d", nextChunkOffset);
        if (nextChunkOffset == 0) {
            // Allocate a new row chunk
            nextChunkOffset = alloc(ROW_SLOT_CHUNK_SIZE, true);
            if (nextChunkOffset == 0) {
                return NULL;
            }
            rowChunk = offsetToPtr(nextChunkOffset);
LOG_WINDOW("allocated new chunk at %d, rowChunk = %p", nextChunkOffset, rowChunk);
            *((uint32_t *)(mData + chunkPtrOffset)) = rowChunk - mData;
            // Mark the new chunk's next 'pointer' as null
            *((uint32_t *)(rowChunk + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t))) = 0;
        } else {
LOG_WINDOW("follwing 'pointer' to next chunk, offset of next pointer is %d", chunkPtrOffset);
            rowChunk = offsetToPtr(nextChunkOffset);
            chunkPtrOffset = rowChunk - mData + (ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t));
        }
    }
    mHeader->numRows++;

    return (row_slot_t *)(rowChunk + (chunkPos * sizeof(row_slot_t)));
}

field_slot_t * CursorWindow::getFieldSlotWithCheck(int row, int column)
{
  if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) {
      LOGE("Bad request for field slot %d,%d. numRows = %d, numColumns = %d", row, column, mHeader->numRows, mHeader->numColumns);
      return NULL;
  }        
  row_slot_t * rowSlot = getRowSlot(row);
  if (!rowSlot) {
      LOGE("Failed to find rowSlot for row %d", row);
      return NULL;
  }
  if (rowSlot->offset == 0 || rowSlot->offset >= mSize) {
      LOGE("Invalid rowSlot, offset = %d", rowSlot->offset);
      return NULL;
  }  
  int fieldDirOffset = rowSlot->offset;
  return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column;  
}

uint32_t CursorWindow::read_field_slot(int row, int column, field_slot_t * slotOut)
{
    if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) {
        LOGE("Bad request for field slot %d,%d. numRows = %d, numColumns = %d", row, column, mHeader->numRows, mHeader->numColumns);
        return -1;
    }        
    row_slot_t * rowSlot = getRowSlot(row);
    if (!rowSlot) {
        LOGE("Failed to find rowSlot for row %d", row);
        return -1;
    }
    if (rowSlot->offset == 0 || rowSlot->offset >= mSize) {
        LOGE("Invalid rowSlot, offset = %d", rowSlot->offset);
        return -1;
    }
LOG_WINDOW("Found field directory for %d,%d at rowSlot %d, offset %d", row, column, (uint8_t *)rowSlot - mData, rowSlot->offset);
    field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(rowSlot->offset);
LOG_WINDOW("Read field_slot_t %d,%d: offset = %d, size = %d, type = %d", row, column, fieldDir[column].data.buffer.offset, fieldDir[column].data.buffer.size, fieldDir[column].type);

    // Copy the data to the out param
    slotOut->data.buffer.offset = fieldDir[column].data.buffer.offset;
    slotOut->data.buffer.size = fieldDir[column].data.buffer.size;
    slotOut->type = fieldDir[column].type;
    return 0;
}

void CursorWindow::copyIn(uint32_t offset, uint8_t const * data, size_t size)
{
    assert(offset + size <= mSize);    
    memcpy(mData + offset, data, size);
}

void CursorWindow::copyIn(uint32_t offset, int64_t data)
{
    assert(offset + sizeof(int64_t) <= mSize);
    memcpy(mData + offset, (uint8_t *)&data, sizeof(int64_t));
}

void CursorWindow::copyIn(uint32_t offset, double data)
{
    assert(offset + sizeof(double) <= mSize);
    memcpy(mData + offset, (uint8_t *)&data, sizeof(double));
}

void CursorWindow::copyOut(uint32_t offset, uint8_t * data, size_t size)
{
    assert(offset + size <= mSize);
    memcpy(data, mData + offset, size);
}

int64_t CursorWindow::copyOutLong(uint32_t offset)
{
    int64_t value;
    assert(offset + sizeof(int64_t) <= mSize);
    memcpy(&value, mData + offset, sizeof(int64_t));
    return value;
}

double CursorWindow::copyOutDouble(uint32_t offset)
{
    double value;
    assert(offset + sizeof(double) <= mSize);
    memcpy(&value, mData + offset, sizeof(double));
    return value;
}

bool CursorWindow::putLong(unsigned int row, unsigned int col, int64_t value)
{
    field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
    if (!fieldSlot) {
        return false;
    }

#if WINDOW_STORAGE_INLINE_NUMERICS
    fieldSlot->data.l = value;
#else
    int offset = alloc(sizeof(int64_t));
    if (!offset) {
        return false;
    }

    copyIn(offset, value);

    fieldSlot->data.buffer.offset = offset;
    fieldSlot->data.buffer.size = sizeof(int64_t);
#endif
    fieldSlot->type = FIELD_TYPE_INTEGER;
    return true;
}

bool CursorWindow::putDouble(unsigned int row, unsigned int col, double value)
{
    field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
    if (!fieldSlot) {
        return false;
    }

#if WINDOW_STORAGE_INLINE_NUMERICS
    fieldSlot->data.d = value;
#else
    int offset = alloc(sizeof(int64_t));
    if (!offset) {
        return false;
    }

    copyIn(offset, value);

    fieldSlot->data.buffer.offset = offset;
    fieldSlot->data.buffer.size = sizeof(double);
#endif
    fieldSlot->type = FIELD_TYPE_FLOAT;
    return true;
}

bool CursorWindow::putNull(unsigned int row, unsigned int col)
{
    field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
    if (!fieldSlot) {
        return false;
    }

    fieldSlot->type = FIELD_TYPE_NULL;
    fieldSlot->data.buffer.offset = 0;
    fieldSlot->data.buffer.size = 0;
    return true;
}

bool CursorWindow::getLong(unsigned int row, unsigned int col, int64_t * valueOut)
{
    field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
    if (!fieldSlot || fieldSlot->type != FIELD_TYPE_INTEGER) {
        return false;
    }
    
#if WINDOW_STORAGE_INLINE_NUMERICS
    *valueOut = fieldSlot->data.l;
#else
    *valueOut = copyOutLong(fieldSlot->data.buffer.offset);
#endif
    return true;
}

bool CursorWindow::getDouble(unsigned int row, unsigned int col, double * valueOut)
{
    field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
    if (!fieldSlot || fieldSlot->type != FIELD_TYPE_FLOAT) {
        return false;
    }

#if WINDOW_STORAGE_INLINE_NUMERICS
    *valueOut = fieldSlot->data.d;
#else
    *valueOut = copyOutDouble(fieldSlot->data.buffer.offset);
#endif
    return true;
}

bool CursorWindow::getNull(unsigned int row, unsigned int col, bool * valueOut)
{
    field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
    if (!fieldSlot) {
        return false;
    }
    
    if (fieldSlot->type != FIELD_TYPE_NULL) {
        *valueOut = false;
    } else {
        *valueOut = true;
    }
    return true;
}

}; // namespace android
Loading