1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkPurgeableMemoryBlock.h" 9 10 #include "android/ashmem.h" 11 #include <sys/mman.h> 12 #include <unistd.h> 13 14 bool SkPurgeableMemoryBlock::IsSupported() { 15 return true; 16 } 17 18 #ifdef SK_DEBUG 19 bool SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks() { 20 return false; 21 } 22 23 bool SkPurgeableMemoryBlock::PurgeAllUnpinnedBlocks() { 24 return false; 25 } 26 27 bool SkPurgeableMemoryBlock::purge() { 28 SkASSERT(!fPinned); 29 if (-1 != fFD) { 30 ashmem_purge_all_caches(fFD); 31 return true; 32 } else { 33 return false; 34 } 35 } 36 #endif 37 38 // ashmem likes lengths on page boundaries. 39 static size_t round_to_page_size(size_t size) { 40 const size_t mask = getpagesize() - 1; 41 size_t newSize = (size + mask) & ~mask; 42 return newSize; 43 } 44 45 SkPurgeableMemoryBlock::SkPurgeableMemoryBlock(size_t size) 46 : fAddr(NULL) 47 , fSize(round_to_page_size(size)) 48 , fPinned(false) 49 , fFD(-1) { 50 } 51 52 SkPurgeableMemoryBlock::~SkPurgeableMemoryBlock() { 53 if (-1 != fFD) { 54 munmap(fAddr, fSize); 55 close(fFD); 56 } 57 } 58 59 void* SkPurgeableMemoryBlock::pin(SkPurgeableMemoryBlock::PinResult* pinResult) { 60 SkASSERT(!fPinned); 61 if (-1 == fFD) { 62 int fd = ashmem_create_region(NULL, fSize); 63 if (-1 == fd) { 64 SkDebugf("ashmem_create_region failed\n"); 65 return NULL; 66 } 67 68 int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE); 69 if (err != 0) { 70 SkDebugf("ashmem_set_prot_region failed\n"); 71 close(fd); 72 return NULL; 73 } 74 75 void* addr = mmap(NULL, fSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 76 if (-1 == (long) addr) { 77 SkDebugf("mmap failed\n"); 78 close(fd); 79 return NULL; 80 } 81 fAddr = addr; 82 fFD = fd; 83 (void) ashmem_pin_region(fd, 0, 0); 84 *pinResult = kUninitialized_PinResult; 85 fPinned = true; 86 } else { 87 int pin = ashmem_pin_region(fFD, 0, 0); 88 if (ASHMEM_NOT_PURGED == pin) { 89 fPinned = true; 90 *pinResult = kRetained_PinResult; 91 } else if (ASHMEM_WAS_PURGED == pin) { 92 fPinned = true; 93 *pinResult = kUninitialized_PinResult; 94 } else { 95 // Failed. 96 munmap(fAddr, fSize); 97 close(fFD); 98 fFD = -1; 99 fAddr = NULL; 100 } 101 } 102 return fAddr; 103 } 104 105 void SkPurgeableMemoryBlock::unpin() { 106 if (-1 != fFD) { 107 ashmem_unpin_region(fFD, 0, 0); 108 fPinned = false; 109 } 110 } 111