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"
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"
23 class ResourceManagerImpl
: public ResourceManager
,
24 public WindowManagerObserver
,
25 public ActivityManagerObserver
,
26 public MemoryPressureObserver
{
28 ResourceManagerImpl(ResourceManagerDelegate
* delegate
);
29 virtual ~ResourceManagerImpl();
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
;
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
);
76 ResourceManagerImpl
* instance
= NULL
;
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
101 activity_list_
.push_back(activity
);
102 UpdateActivityOrder();
103 // Update the activity states.
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
126 UpdateActivityOrder();
127 // Manage the resources of each activity.
131 void ResourceManagerImpl::OnMemoryPressure(
132 MemoryPressureObserver::MemoryPressure pressure
) {
133 current_memory_pressure_
= pressure
;
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)
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
154 case MEMORY_PRESSURE_HIGH
:
155 max_running_activities
= 5;
157 case MEMORY_PRESSURE_CRITICAL
:
158 max_running_activities
= 0;
160 case MEMORY_PRESSURE_MODERATE
:
161 max_running_activities
= 7;
163 case MEMORY_PRESSURE_LOW
:
164 // No need to do anything yet.
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
);
178 oldest_media_activity
= *it
;
182 if (unloadable_activities
.size() > max_running_activities
) {
183 unloadable_activities
.back()->SetCurrentState(Activity::ACTIVITY_UNLOADED
);
185 } else if (current_memory_pressure_
== MEMORY_PRESSURE_CRITICAL
) {
186 if (oldest_media_activity
) {
187 oldest_media_activity
->SetCurrentState(Activity::ACTIVITY_UNLOADED
);
190 LOG(ERROR
) << "[ResourceManager]: Single activity uses too much memory.";
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())
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
);
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
;
230 void ResourceManager::Create() {
232 instance
= new ResourceManagerImpl(
233 ResourceManagerDelegate::CreateResourceManagerDelegate());
237 ResourceManager
* ResourceManager::Get() {
242 void ResourceManager::Shutdown() {
248 ResourceManager::ResourceManager() {}
250 ResourceManager::~ResourceManager() {
255 } // namespace athena