rAc - revert invalid suggestions to edit mode
[chromium-blink-merge.git] / base / memory / discardable_memory_android.cc
blob7b1731a0f63c21df0bd4ec6580c714fb9053e332
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/memory/discardable_memory_android.h"
7 #include <sys/mman.h>
8 #include <unistd.h>
10 #include <limits>
12 #include "base/android/sys_utils.h"
13 #include "base/basictypes.h"
14 #include "base/compiler_specific.h"
15 #include "base/file_util.h"
16 #include "base/lazy_instance.h"
17 #include "base/logging.h"
18 #include "base/memory/discardable_memory_allocator_android.h"
19 #include "base/memory/discardable_memory_emulated.h"
20 #include "base/memory/discardable_memory_malloc.h"
21 #include "third_party/ashmem/ashmem.h"
23 namespace base {
24 namespace {
26 const char kAshmemAllocatorName[] = "DiscardableMemoryAllocator";
28 struct DiscardableMemoryAllocatorWrapper {
29 DiscardableMemoryAllocatorWrapper()
30 : allocator(kAshmemAllocatorName,
31 GetOptimalAshmemRegionSizeForAllocator()) {
34 internal::DiscardableMemoryAllocator allocator;
36 private:
37 // Returns 64 MBytes for a 512 MBytes device, 128 MBytes for 1024 MBytes...
38 static size_t GetOptimalAshmemRegionSizeForAllocator() {
39 // Note that this may do some I/O (without hitting the disk though) so it
40 // should not be called on the critical path.
41 return base::android::SysUtils::AmountOfPhysicalMemoryKB() * 1024 / 8;
45 LazyInstance<DiscardableMemoryAllocatorWrapper>::Leaky g_context =
46 LAZY_INSTANCE_INITIALIZER;
48 } // namespace
50 namespace internal {
52 bool CreateAshmemRegion(const char* name,
53 size_t size,
54 int* out_fd,
55 void** out_address) {
56 int fd = ashmem_create_region(name, size);
57 if (fd < 0) {
58 DLOG(ERROR) << "ashmem_create_region() failed";
59 return false;
61 file_util::ScopedFD fd_closer(&fd);
63 const int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
64 if (err < 0) {
65 DLOG(ERROR) << "Error " << err << " when setting protection of ashmem";
66 return false;
69 // There is a problem using MAP_PRIVATE here. As we are constantly calling
70 // Lock() and Unlock(), data could get lost if they are not written to the
71 // underlying file when Unlock() gets called.
72 void* const address = mmap(
73 NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
74 if (address == MAP_FAILED) {
75 DPLOG(ERROR) << "Failed to map memory.";
76 return false;
79 ignore_result(fd_closer.release());
80 *out_fd = fd;
81 *out_address = address;
82 return true;
85 bool CloseAshmemRegion(int fd, size_t size, void* address) {
86 if (munmap(address, size) == -1) {
87 DPLOG(ERROR) << "Failed to unmap memory.";
88 close(fd);
89 return false;
91 return close(fd) == 0;
94 DiscardableMemoryLockStatus LockAshmemRegion(int fd,
95 size_t off,
96 size_t size,
97 const void* address) {
98 const int result = ashmem_pin_region(fd, off, size);
99 DCHECK_EQ(0, mprotect(address, size, PROT_READ | PROT_WRITE));
100 return result == ASHMEM_WAS_PURGED ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED
101 : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS;
104 bool UnlockAshmemRegion(int fd, size_t off, size_t size, const void* address) {
105 const int failed = ashmem_unpin_region(fd, off, size);
106 if (failed)
107 DLOG(ERROR) << "Failed to unpin memory.";
108 // This allows us to catch accesses to unlocked memory.
109 DCHECK_EQ(0, mprotect(address, size, PROT_NONE));
110 return !failed;
113 } // namespace internal
115 // static
116 void DiscardableMemory::RegisterMemoryPressureListeners() {
117 internal::DiscardableMemoryEmulated::RegisterMemoryPressureListeners();
120 // static
121 void DiscardableMemory::UnregisterMemoryPressureListeners() {
122 internal::DiscardableMemoryEmulated::UnregisterMemoryPressureListeners();
125 // static
126 void DiscardableMemory::GetSupportedTypes(
127 std::vector<DiscardableMemoryType>* types) {
128 const DiscardableMemoryType supported_types[] = {
129 DISCARDABLE_MEMORY_TYPE_ANDROID,
130 DISCARDABLE_MEMORY_TYPE_EMULATED,
131 DISCARDABLE_MEMORY_TYPE_MALLOC
133 types->assign(supported_types, supported_types + arraysize(supported_types));
136 // static
137 scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemoryWithType(
138 DiscardableMemoryType type, size_t size) {
139 switch (type) {
140 case DISCARDABLE_MEMORY_TYPE_NONE:
141 case DISCARDABLE_MEMORY_TYPE_MAC:
142 return scoped_ptr<DiscardableMemory>();
143 case DISCARDABLE_MEMORY_TYPE_ANDROID: {
144 return g_context.Pointer()->allocator.Allocate(size);
146 case DISCARDABLE_MEMORY_TYPE_EMULATED: {
147 scoped_ptr<internal::DiscardableMemoryEmulated> memory(
148 new internal::DiscardableMemoryEmulated(size));
149 if (!memory->Initialize())
150 return scoped_ptr<DiscardableMemory>();
152 return memory.PassAs<DiscardableMemory>();
154 case DISCARDABLE_MEMORY_TYPE_MALLOC: {
155 scoped_ptr<internal::DiscardableMemoryMalloc> memory(
156 new internal::DiscardableMemoryMalloc(size));
157 if (!memory->Initialize())
158 return scoped_ptr<DiscardableMemory>();
160 return memory.PassAs<DiscardableMemory>();
164 NOTREACHED();
165 return scoped_ptr<DiscardableMemory>();
168 // static
169 bool DiscardableMemory::PurgeForTestingSupported() {
170 return false;
173 // static
174 void DiscardableMemory::PurgeForTesting() {
175 NOTIMPLEMENTED();
178 } // namespace base