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

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