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

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: chrisha@ comments. 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
« no previous file with comments | « chrome/browser/memory/tab_manager.h ('k') | chrome/browser/memory/tab_manager_browsertest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 27 matching lines...) Expand all
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
225 void TabManager::TabChangedAt(content::WebContents* contents, 229 void TabManager::TabChangedAt(content::WebContents* contents,
226 int index, 230 int index,
227 TabChangeType change_type) { 231 TabChangeType change_type) {
228 if (change_type != TabChangeType::ALL) 232 if (change_type != TabChangeType::ALL)
229 return; 233 return;
230 234 auto data = GetWebContentsData(contents);
231 bool old_state = WebContentsData::IsRecentlyAudible(contents); 235 bool old_state = data->IsRecentlyAudible();
232 bool current_state = contents->WasRecentlyAudible(); 236 bool current_state = contents->WasRecentlyAudible();
233 if (old_state != current_state) { 237 if (old_state != current_state) {
234 WebContentsData::SetRecentlyAudible(contents, current_state); 238 data->SetRecentlyAudible(current_state);
235 WebContentsData::SetLastAudioChangeTime(contents, TimeTicks::Now()); 239 data->SetLastAudioChangeTime(TimeTicks::Now());
236 } 240 }
237 } 241 }
238 242
243 void TabManager::ActiveTabChanged(content::WebContents* old_contents,
244 content::WebContents* new_contents,
245 int index,
246 int reason) {
247 GetWebContentsData(new_contents)->SetDiscardState(false);
248 }
249
239 /////////////////////////////////////////////////////////////////////////////// 250 ///////////////////////////////////////////////////////////////////////////////
240 // TabManager, private: 251 // TabManager, private:
241 252
242 // static 253 // static
243 void TabManager::PurgeMemoryAndDiscardTab() { 254 void TabManager::PurgeMemoryAndDiscardTab() {
244 if (g_browser_process && g_browser_process->GetTabManager()) { 255 if (g_browser_process && g_browser_process->GetTabManager()) {
245 TabManager* manager = g_browser_process->GetTabManager(); 256 TabManager* manager = g_browser_process->GetTabManager();
246 manager->PurgeBrowserMemory(); 257 manager->PurgeBrowserMemory();
247 manager->DiscardTab(); 258 manager->DiscardTab();
248 } 259 }
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 for (int i = 0; i < model->count(); i++) { 372 for (int i = 0; i < model->count(); i++) {
362 WebContents* contents = model->GetWebContentsAt(i); 373 WebContents* contents = model->GetWebContentsAt(i);
363 if (!contents->IsCrashed()) { 374 if (!contents->IsCrashed()) {
364 TabStats stats; 375 TabStats stats;
365 stats.is_app = is_browser_for_app; 376 stats.is_app = is_browser_for_app;
366 stats.is_internal_page = 377 stats.is_internal_page =
367 IsInternalPage(contents->GetLastCommittedURL()); 378 IsInternalPage(contents->GetLastCommittedURL());
368 stats.is_playing_audio = IsAudioTab(contents); 379 stats.is_playing_audio = IsAudioTab(contents);
369 stats.is_pinned = model->IsTabPinned(i); 380 stats.is_pinned = model->IsTabPinned(i);
370 stats.is_selected = browser_active && model->IsTabSelected(i); 381 stats.is_selected = browser_active && model->IsTabSelected(i);
371 stats.is_discarded = WebContentsData::IsDiscarded(contents); 382 stats.is_discarded = GetWebContentsData(contents)->IsDiscarded();
372 stats.has_form_entry = 383 stats.has_form_entry =
373 contents->GetPageImportanceSignals().had_form_interaction; 384 contents->GetPageImportanceSignals().had_form_interaction;
374 stats.discard_count = WebContentsData::DiscardCount(contents); 385 stats.discard_count = GetWebContentsData(contents)->DiscardCount();
375 stats.last_active = contents->GetLastActiveTime(); 386 stats.last_active = contents->GetLastActiveTime();
376 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); 387 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle();
377 stats.child_process_host_id = contents->GetRenderProcessHost()->GetID(); 388 stats.child_process_host_id = contents->GetRenderProcessHost()->GetID();
378 #if defined(OS_CHROMEOS) 389 #if defined(OS_CHROMEOS)
379 stats.oom_score = delegate_->GetOomScore(stats.child_process_host_id); 390 stats.oom_score = delegate_->GetOomScore(stats.child_process_host_id);
380 #endif 391 #endif
381 stats.title = contents->GetTitle(); 392 stats.title = contents->GetTitle();
382 stats.tab_contents_id = IdFromWebContents(contents); 393 stats.tab_contents_id = IdFromWebContents(contents);
383 stats_list->push_back(stats); 394 stats_list->push_back(stats);
384 } 395 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
434 if (web_contents->GetPageImportanceSignals().had_form_interaction) 445 if (web_contents->GetPageImportanceSignals().had_form_interaction)
435 return false; 446 return false;
436 447
437 // Do not discard tabs that are playing audio as it's too distruptive to the 448 // 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 449 // user experience. Note that tabs that have recently stopped playing audio by
439 // at least |kAudioProtectionTimeSeconds| seconds are protected as well. 450 // at least |kAudioProtectionTimeSeconds| seconds are protected as well.
440 if (IsAudioTab(web_contents)) 451 if (IsAudioTab(web_contents))
441 return false; 452 return false;
442 453
443 // Do not discard a previously discarded tab if that's the desired behavior. 454 // Do not discard a previously discarded tab if that's the desired behavior.
444 if (discard_once_ && WebContentsData::DiscardCount(web_contents) > 0) 455 if (discard_once_ && GetWebContentsData(web_contents)->DiscardCount() > 0)
445 return false; 456 return false;
446 457
447 return true; 458 return true;
448 } 459 }
449 460
450 WebContents* TabManager::DiscardWebContentsAt(int index, TabStripModel* model) { 461 WebContents* TabManager::DiscardWebContentsAt(int index, TabStripModel* model) {
451 // Can't discard active index. 462 // Can't discard active index.
452 if (model->active_index() == index) 463 if (model->active_index() == index)
453 return nullptr; 464 return nullptr;
454 465
455 WebContents* old_contents = model->GetWebContentsAt(index); 466 WebContents* old_contents = model->GetWebContentsAt(index);
456 467
457 // Can't discard tabs that are already discarded. 468 // Can't discard tabs that are already discarded.
458 if (WebContentsData::IsDiscarded(old_contents)) 469 if (GetWebContentsData(old_contents)->IsDiscarded())
459 return nullptr; 470 return nullptr;
460 471
461 // Record statistics before discarding to capture the memory state that leads 472 // Record statistics before discarding to capture the memory state that leads
462 // to the discard. 473 // to the discard.
463 RecordDiscardStatistics(); 474 RecordDiscardStatistics();
464 475
465 WebContents* null_contents = 476 WebContents* null_contents =
466 WebContents::Create(WebContents::CreateParams(model->profile())); 477 WebContents::Create(WebContents::CreateParams(model->profile()));
467 // Copy over the state from the navigation controller to preserve the 478 // Copy over the state from the navigation controller to preserve the
468 // back/forward history and to continue to display the correct title/favicon. 479 // back/forward history and to continue to display the correct title/favicon.
469 null_contents->GetController().CopyStateFrom(old_contents->GetController()); 480 null_contents->GetController().CopyStateFrom(old_contents->GetController());
470 481
471 // Make sure to persist the last active time property. 482 // Make sure to persist the last active time property.
472 null_contents->SetLastActiveTime(old_contents->GetLastActiveTime()); 483 null_contents->SetLastActiveTime(old_contents->GetLastActiveTime());
473 // Copy over the discard count. 484 // Copy over the discard count.
474 WebContentsData::CopyState(old_contents, null_contents); 485 WebContentsData::CopyState(old_contents, null_contents);
475 486
476 // Replace the discarded tab with the null version. 487 // Replace the discarded tab with the null version.
477 model->ReplaceWebContentsAt(index, null_contents); 488 model->ReplaceWebContentsAt(index, null_contents);
478 // Mark the tab so it will reload when clicked on. 489 // Mark the tab so it will reload when clicked on.
479 WebContentsData::SetDiscardState(null_contents, true); 490 GetWebContentsData(null_contents)->SetDiscardState(true);
480 WebContentsData::IncrementDiscardCount(null_contents); 491 GetWebContentsData(null_contents)->IncrementDiscardCount();
481 492
482 // Discard the old tab's renderer. 493 // Discard the old tab's renderer.
483 // TODO(jamescook): This breaks script connections with other tabs. 494 // TODO(jamescook): This breaks script connections with other tabs.
484 // Find a different approach that doesn't do that, perhaps based on navigation 495 // Find a different approach that doesn't do that, perhaps based on navigation
485 // to swappedout://. 496 // to swappedout://.
486 delete old_contents; 497 delete old_contents;
487 recent_tab_discard_ = true; 498 recent_tab_discard_ = true;
488 499
489 return null_contents; 500 return null_contents;
490 } 501 }
(...skipping 10 matching lines...) Expand all
501 LogMemoryAndDiscardTab(); 512 LogMemoryAndDiscardTab();
502 } 513 }
503 // TODO(skuhne): If more memory pressure levels are introduced, consider 514 // TODO(skuhne): If more memory pressure levels are introduced, consider
504 // calling PurgeBrowserMemory() before CRITICAL is reached. 515 // calling PurgeBrowserMemory() before CRITICAL is reached.
505 } 516 }
506 517
507 bool TabManager::IsAudioTab(WebContents* contents) const { 518 bool TabManager::IsAudioTab(WebContents* contents) const {
508 if (contents->WasRecentlyAudible()) 519 if (contents->WasRecentlyAudible())
509 return true; 520 return true;
510 auto delta = 521 auto delta =
511 TimeTicks::Now() - WebContentsData::LastAudioChangeTime(contents); 522 TimeTicks::Now() - GetWebContentsData(contents)->LastAudioChangeTime();
512 return delta < TimeDelta::FromSeconds(kAudioProtectionTimeSeconds); 523 return delta < TimeDelta::FromSeconds(kAudioProtectionTimeSeconds);
513 } 524 }
514 525
526 TabManager::WebContentsData* TabManager::GetWebContentsData(
527 content::WebContents* contents) const {
528 WebContentsData::CreateForWebContents(contents);
529 return WebContentsData::FromWebContents(contents);
530 }
531
515 // static 532 // static
516 bool TabManager::CompareTabStats(TabStats first, TabStats second) { 533 bool TabManager::CompareTabStats(TabStats first, TabStats second) {
517 // Being currently selected is most important to protect. 534 // Being currently selected is most important to protect.
518 if (first.is_selected != second.is_selected) 535 if (first.is_selected != second.is_selected)
519 return first.is_selected; 536 return first.is_selected;
520 537
521 // Protect tabs with pending form entries. 538 // Protect tabs with pending form entries.
522 if (first.has_form_entry != second.has_form_entry) 539 if (first.has_form_entry != second.has_form_entry)
523 return first.has_form_entry; 540 return first.has_form_entry;
524 541
(...skipping 21 matching lines...) Expand all
546 // sudden_termination_allowed false, and that covers too many common pages 563 // sudden_termination_allowed false, and that covers too many common pages
547 // with ad networks and statistics scripts. Ideally check for beforeUnload 564 // 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 565 // handlers, which are likely to present a dialog asking if the user wants to
549 // discard state. crbug.com/123049. 566 // discard state. crbug.com/123049.
550 567
551 // Being more recently active is more important. 568 // Being more recently active is more important.
552 return first.last_active > second.last_active; 569 return first.last_active > second.last_active;
553 } 570 }
554 571
555 } // namespace memory 572 } // namespace memory
OLDNEW
« no previous file with comments | « chrome/browser/memory/tab_manager.h ('k') | chrome/browser/memory/tab_manager_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698