2010-05-27 21:04:23 +00:00
/*
* 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 - - ;
2010-10-26 23:44:44 +00:00
LOG_WINDOW ( " The row failed, so back out the new row accounting from allocRowSlot %d " , mHeader - > numRows ) ;
2010-05-27 21:04:23 +00:00
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 ( ) ) {
2010-10-05 23:50:51 +00:00
LOGV ( " need to grow: mSize = %d, size = %d, freeSpace() = %d, numRows = %d " , mSize , size ,
freeSpace ( ) , mHeader - > numRows ) ;
2010-05-27 21:04:23 +00:00
// Only grow the window if the first row doesn't fit
if ( mHeader - > numRows > 1 ) {
2010-10-05 23:50:51 +00:00
LOGV ( " not growing since there are already %d row(s), max size %d " , mHeader - > numRows ,
mMaxSize ) ;
2010-05-27 21:04:23 +00:00
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 ) {
2010-11-29 19:22:22 +00:00
LOGE ( " Failed to read row# %d, column# from a CursorWindow which has %d rows, %d columns. " ,
row , column , mHeader - > numRows , mHeader - > numColumns ) ;
2010-05-27 21:04:23 +00:00
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 ;
}
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 ;
}
2011-10-06 20:11:04 +00:00
* valueOut = getFieldSlotValueLong ( fieldSlot ) ;
2010-05-27 21:04:23 +00:00
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 ;
}
2011-10-06 20:11:04 +00:00
* valueOut = getFieldSlotValueDouble ( fieldSlot ) ;
2010-05-27 21:04:23 +00:00
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