Index: base/memory/discardable_memory_android.cc |
diff --git a/base/memory/discardable_memory_android.cc b/base/memory/discardable_memory_android.cc |
index 73a25ae419e897b7bf2f3f903edd931a1599be27..40dd2471358d69f7f8bb44c2029506870c17f0a9 100644 |
--- a/base/memory/discardable_memory_android.cc |
+++ b/base/memory/discardable_memory_android.cc |
@@ -13,6 +13,8 @@ |
#include "base/synchronization/lock.h" |
#include "third_party/ashmem/ashmem.h" |
+namespace base { |
+ |
namespace { |
base::LazyInstance<base::Lock>::Leaky g_discardable_memory_lock = |
@@ -25,140 +27,166 @@ int g_num_discardable_memory = 0; |
// descriptor limit. |
const int kDiscardableMemoryNumLimit = 128; |
-} |
- |
-namespace base { |
- |
-// static |
-bool DiscardableMemory::Supported() { |
- return true; |
-} |
+class DiscardableMemoryAndroid : public DiscardableMemory { |
+ public: |
+ DiscardableMemoryAndroid() |
+ : memory_(NULL), |
+ size_(0), |
+ is_locked_(false), |
+ fd_(-1) { |
+ } |
-DiscardableMemory::~DiscardableMemory() { |
- if (is_locked_) |
- Unlock(); |
- // If fd_ is smaller than 0, initialization must have failed and |
- // g_num_discardable_memory is not incremented by the caller. |
- if (fd_ < 0) |
- return; |
- HANDLE_EINTR(close(fd_)); |
- fd_ = -1; |
- ReleaseFileDescriptor(); |
-} |
+ virtual ~DiscardableMemoryAndroid() { |
+ if (is_locked_) |
+ Unlock(); |
+ // If fd_ is smaller than 0, initialization must have failed and |
+ // g_num_discardable_memory is not incremented by the caller. |
+ if (fd_ < 0) |
+ return; |
+ HANDLE_EINTR(close(fd_)); |
+ fd_ = -1; |
+ ReleaseFileDescriptor(); |
+ } |
-bool DiscardableMemory::ReserveFileDescriptor() { |
- base::AutoLock lock(g_discardable_memory_lock.Get()); |
- if (g_num_discardable_memory < kDiscardableMemoryNumLimit) { |
- ++g_num_discardable_memory; |
+ virtual bool InitializeAndLock(size_t size) OVERRIDE { |
+ // When this function returns true, fd_ should be larger or equal than 0 |
+ // and g_num_discardable_memory is incremented by 1. Otherwise, fd_ |
+ // is less than 0 and g_num_discardable_memory is not incremented by |
+ // the caller. |
+ DCHECK_EQ(fd_, -1); |
+ DCHECK(!memory_); |
+ if (!ReserveFileDescriptor()) |
+ return false; |
+ |
+ size_ = size; |
+ fd_ = ashmem_create_region("", size); |
+ |
+ if (fd_ < 0) { |
+ DLOG(ERROR) << "ashmem_create_region() failed"; |
+ ReleaseFileDescriptor(); |
+ return false; |
+ } |
+ |
+ int err = ashmem_set_prot_region(fd_, PROT_READ | PROT_WRITE); |
+ if (err < 0) { |
+ DLOG(ERROR) << "Error " << err << " when setting protection of ashmem"; |
+ HANDLE_EINTR(close(fd_)); |
+ fd_ = -1; |
+ ReleaseFileDescriptor(); |
+ return false; |
+ } |
+ |
+ if (!Map()) { |
+ // Close the file descriptor in case of any initialization errors. |
+ HANDLE_EINTR(close(fd_)); |
+ fd_ = -1; |
+ ReleaseFileDescriptor(); |
+ return false; |
+ } |
+ |
+ is_locked_ = true; |
return true; |
} |
- return false; |
-} |
-void DiscardableMemory::ReleaseFileDescriptor() { |
- base::AutoLock lock(g_discardable_memory_lock.Get()); |
- --g_num_discardable_memory; |
- DCHECK_LE(0, g_num_discardable_memory); |
-} |
+ virtual LockDiscardableMemoryStatus Lock() OVERRIDE { |
+ DCHECK_NE(fd_, -1); |
+ DCHECK(!is_locked_); |
-bool DiscardableMemory::InitializeAndLock(size_t size) { |
- // When this function returns true, fd_ should be larger or equal than 0 |
- // and g_num_discardable_memory is incremented by 1. Otherwise, fd_ |
- // is less than 0 and g_num_discardable_memory is not incremented by |
- // the caller. |
- DCHECK_EQ(fd_, -1); |
- DCHECK(!memory_); |
- if (!ReserveFileDescriptor()) |
- return false; |
+ bool purged = false; |
+ if (ashmem_pin_region(fd_, 0, 0) == ASHMEM_WAS_PURGED) |
+ purged = true; |
- size_ = size; |
- fd_ = ashmem_create_region("", size); |
+ if (!Map()) |
+ return DISCARDABLE_MEMORY_FAILED; |
- if (fd_ < 0) { |
- DLOG(ERROR) << "ashmem_create_region() failed"; |
- ReleaseFileDescriptor(); |
- return false; |
+ is_locked_ = true; |
+ return purged ? DISCARDABLE_MEMORY_PURGED : DISCARDABLE_MEMORY_SUCCESS; |
} |
- int err = ashmem_set_prot_region(fd_, PROT_READ | PROT_WRITE); |
- if (err < 0) { |
- DLOG(ERROR) << "Error " << err << " when setting protection of ashmem"; |
- HANDLE_EINTR(close(fd_)); |
- fd_ = -1; |
- ReleaseFileDescriptor(); |
- return false; |
+ virtual void Unlock() OVERRIDE { |
+ DCHECK_GE(fd_, 0); |
+ DCHECK(is_locked_); |
+ |
+ Unmap(); |
+ if (ashmem_unpin_region(fd_, 0, 0)) |
+ DLOG(ERROR) << "Failed to unpin memory."; |
+ is_locked_ = false; |
} |
- if (!Map()) { |
- // Close the file descriptor in case of any initialization errors. |
- HANDLE_EINTR(close(fd_)); |
- fd_ = -1; |
- ReleaseFileDescriptor(); |
+ virtual void* Memory() OVERRIDE { |
+ return memory_; |
+ } |
+ |
+ bool ReserveFileDescriptor() { |
+ base::AutoLock lock(g_discardable_memory_lock.Get()); |
+ if (g_num_discardable_memory < kDiscardableMemoryNumLimit) { |
+ ++g_num_discardable_memory; |
+ return true; |
+ } |
return false; |
} |
- is_locked_ = true; |
- return true; |
-} |
+ void ReleaseFileDescriptor() { |
+ base::AutoLock lock(g_discardable_memory_lock.Get()); |
+ --g_num_discardable_memory; |
+ DCHECK_LE(0, g_num_discardable_memory); |
+ } |
-LockDiscardableMemoryStatus DiscardableMemory::Lock() { |
- DCHECK_NE(fd_, -1); |
- DCHECK(!is_locked_); |
+ bool Map() { |
+ DCHECK(!memory_); |
+ // There is a problem using MAP_PRIVATE here. As we are constantly calling |
+ // Lock() and Unlock(), data could get lost if they are not written to the |
+ // underlying file when Unlock() gets called. |
+ memory_ = mmap(NULL, size_, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0); |
+ if (memory_ == (void*)-1) { |
+ DPLOG(ERROR) << "Failed to map memory."; |
+ memory_ = NULL; |
+ if (ashmem_unpin_region(fd_, 0, 0)) |
+ DLOG(ERROR) << "Failed to unpin memory."; |
+ return false; |
+ } |
+ return true; |
+ } |
- bool purged = false; |
- if (ashmem_pin_region(fd_, 0, 0) == ASHMEM_WAS_PURGED) |
- purged = true; |
+ void Unmap() { |
+ DCHECK(memory_); |
- if (!Map()) |
- return DISCARDABLE_MEMORY_FAILED; |
+ if (-1 == munmap(memory_, size_)) |
+ DPLOG(ERROR) << "Failed to unmap memory."; |
- is_locked_ = true; |
- return purged ? DISCARDABLE_MEMORY_PURGED : DISCARDABLE_MEMORY_SUCCESS; |
-} |
+ memory_ = NULL; |
+ } |
-void DiscardableMemory::Unlock() { |
- DCHECK_GE(fd_, 0); |
- DCHECK(is_locked_); |
+ private: |
+ void* memory_; |
+ size_t size_; |
+ bool is_locked_; |
+ int fd_; |
- Unmap(); |
- if (ashmem_unpin_region(fd_, 0, 0)) |
- DLOG(ERROR) << "Failed to unpin memory."; |
- is_locked_ = false; |
-} |
+ DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryAndroid); |
+}; |
-bool DiscardableMemory::Map() { |
- DCHECK(!memory_); |
- // There is a problem using MAP_PRIVATE here. As we are constantly calling |
- // Lock() and Unlock(), data could get lost if they are not written to the |
- // underlying file when Unlock() gets called. |
- memory_ = mmap(NULL, size_, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0); |
- if (memory_ == (void*)-1) { |
- DPLOG(ERROR) << "Failed to map memory."; |
- memory_ = NULL; |
- if (ashmem_unpin_region(fd_, 0, 0)) |
- DLOG(ERROR) << "Failed to unpin memory."; |
- return false; |
+class BASE_EXPORT DiscardableMemoryProviderAndroid |
+ : public DiscardableMemoryProvider { |
+ public: |
+ virtual DiscardableMemory* CreateDiscardableMemory() OVERRIDE { |
+ return new DiscardableMemoryAndroid; |
} |
- return true; |
-} |
- |
-void DiscardableMemory::Unmap() { |
- DCHECK(memory_); |
- if (-1 == munmap(memory_, size_)) |
- DPLOG(ERROR) << "Failed to unmap memory."; |
+ virtual bool PurgeForTestingSupported() const OVERRIDE { |
+ return false; |
+ } |
- memory_ = NULL; |
-} |
+ virtual void PurgeForTesting() OVERRIDE { |
+ NOTIMPLEMENTED(); |
+ } |
+}; |
-// static |
-bool DiscardableMemory::PurgeForTestingSupported() { |
- return false; |
-} |
+} // namespace |
// static |
-void DiscardableMemory::PurgeForTesting() { |
- NOTIMPLEMENTED(); |
+DiscardableMemoryProvider* DiscardableMemoryProvider::GetInstance() { |
+ base::Singleton<DiscardableMemoryProviderAndroid>::GetInstance(); |
} |
} // namespace base |