Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(272)

Side by Side Diff: athena/resource_manager/resource_manager_impl.cc

Issue 863033002: Delete athena/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 "athena/resource_manager/public/resource_manager.h"
6
7 #include <algorithm>
8 #include <vector>
9
10 #include "athena/activity/public/activity.h"
11 #include "athena/activity/public/activity_manager.h"
12 #include "athena/activity/public/activity_manager_observer.h"
13 #include "athena/resource_manager/memory_pressure_notifier.h"
14 #include "athena/resource_manager/public/resource_manager_delegate.h"
15 #include "athena/wm/public/window_list_provider.h"
16 #include "athena/wm/public/window_list_provider_observer.h"
17 #include "athena/wm/public/window_manager.h"
18 #include "athena/wm/public/window_manager_observer.h"
19 #include "base/containers/adapters.h"
20 #include "base/logging.h"
21 #include "base/memory/scoped_ptr.h"
22 #include "base/time/time.h"
23 #include "ui/aura/window.h"
24
25 namespace athena {
26 namespace {
27
28 class ResourceManagerImpl : public ResourceManager,
29 public WindowManagerObserver,
30 public ActivityManagerObserver,
31 public MemoryPressureObserver,
32 public WindowListProviderObserver {
33 public:
34 ResourceManagerImpl(ResourceManagerDelegate* delegate);
35 ~ResourceManagerImpl() override;
36
37 // ResourceManager:
38 virtual void SetMemoryPressureAndStopMonitoring(
39 MemoryPressure pressure) override;
40 virtual void SetWaitTimeBetweenResourceManageCalls(int time_in_ms) override {
41 wait_time_for_resource_deallocation_ =
42 base::TimeDelta::FromMilliseconds(time_in_ms);
43 // Reset the timeout to force the next resource call to execute immediately.
44 next_resource_management_time_ = base::Time::Now();
45 }
46
47 virtual void Pause(bool pause) override {
48 if (pause) {
49 if (!pause_)
50 queued_command_ = false;
51 ++pause_;
52 } else {
53 DCHECK(pause_);
54 --pause_;
55 if (!pause && queued_command_)
56 ManageResource();
57 }
58 }
59
60 // ActivityManagerObserver:
61 virtual void OnActivityStarted(Activity* activity) override;
62 virtual void OnActivityEnding(Activity* activity) override;
63 virtual void OnActivityOrderChanged() override;
64
65 // WindowManagerObserver:
66 virtual void OnOverviewModeEnter() override;
67 virtual void OnOverviewModeExit() override;
68 virtual void OnSplitViewModeEnter() override;
69 virtual void OnSplitViewModeExit() override;
70
71 // MemoryPressureObserver:
72 virtual void OnMemoryPressure(MemoryPressure pressure) override;
73 virtual ResourceManagerDelegate* GetDelegate() override;
74
75 // WindowListProviderObserver:
76 virtual void OnWindowStackingChangedInList() override;
77 virtual void OnWindowAddedToList(aura::Window* added_window) override {}
78 virtual void OnWindowRemovedFromList(aura::Window* removed_window,
79 int index) override {}
80
81 private:
82 // Manage the resources for our activities.
83 void ManageResource();
84
85 // Check that the visibility of activities is properly set.
86 void UpdateVisibilityStates();
87
88 // Check if activities can be unloaded to reduce memory pressure.
89 void TryToUnloadAnActivity();
90
91 // Resources were released and a quiet period is needed before we release
92 // more since it takes a while to trickle through the system.
93 void OnResourcesReleased();
94
95 // The memory pressure has increased, previously applied measures did not show
96 // effect and immediate action is required.
97 void OnMemoryPressureIncreased();
98
99 // Returns true when the previous memory release was long enough ago to try
100 // unloading another activity.
101 bool AllowedToUnloadActivity();
102
103 // The resource manager delegate.
104 scoped_ptr<ResourceManagerDelegate> delegate_;
105
106 // Keeping a reference to the current memory pressure.
107 MemoryPressure current_memory_pressure_;
108
109 // The memory pressure notifier.
110 scoped_ptr<MemoryPressureNotifier> memory_pressure_notifier_;
111
112 // A ref counter. As long as not 0, the management is on hold.
113 int pause_;
114
115 // If true, a command came in while the resource manager was paused.
116 bool queued_command_;
117
118 // Used by ManageResource() to determine an activity state change while it
119 // changes Activity properties.
120 bool activity_order_changed_;
121
122 // True if in overview mode - activity order changes will be ignored if true
123 // and postponed till after the overview mode is ending.
124 bool in_overview_mode_;
125
126 // True if we are in split view mode.
127 bool in_split_view_mode_;
128
129 // The last time the resource manager was called to release resources.
130 // Avoid too aggressive resource de-allocation by enforcing a wait time of
131 // |wait_time_for_resource_deallocation_| between executed calls.
132 base::Time next_resource_management_time_;
133
134 // The wait time between two resource managing executions.
135 base::TimeDelta wait_time_for_resource_deallocation_;
136
137 DISALLOW_COPY_AND_ASSIGN(ResourceManagerImpl);
138 };
139
140 namespace {
141 ResourceManagerImpl* instance = nullptr;
142
143 // We allow this many activities to be visible. All others must be at state of
144 // invisible or below.
145 const int kMaxVisibleActivities = 3;
146
147 } // namespace
148
149 ResourceManagerImpl::ResourceManagerImpl(ResourceManagerDelegate* delegate)
150 : delegate_(delegate),
151 current_memory_pressure_(MEMORY_PRESSURE_UNKNOWN),
152 memory_pressure_notifier_(new MemoryPressureNotifier(this)),
153 pause_(false),
154 queued_command_(false),
155 activity_order_changed_(false),
156 in_overview_mode_(false),
157 in_split_view_mode_(false),
158 next_resource_management_time_(base::Time::Now()),
159 wait_time_for_resource_deallocation_(base::TimeDelta::FromMilliseconds(
160 delegate_->MemoryPressureIntervalInMS())) {
161 WindowManager::Get()->AddObserver(this);
162 WindowManager::Get()->GetWindowListProvider()->AddObserver(this);
163 ActivityManager::Get()->AddObserver(this);
164 }
165
166 ResourceManagerImpl::~ResourceManagerImpl() {
167 ActivityManager::Get()->RemoveObserver(this);
168 WindowManager::Get()->GetWindowListProvider()->RemoveObserver(this);
169 WindowManager::Get()->RemoveObserver(this);
170 }
171
172 void ResourceManagerImpl::SetMemoryPressureAndStopMonitoring(
173 MemoryPressure pressure) {
174 memory_pressure_notifier_->StopObserving();
175 OnMemoryPressure(pressure);
176 }
177
178 void ResourceManagerImpl::OnActivityStarted(Activity* activity) {
179 // Update the activity states.
180 ManageResource();
181 activity_order_changed_ = true;
182 }
183
184 void ResourceManagerImpl::OnActivityEnding(Activity* activity) {
185 activity_order_changed_ = true;
186 }
187
188 void ResourceManagerImpl::OnActivityOrderChanged() {
189 activity_order_changed_ = true;
190 }
191
192 void ResourceManagerImpl::OnOverviewModeEnter() {
193 in_overview_mode_ = true;
194 }
195
196 void ResourceManagerImpl::OnOverviewModeExit() {
197 in_overview_mode_ = false;
198 ManageResource();
199 }
200
201 void ResourceManagerImpl::OnSplitViewModeEnter() {
202 // Re-apply the memory pressure to make sure enough items are visible.
203 in_split_view_mode_ = true;
204 ManageResource();
205 }
206
207
208 void ResourceManagerImpl::OnSplitViewModeExit() {
209 // We don't do immediately something yet. The next ManageResource call will
210 // come soon.
211 in_split_view_mode_ = false;
212 }
213
214 void ResourceManagerImpl::OnWindowStackingChangedInList() {
215 if (pause_) {
216 queued_command_ = true;
217 return;
218 }
219
220 // No need to do anything while being in overview mode.
221 if (in_overview_mode_)
222 return;
223
224 // Manage the resources of each activity.
225 ManageResource();
226 }
227
228 void ResourceManagerImpl::OnMemoryPressure(MemoryPressure pressure) {
229 if (pressure > current_memory_pressure_)
230 OnMemoryPressureIncreased();
231 current_memory_pressure_ = pressure;
232 ManageResource();
233 }
234
235 ResourceManagerDelegate* ResourceManagerImpl::GetDelegate() {
236 return delegate_.get();
237 }
238
239 void ResourceManagerImpl::ManageResource() {
240 // If there is none or only one app running we cannot do anything.
241 if (ActivityManager::Get()->GetActivityList().size() <= 1U)
242 return;
243
244 if (pause_) {
245 queued_command_ = true;
246 return;
247 }
248
249 // Check that the visibility of items is properly set. Note that this might
250 // already trigger a release of resources. If this happens,
251 // AllowedToUnloadActivity() will return false.
252 UpdateVisibilityStates();
253
254 // Since resource deallocation takes time, we avoid to release more resources
255 // in short succession. Note that we come here periodically and if one call
256 // is not triggering an unload, the next one will.
257 if (AllowedToUnloadActivity())
258 TryToUnloadAnActivity();
259 }
260
261 void ResourceManagerImpl::UpdateVisibilityStates() {
262 // The first n activities should be treated as "visible", means they updated
263 // in overview mode and will keep their layer resources for faster switch
264 // times. Usually we use |kMaxVisibleActivities| items, but when the memory
265 // pressure gets critical we only hold as many as are really visible.
266 size_t max_activities = kMaxVisibleActivities;
267 if (current_memory_pressure_ == MEMORY_PRESSURE_CRITICAL)
268 max_activities = in_split_view_mode_ ? 2 : 1;
269
270 do {
271 activity_order_changed_ = false;
272
273 // Change the visibility of our activities in a pre-processing step. This is
274 // required since it might change the order/number of activities.
275 // Note: We cannot use the order of items in the ActivityManager since it
276 // does not follow the order of windows.
277 size_t count = 0;
278 const aura::Window::Windows& windows =
279 WindowManager::Get()->GetWindowListProvider()->GetWindowList();
280 for (aura::Window::Windows::const_reverse_iterator it = windows.rbegin();
281 it != windows.rend(); it++) {
282 Activity* activity = ActivityManager::Get()->GetActivityForWindow(*it);
283 // It is possible that the window was not yet added to the ActivityManager
284 // in which case we are not interested in managing it yet.
285 if (!activity)
286 continue;
287 Activity::ActivityState state = activity->GetCurrentState();
288
289 // The first |kMaxVisibleActivities| entries should be visible, all others
290 // invisible or at a lower activity state.
291 if (count < max_activities ||
292 (state == Activity::ACTIVITY_INVISIBLE ||
293 state == Activity::ACTIVITY_VISIBLE)) {
294 Activity::ActivityState visiblity_state =
295 count < max_activities ? Activity::ACTIVITY_VISIBLE :
296 Activity::ACTIVITY_INVISIBLE;
297 // Only change the state when it changes. Note that when the memory
298 // pressure is critical, only the primary activities (1 or 2) are made
299 // visible. Furthermore, in relaxed mode we only want to turn visible,
300 // never invisible.
301 if (visiblity_state != state &&
302 (current_memory_pressure_ != MEMORY_PRESSURE_LOW ||
303 visiblity_state == Activity::ACTIVITY_VISIBLE)) {
304 activity->SetCurrentState(visiblity_state);
305 // If we turned an activity invisible, we are already releasing memory
306 // and can hold off releasing more for now.
307 if (visiblity_state == Activity::ACTIVITY_INVISIBLE)
308 OnResourcesReleased();
309 }
310 }
311
312 // See which count we should handle next.
313 if (activity_order_changed_)
314 break;
315 ++count;
316 }
317 // If we stopped iterating over the list of activities because of the change
318 // in ordering, then restart processing the activities from the beginning.
319 } while (activity_order_changed_);
320 }
321
322 void ResourceManagerImpl::TryToUnloadAnActivity() {
323 // TODO(skuhne): This algorithm needs to take all kinds of predictive analysis
324 // and running applications into account. For this first patch we only do a
325 // very simple "floating window" algorithm which is surely not good enough.
326 size_t max_running_activities = 5;
327 switch (current_memory_pressure_) {
328 case MEMORY_PRESSURE_UNKNOWN:
329 // If we do not know how much memory we have we assume that it must be a
330 // high consumption.
331 // Fallthrough.
332 case MEMORY_PRESSURE_HIGH:
333 max_running_activities = 5;
334 break;
335 case MEMORY_PRESSURE_CRITICAL:
336 max_running_activities = 0;
337 break;
338 case MEMORY_PRESSURE_MODERATE:
339 max_running_activities = 7;
340 break;
341 case MEMORY_PRESSURE_LOW:
342 NOTREACHED();
343 return;
344 }
345
346 // Check if / which activity we want to unload.
347 Activity* oldest_media_activity = nullptr;
348 Activity* oldest_unloadable_activity = nullptr;
349 size_t unloadable_activity_count = 0;
350 const ActivityList& activity_list = ActivityManager::Get()->GetActivityList();
351 for (Activity* activity : activity_list) {
352 Activity::ActivityState state = activity->GetCurrentState();
353 // The activity should neither be unloaded nor visible.
354 if (state != Activity::ACTIVITY_UNLOADED &&
355 state != Activity::ACTIVITY_VISIBLE) {
356 if (activity->GetMediaState() == Activity::ACTIVITY_MEDIA_STATE_NONE) {
357 // Does not play media - so we can unload this immediately.
358 ++unloadable_activity_count;
359 oldest_unloadable_activity = activity;
360 } else {
361 oldest_media_activity = activity;
362 }
363 }
364 }
365
366 if (unloadable_activity_count > max_running_activities) {
367 CHECK(oldest_unloadable_activity);
368 OnResourcesReleased();
369 oldest_unloadable_activity->SetCurrentState(Activity::ACTIVITY_UNLOADED);
370 return;
371 } else if (current_memory_pressure_ == MEMORY_PRESSURE_CRITICAL) {
372 if (oldest_media_activity) {
373 OnResourcesReleased();
374 oldest_media_activity->SetCurrentState(Activity::ACTIVITY_UNLOADED);
375 LOG(WARNING) << "Unloading item to releave critical memory pressure";
376 return;
377 }
378 LOG(ERROR) << "[ResourceManager]: Single activity uses too much memory.";
379 return;
380 }
381
382 if (current_memory_pressure_ != MEMORY_PRESSURE_UNKNOWN) {
383 // Only show this warning when the memory pressure is actually known. This
384 // will suppress warnings in e.g. unit tests.
385 LOG(WARNING) << "[ResourceManager]: No way to release memory pressure (" <<
386 current_memory_pressure_ <<
387 "), Activities (running, allowed, unloadable)=(" <<
388 activity_list.size() << ", " <<
389 max_running_activities << ", " <<
390 unloadable_activity_count << ")";
391 }
392 }
393
394 void ResourceManagerImpl::OnResourcesReleased() {
395 // Do not release too many activities in short succession since it takes time
396 // to release resources. As such wait the memory pressure interval before the
397 // next call.
398 next_resource_management_time_ = base::Time::Now() +
399 wait_time_for_resource_deallocation_;
400 }
401
402 void ResourceManagerImpl::OnMemoryPressureIncreased() {
403 // By setting the timer to Now, the next call will immediately be performed.
404 next_resource_management_time_ = base::Time::Now();
405 }
406
407 bool ResourceManagerImpl::AllowedToUnloadActivity() {
408 return current_memory_pressure_ != MEMORY_PRESSURE_LOW &&
409 base::Time::Now() >= next_resource_management_time_;
410 }
411
412 } // namespace
413
414 // static
415 void ResourceManager::Create() {
416 DCHECK(!instance);
417 instance = new ResourceManagerImpl(
418 ResourceManagerDelegate::CreateResourceManagerDelegate());
419 }
420
421 // static
422 ResourceManager* ResourceManager::Get() {
423 return instance;
424 }
425
426 // static
427 void ResourceManager::Shutdown() {
428 DCHECK(instance);
429 delete instance;
430 instance = nullptr;
431 }
432
433 ResourceManager::ResourceManager() {}
434
435 ResourceManager::~ResourceManager() {
436 DCHECK(instance);
437 instance = nullptr;
438 }
439
440 } // namespace athena
OLDNEW
« no previous file with comments | « athena/resource_manager/public/resource_manager_delegate.h ('k') | athena/resource_manager/resource_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698