| 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
|
|
|