PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/androidfw/CursorWindow.cpp

https://bitbucket.org/Lloir/miragebase
C++ | 351 lines | 287 code | 46 blank | 18 comment | 52 complexity | c1a17c2180351ed5f66e83a25099493a MD5 | raw file
  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. #undef LOG_TAG
  17. #define LOG_TAG "CursorWindow"
  18. #include <utils/Log.h>
  19. #include <androidfw/CursorWindow.h>
  20. #include <cutils/ashmem.h>
  21. #include <sys/mman.h>
  22. #include <assert.h>
  23. #include <string.h>
  24. #include <stdlib.h>
  25. namespace android {
  26. CursorWindow::CursorWindow(const String8& name, int ashmemFd,
  27. void* data, size_t size, bool readOnly) :
  28. mName(name), mAshmemFd(ashmemFd), mData(data), mSize(size), mReadOnly(readOnly) {
  29. mHeader = static_cast<Header*>(mData);
  30. }
  31. CursorWindow::~CursorWindow() {
  32. ::munmap(mData, mSize);
  33. ::close(mAshmemFd);
  34. }
  35. status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {
  36. String8 ashmemName("CursorWindow: ");
  37. ashmemName.append(name);
  38. status_t result;
  39. int ashmemFd = ashmem_create_region(ashmemName.string(), size);
  40. if (ashmemFd < 0) {
  41. result = -errno;
  42. } else {
  43. result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
  44. if (result >= 0) {
  45. void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0);
  46. if (data == MAP_FAILED) {
  47. result = -errno;
  48. } else {
  49. result = ashmem_set_prot_region(ashmemFd, PROT_READ);
  50. if (result >= 0) {
  51. CursorWindow* window = new CursorWindow(name, ashmemFd,
  52. data, size, false /*readOnly*/);
  53. result = window->clear();
  54. if (!result) {
  55. LOG_WINDOW("Created new CursorWindow: freeOffset=%d, "
  56. "numRows=%d, numColumns=%d, mSize=%d, mData=%p",
  57. window->mHeader->freeOffset,
  58. window->mHeader->numRows,
  59. window->mHeader->numColumns,
  60. window->mSize, window->mData);
  61. *outCursorWindow = window;
  62. return OK;
  63. }
  64. delete window;
  65. }
  66. }
  67. ::munmap(data, size);
  68. }
  69. ::close(ashmemFd);
  70. }
  71. *outCursorWindow = NULL;
  72. return result;
  73. }
  74. status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow) {
  75. String8 name = parcel->readString8();
  76. status_t result;
  77. int ashmemFd = parcel->readFileDescriptor();
  78. if (ashmemFd == int(BAD_TYPE)) {
  79. result = BAD_TYPE;
  80. } else {
  81. ssize_t size = ashmem_get_size_region(ashmemFd);
  82. if (size < 0) {
  83. result = UNKNOWN_ERROR;
  84. } else {
  85. int dupAshmemFd = ::dup(ashmemFd);
  86. if (dupAshmemFd < 0) {
  87. result = -errno;
  88. } else {
  89. void* data = ::mmap(NULL, size, PROT_READ, MAP_SHARED, dupAshmemFd, 0);
  90. if (data == MAP_FAILED) {
  91. result = -errno;
  92. } else {
  93. CursorWindow* window = new CursorWindow(name, dupAshmemFd,
  94. data, size, true /*readOnly*/);
  95. LOG_WINDOW("Created CursorWindow from parcel: freeOffset=%d, "
  96. "numRows=%d, numColumns=%d, mSize=%d, mData=%p",
  97. window->mHeader->freeOffset,
  98. window->mHeader->numRows,
  99. window->mHeader->numColumns,
  100. window->mSize, window->mData);
  101. *outCursorWindow = window;
  102. return OK;
  103. }
  104. ::close(dupAshmemFd);
  105. }
  106. }
  107. }
  108. *outCursorWindow = NULL;
  109. return result;
  110. }
  111. status_t CursorWindow::writeToParcel(Parcel* parcel) {
  112. status_t status = parcel->writeString8(mName);
  113. if (!status) {
  114. status = parcel->writeDupFileDescriptor(mAshmemFd);
  115. }
  116. return status;
  117. }
  118. status_t CursorWindow::clear() {
  119. if (mReadOnly) {
  120. return INVALID_OPERATION;
  121. }
  122. mHeader->freeOffset = sizeof(Header) + sizeof(RowSlotChunk);
  123. mHeader->firstChunkOffset = sizeof(Header);
  124. mHeader->numRows = 0;
  125. mHeader->numColumns = 0;
  126. RowSlotChunk* firstChunk = static_cast<RowSlotChunk*>(offsetToPtr(mHeader->firstChunkOffset));
  127. firstChunk->nextChunkOffset = 0;
  128. return OK;
  129. }
  130. status_t CursorWindow::setNumColumns(uint32_t numColumns) {
  131. if (mReadOnly) {
  132. return INVALID_OPERATION;
  133. }
  134. uint32_t cur = mHeader->numColumns;
  135. if ((cur > 0 || mHeader->numRows > 0) && cur != numColumns) {
  136. ALOGE("Trying to go from %d columns to %d", cur, numColumns);
  137. return INVALID_OPERATION;
  138. }
  139. mHeader->numColumns = numColumns;
  140. return OK;
  141. }
  142. status_t CursorWindow::allocRow() {
  143. if (mReadOnly) {
  144. return INVALID_OPERATION;
  145. }
  146. // Fill in the row slot
  147. RowSlot* rowSlot = allocRowSlot();
  148. if (rowSlot == NULL) {
  149. return NO_MEMORY;
  150. }
  151. // Allocate the slots for the field directory
  152. size_t fieldDirSize = mHeader->numColumns * sizeof(FieldSlot);
  153. uint32_t fieldDirOffset = alloc(fieldDirSize, true /*aligned*/);
  154. if (!fieldDirOffset) {
  155. mHeader->numRows--;
  156. LOG_WINDOW("The row failed, so back out the new row accounting "
  157. "from allocRowSlot %d", mHeader->numRows);
  158. return NO_MEMORY;
  159. }
  160. FieldSlot* fieldDir = static_cast<FieldSlot*>(offsetToPtr(fieldDirOffset));
  161. memset(fieldDir, 0, fieldDirSize);
  162. LOG_WINDOW("Allocated row %u, rowSlot is at offset %u, fieldDir is %d bytes at offset %u\n",
  163. mHeader->numRows - 1, offsetFromPtr(rowSlot), fieldDirSize, fieldDirOffset);
  164. rowSlot->offset = fieldDirOffset;
  165. return OK;
  166. }
  167. status_t CursorWindow::freeLastRow() {
  168. if (mReadOnly) {
  169. return INVALID_OPERATION;
  170. }
  171. if (mHeader->numRows > 0) {
  172. mHeader->numRows--;
  173. }
  174. return OK;
  175. }
  176. uint32_t CursorWindow::alloc(size_t size, bool aligned) {
  177. uint32_t padding;
  178. if (aligned) {
  179. // 4 byte alignment
  180. padding = (~mHeader->freeOffset + 1) & 3;
  181. } else {
  182. padding = 0;
  183. }
  184. uint32_t offset = mHeader->freeOffset + padding;
  185. uint32_t nextFreeOffset = offset + size;
  186. if (nextFreeOffset > mSize) {
  187. ALOGW("Window is full: requested allocation %d bytes, "
  188. "free space %d bytes, window size %d bytes",
  189. size, freeSpace(), mSize);
  190. return 0;
  191. }
  192. mHeader->freeOffset = nextFreeOffset;
  193. return offset;
  194. }
  195. CursorWindow::RowSlot* CursorWindow::getRowSlot(uint32_t row) {
  196. uint32_t chunkPos = row;
  197. RowSlotChunk* chunk = static_cast<RowSlotChunk*>(
  198. offsetToPtr(mHeader->firstChunkOffset));
  199. while (chunkPos >= ROW_SLOT_CHUNK_NUM_ROWS) {
  200. chunk = static_cast<RowSlotChunk*>(offsetToPtr(chunk->nextChunkOffset));
  201. chunkPos -= ROW_SLOT_CHUNK_NUM_ROWS;
  202. }
  203. return &chunk->slots[chunkPos];
  204. }
  205. CursorWindow::RowSlot* CursorWindow::allocRowSlot() {
  206. uint32_t chunkPos = mHeader->numRows;
  207. RowSlotChunk* chunk = static_cast<RowSlotChunk*>(
  208. offsetToPtr(mHeader->firstChunkOffset));
  209. while (chunkPos > ROW_SLOT_CHUNK_NUM_ROWS) {
  210. chunk = static_cast<RowSlotChunk*>(offsetToPtr(chunk->nextChunkOffset));
  211. chunkPos -= ROW_SLOT_CHUNK_NUM_ROWS;
  212. }
  213. if (chunkPos == ROW_SLOT_CHUNK_NUM_ROWS) {
  214. if (!chunk->nextChunkOffset) {
  215. chunk->nextChunkOffset = alloc(sizeof(RowSlotChunk), true /*aligned*/);
  216. if (!chunk->nextChunkOffset) {
  217. return NULL;
  218. }
  219. }
  220. chunk = static_cast<RowSlotChunk*>(offsetToPtr(chunk->nextChunkOffset));
  221. chunk->nextChunkOffset = 0;
  222. chunkPos = 0;
  223. }
  224. mHeader->numRows += 1;
  225. return &chunk->slots[chunkPos];
  226. }
  227. CursorWindow::FieldSlot* CursorWindow::getFieldSlot(uint32_t row, uint32_t column) {
  228. if (row >= mHeader->numRows || column >= mHeader->numColumns) {
  229. ALOGE("Failed to read row %d, column %d from a CursorWindow which "
  230. "has %d rows, %d columns.",
  231. row, column, mHeader->numRows, mHeader->numColumns);
  232. return NULL;
  233. }
  234. RowSlot* rowSlot = getRowSlot(row);
  235. if (!rowSlot) {
  236. ALOGE("Failed to find rowSlot for row %d.", row);
  237. return NULL;
  238. }
  239. FieldSlot* fieldDir = static_cast<FieldSlot*>(offsetToPtr(rowSlot->offset));
  240. return &fieldDir[column];
  241. }
  242. status_t CursorWindow::putBlob(uint32_t row, uint32_t column, const void* value, size_t size) {
  243. return putBlobOrString(row, column, value, size, FIELD_TYPE_BLOB);
  244. }
  245. status_t CursorWindow::putString(uint32_t row, uint32_t column, const char* value,
  246. size_t sizeIncludingNull) {
  247. return putBlobOrString(row, column, value, sizeIncludingNull, FIELD_TYPE_STRING);
  248. }
  249. status_t CursorWindow::putBlobOrString(uint32_t row, uint32_t column,
  250. const void* value, size_t size, int32_t type) {
  251. if (mReadOnly) {
  252. return INVALID_OPERATION;
  253. }
  254. FieldSlot* fieldSlot = getFieldSlot(row, column);
  255. if (!fieldSlot) {
  256. return BAD_VALUE;
  257. }
  258. uint32_t offset = alloc(size);
  259. if (!offset) {
  260. return NO_MEMORY;
  261. }
  262. memcpy(offsetToPtr(offset), value, size);
  263. fieldSlot->type = type;
  264. fieldSlot->data.buffer.offset = offset;
  265. fieldSlot->data.buffer.size = size;
  266. return OK;
  267. }
  268. status_t CursorWindow::putLong(uint32_t row, uint32_t column, int64_t value) {
  269. if (mReadOnly) {
  270. return INVALID_OPERATION;
  271. }
  272. FieldSlot* fieldSlot = getFieldSlot(row, column);
  273. if (!fieldSlot) {
  274. return BAD_VALUE;
  275. }
  276. fieldSlot->type = FIELD_TYPE_INTEGER;
  277. fieldSlot->data.l = value;
  278. return OK;
  279. }
  280. status_t CursorWindow::putDouble(uint32_t row, uint32_t column, double value) {
  281. if (mReadOnly) {
  282. return INVALID_OPERATION;
  283. }
  284. FieldSlot* fieldSlot = getFieldSlot(row, column);
  285. if (!fieldSlot) {
  286. return BAD_VALUE;
  287. }
  288. fieldSlot->type = FIELD_TYPE_FLOAT;
  289. fieldSlot->data.d = value;
  290. return OK;
  291. }
  292. status_t CursorWindow::putNull(uint32_t row, uint32_t column) {
  293. if (mReadOnly) {
  294. return INVALID_OPERATION;
  295. }
  296. FieldSlot* fieldSlot = getFieldSlot(row, column);
  297. if (!fieldSlot) {
  298. return BAD_VALUE;
  299. }
  300. fieldSlot->type = FIELD_TYPE_NULL;
  301. fieldSlot->data.buffer.offset = 0;
  302. fieldSlot->data.buffer.size = 0;
  303. return OK;
  304. }
  305. }; // namespace android