Index: athena/resource_manager/resource_manager_impl.cc |
diff --git a/athena/resource_manager/resource_manager_impl.cc b/athena/resource_manager/resource_manager_impl.cc |
deleted file mode 100644 |
index 36a0edd5383b07926cfc91360210e868210a4893..0000000000000000000000000000000000000000 |
--- a/athena/resource_manager/resource_manager_impl.cc |
+++ /dev/null |
@@ -1,440 +0,0 @@ |
-// Copyright 2014 The Chromium Authors. All rights reserved. |
-// 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_list_provider.h" |
-#include "athena/wm/public/window_list_provider_observer.h" |
-#include "athena/wm/public/window_manager.h" |
-#include "athena/wm/public/window_manager_observer.h" |
-#include "base/containers/adapters.h" |
-#include "base/logging.h" |
-#include "base/memory/scoped_ptr.h" |
-#include "base/time/time.h" |
-#include "ui/aura/window.h" |
- |
-namespace athena { |
-namespace { |
- |
-class ResourceManagerImpl : public ResourceManager, |
- public WindowManagerObserver, |
- public ActivityManagerObserver, |
- public MemoryPressureObserver, |
- public WindowListProviderObserver { |
- public: |
- ResourceManagerImpl(ResourceManagerDelegate* delegate); |
- ~ResourceManagerImpl() override; |
- |
- // ResourceManager: |
- virtual void SetMemoryPressureAndStopMonitoring( |
- MemoryPressure pressure) override; |
- virtual void SetWaitTimeBetweenResourceManageCalls(int time_in_ms) override { |
- wait_time_for_resource_deallocation_ = |
- base::TimeDelta::FromMilliseconds(time_in_ms); |
- // Reset the timeout to force the next resource call to execute immediately. |
- next_resource_management_time_ = base::Time::Now(); |
- } |
- |
- virtual void Pause(bool pause) override { |
- if (pause) { |
- if (!pause_) |
- queued_command_ = false; |
- ++pause_; |
- } else { |
- DCHECK(pause_); |
- --pause_; |
- if (!pause && queued_command_) |
- ManageResource(); |
- } |
- } |
- |
- // ActivityManagerObserver: |
- virtual void OnActivityStarted(Activity* activity) override; |
- virtual void OnActivityEnding(Activity* activity) override; |
- virtual void OnActivityOrderChanged() override; |
- |
- // WindowManagerObserver: |
- virtual void OnOverviewModeEnter() override; |
- virtual void OnOverviewModeExit() override; |
- virtual void OnSplitViewModeEnter() override; |
- virtual void OnSplitViewModeExit() override; |
- |
- // MemoryPressureObserver: |
- virtual void OnMemoryPressure(MemoryPressure pressure) override; |
- virtual ResourceManagerDelegate* GetDelegate() override; |
- |
- // WindowListProviderObserver: |
- virtual void OnWindowStackingChangedInList() override; |
- virtual void OnWindowAddedToList(aura::Window* added_window) override {} |
- virtual void OnWindowRemovedFromList(aura::Window* removed_window, |
- int index) override {} |
- |
- private: |
- // Manage the resources for our activities. |
- void ManageResource(); |
- |
- // Check that the visibility of activities is properly set. |
- void UpdateVisibilityStates(); |
- |
- // Check if activities can be unloaded to reduce memory pressure. |
- void TryToUnloadAnActivity(); |
- |
- // Resources were released and a quiet period is needed before we release |
- // more since it takes a while to trickle through the system. |
- void OnResourcesReleased(); |
- |
- // The memory pressure has increased, previously applied measures did not show |
- // effect and immediate action is required. |
- void OnMemoryPressureIncreased(); |
- |
- // Returns true when the previous memory release was long enough ago to try |
- // unloading another activity. |
- bool AllowedToUnloadActivity(); |
- |
- // The resource manager delegate. |
- scoped_ptr<ResourceManagerDelegate> delegate_; |
- |
- // Keeping a reference to the current memory pressure. |
- MemoryPressure current_memory_pressure_; |
- |
- // The memory pressure notifier. |
- scoped_ptr<MemoryPressureNotifier> memory_pressure_notifier_; |
- |
- // A ref counter. As long as not 0, the management is on hold. |
- int pause_; |
- |
- // If true, a command came in while the resource manager was paused. |
- bool queued_command_; |
- |
- // Used by ManageResource() to determine an activity state change while it |
- // changes Activity properties. |
- bool activity_order_changed_; |
- |
- // True if in overview mode - activity order changes will be ignored if true |
- // and postponed till after the overview mode is ending. |
- bool in_overview_mode_; |
- |
- // True if we are in split view mode. |
- bool in_split_view_mode_; |
- |
- // The last time the resource manager was called to release resources. |
- // Avoid too aggressive resource de-allocation by enforcing a wait time of |
- // |wait_time_for_resource_deallocation_| between executed calls. |
- base::Time next_resource_management_time_; |
- |
- // The wait time between two resource managing executions. |
- base::TimeDelta wait_time_for_resource_deallocation_; |
- |
- DISALLOW_COPY_AND_ASSIGN(ResourceManagerImpl); |
-}; |
- |
-namespace { |
-ResourceManagerImpl* instance = nullptr; |
- |
-// We allow this many activities to be visible. All others must be at state of |
-// invisible or below. |
-const int kMaxVisibleActivities = 3; |
- |
-} // namespace |
- |
-ResourceManagerImpl::ResourceManagerImpl(ResourceManagerDelegate* delegate) |
- : delegate_(delegate), |
- current_memory_pressure_(MEMORY_PRESSURE_UNKNOWN), |
- memory_pressure_notifier_(new MemoryPressureNotifier(this)), |
- pause_(false), |
- queued_command_(false), |
- activity_order_changed_(false), |
- in_overview_mode_(false), |
- in_split_view_mode_(false), |
- next_resource_management_time_(base::Time::Now()), |
- wait_time_for_resource_deallocation_(base::TimeDelta::FromMilliseconds( |
- delegate_->MemoryPressureIntervalInMS())) { |
- WindowManager::Get()->AddObserver(this); |
- WindowManager::Get()->GetWindowListProvider()->AddObserver(this); |
- ActivityManager::Get()->AddObserver(this); |
-} |
- |
-ResourceManagerImpl::~ResourceManagerImpl() { |
- ActivityManager::Get()->RemoveObserver(this); |
- WindowManager::Get()->GetWindowListProvider()->RemoveObserver(this); |
- WindowManager::Get()->RemoveObserver(this); |
-} |
- |
-void ResourceManagerImpl::SetMemoryPressureAndStopMonitoring( |
- MemoryPressure pressure) { |
- memory_pressure_notifier_->StopObserving(); |
- OnMemoryPressure(pressure); |
-} |
- |
-void ResourceManagerImpl::OnActivityStarted(Activity* activity) { |
- // Update the activity states. |
- ManageResource(); |
- activity_order_changed_ = true; |
-} |
- |
-void ResourceManagerImpl::OnActivityEnding(Activity* activity) { |
- activity_order_changed_ = true; |
-} |
- |
-void ResourceManagerImpl::OnActivityOrderChanged() { |
- activity_order_changed_ = true; |
-} |
- |
-void ResourceManagerImpl::OnOverviewModeEnter() { |
- in_overview_mode_ = true; |
-} |
- |
-void ResourceManagerImpl::OnOverviewModeExit() { |
- in_overview_mode_ = false; |
- ManageResource(); |
-} |
- |
-void ResourceManagerImpl::OnSplitViewModeEnter() { |
- // Re-apply the memory pressure to make sure enough items are visible. |
- in_split_view_mode_ = true; |
- ManageResource(); |
-} |
- |
- |
-void ResourceManagerImpl::OnSplitViewModeExit() { |
- // We don't do immediately something yet. The next ManageResource call will |
- // come soon. |
- in_split_view_mode_ = false; |
-} |
- |
-void ResourceManagerImpl::OnWindowStackingChangedInList() { |
- if (pause_) { |
- queued_command_ = true; |
- return; |
- } |
- |
- // No need to do anything while being in overview mode. |
- if (in_overview_mode_) |
- return; |
- |
- // Manage the resources of each activity. |
- ManageResource(); |
-} |
- |
-void ResourceManagerImpl::OnMemoryPressure(MemoryPressure pressure) { |
- if (pressure > current_memory_pressure_) |
- OnMemoryPressureIncreased(); |
- 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 (ActivityManager::Get()->GetActivityList().size() <= 1U) |
- return; |
- |
- if (pause_) { |
- queued_command_ = true; |
- return; |
- } |
- |
- // Check that the visibility of items is properly set. Note that this might |
- // already trigger a release of resources. If this happens, |
- // AllowedToUnloadActivity() will return false. |
- UpdateVisibilityStates(); |
- |
- // Since resource deallocation takes time, we avoid to release more resources |
- // in short succession. Note that we come here periodically and if one call |
- // is not triggering an unload, the next one will. |
- if (AllowedToUnloadActivity()) |
- TryToUnloadAnActivity(); |
-} |
- |
-void ResourceManagerImpl::UpdateVisibilityStates() { |
- // The first n activities should be treated as "visible", means they updated |
- // in overview mode and will keep their layer resources for faster switch |
- // times. Usually we use |kMaxVisibleActivities| items, but when the memory |
- // pressure gets critical we only hold as many as are really visible. |
- size_t max_activities = kMaxVisibleActivities; |
- if (current_memory_pressure_ == MEMORY_PRESSURE_CRITICAL) |
- max_activities = in_split_view_mode_ ? 2 : 1; |
- |
- do { |
- activity_order_changed_ = false; |
- |
- // Change the visibility of our activities in a pre-processing step. This is |
- // required since it might change the order/number of activities. |
- // Note: We cannot use the order of items in the ActivityManager since it |
- // does not follow the order of windows. |
- size_t count = 0; |
- const aura::Window::Windows& windows = |
- WindowManager::Get()->GetWindowListProvider()->GetWindowList(); |
- for (aura::Window::Windows::const_reverse_iterator it = windows.rbegin(); |
- it != windows.rend(); it++) { |
- Activity* activity = ActivityManager::Get()->GetActivityForWindow(*it); |
- // It is possible that the window was not yet added to the ActivityManager |
- // in which case we are not interested in managing it yet. |
- if (!activity) |
- continue; |
- Activity::ActivityState state = activity->GetCurrentState(); |
- |
- // The first |kMaxVisibleActivities| entries should be visible, all others |
- // invisible or at a lower activity state. |
- if (count < max_activities || |
- (state == Activity::ACTIVITY_INVISIBLE || |
- state == Activity::ACTIVITY_VISIBLE)) { |
- Activity::ActivityState visiblity_state = |
- count < max_activities ? Activity::ACTIVITY_VISIBLE : |
- Activity::ACTIVITY_INVISIBLE; |
- // Only change the state when it changes. Note that when the memory |
- // pressure is critical, only the primary activities (1 or 2) are made |
- // visible. Furthermore, in relaxed mode we only want to turn visible, |
- // never invisible. |
- if (visiblity_state != state && |
- (current_memory_pressure_ != MEMORY_PRESSURE_LOW || |
- visiblity_state == Activity::ACTIVITY_VISIBLE)) { |
- activity->SetCurrentState(visiblity_state); |
- // If we turned an activity invisible, we are already releasing memory |
- // and can hold off releasing more for now. |
- if (visiblity_state == Activity::ACTIVITY_INVISIBLE) |
- OnResourcesReleased(); |
- } |
- } |
- |
- // See which count we should handle next. |
- if (activity_order_changed_) |
- break; |
- ++count; |
- } |
- // If we stopped iterating over the list of activities because of the change |
- // in ordering, then restart processing the activities from the beginning. |
- } while (activity_order_changed_); |
-} |
- |
-void ResourceManagerImpl::TryToUnloadAnActivity() { |
- // 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: |
- // If we do not know how much memory we have we assume that it must be a |
- // high consumption. |
- // Fallthrough. |
- case MEMORY_PRESSURE_HIGH: |
- max_running_activities = 5; |
- break; |
- case MEMORY_PRESSURE_CRITICAL: |
- max_running_activities = 0; |
- break; |
- case MEMORY_PRESSURE_MODERATE: |
- max_running_activities = 7; |
- break; |
- case MEMORY_PRESSURE_LOW: |
- NOTREACHED(); |
- return; |
- } |
- |
- // Check if / which activity we want to unload. |
- Activity* oldest_media_activity = nullptr; |
- Activity* oldest_unloadable_activity = nullptr; |
- size_t unloadable_activity_count = 0; |
- const ActivityList& activity_list = ActivityManager::Get()->GetActivityList(); |
- for (Activity* activity : activity_list) { |
- Activity::ActivityState state = activity->GetCurrentState(); |
- // The activity should neither be unloaded nor visible. |
- if (state != Activity::ACTIVITY_UNLOADED && |
- state != Activity::ACTIVITY_VISIBLE) { |
- if (activity->GetMediaState() == Activity::ACTIVITY_MEDIA_STATE_NONE) { |
- // Does not play media - so we can unload this immediately. |
- ++unloadable_activity_count; |
- oldest_unloadable_activity = activity; |
- } else { |
- oldest_media_activity = activity; |
- } |
- } |
- } |
- |
- if (unloadable_activity_count > max_running_activities) { |
- CHECK(oldest_unloadable_activity); |
- OnResourcesReleased(); |
- oldest_unloadable_activity->SetCurrentState(Activity::ACTIVITY_UNLOADED); |
- return; |
- } else if (current_memory_pressure_ == MEMORY_PRESSURE_CRITICAL) { |
- if (oldest_media_activity) { |
- OnResourcesReleased(); |
- oldest_media_activity->SetCurrentState(Activity::ACTIVITY_UNLOADED); |
- LOG(WARNING) << "Unloading item to releave critical memory pressure"; |
- return; |
- } |
- LOG(ERROR) << "[ResourceManager]: Single activity uses too much memory."; |
- return; |
- } |
- |
- if (current_memory_pressure_ != MEMORY_PRESSURE_UNKNOWN) { |
- // Only show this warning when the memory pressure is actually known. This |
- // will suppress warnings in e.g. unit tests. |
- LOG(WARNING) << "[ResourceManager]: No way to release memory pressure (" << |
- current_memory_pressure_ << |
- "), Activities (running, allowed, unloadable)=(" << |
- activity_list.size() << ", " << |
- max_running_activities << ", " << |
- unloadable_activity_count << ")"; |
- } |
-} |
- |
-void ResourceManagerImpl::OnResourcesReleased() { |
- // Do not release too many activities in short succession since it takes time |
- // to release resources. As such wait the memory pressure interval before the |
- // next call. |
- next_resource_management_time_ = base::Time::Now() + |
- wait_time_for_resource_deallocation_; |
-} |
- |
-void ResourceManagerImpl::OnMemoryPressureIncreased() { |
- // By setting the timer to Now, the next call will immediately be performed. |
- next_resource_management_time_ = base::Time::Now(); |
-} |
- |
-bool ResourceManagerImpl::AllowedToUnloadActivity() { |
- return current_memory_pressure_ != MEMORY_PRESSURE_LOW && |
- base::Time::Now() >= next_resource_management_time_; |
-} |
- |
-} // namespace |
- |
-// 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 = nullptr; |
-} |
- |
-ResourceManager::ResourceManager() {} |
- |
-ResourceManager::~ResourceManager() { |
- DCHECK(instance); |
- instance = nullptr; |
-} |
- |
-} // namespace athena |