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"
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"
26 const char kAshmemAllocatorName
[] = "DiscardableMemoryAllocator";
28 struct DiscardableMemoryAllocatorWrapper
{
29 DiscardableMemoryAllocatorWrapper()
30 : allocator(kAshmemAllocatorName
,
31 GetOptimalAshmemRegionSizeForAllocator()) {
34 internal::DiscardableMemoryAllocator allocator
;
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
;
52 bool CreateAshmemRegion(const char* name
,
56 int fd
= ashmem_create_region(name
, size
);
58 DLOG(ERROR
) << "ashmem_create_region() failed";
61 file_util::ScopedFD
fd_closer(&fd
);
63 const int err
= ashmem_set_prot_region(fd
, PROT_READ
| PROT_WRITE
);
65 DLOG(ERROR
) << "Error " << err
<< " when setting protection of ashmem";
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.";
79 ignore_result(fd_closer
.release());
81 *out_address
= address
;
85 bool CloseAshmemRegion(int fd
, size_t size
, void* address
) {
86 if (munmap(address
, size
) == -1) {
87 DPLOG(ERROR
) << "Failed to unmap memory.";
91 return close(fd
) == 0;
94 DiscardableMemoryLockStatus
LockAshmemRegion(int fd
,
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
);
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
));
113 } // namespace internal
116 void DiscardableMemory::RegisterMemoryPressureListeners() {
117 internal::DiscardableMemoryEmulated::RegisterMemoryPressureListeners();
121 void DiscardableMemory::UnregisterMemoryPressureListeners() {
122 internal::DiscardableMemoryEmulated::UnregisterMemoryPressureListeners();
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
));
137 scoped_ptr
<DiscardableMemory
> DiscardableMemory::CreateLockedMemoryWithType(
138 DiscardableMemoryType type
, size_t size
) {
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
>();
165 return scoped_ptr
<DiscardableMemory
>();
169 bool DiscardableMemory::PurgeForTestingSupported() {
174 void DiscardableMemory::PurgeForTesting() {