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 <unistd.h> 9 #include <sys/mman.h> 10 #include "SkDiscardableMemory.h" 11 #include "SkTypes.h" 12 #include "android/ashmem.h" 13 14 //////////////////////////////////////////////////////////////////////////////// 15 namespace { 16 /** 17 * DiscardableMemory implementation that uses the Android kernel's 18 * ashmem (Android shared memory). 19 */ 20 class SkAshmemDiscardableMemory : public SkDiscardableMemory { 21 public: 22 SkAshmemDiscardableMemory(int fd, void* address, size_t size); 23 virtual ~SkAshmemDiscardableMemory(); 24 virtual bool lock() SK_OVERRIDE; 25 virtual void* data() SK_OVERRIDE; 26 virtual void unlock() SK_OVERRIDE; 27 private: 28 bool fLocked; 29 int fFd; 30 void* fMemory; 31 const size_t fSize; 32 }; 33 34 SkAshmemDiscardableMemory::SkAshmemDiscardableMemory(int fd, 35 void* address, 36 size_t size) 37 : fLocked(true) // Ashmem pages are pinned by default. 38 , fFd(fd) 39 , fMemory(address) 40 , fSize(size) { 41 SkASSERT(fFd >= 0); 42 SkASSERT(fMemory != NULL); 43 SkASSERT(fSize > 0); 44 } 45 46 SkAshmemDiscardableMemory::~SkAshmemDiscardableMemory() { 47 SkASSERT(!fLocked); 48 if (NULL != fMemory) { 49 munmap(fMemory, fSize); 50 } 51 if (fFd != -1) { 52 close(fFd); 53 } 54 } 55 56 bool SkAshmemDiscardableMemory::lock() { 57 SkASSERT(!fLocked); 58 if (-1 == fFd) { 59 fLocked = false; 60 return false; 61 } 62 SkASSERT(fMemory != NULL); 63 if (fLocked || (ASHMEM_NOT_PURGED == ashmem_pin_region(fFd, 0, 0))) { 64 fLocked = true; 65 return true; 66 } else { 67 munmap(fMemory, fSize); 68 fMemory = NULL; 69 70 close(fFd); 71 fFd = -1; 72 fLocked = false; 73 return false; 74 } 75 } 76 77 void* SkAshmemDiscardableMemory::data() { 78 SkASSERT(fLocked); 79 return fLocked ? fMemory : NULL; 80 } 81 82 void SkAshmemDiscardableMemory::unlock() { 83 SkASSERT(fLocked); 84 if (fLocked && (fFd != -1)) { 85 ashmem_unpin_region(fFd, 0, 0); 86 } 87 fLocked = false; 88 } 89 } // namespace 90 //////////////////////////////////////////////////////////////////////////////// 91 92 SkDiscardableMemory* SkDiscardableMemory::Create(size_t bytes) { 93 // ashmem likes lengths on page boundaries. 94 const size_t mask = getpagesize() - 1; 95 size_t size = (bytes + mask) & ~mask; 96 97 static const char name[] = "Skia_Ashmem_Discardable_Memory"; 98 int fd = ashmem_create_region(name, size); 99 if (fd < 0) { 100 return NULL; 101 } 102 if (0 != ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE)) { 103 close(fd); 104 return NULL; 105 } 106 void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 107 if ((MAP_FAILED == addr) || (NULL == addr)) { 108 close(fd); 109 return NULL; 110 } 111 112 return SkNEW_ARGS(SkAshmemDiscardableMemory, (fd, addr, size)); 113 } 114