OLD | NEW |
(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_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" |
| 20 |
| 21 namespace athena { |
| 22 |
| 23 class ResourceManagerImpl : public ResourceManager, |
| 24 public WindowManagerObserver, |
| 25 public ActivityManagerObserver, |
| 26 public MemoryPressureObserver { |
| 27 public: |
| 28 ResourceManagerImpl(ResourceManagerDelegate* delegate); |
| 29 virtual ~ResourceManagerImpl(); |
| 30 |
| 31 // ResourceManager: |
| 32 virtual void SetMemoryPressureAndStopMonitoring( |
| 33 MemoryPressureObserver::MemoryPressure pressure) OVERRIDE; |
| 34 |
| 35 // ActivityManagerObserver: |
| 36 virtual void OnActivityStarted(Activity* activity) OVERRIDE; |
| 37 virtual void OnActivityEnding(Activity* activity) OVERRIDE; |
| 38 |
| 39 // WindowManagerObserver: |
| 40 virtual void OnOverviewModeEnter() OVERRIDE; |
| 41 virtual void OnOverviewModeExit() OVERRIDE; |
| 42 virtual void OnActivityOrderHasChanged() OVERRIDE; |
| 43 |
| 44 // MemoryPressureObserver: |
| 45 virtual void OnMemoryPressure( |
| 46 MemoryPressureObserver::MemoryPressure pressure) OVERRIDE; |
| 47 virtual ResourceManagerDelegate* GetDelegate() OVERRIDE; |
| 48 |
| 49 private: |
| 50 // Manage the resources for our activities. |
| 51 void ManageResource(); |
| 52 |
| 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(); |
| 57 |
| 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_; |
| 62 |
| 63 // The resource manager delegate. |
| 64 scoped_ptr<ResourceManagerDelegate> delegate_; |
| 65 |
| 66 // Keeping a reference to the current memory pressure. |
| 67 MemoryPressureObserver::MemoryPressure current_memory_pressure_; |
| 68 |
| 69 // The memory pressure notifier. |
| 70 scoped_ptr<MemoryPressureNotifier> memory_pressure_notifier_; |
| 71 |
| 72 DISALLOW_COPY_AND_ASSIGN(ResourceManagerImpl); |
| 73 }; |
| 74 |
| 75 namespace { |
| 76 ResourceManagerImpl* instance = NULL; |
| 77 } // namespace |
| 78 |
| 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); |
| 85 } |
| 86 |
| 87 ResourceManagerImpl::~ResourceManagerImpl() { |
| 88 ActivityManager::Get()->RemoveObserver(this); |
| 89 WindowManager::GetInstance()->RemoveObserver(this); |
| 90 } |
| 91 |
| 92 void ResourceManagerImpl::SetMemoryPressureAndStopMonitoring( |
| 93 MemoryPressureObserver::MemoryPressure pressure) { |
| 94 memory_pressure_notifier_->StopObserving(); |
| 95 OnMemoryPressure(pressure); |
| 96 } |
| 97 |
| 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(); |
| 105 } |
| 106 |
| 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); |
| 113 } |
| 114 |
| 115 void ResourceManagerImpl::OnOverviewModeEnter() { |
| 116 // Nothing to do here. |
| 117 } |
| 118 |
| 119 void ResourceManagerImpl::OnOverviewModeExit() { |
| 120 // Nothing to do here. |
| 121 } |
| 122 |
| 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(); |
| 129 } |
| 130 |
| 131 void ResourceManagerImpl::OnMemoryPressure( |
| 132 MemoryPressureObserver::MemoryPressure pressure) { |
| 133 current_memory_pressure_ = pressure; |
| 134 ManageResource(); |
| 135 } |
| 136 |
| 137 ResourceManagerDelegate* ResourceManagerImpl::GetDelegate() { |
| 138 return delegate_.get(); |
| 139 } |
| 140 |
| 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; |
| 166 } |
| 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; |
| 179 } |
| 180 } |
| 181 } |
| 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; |
| 189 } |
| 190 LOG(ERROR) << "[ResourceManager]: Single activity uses too much memory."; |
| 191 return; |
| 192 } |
| 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() << ")"; |
| 202 } |
| 203 } |
| 204 |
| 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; |
| 221 } |
| 222 } |
| 223 } |
| 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; |
| 227 } |
| 228 |
| 229 // static |
| 230 void ResourceManager::Create() { |
| 231 DCHECK(!instance); |
| 232 instance = new ResourceManagerImpl( |
| 233 ResourceManagerDelegate::CreateResourceManagerDelegate()); |
| 234 } |
| 235 |
| 236 // static |
| 237 ResourceManager* ResourceManager::Get() { |
| 238 return instance; |
| 239 } |
| 240 |
| 241 // static |
| 242 void ResourceManager::Shutdown() { |
| 243 DCHECK(instance); |
| 244 delete instance; |
| 245 instance = NULL; |
| 246 } |
| 247 |
| 248 ResourceManager::ResourceManager() {} |
| 249 |
| 250 ResourceManager::~ResourceManager() { |
| 251 DCHECK(instance); |
| 252 instance = NULL; |
| 253 } |
| 254 |
| 255 } // namespace athena |
OLD | NEW |