Index: src/ports/SkPurgeableMemoryBlock_android.cpp |
diff --git a/src/ports/SkPurgeableMemoryBlock_android.cpp b/src/ports/SkPurgeableMemoryBlock_android.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7c06b933edecd345f2b5cf83f71ae97b2b1ba3e5 |
--- /dev/null |
+++ b/src/ports/SkPurgeableMemoryBlock_android.cpp |
@@ -0,0 +1,117 @@ |
+/* |
+ * Copyright 2013 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#include "SkPurgeableMemoryBlock.h" |
+ |
+#include "android/ashmem.h" |
+#include <sys/mman.h> |
+#include <unistd.h> |
+ |
+bool SkPurgeableMemoryBlock::PlatformSupportsPurgeableMemory() { |
+ return true; |
+} |
+ |
+#ifdef SK_DEBUG |
+bool SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks() { |
+ return false; |
+} |
+ |
+bool SkPurgeableMemoryBlock::PurgeAllUnpinnedBlocks() { |
+ return false; |
+} |
+ |
+bool SkPurgeableMemoryBlock::purge() { |
+ SkASSERT(!fPinned); |
+ if (-1 != fFD) { |
+ munmap(fAddr, fSize); |
+ close(fFD); |
+ fFD = -1; |
+ fAddr = NULL; |
+ fSize = 0; |
+ return true; |
+ } else { |
+ return false; |
+ } |
+} |
+#endif |
+ |
+// ashmem likes lengths on page boundaries. |
+static size_t round_to_page_size(size_t size) { |
+ const size_t mask = getpagesize() - 1; |
+ size_t newSize = (size + mask) & ~mask; |
+ return newSize; |
+} |
+ |
+SkPurgeableMemoryBlock::SkPurgeableMemoryBlock(size_t size) |
+ : fAddr(NULL) |
+ , fSize(0) |
+ , fPinned(false) |
+ , fFD(-1) { |
+ size = round_to_page_size(size); |
+ int fd = ashmem_create_region(NULL, size); |
+ if (-1 == fd) { |
+ SkDebugf("ashmem_create_region failed\n"); |
+ return; |
+ } |
+ |
+ int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE); |
+ if (err != 0) { |
+ SkDebugf("ashmem_set_prot_region failed\n"); |
+ close(fd); |
+ return; |
+ } |
+ |
+ void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); |
+ if (-1 == (long) addr) { |
+ SkDebugf("mmap failed\n"); |
+ close(fd); |
+ return; |
+ } |
+ fAddr = addr; |
+ fSize = size; |
+ fFD = fd; |
+ (void) ashmem_pin_region(fd, 0, 0); |
+ fPinned = true; |
+} |
+ |
+SkPurgeableMemoryBlock::~SkPurgeableMemoryBlock() { |
+ if (-1 != fFD) { |
+ munmap(fAddr, fSize); |
+ close(fFD); |
+ } |
+} |
+ |
+SkPurgeableMemoryBlock::PinResult SkPurgeableMemoryBlock::pin() { |
+ SkASSERT(!fPinned); |
+ if (-1 != fFD) { |
+ int pin = ashmem_pin_region(fFD, 0, 0); |
+ if (ASHMEM_NOT_PURGED == pin) { |
+ fPinned = true; |
+ return kRetained_PinResult; |
+ } else if (ASHMEM_WAS_PURGED == pin) { |
+ fPinned = true; |
+ return kUninitialized_PinResult; |
+ } else { |
+ // Failed. |
+ munmap(fAddr, fSize); |
+ close(fFD); |
+ fFD = -1; |
+ fAddr = NULL; |
+ fSize = 0; |
+ // Fall through |
+ } |
+ } |
+ return kFailed_PinResult; |
+} |
+ |
+void SkPurgeableMemoryBlock::unpin() { |
+ if (-1 != fFD) { |
+ ashmem_unpin_region(fFD, 0, 0); |
+ fPinned = false; |
+ } |
+} |
+ |