OLD | NEW |
| (Empty) |
1 // Copyright 2014 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. | |
4 | |
5 #include "content/common/host_discardable_shared_memory_manager.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <stdint.h> | |
9 #include <string.h> | |
10 | |
11 #include "base/threading/simple_thread.h" | |
12 #include "content/public/common/child_process_host.h" | |
13 #include "testing/gtest/include/gtest/gtest.h" | |
14 | |
15 namespace content { | |
16 namespace { | |
17 | |
18 class TestDiscardableSharedMemory : public base::DiscardableSharedMemory { | |
19 public: | |
20 TestDiscardableSharedMemory() {} | |
21 | |
22 explicit TestDiscardableSharedMemory(base::SharedMemoryHandle handle) | |
23 : DiscardableSharedMemory(handle) {} | |
24 | |
25 void SetNow(base::Time now) { now_ = now; } | |
26 | |
27 private: | |
28 // Overriden from base::DiscardableSharedMemory: | |
29 base::Time Now() const override { return now_; } | |
30 | |
31 base::Time now_; | |
32 }; | |
33 | |
34 class TestHostDiscardableSharedMemoryManager | |
35 : public HostDiscardableSharedMemoryManager { | |
36 public: | |
37 TestHostDiscardableSharedMemoryManager() | |
38 : enforce_memory_policy_pending_(false) {} | |
39 | |
40 void SetNow(base::Time now) { now_ = now; } | |
41 | |
42 void set_enforce_memory_policy_pending(bool enforce_memory_policy_pending) { | |
43 enforce_memory_policy_pending_ = enforce_memory_policy_pending; | |
44 } | |
45 bool enforce_memory_policy_pending() const { | |
46 return enforce_memory_policy_pending_; | |
47 } | |
48 | |
49 private: | |
50 // Overriden from HostDiscardableSharedMemoryManager: | |
51 base::Time Now() const override { return now_; } | |
52 void ScheduleEnforceMemoryPolicy() override { | |
53 enforce_memory_policy_pending_ = true; | |
54 } | |
55 | |
56 base::Time now_; | |
57 bool enforce_memory_policy_pending_; | |
58 }; | |
59 | |
60 class HostDiscardableSharedMemoryManagerTest : public testing::Test { | |
61 protected: | |
62 // Overridden from testing::Test: | |
63 void SetUp() override { | |
64 manager_.reset(new TestHostDiscardableSharedMemoryManager); | |
65 } | |
66 | |
67 // HostDiscardableSharedMemoryManager requires a message loop. | |
68 base::MessageLoop message_loop_; | |
69 std::unique_ptr<TestHostDiscardableSharedMemoryManager> manager_; | |
70 }; | |
71 | |
72 TEST_F(HostDiscardableSharedMemoryManagerTest, AllocateForChild) { | |
73 const int kDataSize = 1024; | |
74 uint8_t data[kDataSize]; | |
75 memset(data, 0x80, kDataSize); | |
76 | |
77 base::SharedMemoryHandle shared_handle; | |
78 manager_->AllocateLockedDiscardableSharedMemoryForChild( | |
79 base::GetCurrentProcessHandle(), ChildProcessHost::kInvalidUniqueID, | |
80 kDataSize, 0, &shared_handle); | |
81 ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle)); | |
82 | |
83 TestDiscardableSharedMemory memory(shared_handle); | |
84 bool rv = memory.Map(kDataSize); | |
85 ASSERT_TRUE(rv); | |
86 | |
87 memcpy(memory.memory(), data, kDataSize); | |
88 memory.SetNow(base::Time::FromDoubleT(1)); | |
89 memory.Unlock(0, 0); | |
90 | |
91 ASSERT_EQ(base::DiscardableSharedMemory::SUCCESS, memory.Lock(0, 0)); | |
92 EXPECT_EQ(memcmp(data, memory.memory(), kDataSize), 0); | |
93 memory.Unlock(0, 0); | |
94 } | |
95 | |
96 TEST_F(HostDiscardableSharedMemoryManagerTest, Purge) { | |
97 const int kDataSize = 1024; | |
98 | |
99 base::SharedMemoryHandle shared_handle1; | |
100 manager_->AllocateLockedDiscardableSharedMemoryForChild( | |
101 base::GetCurrentProcessHandle(), ChildProcessHost::kInvalidUniqueID, | |
102 kDataSize, 1, &shared_handle1); | |
103 ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle1)); | |
104 | |
105 TestDiscardableSharedMemory memory1(shared_handle1); | |
106 bool rv = memory1.Map(kDataSize); | |
107 ASSERT_TRUE(rv); | |
108 | |
109 base::SharedMemoryHandle shared_handle2; | |
110 manager_->AllocateLockedDiscardableSharedMemoryForChild( | |
111 base::GetCurrentProcessHandle(), ChildProcessHost::kInvalidUniqueID, | |
112 kDataSize, 2, &shared_handle2); | |
113 ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle2)); | |
114 | |
115 TestDiscardableSharedMemory memory2(shared_handle2); | |
116 rv = memory2.Map(kDataSize); | |
117 ASSERT_TRUE(rv); | |
118 | |
119 // Enough memory for both allocations. | |
120 manager_->SetNow(base::Time::FromDoubleT(1)); | |
121 manager_->SetMemoryLimit(memory1.mapped_size() + memory2.mapped_size()); | |
122 | |
123 memory1.SetNow(base::Time::FromDoubleT(2)); | |
124 memory1.Unlock(0, 0); | |
125 memory2.SetNow(base::Time::FromDoubleT(2)); | |
126 memory2.Unlock(0, 0); | |
127 | |
128 // Manager should not have to schedule another call to EnforceMemoryPolicy(). | |
129 manager_->SetNow(base::Time::FromDoubleT(3)); | |
130 manager_->EnforceMemoryPolicy(); | |
131 EXPECT_FALSE(manager_->enforce_memory_policy_pending()); | |
132 | |
133 // Memory should still be resident. | |
134 EXPECT_TRUE(memory1.IsMemoryResident()); | |
135 EXPECT_TRUE(memory2.IsMemoryResident()); | |
136 | |
137 auto lock_rv = memory1.Lock(0, 0); | |
138 EXPECT_EQ(base::DiscardableSharedMemory::SUCCESS, lock_rv); | |
139 lock_rv = memory2.Lock(0, 0); | |
140 EXPECT_EQ(base::DiscardableSharedMemory::SUCCESS, lock_rv); | |
141 | |
142 memory1.SetNow(base::Time::FromDoubleT(4)); | |
143 memory1.Unlock(0, 0); | |
144 memory2.SetNow(base::Time::FromDoubleT(5)); | |
145 memory2.Unlock(0, 0); | |
146 | |
147 // Just enough memory for one allocation. | |
148 manager_->SetNow(base::Time::FromDoubleT(6)); | |
149 manager_->SetMemoryLimit(memory2.mapped_size()); | |
150 EXPECT_FALSE(manager_->enforce_memory_policy_pending()); | |
151 | |
152 // LRU allocation should still be resident. | |
153 EXPECT_FALSE(memory1.IsMemoryResident()); | |
154 EXPECT_TRUE(memory2.IsMemoryResident()); | |
155 | |
156 lock_rv = memory1.Lock(0, 0); | |
157 EXPECT_EQ(base::DiscardableSharedMemory::FAILED, lock_rv); | |
158 lock_rv = memory2.Lock(0, 0); | |
159 EXPECT_EQ(base::DiscardableSharedMemory::SUCCESS, lock_rv); | |
160 } | |
161 | |
162 TEST_F(HostDiscardableSharedMemoryManagerTest, EnforceMemoryPolicy) { | |
163 const int kDataSize = 1024; | |
164 | |
165 base::SharedMemoryHandle shared_handle; | |
166 manager_->AllocateLockedDiscardableSharedMemoryForChild( | |
167 base::GetCurrentProcessHandle(), ChildProcessHost::kInvalidUniqueID, | |
168 kDataSize, 0, &shared_handle); | |
169 ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle)); | |
170 | |
171 TestDiscardableSharedMemory memory(shared_handle); | |
172 bool rv = memory.Map(kDataSize); | |
173 ASSERT_TRUE(rv); | |
174 | |
175 // Not enough memory for one allocation. | |
176 manager_->SetNow(base::Time::FromDoubleT(1)); | |
177 manager_->SetMemoryLimit(memory.mapped_size() - 1); | |
178 // We need to enforce memory policy as our memory usage is currently above | |
179 // the limit. | |
180 EXPECT_TRUE(manager_->enforce_memory_policy_pending()); | |
181 | |
182 manager_->set_enforce_memory_policy_pending(false); | |
183 manager_->SetNow(base::Time::FromDoubleT(2)); | |
184 manager_->EnforceMemoryPolicy(); | |
185 // Still need to enforce memory policy as nothing can be purged. | |
186 EXPECT_TRUE(manager_->enforce_memory_policy_pending()); | |
187 | |
188 memory.SetNow(base::Time::FromDoubleT(3)); | |
189 memory.Unlock(0, 0); | |
190 | |
191 manager_->set_enforce_memory_policy_pending(false); | |
192 manager_->SetNow(base::Time::FromDoubleT(4)); | |
193 manager_->EnforceMemoryPolicy(); | |
194 // Memory policy should have successfully been enforced. | |
195 EXPECT_FALSE(manager_->enforce_memory_policy_pending()); | |
196 | |
197 EXPECT_EQ(base::DiscardableSharedMemory::FAILED, memory.Lock(0, 0)); | |
198 } | |
199 | |
200 TEST_F(HostDiscardableSharedMemoryManagerTest, | |
201 ReduceMemoryAfterSegmentHasBeenDeleted) { | |
202 const int kDataSize = 1024; | |
203 | |
204 base::SharedMemoryHandle shared_handle1; | |
205 manager_->AllocateLockedDiscardableSharedMemoryForChild( | |
206 base::GetCurrentProcessHandle(), ChildProcessHost::kInvalidUniqueID, | |
207 kDataSize, 1, &shared_handle1); | |
208 ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle1)); | |
209 | |
210 TestDiscardableSharedMemory memory1(shared_handle1); | |
211 bool rv = memory1.Map(kDataSize); | |
212 ASSERT_TRUE(rv); | |
213 | |
214 base::SharedMemoryHandle shared_handle2; | |
215 manager_->AllocateLockedDiscardableSharedMemoryForChild( | |
216 base::GetCurrentProcessHandle(), ChildProcessHost::kInvalidUniqueID, | |
217 kDataSize, 2, &shared_handle2); | |
218 ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle2)); | |
219 | |
220 TestDiscardableSharedMemory memory2(shared_handle2); | |
221 rv = memory2.Map(kDataSize); | |
222 ASSERT_TRUE(rv); | |
223 | |
224 // Unlock and delete segment 1. | |
225 memory1.SetNow(base::Time::FromDoubleT(1)); | |
226 memory1.Unlock(0, 0); | |
227 memory1.Unmap(); | |
228 memory1.Close(); | |
229 manager_->ChildDeletedDiscardableSharedMemory( | |
230 1, ChildProcessHost::kInvalidUniqueID); | |
231 | |
232 // Make sure the manager is able to reduce memory after the segment 1 was | |
233 // deleted. | |
234 manager_->SetNow(base::Time::FromDoubleT(2)); | |
235 manager_->SetMemoryLimit(0); | |
236 | |
237 // Unlock segment 2. | |
238 memory2.SetNow(base::Time::FromDoubleT(3)); | |
239 memory2.Unlock(0, 0); | |
240 } | |
241 | |
242 class HostDiscardableSharedMemoryManagerScheduleEnforceMemoryPolicyTest | |
243 : public testing::Test { | |
244 protected: | |
245 // Overridden from testing::Test: | |
246 void SetUp() override { | |
247 manager_.reset(new HostDiscardableSharedMemoryManager); | |
248 } | |
249 | |
250 // HostDiscardableSharedMemoryManager requires a message loop. | |
251 base::MessageLoop message_loop_; | |
252 std::unique_ptr<HostDiscardableSharedMemoryManager> manager_; | |
253 }; | |
254 | |
255 class SetMemoryLimitRunner : public base::DelegateSimpleThread::Delegate { | |
256 public: | |
257 SetMemoryLimitRunner(HostDiscardableSharedMemoryManager* manager, | |
258 size_t limit) | |
259 : manager_(manager), limit_(limit) {} | |
260 ~SetMemoryLimitRunner() override {} | |
261 | |
262 void Run() override { manager_->SetMemoryLimit(limit_); } | |
263 | |
264 private: | |
265 HostDiscardableSharedMemoryManager* const manager_; | |
266 const size_t limit_; | |
267 }; | |
268 | |
269 TEST_F(HostDiscardableSharedMemoryManagerScheduleEnforceMemoryPolicyTest, | |
270 SetMemoryLimitOnSimpleThread) { | |
271 const int kDataSize = 1024; | |
272 | |
273 base::SharedMemoryHandle shared_handle; | |
274 manager_->AllocateLockedDiscardableSharedMemoryForChild( | |
275 base::GetCurrentProcessHandle(), ChildProcessHost::kInvalidUniqueID, | |
276 kDataSize, 0, &shared_handle); | |
277 ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle)); | |
278 | |
279 // Set the memory limit to a value that will require EnforceMemoryPolicy() | |
280 // to be schedule on a thread without a message loop. | |
281 SetMemoryLimitRunner runner(manager_.get(), kDataSize - 1); | |
282 base::DelegateSimpleThread thread(&runner, "memory_limit_setter"); | |
283 thread.Start(); | |
284 thread.Join(); | |
285 } | |
286 | |
287 } // namespace | |
288 } // namespace content | |
OLD | NEW |