Chromium Code Reviews| Index: athena/resource_manager/resource_manager.cc |
| diff --git a/athena/resource_manager/resource_manager.cc b/athena/resource_manager/resource_manager.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4742132bc0a03a5e3fbb900982cb5212584c5743 |
| --- /dev/null |
| +++ b/athena/resource_manager/resource_manager.cc |
| @@ -0,0 +1,249 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
|
Jun Mukai
2014/08/27 01:21:19
In athena, usually this file is named as resoure_m
Mr4D (OOO till 08-26)
2014/08/27 16:12:14
Done.
|
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "athena/resource_manager/public/resource_manager.h" |
| + |
| +#include <algorithm> |
| +#include <vector> |
| + |
| +#include "athena/activity/public/activity.h" |
| +#include "athena/activity/public/activity_manager.h" |
| +#include "athena/activity/public/activity_manager_observer.h" |
| +#include "athena/resource_manager/memory_pressure_notifier.h" |
| +#include "athena/resource_manager/public/resource_manager_delegate.h" |
| +#include "athena/wm/public/window_manager.h" |
| +#include "athena/wm/public/window_manager_observer.h" |
| +#include "base/logging.h" |
| +#include "base/memory/scoped_ptr.h" |
| +#include "ui/aura/window.h" |
| + |
| +namespace athena { |
| + |
| +class ResourceManagerImpl : public ResourceManager, |
| + public WindowManagerObserver, |
| + public ActivityManagerObserver, |
| + public MemoryPressureObserver { |
| + public: |
| + ResourceManagerImpl(ResourceManagerDelegate* delegate); |
| + virtual ~ResourceManagerImpl(); |
| + |
| + // ResourceManager: |
| + virtual void SetMemoryPressureForTest( |
| + MemoryPressureObserver::MemoryPressure pressure) OVERRIDE; |
| + |
| + // ActivityManagerObserver: |
| + virtual void OnActivityStarted(Activity* activity) OVERRIDE; |
| + virtual void OnActivityEnding(Activity* activity) OVERRIDE; |
| + |
| + // WindowManagerObserver: |
| + virtual void OnOverviewModeEnter() OVERRIDE; |
| + virtual void OnOverviewModeExit() OVERRIDE; |
| + virtual void OnActivityOrderHasChanged() OVERRIDE; |
| + |
| + // MemoryPressureObserver: |
| + virtual void OnMemoryPressure( |
| + MemoryPressureObserver::MemoryPressure pressure) OVERRIDE; |
| + virtual ResourceManagerDelegate* GetDelegate() OVERRIDE; |
| + |
| + private: |
| + // Manage the resources for our activities. |
| + void ManageResource(); |
| + |
| + // Order our activity list to the order of activities of the stream. |
| + // TODO(skuhne): Once the ActivityManager is responsible to create this list |
| + // for us, we can remove this code here. |
| + void UpdateActivityOrder(); |
| + |
| + // The sorted (new(front) -> old(back)) activity list. |
| + // TODO(skuhne): Once the ActivityManager is responsible to create this list |
| + // for us, we can remove this code here. |
|
Jun Mukai
2014/08/27 01:21:18
Also, it's better to be unified with WindowListPro
Mr4D (OOO till 08-26)
2014/08/27 16:12:13
I know. I have a CL queued (480293003) which adds
Jun Mukai
2014/08/27 16:57:47
Turns out I was still confused by the difference b
|
| + std::vector<Activity*> activity_list_; |
| + |
| + // The resource manager delegate. |
| + scoped_ptr<ResourceManagerDelegate> delegate_; |
| + |
| + // Keeping a reference to the current memory pressure. |
| + MemoryPressureObserver::MemoryPressure current_memory_pressure_; |
| + |
| + // The memory pressure notifier. |
| + scoped_ptr<MemoryPressureNotifier> memory_pressure_notifier_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ResourceManagerImpl); |
| +}; |
| + |
| +namespace { |
| +ResourceManagerImpl* instance = NULL; |
| +} // namespace |
| + |
| +ResourceManagerImpl::ResourceManagerImpl(ResourceManagerDelegate* delegate) |
| + : delegate_(delegate), |
| + current_memory_pressure_(MemoryPressureObserver::MEMORY_PRESSURE_UNKNOWN), |
| + memory_pressure_notifier_(new MemoryPressureNotifier(this)) { |
| + WindowManager::GetInstance()->AddObserver(this); |
| + ActivityManager::Get()->AddObserver(this); |
| +} |
| + |
| +ResourceManagerImpl::~ResourceManagerImpl() { |
| + ActivityManager::Get()->RemoveObserver(this); |
| + WindowManager::GetInstance()->RemoveObserver(this); |
| +} |
| + |
| +void ResourceManagerImpl::SetMemoryPressureForTest( |
|
Jun Mukai
2014/08/27 01:21:19
It might be great to cancel memory_pressure_notifi
Mr4D (OOO till 08-26)
2014/08/27 16:12:13
The TestResourceManagerDelegate will never report
Jun Mukai
2014/08/27 16:57:48
Acknowledged.
|
| + MemoryPressureObserver::MemoryPressure pressure) { |
| + OnMemoryPressure(pressure); |
| +} |
| + |
| +void ResourceManagerImpl::OnActivityStarted(Activity* activity) { |
| + // As long as we have to manage the list of activities ourselves, we need to |
| + // order it here. |
| + activity_list_.push_back(activity); |
| + UpdateActivityOrder(); |
| + // Update the activity states. |
| + ManageResource(); |
| +} |
| + |
| +void ResourceManagerImpl::OnActivityEnding(Activity* activity) { |
| + // Remove the activity from the list again. |
| + std::vector<Activity*>::iterator it = |
| + std::find(activity_list_.begin(), activity_list_.end(), activity); |
| + DCHECK(it != activity_list_.end()); |
| + activity_list_.erase(it); |
| +} |
| + |
| +void ResourceManagerImpl::OnOverviewModeEnter() { |
| + // Nothing to do here. |
| +} |
| + |
| +void ResourceManagerImpl::OnOverviewModeExit() { |
| + // Nothing to do here. |
| +} |
| + |
| +void ResourceManagerImpl::OnActivityOrderHasChanged() { |
| + // As long as we have to manage the list of activities ourselves, we need to |
| + // order it here. |
| + UpdateActivityOrder(); |
| + // Manage the resources of each activity. |
| + ManageResource(); |
| +} |
| + |
| +void ResourceManagerImpl::OnMemoryPressure( |
| + MemoryPressureObserver::MemoryPressure pressure) { |
| + current_memory_pressure_ = pressure; |
| + ManageResource(); |
| +} |
| + |
| +ResourceManagerDelegate* ResourceManagerImpl::GetDelegate() { |
| + return delegate_.get(); |
| +} |
| + |
| +void ResourceManagerImpl::ManageResource() { |
| + // If there is none or only one app running we cannot do anything. |
| + if (activity_list_.size() <= 1U) |
| + return; |
| + // TODO(skuhne): This algorithm needs to take all kinds of predictive analysis |
| + // and running applications into account. For this first patch we only do a |
| + // very simple "floating window" algorithm which is surely not good enough. |
| + size_t max_running_activities = 5; |
| + switch (current_memory_pressure_) { |
| + case MEMORY_PRESSURE_UNKNOWN: |
| + max_running_activities = 5; |
| + break; |
| + case MEMORY_PRESSURE_CRITICAL: |
| + max_running_activities = 0; |
| + break; |
| + case MEMORY_PRESSURE_HIGH: |
| + max_running_activities = 5; |
| + break; |
| + case MEMORY_PRESSURE_MODERATE: |
| + max_running_activities = 7; |
| + break; |
| + case MEMORY_PRESSURE_LOW: |
| + // No need to do anything yet. |
|
Jun Mukai
2014/08/27 01:21:19
Not sure the difference between HIGH/UNKNOWN (sett
Mr4D (OOO till 08-26)
2014/08/27 16:12:13
I added another comment for unknown. You can find
|
| + return; |
| + } |
| + Activity* oldest_media_activity = NULL; |
| + std::vector<Activity*> unloadable_activities; |
| + for (std::vector<Activity*>::iterator it = activity_list_.begin(); |
| + it != activity_list_.end(); ++it) { |
| + // The activity should not be unloaded or visible. |
| + if ((*it)->GetCurrentState() != Activity::ACTIVITY_UNLOADED && |
| + !(*it)->IsVisible()) { |
| + if ((*it)->GetMediaState() == Activity::ACTIVITY_MEDIA_STATE_NONE) { |
| + // Does not play media - so we can unload this immediately. |
| + unloadable_activities.push_back(*it); |
| + } else { |
| + oldest_media_activity = *it; |
| + } |
| + } |
| + } |
| + if (unloadable_activities.size() > max_running_activities) { |
| + unloadable_activities.back()->SetCurrentState(Activity::ACTIVITY_UNLOADED); |
|
Jun Mukai
2014/08/27 01:21:18
Is it enough to set the state on only the oldest u
Mr4D (OOO till 08-26)
2014/08/27 16:12:13
The crux here is that any resource change takes ti
Jun Mukai
2014/08/27 16:57:47
Ah, I see.
|
| + return; |
| + } else if (current_memory_pressure_ == MEMORY_PRESSURE_CRITICAL) { |
|
Jun Mukai
2014/08/27 01:21:18
Think that there are multiple media activities and
Mr4D (OOO till 08-26)
2014/08/27 16:12:13
That was the intent. If there is no memory left an
Jun Mukai
2014/08/27 16:57:47
Acknowledged.
|
| + if (oldest_media_activity) { |
| + oldest_media_activity->SetCurrentState(Activity::ACTIVITY_UNLOADED); |
| + return; |
| + } |
| + LOG(ERROR) << "[ResourceManager]: Single activity uses too much memory."; |
| + return; |
| + } |
| + LOG(WARNING) << "[ResourceManager]: No way to release memory pressure (" << |
| + current_memory_pressure_ << |
| + "), Activities (running, allowed, unloadable)=(" << |
| + activity_list_.size() << ", " << |
| + max_running_activities << ", " << |
| + unloadable_activities.size() << ")"; |
| +} |
| + |
| +void ResourceManagerImpl::UpdateActivityOrder() { |
| + if (!activity_list_.size()) |
|
Jun Mukai
2014/08/27 01:21:18
activity_list_.empty() is clearer to me
Mr4D (OOO till 08-26)
2014/08/27 16:12:13
Done.
|
| + return; |
| + std::vector<Activity*> new_activity_list; |
| + const aura::Window::Windows children = |
| + activity_list_[0]->GetWindow()->parent()->children();; |
|
Jun Mukai
2014/08/27 01:21:18
double semicolon at end
Mr4D (OOO till 08-26)
2014/08/27 16:12:14
Done.
|
| + // Find the first window in the container which is part of the application. |
| + for (aura::Window::Windows::const_iterator child_iterator = children.begin(); |
| + child_iterator != children.end(); ++child_iterator) { |
| + for (std::vector<Activity*>::iterator activity_iterator = |
| + activity_list_.begin(); |
| + activity_iterator != activity_list_.end(); ++activity_iterator) { |
| + if (*child_iterator == (*activity_iterator)->GetWindow()) { |
| + new_activity_list.push_back(*activity_iterator); |
| + activity_list_.erase(activity_iterator); |
| + break; |
| + } |
| + } |
| + } |
| + // At this point the old list should be empty and we can swap the lists. |
| + DCHECK(!activity_list_.size()); |
| + activity_list_ = new_activity_list; |
| +} |
| + |
| +// static |
| +void ResourceManager::Create() { |
| + DCHECK(!instance); |
| + instance = new ResourceManagerImpl( |
| + ResourceManagerDelegate::CreateResourceManagerDelegate()); |
| +} |
| + |
| +// static |
| +ResourceManager* ResourceManager::Get() { |
| + return instance; |
| +} |
| + |
| +// static |
| +void ResourceManager::Shutdown() { |
| + DCHECK(instance); |
| + delete instance; |
| + instance = NULL; |
| +} |
| + |
| +ResourceManager::ResourceManager() {} |
| + |
| +ResourceManager::~ResourceManager() { |
| + DCHECK(instance); |
| + instance = NULL; |
| +} |
| + |
| +} // namespace athena |