Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5223)

Unified Diff: chrome/browser/memory/tab_manager.cc

Issue 2387603003: Resume a backgrounded renderer that was purged and suspended (Closed)
Patch Set: Added transition: => RUNNING Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/memory/tab_manager.cc
diff --git a/chrome/browser/memory/tab_manager.cc b/chrome/browser/memory/tab_manager.cc
index e761e81a7c43a1d31ef1ebd15c33c984e6faa98b..3223e39cd746bf4c21d58a88ae1ba1db23729b43 100644
--- a/chrome/browser/memory/tab_manager.cc
+++ b/chrome/browser/memory/tab_manager.cc
@@ -84,6 +84,16 @@ const int kRecentTabDiscardIntervalSeconds = 60;
// machine was suspended and correct the timing statistics.
const int kSuspendThresholdSeconds = kAdjustmentIntervalSeconds * 4;
+// The backgrounded renderer is allowed to be suspended for this duration
+// before resume.
haraken 2016/10/20 16:52:16 A suspended renderer is suspended for this duratio
+constexpr base::TimeDelta kMaxTimeRendererAllowedToBeSuspendedBeforeResume =
haraken 2016/10/20 16:52:16 kDurationOfRendererSuspension ?
+ base::TimeDelta::FromSeconds(120);
+
+// When the suspended backgrounded renderer is resumed, the renderer runs
+// for this duration.
haraken 2016/10/20 16:52:16 A resumed renderer is resumed for this duration.
+constexpr base::TimeDelta kSuspendedRendererLengthOfResumption =
haraken 2016/10/20 16:52:16 kDurationOfRendererResumption ?
+ base::TimeDelta::FromSeconds(10);
+
// The time during which a tab is protected from discarding after it stops being
// audible.
const int kAudioProtectionTimeSeconds = 60;
@@ -418,17 +428,24 @@ void TabManager::SetTabAutoDiscardableState(content::WebContents* contents,
GetWebContentsData(contents)->SetAutoDiscardableState(state);
}
+content::WebContents* TabManager::GetWebContentsByContentsId(
+ int64_t tab_contents_id) {
+ TabStripModel* model;
+ int index = FindTabStripModelById(tab_contents_id, &model);
+ if (index == -1)
+ return nullptr;
+ return model->GetWebContentsAt(index);
+}
+
bool TabManager::CanSuspendBackgroundedRenderer(int render_process_id) {
// A renderer can be suspended if it's not playing media.
auto tab_stats = GetUnsortedTabStats();
for (auto& tab : tab_stats) {
if (tab.child_process_host_id != render_process_id)
continue;
- TabStripModel* model;
- int index = FindTabStripModelById(tab.tab_contents_id, &model);
- if (index == -1)
+ WebContents* web_contents = GetWebContentsByContentsId(tab.tab_contents_id);
+ if (!web_contents)
return false;
- WebContents* web_contents = model->GetWebContentsAt(index);
if (IsMediaTab(web_contents))
return false;
}
@@ -687,6 +704,47 @@ void TabManager::UpdateTimerCallback() {
PurgeAndSuspendBackgroundedTabs();
}
+bool TabManager::ShouldUpdatePurgeAndSuspendState(
+ const base::TimeTicks& current_time,
+ const TabStats& tab,
+ const base::TimeDelta& purge_and_suspend_threshold,
+ PurgeAndSuspendState* next_state) {
+ DCHECK(next_state);
+ content::WebContents* content =
+ GetWebContentsByContentsId(tab.tab_contents_id);
+ if (!content)
+ return false;
+
+ base::TimeTicks last_modified_time =
+ GetWebContentsData(content)->LastPurgeAndSuspendModifiedTime();
+ PurgeAndSuspendState state =
+ GetWebContentsData(content)->GetPurgeAndSuspendState();
+ DCHECK(state == RUNNING || tab.last_active < last_modified_time);
haraken 2016/10/20 16:52:16 Add a comment about what 'tab.last_active < last_m
+
+ auto time_passed = current_time - last_modified_time;
+ switch (state) {
+ case RUNNING:
+ if (time_passed > purge_and_suspend_threshold) {
+ *next_state = SUSPENDED;
+ return true;
+ }
+ break;
+ case RESUMED:
+ if (time_passed > kSuspendedRendererLengthOfResumption) {
+ *next_state = SUSPENDED;
+ return true;
+ }
+ break;
+ case SUSPENDED:
+ if (time_passed > kMaxTimeRendererAllowedToBeSuspendedBeforeResume) {
+ *next_state = RESUMED;
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
void TabManager::PurgeAndSuspendBackgroundedTabs() {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
@@ -700,21 +758,36 @@ void TabManager::PurgeAndSuspendBackgroundedTabs() {
}
if (purge_and_suspend_time <= 0)
return;
- auto purge_and_suspend_time_threshold =
- NowTicks() - base::TimeDelta::FromSeconds(purge_and_suspend_time);
+ base::TimeTicks current_time = NowTicks();
+ base::TimeDelta purge_and_suspend_threshold =
+ base::TimeDelta::FromSeconds(purge_and_suspend_time);
auto tab_stats = GetUnsortedTabStats();
for (auto& tab : tab_stats) {
if (!tab.render_process_host->IsProcessBackgrounded())
continue;
+ if (!CanSuspendBackgroundedRenderer(tab.child_process_host_id))
+ continue;
+
// TODO(hajimehoshi): Now calling PurgeAndSuspend is implemented without
// timers for simplicity, so PurgeAndSuspend is called even after the
// renderer is purged and suspended once. This should be replaced with
// timers if we want necessary and sufficient signals.
- if (tab.last_active > purge_and_suspend_time_threshold)
+ PurgeAndSuspendState state = RUNNING;
+ if (!ShouldUpdatePurgeAndSuspendState(current_time, tab,
haraken 2016/10/20 16:52:16 How about just making this method return the next
+ purge_and_suspend_threshold, &state))
continue;
- if (!CanSuspendBackgroundedRenderer(tab.child_process_host_id))
- continue;
- tab.render_process_host->PurgeAndSuspend();
+ WebContents* content = GetWebContentsByContentsId(tab.tab_contents_id);
+ GetWebContentsData(content)->SetPurgeAndSuspendState(state);
+ switch (state) {
+ case SUSPENDED:
+ tab.render_process_host->PurgeAndSuspend();
+ break;
+ case RESUMED:
+ tab.render_process_host->Resume();
+ break;
+ case RUNNING:
+ NOTREACHED();
+ }
}
}
@@ -815,6 +888,7 @@ void TabManager::ActiveTabChanged(content::WebContents* old_contents,
int index,
int reason) {
GetWebContentsData(new_contents)->SetDiscardState(false);
+ GetWebContentsData(new_contents)->SetPurgeAndSuspendState(RUNNING);
// If |old_contents| is set, that tab has switched from being active to
// inactive, so record the time of that transition.
if (old_contents)

Powered by Google App Engine
This is Rietveld 408576698