1096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger/* 2096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger * Copyright 2013 Google Inc. 3096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger * 4096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be 5096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger * found in the LICENSE file. 6096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger */ 7096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 8096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "SkPurgeableMemoryBlock.h" 9096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 10096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "android/ashmem.h" 11096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include <sys/mman.h> 12096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include <unistd.h> 13096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 14096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerbool SkPurgeableMemoryBlock::IsSupported() { 15096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return true; 16096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger} 17096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 18096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#ifdef SK_DEBUG 19096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerbool SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks() { 20096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return false; 21096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger} 22096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 23096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerbool SkPurgeableMemoryBlock::PurgeAllUnpinnedBlocks() { 24096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return false; 25096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger} 26096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 27096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerbool SkPurgeableMemoryBlock::purge() { 28096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger SkASSERT(!fPinned); 29096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (-1 != fFD) { 30096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger ashmem_purge_all_caches(fFD); 31096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return true; 32096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } else { 33096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return false; 34096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 35096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger} 36096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#endif 37096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 38096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger// ashmem likes lengths on page boundaries. 39096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerstatic size_t round_to_page_size(size_t size) { 40096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger const size_t mask = getpagesize() - 1; 41096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger size_t newSize = (size + mask) & ~mask; 42096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return newSize; 43096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger} 44096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 45096defe64d408e54474fe19f418c95bf1a554fc7Derek SollenbergerSkPurgeableMemoryBlock::SkPurgeableMemoryBlock(size_t size) 46096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger : fAddr(NULL) 47096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger , fSize(round_to_page_size(size)) 48096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger , fPinned(false) 49096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger , fFD(-1) { 50096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger} 51096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 52096defe64d408e54474fe19f418c95bf1a554fc7Derek SollenbergerSkPurgeableMemoryBlock::~SkPurgeableMemoryBlock() { 53096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (-1 != fFD) { 54096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger munmap(fAddr, fSize); 55096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger close(fFD); 56096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 57096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger} 58096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 59096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergervoid* SkPurgeableMemoryBlock::pin(SkPurgeableMemoryBlock::PinResult* pinResult) { 60096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger SkASSERT(!fPinned); 61096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (-1 == fFD) { 62096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger int fd = ashmem_create_region(NULL, fSize); 63096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (-1 == fd) { 64096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger SkDebugf("ashmem_create_region failed\n"); 65096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return NULL; 66096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 67096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 68096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE); 69096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (err != 0) { 70096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger SkDebugf("ashmem_set_prot_region failed\n"); 71096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger close(fd); 72096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return NULL; 73096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 74096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 75096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger void* addr = mmap(NULL, fSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 76096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (-1 == (long) addr) { 77096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger SkDebugf("mmap failed\n"); 78096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger close(fd); 79096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return NULL; 80096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 81096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger fAddr = addr; 82096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger fFD = fd; 83096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger (void) ashmem_pin_region(fd, 0, 0); 84096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger *pinResult = kUninitialized_PinResult; 85096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger fPinned = true; 86096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } else { 87096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger int pin = ashmem_pin_region(fFD, 0, 0); 88096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (ASHMEM_NOT_PURGED == pin) { 89096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger fPinned = true; 90096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger *pinResult = kRetained_PinResult; 91096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } else if (ASHMEM_WAS_PURGED == pin) { 92096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger fPinned = true; 93096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger *pinResult = kUninitialized_PinResult; 94096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } else { 95096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger // Failed. 96096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger munmap(fAddr, fSize); 97096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger close(fFD); 98096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger fFD = -1; 99096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger fAddr = NULL; 100096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 101096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 102096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return fAddr; 103096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger} 104096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 105096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergervoid SkPurgeableMemoryBlock::unpin() { 106096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (-1 != fFD) { 107096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger ashmem_unpin_region(fFD, 0, 0); 108096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger fPinned = false; 109096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 110096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger} 111