summaryrefslogtreecommitdiff
path: root/libs/androidfw/CursorWindow.cpp
diff options
context:
space:
mode:
authorScott Lobdell <slobdell@google.com>2020-10-15 11:45:45 -0700
committerDaniel Norman <danielnorman@google.com>2020-10-27 13:09:24 -0700
commit449f659b21d039b8692602294b040038ac1e6ccb (patch)
tree8d7f4ce2697ad1b591d2f953e69656bc9b0a4080 /libs/androidfw/CursorWindow.cpp
parent5cced294627474a5a42b42e442a50690d5c76661 (diff)
parentfb4ede1992df0344082bbdac60bcbc2a3a0a65ba (diff)
Merge SP1A.201015.001
Change-Id: Ie33f12a2f4c73443640c28ad128be96b3533fd8c
Diffstat (limited to 'libs/androidfw/CursorWindow.cpp')
-rw-r--r--libs/androidfw/CursorWindow.cpp193
1 files changed, 155 insertions, 38 deletions
diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp
index 6f05cbd0ebb3..71c8e1f6121f 100644
--- a/libs/androidfw/CursorWindow.cpp
+++ b/libs/androidfw/CursorWindow.cpp
@@ -30,23 +30,62 @@
namespace android {
-CursorWindow::CursorWindow(const String8& name, int ashmemFd,
- void* data, size_t size, bool readOnly) :
- mName(name), mAshmemFd(ashmemFd), mData(data), mSize(size), mReadOnly(readOnly) {
+/**
+ * By default windows are lightweight inline allocations of this size;
+ * they're only inflated to ashmem regions when more space is needed.
+ */
+static constexpr const size_t kInlineSize = 16384;
+
+CursorWindow::CursorWindow(const String8& name, int ashmemFd, void* data, size_t size,
+ size_t inflatedSize, bool readOnly) :
+ mName(name), mAshmemFd(ashmemFd), mData(data), mSize(size),
+ mInflatedSize(inflatedSize), mReadOnly(readOnly) {
mHeader = static_cast<Header*>(mData);
}
CursorWindow::~CursorWindow() {
- ::munmap(mData, mSize);
- ::close(mAshmemFd);
+ if (mAshmemFd != -1) {
+ ::munmap(mData, mSize);
+ ::close(mAshmemFd);
+ } else {
+ free(mData);
+ }
+}
+
+status_t CursorWindow::create(const String8& name, size_t inflatedSize,
+ CursorWindow** outCursorWindow) {
+ *outCursorWindow = nullptr;
+
+ size_t size = std::min(kInlineSize, inflatedSize);
+ void* data = calloc(size, 1);
+ if (!data) return NO_MEMORY;
+
+ CursorWindow* window = new CursorWindow(name, -1, data, size,
+ inflatedSize, false /*readOnly*/);
+ status_t result = window->clear();
+ if (!result) {
+ LOG_WINDOW("Created new CursorWindow: freeOffset=%d, "
+ "numRows=%d, numColumns=%d, mSize=%zu, mData=%p",
+ window->mHeader->freeOffset,
+ window->mHeader->numRows,
+ window->mHeader->numColumns,
+ window->mSize, window->mData);
+ *outCursorWindow = window;
+ return OK;
+ }
+ delete window;
+ return result;
}
-status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {
+status_t CursorWindow::inflate() {
+ // Shortcut when we can't expand any further
+ if (mSize == mInflatedSize) return INVALID_OPERATION;
+
String8 ashmemName("CursorWindow: ");
- ashmemName.append(name);
+ ashmemName.append(mName);
status_t result;
- int ashmemFd = ashmem_create_region(ashmemName.string(), size);
+ int ashmemFd = ashmem_create_region(ashmemName.string(), mInflatedSize);
if (ashmemFd < 0) {
result = -errno;
ALOGE("CursorWindow: ashmem_create_region() failed: errno=%d.", errno);
@@ -55,7 +94,8 @@ status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** o
if (result < 0) {
ALOGE("CursorWindow: ashmem_set_prot_region() failed: errno=%d",errno);
} else {
- void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0);
+ void* data = ::mmap(NULL, mInflatedSize, PROT_READ | PROT_WRITE,
+ MAP_SHARED, ashmemFd, 0);
if (data == MAP_FAILED) {
result = -errno;
ALOGE("CursorWindow: mmap() failed: errno=%d.", errno);
@@ -64,33 +104,49 @@ status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** o
if (result < 0) {
ALOGE("CursorWindow: ashmem_set_prot_region() failed: errno=%d.", errno);
} else {
- CursorWindow* window = new CursorWindow(name, ashmemFd,
- data, size, false /*readOnly*/);
- result = window->clear();
- if (!result) {
- LOG_WINDOW("Created new CursorWindow: freeOffset=%d, "
- "numRows=%d, numColumns=%d, mSize=%zu, mData=%p",
- window->mHeader->freeOffset,
- window->mHeader->numRows,
- window->mHeader->numColumns,
- window->mSize, window->mData);
- *outCursorWindow = window;
- return OK;
- }
- delete window;
+ // Move inline contents into new ashmem region
+ memcpy(data, mData, mSize);
+ free(mData);
+ mAshmemFd = ashmemFd;
+ mData = data;
+ mHeader = static_cast<Header*>(mData);
+ mSize = mInflatedSize;
+ LOG_WINDOW("Inflated CursorWindow: freeOffset=%d, "
+ "numRows=%d, numColumns=%d, mSize=%zu, mData=%p",
+ mHeader->freeOffset,
+ mHeader->numRows,
+ mHeader->numColumns,
+ mSize, mData);
+ return OK;
}
}
- ::munmap(data, size);
+ ::munmap(data, mInflatedSize);
}
::close(ashmemFd);
}
- *outCursorWindow = NULL;
return result;
}
status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow) {
- String8 name = parcel->readString8();
+ *outCursorWindow = nullptr;
+
+ String8 name;
+ status_t result = parcel->readString8(&name);
+ if (result) return result;
+
+ bool isAshmem;
+ result = parcel->readBool(&isAshmem);
+ if (result) return result;
+ if (isAshmem) {
+ return createFromParcelAshmem(parcel, name, outCursorWindow);
+ } else {
+ return createFromParcelInline(parcel, name, outCursorWindow);
+ }
+}
+
+status_t CursorWindow::createFromParcelAshmem(Parcel* parcel, String8& name,
+ CursorWindow** outCursorWindow) {
status_t result;
int actualSize;
int ashmemFd = parcel->readFileDescriptor();
@@ -122,8 +178,8 @@ status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursor
actualSize, (int) size, errno);
} else {
CursorWindow* window = new CursorWindow(name, dupAshmemFd,
- data, size, true /*readOnly*/);
- LOG_WINDOW("Created CursorWindow from parcel: freeOffset=%d, "
+ data, size, size, true /*readOnly*/);
+ LOG_WINDOW("Created CursorWindow from ashmem parcel: freeOffset=%d, "
"numRows=%d, numColumns=%d, mSize=%zu, mData=%p",
window->mHeader->freeOffset,
window->mHeader->numRows,
@@ -140,12 +196,62 @@ status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursor
return result;
}
+status_t CursorWindow::createFromParcelInline(Parcel* parcel, String8& name,
+ CursorWindow** outCursorWindow) {
+ uint32_t sentSize;
+ status_t result = parcel->readUint32(&sentSize);
+ if (result) return result;
+ if (sentSize > kInlineSize) return NO_MEMORY;
+
+ void* data = calloc(sentSize, 1);
+ if (!data) return NO_MEMORY;
+
+ result = parcel->read(data, sentSize);
+ if (result) return result;
+
+ CursorWindow* window = new CursorWindow(name, -1, data, sentSize,
+ sentSize, true /*readOnly*/);
+ LOG_WINDOW("Created CursorWindow from inline parcel: freeOffset=%d, "
+ "numRows=%d, numColumns=%d, mSize=%zu, mData=%p",
+ window->mHeader->freeOffset,
+ window->mHeader->numRows,
+ window->mHeader->numColumns,
+ window->mSize, window->mData);
+ *outCursorWindow = window;
+ return OK;
+}
+
status_t CursorWindow::writeToParcel(Parcel* parcel) {
- status_t status = parcel->writeString8(mName);
- if (!status) {
- status = parcel->writeDupFileDescriptor(mAshmemFd);
+ LOG_WINDOW("Writing CursorWindow: freeOffset=%d, "
+ "numRows=%d, numColumns=%d, mSize=%zu, mData=%p",
+ mHeader->freeOffset,
+ mHeader->numRows,
+ mHeader->numColumns,
+ mSize, mData);
+
+ status_t result = parcel->writeString8(mName);
+ if (result) return result;
+
+ if (mAshmemFd != -1) {
+ result = parcel->writeBool(true);
+ if (result) return result;
+ return writeToParcelAshmem(parcel);
+ } else {
+ result = parcel->writeBool(false);
+ if (result) return result;
+ return writeToParcelInline(parcel);
}
- return status;
+}
+
+status_t CursorWindow::writeToParcelAshmem(Parcel* parcel) {
+ return parcel->writeDupFileDescriptor(mAshmemFd);
+}
+
+status_t CursorWindow::writeToParcelInline(Parcel* parcel) {
+ status_t result = parcel->writeUint32(mHeader->freeOffset);
+ if (result) return result;
+
+ return parcel->write(mData, mHeader->freeOffset);
}
status_t CursorWindow::clear() {
@@ -187,6 +293,7 @@ status_t CursorWindow::allocRow() {
if (rowSlot == NULL) {
return NO_MEMORY;
}
+ uint32_t rowSlotOffset = offsetFromPtr(rowSlot);
// Allocate the slots for the field directory
size_t fieldDirSize = mHeader->numColumns * sizeof(FieldSlot);
@@ -201,7 +308,8 @@ status_t CursorWindow::allocRow() {
memset(fieldDir, 0, fieldDirSize);
LOG_WINDOW("Allocated row %u, rowSlot is at offset %u, fieldDir is %zu bytes at offset %u\n",
- mHeader->numRows - 1, offsetFromPtr(rowSlot), fieldDirSize, fieldDirOffset);
+ mHeader->numRows - 1, rowSlotOffset, fieldDirSize, fieldDirOffset);
+ rowSlot = static_cast<RowSlot*>(offsetToPtr(rowSlotOffset));
rowSlot->offset = fieldDirOffset;
return OK;
}
@@ -229,10 +337,14 @@ uint32_t CursorWindow::alloc(size_t size, bool aligned) {
uint32_t offset = mHeader->freeOffset + padding;
uint32_t nextFreeOffset = offset + size;
if (nextFreeOffset > mSize) {
- ALOGW("Window is full: requested allocation %zu bytes, "
- "free space %zu bytes, window size %zu bytes",
- size, freeSpace(), mSize);
- return 0;
+ // Try inflating to ashmem before finally giving up
+ inflate();
+ if (nextFreeOffset > mSize) {
+ ALOGW("Window is full: requested allocation %zu bytes, "
+ "free space %zu bytes, window size %zu bytes",
+ size, freeSpace(), mSize);
+ return 0;
+ }
}
mHeader->freeOffset = nextFreeOffset;
@@ -260,7 +372,10 @@ CursorWindow::RowSlot* CursorWindow::allocRowSlot() {
}
if (chunkPos == ROW_SLOT_CHUNK_NUM_ROWS) {
if (!chunk->nextChunkOffset) {
- chunk->nextChunkOffset = alloc(sizeof(RowSlotChunk), true /*aligned*/);
+ uint32_t chunkOffset = offsetFromPtr(chunk);
+ uint32_t newChunk = alloc(sizeof(RowSlotChunk), true /*aligned*/);
+ chunk = static_cast<RowSlotChunk*>(offsetToPtr(chunkOffset));
+ chunk->nextChunkOffset = newChunk;
if (!chunk->nextChunkOffset) {
return NULL;
}
@@ -308,6 +423,7 @@ status_t CursorWindow::putBlobOrString(uint32_t row, uint32_t column,
if (!fieldSlot) {
return BAD_VALUE;
}
+ uint32_t fieldSlotOffset = offsetFromPtr(fieldSlot);
uint32_t offset = alloc(size);
if (!offset) {
@@ -316,6 +432,7 @@ status_t CursorWindow::putBlobOrString(uint32_t row, uint32_t column,
memcpy(offsetToPtr(offset), value, size);
+ fieldSlot = static_cast<FieldSlot*>(offsetToPtr(fieldSlotOffset));
fieldSlot->type = type;
fieldSlot->data.buffer.offset = offset;
fieldSlot->data.buffer.size = size;