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

Side by Side Diff: chrome/browser/memory/tab_manager.cc

Issue 1427613002: [TabManager] Move remaining discard logic from TabStripModel to TabManager. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/memory/tab_manager.h" 5 #include "chrome/browser/memory/tab_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 #include <vector> 9 #include <vector>
10 10
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 AddTabStats(BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH), false, 173 AddTabStats(BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH), false,
174 &stats_list); 174 &stats_list);
175 } 175 }
176 176
177 // Sort the collected data so that least desirable to be killed is first, most 177 // Sort the collected data so that least desirable to be killed is first, most
178 // desirable is last. 178 // desirable is last.
179 std::sort(stats_list.begin(), stats_list.end(), CompareTabStats); 179 std::sort(stats_list.begin(), stats_list.end(), CompareTabStats);
180 return stats_list; 180 return stats_list;
181 } 181 }
182 182
183 bool TabManager::IsTabDiscarded(content::WebContents* contents) const {
184 return GetWebContentsData(contents)->IsDiscarded();
185 }
186
183 // TODO(jamescook): This should consider tabs with references to other tabs, 187 // TODO(jamescook): This should consider tabs with references to other tabs,
184 // such as tabs created with JavaScript window.open(). Potentially consider 188 // such as tabs created with JavaScript window.open(). Potentially consider
185 // discarding the entire set together, or use that in the priority computation. 189 // discarding the entire set together, or use that in the priority computation.
186 bool TabManager::DiscardTab() { 190 bool TabManager::DiscardTab() {
187 DCHECK_CURRENTLY_ON(BrowserThread::UI); 191 DCHECK_CURRENTLY_ON(BrowserThread::UI);
188 TabStatsList stats = GetTabStats(); 192 TabStatsList stats = GetTabStats();
189 if (stats.empty()) 193 if (stats.empty())
190 return false; 194 return false;
191 // Loop until a non-discarded tab to kill is found. 195 // Loop until a non-discarded tab to kill is found.
192 for (TabStatsList::const_reverse_iterator stats_rit = stats.rbegin(); 196 for (TabStatsList::const_reverse_iterator stats_rit = stats.rbegin();
(...skipping 22 matching lines...) Expand all
215 LogMemory("Tab Discards Memory details", 219 LogMemory("Tab Discards Memory details",
216 base::Bind(&TabManager::PurgeMemoryAndDiscardTab)); 220 base::Bind(&TabManager::PurgeMemoryAndDiscardTab));
217 } 221 }
218 222
219 void TabManager::LogMemory(const std::string& title, 223 void TabManager::LogMemory(const std::string& title,
220 const base::Closure& callback) { 224 const base::Closure& callback) {
221 DCHECK_CURRENTLY_ON(BrowserThread::UI); 225 DCHECK_CURRENTLY_ON(BrowserThread::UI);
222 OomMemoryDetails::Log(title, callback); 226 OomMemoryDetails::Log(title, callback);
223 } 227 }
224 228
229 void TabManager::TabInsertedAt(content::WebContents* contents,
230 int index,
231 bool foreground) {
232 WebContentsData::CreateForWebContents(contents);
sky 2015/10/27 21:16:46 Is this necessary? Doesn't GetWebContentsData() im
Georges Khalil 2015/10/30 14:17:44 Correct, this is not needed. Removed.
233 }
234
225 void TabManager::TabChangedAt(content::WebContents* contents, 235 void TabManager::TabChangedAt(content::WebContents* contents,
226 int index, 236 int index,
227 TabChangeType change_type) { 237 TabChangeType change_type) {
238 WebContentsData::CreateForWebContents(contents);
228 if (change_type != TabChangeType::ALL) 239 if (change_type != TabChangeType::ALL)
229 return; 240 return;
230 241 auto data = GetWebContentsData(contents);
231 bool old_state = WebContentsData::IsRecentlyAudible(contents); 242 bool old_state = data->IsRecentlyAudible();
232 bool current_state = contents->WasRecentlyAudible(); 243 bool current_state = contents->WasRecentlyAudible();
233 if (old_state != current_state) { 244 if (old_state != current_state) {
234 WebContentsData::SetRecentlyAudible(contents, current_state); 245 data->SetRecentlyAudible(current_state);
235 WebContentsData::SetLastAudioChangeTime(contents, TimeTicks::Now()); 246 data->SetLastAudioChangeTime(TimeTicks::Now());
236 } 247 }
237 } 248 }
238 249
250 void TabManager::ActiveTabChanged(content::WebContents* old_contents,
251 content::WebContents* new_contents,
252 int index,
253 int reason) {
254 GetWebContentsData(new_contents)->SetDiscardState(false);
255 }
256
239 /////////////////////////////////////////////////////////////////////////////// 257 ///////////////////////////////////////////////////////////////////////////////
240 // TabManager, private: 258 // TabManager, private:
241 259
242 // static 260 // static
243 void TabManager::PurgeMemoryAndDiscardTab() { 261 void TabManager::PurgeMemoryAndDiscardTab() {
244 if (g_browser_process && g_browser_process->GetTabManager()) { 262 if (g_browser_process && g_browser_process->GetTabManager()) {
245 TabManager* manager = g_browser_process->GetTabManager(); 263 TabManager* manager = g_browser_process->GetTabManager();
246 manager->PurgeBrowserMemory(); 264 manager->PurgeBrowserMemory();
247 manager->DiscardTab(); 265 manager->DiscardTab();
248 } 266 }
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 for (int i = 0; i < model->count(); i++) { 379 for (int i = 0; i < model->count(); i++) {
362 WebContents* contents = model->GetWebContentsAt(i); 380 WebContents* contents = model->GetWebContentsAt(i);
363 if (!contents->IsCrashed()) { 381 if (!contents->IsCrashed()) {
364 TabStats stats; 382 TabStats stats;
365 stats.is_app = is_browser_for_app; 383 stats.is_app = is_browser_for_app;
366 stats.is_internal_page = 384 stats.is_internal_page =
367 IsInternalPage(contents->GetLastCommittedURL()); 385 IsInternalPage(contents->GetLastCommittedURL());
368 stats.is_playing_audio = IsAudioTab(contents); 386 stats.is_playing_audio = IsAudioTab(contents);
369 stats.is_pinned = model->IsTabPinned(i); 387 stats.is_pinned = model->IsTabPinned(i);
370 stats.is_selected = browser_active && model->IsTabSelected(i); 388 stats.is_selected = browser_active && model->IsTabSelected(i);
371 stats.is_discarded = WebContentsData::IsDiscarded(contents); 389 stats.is_discarded = GetWebContentsData(contents)->IsDiscarded();
372 stats.has_form_entry = 390 stats.has_form_entry =
373 contents->GetPageImportanceSignals().had_form_interaction; 391 contents->GetPageImportanceSignals().had_form_interaction;
374 stats.discard_count = WebContentsData::DiscardCount(contents); 392 stats.discard_count = GetWebContentsData(contents)->DiscardCount();
375 stats.last_active = contents->GetLastActiveTime(); 393 stats.last_active = contents->GetLastActiveTime();
376 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); 394 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle();
377 stats.child_process_host_id = contents->GetRenderProcessHost()->GetID(); 395 stats.child_process_host_id = contents->GetRenderProcessHost()->GetID();
378 #if defined(OS_CHROMEOS) 396 #if defined(OS_CHROMEOS)
379 stats.oom_score = delegate_->GetOomScore(stats.child_process_host_id); 397 stats.oom_score = delegate_->GetOomScore(stats.child_process_host_id);
380 #endif 398 #endif
381 stats.title = contents->GetTitle(); 399 stats.title = contents->GetTitle();
382 stats.tab_contents_id = IdFromWebContents(contents); 400 stats.tab_contents_id = IdFromWebContents(contents);
383 stats_list->push_back(stats); 401 stats_list->push_back(stats);
384 } 402 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
434 if (web_contents->GetPageImportanceSignals().had_form_interaction) 452 if (web_contents->GetPageImportanceSignals().had_form_interaction)
435 return false; 453 return false;
436 454
437 // Do not discard tabs that are playing audio as it's too distruptive to the 455 // Do not discard tabs that are playing audio as it's too distruptive to the
438 // user experience. Note that tabs that have recently stopped playing audio by 456 // user experience. Note that tabs that have recently stopped playing audio by
439 // at least |kAudioProtectionTimeSeconds| seconds are protected as well. 457 // at least |kAudioProtectionTimeSeconds| seconds are protected as well.
440 if (IsAudioTab(web_contents)) 458 if (IsAudioTab(web_contents))
441 return false; 459 return false;
442 460
443 // Do not discard a previously discarded tab if that's the desired behavior. 461 // Do not discard a previously discarded tab if that's the desired behavior.
444 if (discard_once_ && WebContentsData::DiscardCount(web_contents) > 0) 462 if (discard_once_ && GetWebContentsData(web_contents)->DiscardCount() > 0)
445 return false; 463 return false;
446 464
447 return true; 465 return true;
448 } 466 }
449 467
450 WebContents* TabManager::DiscardWebContentsAt(int index, TabStripModel* model) { 468 WebContents* TabManager::DiscardWebContentsAt(int index, TabStripModel* model) {
451 // Can't discard active index. 469 // Can't discard active index.
452 if (model->active_index() == index) 470 if (model->active_index() == index)
453 return nullptr; 471 return nullptr;
454 472
455 WebContents* old_contents = model->GetWebContentsAt(index); 473 WebContents* old_contents = model->GetWebContentsAt(index);
456 474
457 // Can't discard tabs that are already discarded. 475 // Can't discard tabs that are already discarded.
458 if (WebContentsData::IsDiscarded(old_contents)) 476 if (GetWebContentsData(old_contents)->IsDiscarded())
459 return nullptr; 477 return nullptr;
460 478
461 // Record statistics before discarding to capture the memory state that leads 479 // Record statistics before discarding to capture the memory state that leads
462 // to the discard. 480 // to the discard.
463 RecordDiscardStatistics(); 481 RecordDiscardStatistics();
464 482
465 WebContents* null_contents = 483 WebContents* null_contents =
466 WebContents::Create(WebContents::CreateParams(model->profile())); 484 WebContents::Create(WebContents::CreateParams(model->profile()));
467 // Copy over the state from the navigation controller to preserve the 485 // Copy over the state from the navigation controller to preserve the
468 // back/forward history and to continue to display the correct title/favicon. 486 // back/forward history and to continue to display the correct title/favicon.
469 null_contents->GetController().CopyStateFrom(old_contents->GetController()); 487 null_contents->GetController().CopyStateFrom(old_contents->GetController());
470 488
471 // Make sure to persist the last active time property. 489 // Make sure to persist the last active time property.
472 null_contents->SetLastActiveTime(old_contents->GetLastActiveTime()); 490 null_contents->SetLastActiveTime(old_contents->GetLastActiveTime());
473 // Copy over the discard count. 491 // Copy over the discard count.
474 WebContentsData::CopyState(old_contents, null_contents); 492 WebContentsData::CopyState(old_contents, null_contents);
475 493
476 // Replace the discarded tab with the null version. 494 // Replace the discarded tab with the null version.
477 model->ReplaceWebContentsAt(index, null_contents); 495 model->ReplaceWebContentsAt(index, null_contents);
478 // Mark the tab so it will reload when clicked on. 496 // Mark the tab so it will reload when clicked on.
479 WebContentsData::SetDiscardState(null_contents, true); 497 GetWebContentsData(null_contents)->SetDiscardState(true);
480 WebContentsData::IncrementDiscardCount(null_contents); 498 GetWebContentsData(null_contents)->IncrementDiscardCount();
481 499
482 // Discard the old tab's renderer. 500 // Discard the old tab's renderer.
483 // TODO(jamescook): This breaks script connections with other tabs. 501 // TODO(jamescook): This breaks script connections with other tabs.
484 // Find a different approach that doesn't do that, perhaps based on navigation 502 // Find a different approach that doesn't do that, perhaps based on navigation
485 // to swappedout://. 503 // to swappedout://.
486 delete old_contents; 504 delete old_contents;
487 recent_tab_discard_ = true; 505 recent_tab_discard_ = true;
488 506
489 return null_contents; 507 return null_contents;
490 } 508 }
(...skipping 10 matching lines...) Expand all
501 LogMemoryAndDiscardTab(); 519 LogMemoryAndDiscardTab();
502 } 520 }
503 // TODO(skuhne): If more memory pressure levels are introduced, consider 521 // TODO(skuhne): If more memory pressure levels are introduced, consider
504 // calling PurgeBrowserMemory() before CRITICAL is reached. 522 // calling PurgeBrowserMemory() before CRITICAL is reached.
505 } 523 }
506 524
507 bool TabManager::IsAudioTab(WebContents* contents) const { 525 bool TabManager::IsAudioTab(WebContents* contents) const {
508 if (contents->WasRecentlyAudible()) 526 if (contents->WasRecentlyAudible())
509 return true; 527 return true;
510 auto delta = 528 auto delta =
511 TimeTicks::Now() - WebContentsData::LastAudioChangeTime(contents); 529 TimeTicks::Now() - GetWebContentsData(contents)->LastAudioChangeTime();
512 return delta < TimeDelta::FromSeconds(kAudioProtectionTimeSeconds); 530 return delta < TimeDelta::FromSeconds(kAudioProtectionTimeSeconds);
513 } 531 }
514 532
533 TabManager::WebContentsData* TabManager::GetWebContentsData(
534 content::WebContents* contents) const {
535 WebContentsData::CreateForWebContents(contents);
536 return WebContentsData::FromWebContents(contents);
537 }
538
515 // static 539 // static
516 bool TabManager::CompareTabStats(TabStats first, TabStats second) { 540 bool TabManager::CompareTabStats(TabStats first, TabStats second) {
517 // Being currently selected is most important to protect. 541 // Being currently selected is most important to protect.
518 if (first.is_selected != second.is_selected) 542 if (first.is_selected != second.is_selected)
519 return first.is_selected; 543 return first.is_selected;
520 544
521 // Protect tabs with pending form entries. 545 // Protect tabs with pending form entries.
522 if (first.has_form_entry != second.has_form_entry) 546 if (first.has_form_entry != second.has_form_entry)
523 return first.has_form_entry; 547 return first.has_form_entry;
524 548
(...skipping 21 matching lines...) Expand all
546 // sudden_termination_allowed false, and that covers too many common pages 570 // sudden_termination_allowed false, and that covers too many common pages
547 // with ad networks and statistics scripts. Ideally check for beforeUnload 571 // with ad networks and statistics scripts. Ideally check for beforeUnload
548 // handlers, which are likely to present a dialog asking if the user wants to 572 // handlers, which are likely to present a dialog asking if the user wants to
549 // discard state. crbug.com/123049. 573 // discard state. crbug.com/123049.
550 574
551 // Being more recently active is more important. 575 // Being more recently active is more important.
552 return first.last_active > second.last_active; 576 return first.last_active > second.last_active;
553 } 577 }
554 578
555 } // namespace memory 579 } // namespace memory
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698