1/* 2 * Copyright (C) 2006-2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#undef LOG_TAG 18#define LOG_TAG "CursorWindow" 19 20#include <utils/Log.h> 21#include <binder/MemoryDealer.h> 22 23#include <assert.h> 24#include <string.h> 25#include <stdlib.h> 26 27#include <jni.h> 28#include <JNIHelp.h> 29 30#include "CursorWindow.h" 31 32 33namespace android { 34 35CursorWindow::CursorWindow(size_t maxSize) : 36 mMaxSize(maxSize) 37{ 38} 39 40bool CursorWindow::setMemory(sp<IMemory> memory) 41{ 42 mMemory = memory; 43 mData = (uint8_t *) memory->pointer(); 44 if (mData == NULL) { 45 return false; 46 } 47 mHeader = (window_header_t *) mData; 48 49 // Make the window read-only 50 mHeap = NULL; 51 ssize_t size = memory->size(); 52 mSize = size; 53 mMaxSize = size; 54 mFreeOffset = size; 55LOG_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); 56 return true; 57} 58 59bool CursorWindow::initBuffer(bool localOnly) 60{ 61 //TODO Use a non-memory dealer mmap region for localOnly 62 63 mHeap = new MemoryDealer(new SharedHeap(mMaxSize, 0, "CursorWindow")); 64 if (mHeap != NULL) { 65 mMemory = mHeap->allocate(mMaxSize); 66 if (mMemory != NULL) { 67 mData = (uint8_t *) mMemory->pointer(); 68 if (mData) { 69 mHeader = (window_header_t *) mData; 70 mSize = mMaxSize; 71 72 // Put the window into a clean state 73 clear(); 74 LOG_WINDOW("Created CursorWindow with new MemoryDealer: mFreeOffset = %d, mSize = %d, mMaxSize = %d, mData = %p", mFreeOffset, mSize, mMaxSize, mData); 75 return true; 76 } 77 } 78 LOGE("memory dealer allocation failed"); 79 return false; 80 } else { 81 LOGE("failed to create the memory dealer"); 82 return false; 83 } 84} 85 86CursorWindow::~CursorWindow() 87{ 88 // Everything that matters is a smart pointer 89} 90 91void CursorWindow::clear() 92{ 93 mHeader->numRows = 0; 94 mHeader->numColumns = 0; 95 mFreeOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE; 96 // Mark the first chunk's next 'pointer' as null 97 *((uint32_t *)(mData + mFreeOffset - sizeof(uint32_t))) = 0; 98} 99 100int32_t CursorWindow::freeSpace() 101{ 102 int32_t freeSpace = mSize - mFreeOffset; 103 if (freeSpace < 0) { 104 freeSpace = 0; 105 } 106 return freeSpace; 107} 108 109field_slot_t * CursorWindow::allocRow() 110{ 111 // Fill in the row slot 112 row_slot_t * rowSlot = allocRowSlot(); 113 if (rowSlot == NULL) { 114 return NULL; 115 } 116 117 // Allocate the slots for the field directory 118 size_t fieldDirSize = mHeader->numColumns * sizeof(field_slot_t); 119 uint32_t fieldDirOffset = alloc(fieldDirSize); 120 if (!fieldDirOffset) { 121 mHeader->numRows--; 122 LOGE("The row failed, so back out the new row accounting from allocRowSlot %d", mHeader->numRows); 123 return NULL; 124 } 125 field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(fieldDirOffset); 126 memset(fieldDir, 0x0, fieldDirSize); 127 128LOG_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); 129 rowSlot->offset = fieldDirOffset; 130 131 return fieldDir; 132} 133 134uint32_t CursorWindow::alloc(size_t requestedSize, bool aligned) 135{ 136 int32_t size; 137 uint32_t padding; 138 if (aligned) { 139 // 4 byte alignment 140 padding = 4 - (mFreeOffset & 0x3); 141 } else { 142 padding = 0; 143 } 144 145 size = requestedSize + padding; 146 147 if (size > freeSpace()) { 148 LOGE("need to grow: mSize = %d, size = %d, freeSpace() = %d, numRows = %d", mSize, size, freeSpace(), mHeader->numRows); 149 // Only grow the window if the first row doesn't fit 150 if (mHeader->numRows > 1) { 151LOGE("not growing since there are already %d row(s), max size %d", mHeader->numRows, mMaxSize); 152 return 0; 153 } 154 155 // Find a new size that will fit the allocation 156 int allocated = mSize - freeSpace(); 157 int newSize = mSize + WINDOW_ALLOCATION_SIZE; 158 while (size > (newSize - allocated)) { 159 newSize += WINDOW_ALLOCATION_SIZE; 160 if (newSize > mMaxSize) { 161 LOGE("Attempting to grow window beyond max size (%d)", mMaxSize); 162 return 0; 163 } 164 } 165LOG_WINDOW("found size %d", newSize); 166 mSize = newSize; 167 } 168 169 uint32_t offset = mFreeOffset + padding; 170 mFreeOffset += size; 171 return offset; 172} 173 174row_slot_t * CursorWindow::getRowSlot(int row) 175{ 176 LOG_WINDOW("enter getRowSlot current row num %d, this row %d", mHeader->numRows, row); 177 int chunkNum = row / ROW_SLOT_CHUNK_NUM_ROWS; 178 int chunkPos = row % ROW_SLOT_CHUNK_NUM_ROWS; 179 int chunkPtrOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t); 180 uint8_t * rowChunk = mData + sizeof(window_header_t); 181 for (int i = 0; i < chunkNum; i++) { 182 rowChunk = offsetToPtr(*((uint32_t *)(mData + chunkPtrOffset))); 183 chunkPtrOffset = rowChunk - mData + (ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t)); 184 } 185 return (row_slot_t *)(rowChunk + (chunkPos * sizeof(row_slot_t))); 186 LOG_WINDOW("exit getRowSlot current row num %d, this row %d", mHeader->numRows, row); 187} 188 189row_slot_t * CursorWindow::allocRowSlot() 190{ 191 int chunkNum = mHeader->numRows / ROW_SLOT_CHUNK_NUM_ROWS; 192 int chunkPos = mHeader->numRows % ROW_SLOT_CHUNK_NUM_ROWS; 193 int chunkPtrOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t); 194 uint8_t * rowChunk = mData + sizeof(window_header_t); 195LOG_WINDOW("Allocating row slot, mHeader->numRows is %d, chunkNum is %d, chunkPos is %d", mHeader->numRows, chunkNum, chunkPos); 196 for (int i = 0; i < chunkNum; i++) { 197 uint32_t nextChunkOffset = *((uint32_t *)(mData + chunkPtrOffset)); 198LOG_WINDOW("nextChunkOffset is %d", nextChunkOffset); 199 if (nextChunkOffset == 0) { 200 // Allocate a new row chunk 201 nextChunkOffset = alloc(ROW_SLOT_CHUNK_SIZE, true); 202 if (nextChunkOffset == 0) { 203 return NULL; 204 } 205 rowChunk = offsetToPtr(nextChunkOffset); 206LOG_WINDOW("allocated new chunk at %d, rowChunk = %p", nextChunkOffset, rowChunk); 207 *((uint32_t *)(mData + chunkPtrOffset)) = rowChunk - mData; 208 // Mark the new chunk's next 'pointer' as null 209 *((uint32_t *)(rowChunk + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t))) = 0; 210 } else { 211LOG_WINDOW("follwing 'pointer' to next chunk, offset of next pointer is %d", chunkPtrOffset); 212 rowChunk = offsetToPtr(nextChunkOffset); 213 chunkPtrOffset = rowChunk - mData + (ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t)); 214 } 215 } 216 mHeader->numRows++; 217 218 return (row_slot_t *)(rowChunk + (chunkPos * sizeof(row_slot_t))); 219} 220 221field_slot_t * CursorWindow::getFieldSlotWithCheck(int row, int column) 222{ 223 if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) { 224 LOGE("Bad request for field slot %d,%d. numRows = %d, numColumns = %d", row, column, mHeader->numRows, mHeader->numColumns); 225 return NULL; 226 } 227 row_slot_t * rowSlot = getRowSlot(row); 228 if (!rowSlot) { 229 LOGE("Failed to find rowSlot for row %d", row); 230 return NULL; 231 } 232 if (rowSlot->offset == 0 || rowSlot->offset >= mSize) { 233 LOGE("Invalid rowSlot, offset = %d", rowSlot->offset); 234 return NULL; 235 } 236 int fieldDirOffset = rowSlot->offset; 237 return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column; 238} 239 240uint32_t CursorWindow::read_field_slot(int row, int column, field_slot_t * slotOut) 241{ 242 if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) { 243 LOGE("Bad request for field slot %d,%d. numRows = %d, numColumns = %d", row, column, mHeader->numRows, mHeader->numColumns); 244 return -1; 245 } 246 row_slot_t * rowSlot = getRowSlot(row); 247 if (!rowSlot) { 248 LOGE("Failed to find rowSlot for row %d", row); 249 return -1; 250 } 251 if (rowSlot->offset == 0 || rowSlot->offset >= mSize) { 252 LOGE("Invalid rowSlot, offset = %d", rowSlot->offset); 253 return -1; 254 } 255LOG_WINDOW("Found field directory for %d,%d at rowSlot %d, offset %d", row, column, (uint8_t *)rowSlot - mData, rowSlot->offset); 256 field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(rowSlot->offset); 257LOG_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); 258 259 // Copy the data to the out param 260 slotOut->data.buffer.offset = fieldDir[column].data.buffer.offset; 261 slotOut->data.buffer.size = fieldDir[column].data.buffer.size; 262 slotOut->type = fieldDir[column].type; 263 return 0; 264} 265 266void CursorWindow::copyIn(uint32_t offset, uint8_t const * data, size_t size) 267{ 268 assert(offset + size <= mSize); 269 memcpy(mData + offset, data, size); 270} 271 272void CursorWindow::copyIn(uint32_t offset, int64_t data) 273{ 274 assert(offset + sizeof(int64_t) <= mSize); 275 memcpy(mData + offset, (uint8_t *)&data, sizeof(int64_t)); 276} 277 278void CursorWindow::copyIn(uint32_t offset, double data) 279{ 280 assert(offset + sizeof(double) <= mSize); 281 memcpy(mData + offset, (uint8_t *)&data, sizeof(double)); 282} 283 284void CursorWindow::copyOut(uint32_t offset, uint8_t * data, size_t size) 285{ 286 assert(offset + size <= mSize); 287 memcpy(data, mData + offset, size); 288} 289 290int64_t CursorWindow::copyOutLong(uint32_t offset) 291{ 292 int64_t value; 293 assert(offset + sizeof(int64_t) <= mSize); 294 memcpy(&value, mData + offset, sizeof(int64_t)); 295 return value; 296} 297 298double CursorWindow::copyOutDouble(uint32_t offset) 299{ 300 double value; 301 assert(offset + sizeof(double) <= mSize); 302 memcpy(&value, mData + offset, sizeof(double)); 303 return value; 304} 305 306bool CursorWindow::putLong(unsigned int row, unsigned int col, int64_t value) 307{ 308 field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); 309 if (!fieldSlot) { 310 return false; 311 } 312 313#if WINDOW_STORAGE_INLINE_NUMERICS 314 fieldSlot->data.l = value; 315#else 316 int offset = alloc(sizeof(int64_t)); 317 if (!offset) { 318 return false; 319 } 320 321 copyIn(offset, value); 322 323 fieldSlot->data.buffer.offset = offset; 324 fieldSlot->data.buffer.size = sizeof(int64_t); 325#endif 326 fieldSlot->type = FIELD_TYPE_INTEGER; 327 return true; 328} 329 330bool CursorWindow::putDouble(unsigned int row, unsigned int col, double value) 331{ 332 field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); 333 if (!fieldSlot) { 334 return false; 335 } 336 337#if WINDOW_STORAGE_INLINE_NUMERICS 338 fieldSlot->data.d = value; 339#else 340 int offset = alloc(sizeof(int64_t)); 341 if (!offset) { 342 return false; 343 } 344 345 copyIn(offset, value); 346 347 fieldSlot->data.buffer.offset = offset; 348 fieldSlot->data.buffer.size = sizeof(double); 349#endif 350 fieldSlot->type = FIELD_TYPE_FLOAT; 351 return true; 352} 353 354bool CursorWindow::putNull(unsigned int row, unsigned int col) 355{ 356 field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); 357 if (!fieldSlot) { 358 return false; 359 } 360 361 fieldSlot->type = FIELD_TYPE_NULL; 362 fieldSlot->data.buffer.offset = 0; 363 fieldSlot->data.buffer.size = 0; 364 return true; 365} 366 367bool CursorWindow::getLong(unsigned int row, unsigned int col, int64_t * valueOut) 368{ 369 field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); 370 if (!fieldSlot || fieldSlot->type != FIELD_TYPE_INTEGER) { 371 return false; 372 } 373 374#if WINDOW_STORAGE_INLINE_NUMERICS 375 *valueOut = fieldSlot->data.l; 376#else 377 *valueOut = copyOutLong(fieldSlot->data.buffer.offset); 378#endif 379 return true; 380} 381 382bool CursorWindow::getDouble(unsigned int row, unsigned int col, double * valueOut) 383{ 384 field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); 385 if (!fieldSlot || fieldSlot->type != FIELD_TYPE_FLOAT) { 386 return false; 387 } 388 389#if WINDOW_STORAGE_INLINE_NUMERICS 390 *valueOut = fieldSlot->data.d; 391#else 392 *valueOut = copyOutDouble(fieldSlot->data.buffer.offset); 393#endif 394 return true; 395} 396 397bool CursorWindow::getNull(unsigned int row, unsigned int col, bool * valueOut) 398{ 399 field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); 400 if (!fieldSlot) { 401 return false; 402 } 403 404 if (fieldSlot->type != FIELD_TYPE_NULL) { 405 *valueOut = false; 406 } else { 407 *valueOut = true; 408 } 409 return true; 410} 411 412}; // namespace android 413