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.
5 #include "athena/activity/public/activity.h"
6 #include "athena/activity/public/activity_manager.h"
7 #include "athena/activity/public/activity_view_model.h"
8 #include "athena/resource_manager/memory_pressure_notifier.h"
9 #include "athena/resource_manager/public/resource_manager.h"
10 #include "athena/test/base/athena_test_base.h"
11 #include "athena/test/base/sample_activity.h"
12 #include "athena/wm/public/window_manager.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "ui/gfx/image/image_skia.h"
15 #include "ui/views/view.h"
16 #include "ui/views/widget/widget.h"
23 // A dummy test app activity which works without content / ShellAppWindow.
24 class TestActivity
: public SampleActivity
{
26 explicit TestActivity(const std::string
& title
)
27 : SampleActivity(0, 0, base::UTF8ToUTF16(title
)),
28 media_state_(ACTIVITY_MEDIA_STATE_NONE
),
30 virtual ~TestActivity() {}
32 void set_media_state(ActivityMediaState media_state
) {
33 media_state_
= media_state
;
35 void set_visible(bool visible
) { is_visible_
= visible
; }
37 // Activity overrides:
38 virtual bool IsVisible() override
{ return is_visible_
; }
39 virtual ActivityMediaState
GetMediaState() override
{ return media_state_
; }
42 // The current media state.
43 ActivityMediaState media_state_
;
45 // Returns if it is visible or not.
48 DISALLOW_COPY_AND_ASSIGN(TestActivity
);
54 class ResourceManagerTest
: public AthenaTestBase
{
56 ResourceManagerTest() {}
57 virtual ~ResourceManagerTest() {}
59 virtual void SetUp() override
{
60 AthenaTestBase::SetUp();
61 // Override the delay to be instantaneous.
62 ResourceManager::Get()->SetWaitTimeBetweenResourceManageCalls(0);
64 virtual void TearDown() override
{
65 while (!activity_list_
.empty())
66 DeleteActivity(activity_list_
[0]);
67 AthenaTestBase::TearDown();
70 TestActivity
* CreateActivity(const std::string
& title
) {
71 TestActivity
* activity
= new TestActivity(title
);
72 ActivityManager::Get()->AddActivity(activity
);
73 activity
->SetCurrentState(Activity::ACTIVITY_INVISIBLE
);
74 activity_list_
.push_back(activity
);
78 void DeleteActivity(Activity
* activity
) {
79 Activity::Delete(activity
);
80 RunAllPendingInMessageLoop();
81 std::vector
<TestActivity
*>::iterator it
= std::find(activity_list_
.begin(),
84 DCHECK(it
!= activity_list_
.end());
85 activity_list_
.erase(it
);
89 std::vector
<TestActivity
*> activity_list_
;
91 DISALLOW_COPY_AND_ASSIGN(ResourceManagerTest
);
94 // Only creates and destroys it to see that the system gets properly shut down.
95 TEST_F(ResourceManagerTest
, SimpleTest
) {
98 // Test that we release an activity when the memory pressure goes critical.
99 TEST_F(ResourceManagerTest
, OnCriticalWillUnloadOneActivity
) {
100 // Create a few dummy activities in the reverse order as we need them.
101 TestActivity
* app_unloadable2
= CreateActivity("unloadable2");
102 TestActivity
* app_unloadable1
= CreateActivity("unloadable1");
103 TestActivity
* app_visible
= CreateActivity("visible");
104 app_visible
->set_visible(true);
105 app_unloadable1
->set_visible(false);
106 app_unloadable2
->set_visible(false);
108 // Set the initial visibility states.
109 app_visible
->SetCurrentState(Activity::ACTIVITY_VISIBLE
);
110 app_unloadable1
->SetCurrentState(Activity::ACTIVITY_INVISIBLE
);
111 app_unloadable2
->SetCurrentState(Activity::ACTIVITY_INVISIBLE
);
113 // Call the resource manager and say we are in a critical memory condition.
114 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
115 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
116 DCHECK_NE(Activity::ACTIVITY_UNLOADED
, app_visible
->GetCurrentState());
117 DCHECK_NE(Activity::ACTIVITY_UNLOADED
, app_unloadable1
->GetCurrentState());
118 DCHECK_EQ(Activity::ACTIVITY_UNLOADED
, app_unloadable2
->GetCurrentState());
120 // Calling it a second time will release the second app.
121 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
122 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
123 DCHECK_NE(Activity::ACTIVITY_UNLOADED
, app_visible
->GetCurrentState());
124 DCHECK_EQ(Activity::ACTIVITY_UNLOADED
, app_unloadable1
->GetCurrentState());
125 DCHECK_EQ(Activity::ACTIVITY_UNLOADED
, app_unloadable2
->GetCurrentState());
127 // Calling it once more will change nothing.
128 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
129 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
130 DCHECK_NE(Activity::ACTIVITY_UNLOADED
, app_visible
->GetCurrentState());
131 DCHECK_EQ(Activity::ACTIVITY_UNLOADED
, app_unloadable1
->GetCurrentState());
132 DCHECK_EQ(Activity::ACTIVITY_UNLOADED
, app_unloadable2
->GetCurrentState());
135 // Test that media playing activities only get unloaded if there is no other
137 TEST_F(ResourceManagerTest
, OnCriticalMediaHandling
) {
138 // Create a few dummy activities in the reverse order as we need them.
139 TestActivity
* app_media_locked2
= CreateActivity("medialocked2");
140 TestActivity
* app_unloadable
= CreateActivity("unloadable2");
141 TestActivity
* app_media_locked1
= CreateActivity("medialocked1");
142 TestActivity
* app_visible
= CreateActivity("visible");
143 app_visible
->set_visible(true);
144 app_unloadable
->set_visible(false);
145 app_media_locked1
->set_visible(false);
146 app_media_locked2
->set_visible(false);
148 app_media_locked1
->set_media_state(
149 Activity::ACTIVITY_MEDIA_STATE_AUDIO_PLAYING
);
150 app_media_locked2
->set_media_state(Activity::ACTIVITY_MEDIA_STATE_RECORDING
);
152 // Set the initial visibility states.
153 app_visible
->SetCurrentState(Activity::ACTIVITY_VISIBLE
);
154 app_media_locked1
->SetCurrentState(Activity::ACTIVITY_INVISIBLE
);
155 app_unloadable
->SetCurrentState(Activity::ACTIVITY_INVISIBLE
);
156 app_media_locked2
->SetCurrentState(Activity::ACTIVITY_INVISIBLE
);
158 DCHECK_NE(Activity::ACTIVITY_UNLOADED
, app_visible
->GetCurrentState());
159 DCHECK_NE(Activity::ACTIVITY_UNLOADED
, app_media_locked1
->GetCurrentState());
160 DCHECK_NE(Activity::ACTIVITY_UNLOADED
, app_unloadable
->GetCurrentState());
161 DCHECK_NE(Activity::ACTIVITY_UNLOADED
, app_media_locked2
->GetCurrentState());
163 // Calling it with a critical situation first, it will release the non media
165 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
166 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
167 DCHECK_NE(Activity::ACTIVITY_UNLOADED
, app_visible
->GetCurrentState());
168 DCHECK_NE(Activity::ACTIVITY_UNLOADED
, app_media_locked1
->GetCurrentState());
169 DCHECK_EQ(Activity::ACTIVITY_UNLOADED
, app_unloadable
->GetCurrentState());
170 DCHECK_NE(Activity::ACTIVITY_UNLOADED
, app_media_locked2
->GetCurrentState());
172 // Calling it the second time, the oldest media playing activity will get
174 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
175 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
176 DCHECK_NE(Activity::ACTIVITY_UNLOADED
, app_visible
->GetCurrentState());
177 DCHECK_NE(Activity::ACTIVITY_UNLOADED
, app_media_locked1
->GetCurrentState());
178 DCHECK_EQ(Activity::ACTIVITY_UNLOADED
, app_unloadable
->GetCurrentState());
179 DCHECK_EQ(Activity::ACTIVITY_UNLOADED
, app_media_locked2
->GetCurrentState());
181 // Calling it the third time, the oldest media playing activity will get
183 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
184 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
185 DCHECK_NE(Activity::ACTIVITY_UNLOADED
, app_visible
->GetCurrentState());
186 DCHECK_EQ(Activity::ACTIVITY_UNLOADED
, app_media_locked1
->GetCurrentState());
187 DCHECK_EQ(Activity::ACTIVITY_UNLOADED
, app_unloadable
->GetCurrentState());
188 DCHECK_EQ(Activity::ACTIVITY_UNLOADED
, app_media_locked2
->GetCurrentState());
191 // Test the visibility of items.
192 TEST_F(ResourceManagerTest
, VisibilityChanges
) {
193 // Create a few dummy activities in the reverse order as we need them.
194 TestActivity
* app4
= CreateActivity("app4");
195 TestActivity
* app3
= CreateActivity("app3");
196 TestActivity
* app2
= CreateActivity("app2");
197 TestActivity
* app1
= CreateActivity("app1");
198 app1
->SetCurrentState(Activity::ACTIVITY_VISIBLE
);
199 app2
->SetCurrentState(Activity::ACTIVITY_VISIBLE
);
200 app3
->SetCurrentState(Activity::ACTIVITY_VISIBLE
);
201 app4
->SetCurrentState(Activity::ACTIVITY_VISIBLE
);
203 // Applying low resource pressure should keep everything as is.
204 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
205 ResourceManager::MEMORY_PRESSURE_LOW
);
206 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app1
->GetCurrentState());
207 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app2
->GetCurrentState());
208 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app3
->GetCurrentState());
209 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app4
->GetCurrentState());
211 // Applying moderate resource pressure we should see 3 visible activities.
212 // This is testing an internal algorithm constant, but for the time being
213 // this should suffice.
214 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
215 ResourceManager::MEMORY_PRESSURE_MODERATE
);
216 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app1
->GetCurrentState());
217 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app2
->GetCurrentState());
218 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app3
->GetCurrentState());
219 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app4
->GetCurrentState());
221 // Applying higher pressure should get rid of everything unneeded.
222 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
223 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
224 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app1
->GetCurrentState());
225 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app2
->GetCurrentState());
226 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app3
->GetCurrentState());
227 // Note: This might very well be unloaded with this memory pressure.
228 EXPECT_NE(Activity::ACTIVITY_VISIBLE
, app4
->GetCurrentState());
230 // Once the split view mode gets turned on, more windows should become
232 WindowManager::Get()->ToggleSplitViewForTest();
233 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app1
->GetCurrentState());
234 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app2
->GetCurrentState());
235 EXPECT_NE(Activity::ACTIVITY_VISIBLE
, app3
->GetCurrentState());
236 EXPECT_NE(Activity::ACTIVITY_VISIBLE
, app4
->GetCurrentState());
238 // Going back to a relaxed memory pressure should reload the old activities.
239 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
240 ResourceManager::MEMORY_PRESSURE_LOW
);
241 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app1
->GetCurrentState());
242 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app2
->GetCurrentState());
243 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app3
->GetCurrentState());
244 EXPECT_NE(Activity::ACTIVITY_INVISIBLE
, app4
->GetCurrentState());
247 // Make sure that an activity which got just reduced from visible to invisible,
248 // does not get thrown out of memory in the same step.
249 TEST_F(ResourceManagerTest
, NoUnloadFromVisible
) {
250 // The timeout override in milliseconds.
251 const int kTimeoutOverrideInMs
= 20;
252 // Tell the resource manager to wait for 20ms between calls.
253 ResourceManager::Get()->SetWaitTimeBetweenResourceManageCalls(
254 kTimeoutOverrideInMs
);
256 // Create a few dummy activities in the reverse order as we need them.
257 TestActivity
* app2
= CreateActivity("app2");
258 TestActivity
* app1
= CreateActivity("app1");
259 app1
->SetCurrentState(Activity::ACTIVITY_VISIBLE
);
260 app2
->SetCurrentState(Activity::ACTIVITY_VISIBLE
);
262 // Applying low resource pressure should turn one item invisible.
263 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
264 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
265 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app1
->GetCurrentState());
266 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app2
->GetCurrentState());
268 // Trying to apply the memory pressure again does not do anything.
269 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
270 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
271 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app1
->GetCurrentState());
272 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app2
->GetCurrentState());
274 // Waiting and applying the pressure again should unload it.
275 usleep(kTimeoutOverrideInMs
* 1000);
276 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
277 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
278 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app1
->GetCurrentState());
279 EXPECT_EQ(Activity::ACTIVITY_UNLOADED
, app2
->GetCurrentState());
282 // Make sure that ActivityVisibility changes will be updated instantaneously
283 // when the ResourceManager is called for operation.
284 TEST_F(ResourceManagerTest
, VisibilityChangeIsInstantaneous
) {
285 // Create a few dummy activities in the reverse order as we need them.
286 TestActivity
* app3
= CreateActivity("app3");
287 TestActivity
* app2
= CreateActivity("app2");
288 TestActivity
* app1
= CreateActivity("app1");
289 app1
->SetCurrentState(Activity::ACTIVITY_VISIBLE
);
290 app2
->SetCurrentState(Activity::ACTIVITY_VISIBLE
);
291 app3
->SetCurrentState(Activity::ACTIVITY_VISIBLE
);
293 // Tell the resource manager to wait for a long time between calls.
294 ResourceManager::Get()->SetWaitTimeBetweenResourceManageCalls(1000);
296 // Applying higher pressure should get rid of everything unneeded.
297 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
298 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
299 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app1
->GetCurrentState());
300 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app2
->GetCurrentState());
301 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app3
->GetCurrentState());
303 // Setting now one window visible again and call a second time should
304 // immediately change the state again.
305 app2
->SetCurrentState(Activity::ACTIVITY_VISIBLE
);
306 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app1
->GetCurrentState());
307 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app2
->GetCurrentState());
308 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app3
->GetCurrentState());
309 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
310 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
312 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app1
->GetCurrentState());
313 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app2
->GetCurrentState());
314 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app3
->GetCurrentState());
317 // Make sure that a timeout has to be reached before another resource managing
318 // operations can be performed.
319 TEST_F(ResourceManagerTest
, ResourceChangeDelayed
) {
320 // Create a few dummy activities in the reverse order as we need them.
321 TestActivity
* app4
= CreateActivity("app4");
322 TestActivity
* app3
= CreateActivity("app3");
323 TestActivity
* app2
= CreateActivity("app2");
324 TestActivity
* app1
= CreateActivity("app1");
325 app1
->SetCurrentState(Activity::ACTIVITY_VISIBLE
);
326 app2
->SetCurrentState(Activity::ACTIVITY_INVISIBLE
);
327 app3
->SetCurrentState(Activity::ACTIVITY_INVISIBLE
);
328 app4
->SetCurrentState(Activity::ACTIVITY_INVISIBLE
);
330 // The timeout override in milliseconds.
331 const int kTimeoutOverrideInMs
= 20;
332 // Tell the resource manager to wait for 20ms between calls.
333 ResourceManager::Get()->SetWaitTimeBetweenResourceManageCalls(
334 kTimeoutOverrideInMs
);
335 // Applying higher pressure should get unload the oldest activity.
336 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
337 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
338 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app1
->GetCurrentState());
339 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app2
->GetCurrentState());
340 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app3
->GetCurrentState());
341 EXPECT_EQ(Activity::ACTIVITY_UNLOADED
, app4
->GetCurrentState());
342 // Trying to apply the resource pressure again within the timeout time should
343 // not trigger any operation.
344 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
345 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
346 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app1
->GetCurrentState());
347 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app2
->GetCurrentState());
348 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app3
->GetCurrentState());
349 EXPECT_EQ(Activity::ACTIVITY_UNLOADED
, app4
->GetCurrentState());
351 // Passing the timeout however should allow for another call.
352 usleep(kTimeoutOverrideInMs
* 1000);
353 ResourceManager::Get()->SetMemoryPressureAndStopMonitoring(
354 ResourceManager::MEMORY_PRESSURE_CRITICAL
);
355 EXPECT_EQ(Activity::ACTIVITY_VISIBLE
, app1
->GetCurrentState());
356 EXPECT_EQ(Activity::ACTIVITY_INVISIBLE
, app2
->GetCurrentState());
357 EXPECT_EQ(Activity::ACTIVITY_UNLOADED
, app3
->GetCurrentState());
358 EXPECT_EQ(Activity::ACTIVITY_UNLOADED
, app4
->GetCurrentState());
362 } // namespace athena