Adding Baseframework of the ResourceManager (all hooks and observers)
[chromium-blink-merge.git] / athena / resource_manager / resource_manager_impl.cc
blob74e5baf75329a2c6fa703856de34e782fb82223a
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/resource_manager/public/resource_manager.h"
7 #include <algorithm>
8 #include <vector>
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_manager.h"
16 #include "athena/wm/public/window_manager_observer.h"
17 #include "base/logging.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "ui/aura/window.h"
21 namespace athena {
23 class ResourceManagerImpl : public ResourceManager,
24 public WindowManagerObserver,
25 public ActivityManagerObserver,
26 public MemoryPressureObserver {
27 public:
28 ResourceManagerImpl(ResourceManagerDelegate* delegate);
29 virtual ~ResourceManagerImpl();
31 // ResourceManager:
32 virtual void SetMemoryPressureAndStopMonitoring(
33 MemoryPressureObserver::MemoryPressure pressure) OVERRIDE;
35 // ActivityManagerObserver:
36 virtual void OnActivityStarted(Activity* activity) OVERRIDE;
37 virtual void OnActivityEnding(Activity* activity) OVERRIDE;
39 // WindowManagerObserver:
40 virtual void OnOverviewModeEnter() OVERRIDE;
41 virtual void OnOverviewModeExit() OVERRIDE;
42 virtual void OnActivityOrderHasChanged() OVERRIDE;
44 // MemoryPressureObserver:
45 virtual void OnMemoryPressure(
46 MemoryPressureObserver::MemoryPressure pressure) OVERRIDE;
47 virtual ResourceManagerDelegate* GetDelegate() OVERRIDE;
49 private:
50 // Manage the resources for our activities.
51 void ManageResource();
53 // Order our activity list to the order of activities of the stream.
54 // TODO(skuhne): Once the ActivityManager is responsible to create this list
55 // for us, we can remove this code here.
56 void UpdateActivityOrder();
58 // The sorted (new(front) -> old(back)) activity list.
59 // TODO(skuhne): Once the ActivityManager is responsible to create this list
60 // for us, we can remove this code here.
61 std::vector<Activity*> activity_list_;
63 // The resource manager delegate.
64 scoped_ptr<ResourceManagerDelegate> delegate_;
66 // Keeping a reference to the current memory pressure.
67 MemoryPressureObserver::MemoryPressure current_memory_pressure_;
69 // The memory pressure notifier.
70 scoped_ptr<MemoryPressureNotifier> memory_pressure_notifier_;
72 DISALLOW_COPY_AND_ASSIGN(ResourceManagerImpl);
75 namespace {
76 ResourceManagerImpl* instance = NULL;
77 } // namespace
79 ResourceManagerImpl::ResourceManagerImpl(ResourceManagerDelegate* delegate)
80 : delegate_(delegate),
81 current_memory_pressure_(MemoryPressureObserver::MEMORY_PRESSURE_UNKNOWN),
82 memory_pressure_notifier_(new MemoryPressureNotifier(this)) {
83 WindowManager::GetInstance()->AddObserver(this);
84 ActivityManager::Get()->AddObserver(this);
87 ResourceManagerImpl::~ResourceManagerImpl() {
88 ActivityManager::Get()->RemoveObserver(this);
89 WindowManager::GetInstance()->RemoveObserver(this);
92 void ResourceManagerImpl::SetMemoryPressureAndStopMonitoring(
93 MemoryPressureObserver::MemoryPressure pressure) {
94 memory_pressure_notifier_->StopObserving();
95 OnMemoryPressure(pressure);
98 void ResourceManagerImpl::OnActivityStarted(Activity* activity) {
99 // As long as we have to manage the list of activities ourselves, we need to
100 // order it here.
101 activity_list_.push_back(activity);
102 UpdateActivityOrder();
103 // Update the activity states.
104 ManageResource();
107 void ResourceManagerImpl::OnActivityEnding(Activity* activity) {
108 // Remove the activity from the list again.
109 std::vector<Activity*>::iterator it =
110 std::find(activity_list_.begin(), activity_list_.end(), activity);
111 DCHECK(it != activity_list_.end());
112 activity_list_.erase(it);
115 void ResourceManagerImpl::OnOverviewModeEnter() {
116 // Nothing to do here.
119 void ResourceManagerImpl::OnOverviewModeExit() {
120 // Nothing to do here.
123 void ResourceManagerImpl::OnActivityOrderHasChanged() {
124 // As long as we have to manage the list of activities ourselves, we need to
125 // order it here.
126 UpdateActivityOrder();
127 // Manage the resources of each activity.
128 ManageResource();
131 void ResourceManagerImpl::OnMemoryPressure(
132 MemoryPressureObserver::MemoryPressure pressure) {
133 current_memory_pressure_ = pressure;
134 ManageResource();
137 ResourceManagerDelegate* ResourceManagerImpl::GetDelegate() {
138 return delegate_.get();
141 void ResourceManagerImpl::ManageResource() {
142 // If there is none or only one app running we cannot do anything.
143 if (activity_list_.size() <= 1U)
144 return;
145 // TODO(skuhne): This algorithm needs to take all kinds of predictive analysis
146 // and running applications into account. For this first patch we only do a
147 // very simple "floating window" algorithm which is surely not good enough.
148 size_t max_running_activities = 5;
149 switch (current_memory_pressure_) {
150 case MEMORY_PRESSURE_UNKNOWN:
151 // If we do not know how much memory we have we assume that it must be a
152 // high consumption.
153 // Fallthrough.
154 case MEMORY_PRESSURE_HIGH:
155 max_running_activities = 5;
156 break;
157 case MEMORY_PRESSURE_CRITICAL:
158 max_running_activities = 0;
159 break;
160 case MEMORY_PRESSURE_MODERATE:
161 max_running_activities = 7;
162 break;
163 case MEMORY_PRESSURE_LOW:
164 // No need to do anything yet.
165 return;
167 Activity* oldest_media_activity = NULL;
168 std::vector<Activity*> unloadable_activities;
169 for (std::vector<Activity*>::iterator it = activity_list_.begin();
170 it != activity_list_.end(); ++it) {
171 // The activity should not be unloaded or visible.
172 if ((*it)->GetCurrentState() != Activity::ACTIVITY_UNLOADED &&
173 !(*it)->IsVisible()) {
174 if ((*it)->GetMediaState() == Activity::ACTIVITY_MEDIA_STATE_NONE) {
175 // Does not play media - so we can unload this immediately.
176 unloadable_activities.push_back(*it);
177 } else {
178 oldest_media_activity = *it;
182 if (unloadable_activities.size() > max_running_activities) {
183 unloadable_activities.back()->SetCurrentState(Activity::ACTIVITY_UNLOADED);
184 return;
185 } else if (current_memory_pressure_ == MEMORY_PRESSURE_CRITICAL) {
186 if (oldest_media_activity) {
187 oldest_media_activity->SetCurrentState(Activity::ACTIVITY_UNLOADED);
188 return;
190 LOG(ERROR) << "[ResourceManager]: Single activity uses too much memory.";
191 return;
193 if (current_memory_pressure_ != MEMORY_PRESSURE_UNKNOWN) {
194 // Only show this warning when the memory pressure is actually known. This
195 // will suppress warnings in e.g. unit tests.
196 LOG(WARNING) << "[ResourceManager]: No way to release memory pressure (" <<
197 current_memory_pressure_ <<
198 "), Activities (running, allowed, unloadable)=(" <<
199 activity_list_.size() << ", " <<
200 max_running_activities << ", " <<
201 unloadable_activities.size() << ")";
205 void ResourceManagerImpl::UpdateActivityOrder() {
206 if (activity_list_.empty())
207 return;
208 std::vector<Activity*> new_activity_list;
209 const aura::Window::Windows children =
210 activity_list_[0]->GetWindow()->parent()->children();
211 // Find the first window in the container which is part of the application.
212 for (aura::Window::Windows::const_iterator child_iterator = children.begin();
213 child_iterator != children.end(); ++child_iterator) {
214 for (std::vector<Activity*>::iterator activity_iterator =
215 activity_list_.begin();
216 activity_iterator != activity_list_.end(); ++activity_iterator) {
217 if (*child_iterator == (*activity_iterator)->GetWindow()) {
218 new_activity_list.push_back(*activity_iterator);
219 activity_list_.erase(activity_iterator);
220 break;
224 // At this point the old list should be empty and we can swap the lists.
225 DCHECK(!activity_list_.size());
226 activity_list_ = new_activity_list;
229 // static
230 void ResourceManager::Create() {
231 DCHECK(!instance);
232 instance = new ResourceManagerImpl(
233 ResourceManagerDelegate::CreateResourceManagerDelegate());
236 // static
237 ResourceManager* ResourceManager::Get() {
238 return instance;
241 // static
242 void ResourceManager::Shutdown() {
243 DCHECK(instance);
244 delete instance;
245 instance = NULL;
248 ResourceManager::ResourceManager() {}
250 ResourceManager::~ResourceManager() {
251 DCHECK(instance);
252 instance = NULL;
255 } // namespace athena