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

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

Issue 2228473003: Order TabManager functions. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 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 unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | 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 <stddef.h> 7 #include <stddef.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <set> 10 #include <set>
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 sorted_renderers.push_back(renderer); 264 sorted_renderers.push_back(renderer);
265 } 265 }
266 266
267 return sorted_renderers; 267 return sorted_renderers;
268 } 268 }
269 269
270 bool TabManager::IsTabDiscarded(content::WebContents* contents) const { 270 bool TabManager::IsTabDiscarded(content::WebContents* contents) const {
271 return GetWebContentsData(contents)->IsDiscarded(); 271 return GetWebContentsData(contents)->IsDiscarded();
272 } 272 }
273 273
274 bool TabManager::CanDiscardTab(int64_t target_web_contents_id) const {
275 TabStripModel* model;
276 int idx = FindTabStripModelById(target_web_contents_id, &model);
277
278 if (idx == -1)
279 return false;
280
281 WebContents* web_contents = model->GetWebContentsAt(idx);
282
283 // Do not discard tabs that don't have a valid URL (most probably they have
284 // just been opened and dicarding them would lose the URL).
285 // TODO(georgesak): Look into a workaround to be able to kill the tab without
286 // losing the pending navigation.
287 if (!web_contents->GetLastCommittedURL().is_valid() ||
288 web_contents->GetLastCommittedURL().is_empty()) {
289 return false;
290 }
291
292 // Do not discard tabs in which the user has entered text in a form, lest that
293 // state gets lost.
294 if (web_contents->GetPageImportanceSignals().had_form_interaction)
295 return false;
296
297 // Do not discard tabs that are playing either playing audio or accessing the
298 // microphone or camera as it's too distruptive to the user experience. Note
299 // that tabs that have recently stopped playing audio by at least
300 // |kAudioProtectionTimeSeconds| seconds are protected as well.
301 if (IsMediaTab(web_contents))
302 return false;
303
304 // Do not discard PDFs as they might contain entry that is not saved and they
305 // don't remember their scrolling positions. See crbug.com/547286 and
306 // crbug.com/65244.
307 // TODO(georgesak): Remove this workaround when the bugs are fixed.
308 if (web_contents->GetContentsMimeType() == "application/pdf")
309 return false;
310
311 // Do not discard a previously discarded tab if that's the desired behavior.
312 if (discard_once_ && GetWebContentsData(web_contents)->DiscardCount() > 0)
313 return false;
314
315 // Do not discard a recently used tab.
316 if (minimum_protection_time_.InSeconds() > 0) {
317 auto delta =
318 NowTicks() - GetWebContentsData(web_contents)->LastInactiveTime();
319 if (delta < minimum_protection_time_)
320 return false;
321 }
322
323 // Do not discard a tab that was explicitly disallowed to.
324 if (!IsTabAutoDiscardable(web_contents))
325 return false;
326
327 return true;
328 }
329
274 void TabManager::DiscardTab() { 330 void TabManager::DiscardTab() {
275 #if defined(OS_CHROMEOS) 331 #if defined(OS_CHROMEOS)
276 // Call Chrome OS specific low memory handling process. 332 // Call Chrome OS specific low memory handling process.
277 if (base::FeatureList::IsEnabled(features::kArcMemoryManagement)) { 333 if (base::FeatureList::IsEnabled(features::kArcMemoryManagement)) {
278 delegate_->LowMemoryKill(GetUnsortedTabStats()); 334 delegate_->LowMemoryKill(GetUnsortedTabStats());
279 return; 335 return;
280 } 336 }
281 #endif 337 #endif
282 DiscardTabImpl(); 338 DiscardTabImpl();
283 } 339 }
(...skipping 25 matching lines...) Expand all
309 void TabManager::LogMemory(const std::string& title, 365 void TabManager::LogMemory(const std::string& title,
310 const base::Closure& callback) { 366 const base::Closure& callback) {
311 DCHECK_CURRENTLY_ON(BrowserThread::UI); 367 DCHECK_CURRENTLY_ON(BrowserThread::UI);
312 OomMemoryDetails::Log(title, callback); 368 OomMemoryDetails::Log(title, callback);
313 } 369 }
314 370
315 void TabManager::set_test_tick_clock(base::TickClock* test_tick_clock) { 371 void TabManager::set_test_tick_clock(base::TickClock* test_tick_clock) {
316 test_tick_clock_ = test_tick_clock; 372 test_tick_clock_ = test_tick_clock;
317 } 373 }
318 374
319 void TabManager::TabChangedAt(content::WebContents* contents, 375 // Things to collect on the browser thread (because TabStripModel isn't thread
320 int index, 376 // safe):
321 TabChangeType change_type) { 377 // 1) whether or not a tab is pinned
322 if (change_type != TabChangeType::ALL) 378 // 2) last time a tab was selected
323 return; 379 // 3) is the tab currently selected
324 auto* data = GetWebContentsData(contents); 380 TabStatsList TabManager::GetUnsortedTabStats() {
325 bool old_state = data->IsRecentlyAudible(); 381 DCHECK_CURRENTLY_ON(BrowserThread::UI);
326 bool current_state = contents->WasRecentlyAudible(); 382 TabStatsList stats_list;
327 if (old_state != current_state) { 383 stats_list.reserve(32); // 99% of users have < 30 tabs open.
328 data->SetRecentlyAudible(current_state); 384
329 data->SetLastAudioChangeTime(NowTicks()); 385 // TODO(chrisha): Move this code to a TabStripModel enumeration delegate!
386 if (!test_tab_strip_models_.empty()) {
387 for (size_t i = 0; i < test_tab_strip_models_.size(); ++i) {
388 AddTabStats(test_tab_strip_models_[i].first, // tab_strip_model
389 test_tab_strip_models_[i].second, // is_app
390 i == 0, // is_active
391 &stats_list);
392 }
393 } else {
394 // The code here can only be tested under a full browser test.
395 AddTabStats(&stats_list);
330 } 396 }
397
398 return stats_list;
331 } 399 }
332 400
333 void TabManager::ActiveTabChanged(content::WebContents* old_contents, 401 void TabManager::AddObserver(TabManagerObserver* observer) {
334 content::WebContents* new_contents, 402 observers_.AddObserver(observer);
335 int index,
336 int reason) {
337 GetWebContentsData(new_contents)->SetDiscardState(false);
338 // If |old_contents| is set, that tab has switched from being active to
339 // inactive, so record the time of that transition.
340 if (old_contents)
341 GetWebContentsData(old_contents)->SetLastInactiveTime(NowTicks());
342 } 403 }
343 404
344 void TabManager::TabInsertedAt(content::WebContents* contents, 405 void TabManager::RemoveObserver(TabManagerObserver* observer) {
345 int index, 406 observers_.RemoveObserver(observer);
346 bool foreground) { 407 }
347 // Only interested in background tabs, as foreground tabs get taken care of by
348 // ActiveTabChanged.
349 if (foreground)
350 return;
351 408
352 // A new background tab is similar to having a tab switch from being active to 409 void TabManager::set_minimum_protection_time_for_tests(
353 // inactive. 410 base::TimeDelta minimum_protection_time) {
354 GetWebContentsData(contents)->SetLastInactiveTime(NowTicks()); 411 minimum_protection_time_ = minimum_protection_time;
412 }
413
414 bool TabManager::IsTabAutoDiscardable(content::WebContents* contents) const {
415 return GetWebContentsData(contents)->IsAutoDiscardable();
416 }
417
418 void TabManager::SetTabAutoDiscardableState(content::WebContents* contents,
419 bool state) {
420 GetWebContentsData(contents)->SetAutoDiscardableState(state);
421 }
422
423 // static
424 bool TabManager::CompareTabStats(const TabStats& first,
425 const TabStats& second) {
426 // Being currently selected is most important to protect.
427 if (first.is_selected != second.is_selected)
428 return first.is_selected;
429
430 // Non auto-discardable tabs are more important to protect.
431 if (first.is_auto_discardable != second.is_auto_discardable)
432 return !first.is_auto_discardable;
433
434 // Protect tabs with pending form entries.
435 if (first.has_form_entry != second.has_form_entry)
436 return first.has_form_entry;
437
438 // Protect streaming audio and video conferencing tabs as these are similar to
439 // active tabs.
440 if (first.is_media != second.is_media)
441 return first.is_media;
442
443 // Tab with internal web UI like NTP or Settings are good choices to discard,
444 // so protect non-Web UI and let the other conditionals finish the sort.
445 if (first.is_internal_page != second.is_internal_page)
446 return !first.is_internal_page;
447
448 // Being pinned is important to protect.
449 if (first.is_pinned != second.is_pinned)
450 return first.is_pinned;
451
452 // Being an app is important too, as it's the only visible surface in the
453 // window and should not be discarded.
454 if (first.is_app != second.is_app)
455 return first.is_app;
456
457 // TODO(jamescook): Incorporate sudden_termination_allowed into the sort
458 // order. This is currently not done because pages with unload handlers set
459 // sudden_termination_allowed false, and that covers too many common pages
460 // with ad networks and statistics scripts. Ideally check for beforeUnload
461 // handlers, which are likely to present a dialog asking if the user wants to
462 // discard state. crbug.com/123049.
463
464 // Being more recently active is more important.
465 return first.last_active > second.last_active;
355 } 466 }
356 467
357 /////////////////////////////////////////////////////////////////////////////// 468 ///////////////////////////////////////////////////////////////////////////////
358 // TabManager, private: 469 // TabManager, private:
359 470
471 void TabManager::OnDiscardedStateChange(content::WebContents* contents,
472 bool is_discarded) {
473 FOR_EACH_OBSERVER(TabManagerObserver, observers_,
474 OnDiscardedStateChange(contents, is_discarded));
475 }
476
477 void TabManager::OnAutoDiscardableStateChange(content::WebContents* contents,
478 bool is_auto_discardable) {
479 FOR_EACH_OBSERVER(
480 TabManagerObserver, observers_,
481 OnAutoDiscardableStateChange(contents, is_auto_discardable));
482 }
483
360 // static 484 // static
361 void TabManager::PurgeMemoryAndDiscardTab() { 485 void TabManager::PurgeMemoryAndDiscardTab() {
362 if (g_browser_process && g_browser_process->GetTabManager()) { 486 if (g_browser_process && g_browser_process->GetTabManager()) {
363 TabManager* manager = g_browser_process->GetTabManager(); 487 TabManager* manager = g_browser_process->GetTabManager();
364 manager->PurgeBrowserMemory(); 488 manager->PurgeBrowserMemory();
365 manager->DiscardTab(); 489 manager->DiscardTab();
366 } 490 }
367 } 491 }
368 492
369 // static 493 // static
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
481 605
482 void TabManager::AddTabStats(const TabStripModel* model, 606 void TabManager::AddTabStats(const TabStripModel* model,
483 bool is_app, 607 bool is_app,
484 bool active_model, 608 bool active_model,
485 TabStatsList* stats_list) { 609 TabStatsList* stats_list) {
486 for (int i = 0; i < model->count(); i++) { 610 for (int i = 0; i < model->count(); i++) {
487 WebContents* contents = model->GetWebContentsAt(i); 611 WebContents* contents = model->GetWebContentsAt(i);
488 if (!contents->IsCrashed()) { 612 if (!contents->IsCrashed()) {
489 TabStats stats; 613 TabStats stats;
490 stats.is_app = is_app; 614 stats.is_app = is_app;
491 stats.is_internal_page = 615 stats.is_internal_page = IsInternalPage(contents->GetLastCommittedURL());
492 IsInternalPage(contents->GetLastCommittedURL());
493 stats.is_media = IsMediaTab(contents); 616 stats.is_media = IsMediaTab(contents);
494 stats.is_pinned = model->IsTabPinned(i); 617 stats.is_pinned = model->IsTabPinned(i);
495 stats.is_selected = active_model && model->IsTabSelected(i); 618 stats.is_selected = active_model && model->IsTabSelected(i);
496 stats.is_discarded = GetWebContentsData(contents)->IsDiscarded(); 619 stats.is_discarded = GetWebContentsData(contents)->IsDiscarded();
497 stats.has_form_entry = 620 stats.has_form_entry =
498 contents->GetPageImportanceSignals().had_form_interaction; 621 contents->GetPageImportanceSignals().had_form_interaction;
499 stats.discard_count = GetWebContentsData(contents)->DiscardCount(); 622 stats.discard_count = GetWebContentsData(contents)->DiscardCount();
500 stats.last_active = contents->GetLastActiveTime(); 623 stats.last_active = contents->GetLastActiveTime();
501 stats.render_process_host = contents->GetRenderProcessHost(); 624 stats.render_process_host = contents->GetRenderProcessHost();
502 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); 625 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle();
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 // TODO(hajimehoshi): Now calling PurgeAndSuspend is implemented without 691 // TODO(hajimehoshi): Now calling PurgeAndSuspend is implemented without
569 // timers for simplicity, so PurgeAndSuspend is called even after the 692 // timers for simplicity, so PurgeAndSuspend is called even after the
570 // renderer is purged and suspended once. This should be replaced with 693 // renderer is purged and suspended once. This should be replaced with
571 // timers if we want necessary and sufficient signals. 694 // timers if we want necessary and sufficient signals.
572 if (tab.last_active > purge_and_suspend_time_threshold) 695 if (tab.last_active > purge_and_suspend_time_threshold)
573 continue; 696 continue;
574 tab.render_process_host->PurgeAndSuspend(); 697 tab.render_process_host->PurgeAndSuspend();
575 } 698 }
576 } 699 }
577 700
578 bool TabManager::CanDiscardTab(int64_t target_web_contents_id) const {
579 TabStripModel* model;
580 int idx = FindTabStripModelById(target_web_contents_id, &model);
581
582 if (idx == -1)
583 return false;
584
585 WebContents* web_contents = model->GetWebContentsAt(idx);
586
587 // Do not discard tabs that don't have a valid URL (most probably they have
588 // just been opened and dicarding them would lose the URL).
589 // TODO(georgesak): Look into a workaround to be able to kill the tab without
590 // losing the pending navigation.
591 if (!web_contents->GetLastCommittedURL().is_valid() ||
592 web_contents->GetLastCommittedURL().is_empty()) {
593 return false;
594 }
595
596 // Do not discard tabs in which the user has entered text in a form, lest that
597 // state gets lost.
598 if (web_contents->GetPageImportanceSignals().had_form_interaction)
599 return false;
600
601 // Do not discard tabs that are playing either playing audio or accessing the
602 // microphone or camera as it's too distruptive to the user experience. Note
603 // that tabs that have recently stopped playing audio by at least
604 // |kAudioProtectionTimeSeconds| seconds are protected as well.
605 if (IsMediaTab(web_contents))
606 return false;
607
608 // Do not discard PDFs as they might contain entry that is not saved and they
609 // don't remember their scrolling positions. See crbug.com/547286 and
610 // crbug.com/65244.
611 // TODO(georgesak): Remove this workaround when the bugs are fixed.
612 if (web_contents->GetContentsMimeType() == "application/pdf")
613 return false;
614
615 // Do not discard a previously discarded tab if that's the desired behavior.
616 if (discard_once_ && GetWebContentsData(web_contents)->DiscardCount() > 0)
617 return false;
618
619 // Do not discard a recently used tab.
620 if (minimum_protection_time_.InSeconds() > 0) {
621 auto delta =
622 NowTicks() - GetWebContentsData(web_contents)->LastInactiveTime();
623 if (delta < minimum_protection_time_)
624 return false;
625 }
626
627 // Do not discard a tab that was explicitly disallowed to.
628 if (!IsTabAutoDiscardable(web_contents))
629 return false;
630
631 return true;
632 }
633
634 WebContents* TabManager::DiscardWebContentsAt(int index, TabStripModel* model) { 701 WebContents* TabManager::DiscardWebContentsAt(int index, TabStripModel* model) {
635 // Can't discard active index. 702 // Can't discard active index.
636 if (model->active_index() == index) 703 if (model->active_index() == index)
637 return nullptr; 704 return nullptr;
638 705
639 WebContents* old_contents = model->GetWebContentsAt(index); 706 WebContents* old_contents = model->GetWebContentsAt(index);
640 707
641 // Can't discard tabs that are already discarded. 708 // Can't discard tabs that are already discarded.
642 if (GetWebContentsData(old_contents)->IsDiscarded()) 709 if (GetWebContentsData(old_contents)->IsDiscarded())
643 return nullptr; 710 return nullptr;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
702 // implementation that supports "CurrentPressureLevel". This is true on all 769 // implementation that supports "CurrentPressureLevel". This is true on all
703 // platforms on which TabManager is used. 770 // platforms on which TabManager is used.
704 #if !defined(OS_CHROMEOS) 771 #if !defined(OS_CHROMEOS)
705 // Running GC under memory pressure can cause thrashing. Disable it on 772 // Running GC under memory pressure can cause thrashing. Disable it on
706 // ChromeOS until the thrashing is fixed. crbug.com/588172. 773 // ChromeOS until the thrashing is fixed. crbug.com/588172.
707 if (!under_memory_pressure_) 774 if (!under_memory_pressure_)
708 DoChildProcessDispatch(); 775 DoChildProcessDispatch();
709 #endif 776 #endif
710 } 777 }
711 778
779 void TabManager::TabChangedAt(content::WebContents* contents,
780 int index,
781 TabChangeType change_type) {
782 if (change_type != TabChangeType::ALL)
783 return;
784 auto* data = GetWebContentsData(contents);
785 bool old_state = data->IsRecentlyAudible();
786 bool current_state = contents->WasRecentlyAudible();
787 if (old_state != current_state) {
788 data->SetRecentlyAudible(current_state);
789 data->SetLastAudioChangeTime(NowTicks());
790 }
791 }
792
793 void TabManager::ActiveTabChanged(content::WebContents* old_contents,
794 content::WebContents* new_contents,
795 int index,
796 int reason) {
797 GetWebContentsData(new_contents)->SetDiscardState(false);
798 // If |old_contents| is set, that tab has switched from being active to
799 // inactive, so record the time of that transition.
800 if (old_contents)
801 GetWebContentsData(old_contents)->SetLastInactiveTime(NowTicks());
802 }
803
804 void TabManager::TabInsertedAt(content::WebContents* contents,
805 int index,
806 bool foreground) {
807 // Only interested in background tabs, as foreground tabs get taken care of by
808 // ActiveTabChanged.
809 if (foreground)
810 return;
811
812 // A new background tab is similar to having a tab switch from being active to
813 // inactive.
814 GetWebContentsData(contents)->SetLastInactiveTime(NowTicks());
815 }
816
712 bool TabManager::IsMediaTab(WebContents* contents) const { 817 bool TabManager::IsMediaTab(WebContents* contents) const {
713 if (contents->WasRecentlyAudible()) 818 if (contents->WasRecentlyAudible())
714 return true; 819 return true;
715 820
716 scoped_refptr<MediaStreamCaptureIndicator> media_indicator = 821 scoped_refptr<MediaStreamCaptureIndicator> media_indicator =
717 MediaCaptureDevicesDispatcher::GetInstance() 822 MediaCaptureDevicesDispatcher::GetInstance()
718 ->GetMediaStreamCaptureIndicator(); 823 ->GetMediaStreamCaptureIndicator();
719 if (media_indicator->IsCapturingUserMedia(contents) || 824 if (media_indicator->IsCapturingUserMedia(contents) ||
720 media_indicator->IsBeingMirrored(contents)) { 825 media_indicator->IsBeingMirrored(contents)) {
721 return true; 826 return true;
722 } 827 }
723 828
724 auto delta = NowTicks() - GetWebContentsData(contents)->LastAudioChangeTime(); 829 auto delta = NowTicks() - GetWebContentsData(contents)->LastAudioChangeTime();
725 return delta < TimeDelta::FromSeconds(kAudioProtectionTimeSeconds); 830 return delta < TimeDelta::FromSeconds(kAudioProtectionTimeSeconds);
726 } 831 }
727 832
728 TabManager::WebContentsData* TabManager::GetWebContentsData( 833 TabManager::WebContentsData* TabManager::GetWebContentsData(
729 content::WebContents* contents) const { 834 content::WebContents* contents) const {
730 WebContentsData::CreateForWebContents(contents); 835 WebContentsData::CreateForWebContents(contents);
731 auto* web_contents_data = WebContentsData::FromWebContents(contents); 836 auto* web_contents_data = WebContentsData::FromWebContents(contents);
732 web_contents_data->set_test_tick_clock(test_tick_clock_); 837 web_contents_data->set_test_tick_clock(test_tick_clock_);
733 return web_contents_data; 838 return web_contents_data;
734 } 839 }
735 840
736 // static
737 bool TabManager::CompareTabStats(const TabStats& first,
738 const TabStats& second) {
739 // Being currently selected is most important to protect.
740 if (first.is_selected != second.is_selected)
741 return first.is_selected;
742
743 // Non auto-discardable tabs are more important to protect.
744 if (first.is_auto_discardable != second.is_auto_discardable)
745 return !first.is_auto_discardable;
746
747 // Protect tabs with pending form entries.
748 if (first.has_form_entry != second.has_form_entry)
749 return first.has_form_entry;
750
751 // Protect streaming audio and video conferencing tabs as these are similar to
752 // active tabs.
753 if (first.is_media != second.is_media)
754 return first.is_media;
755
756 // Tab with internal web UI like NTP or Settings are good choices to discard,
757 // so protect non-Web UI and let the other conditionals finish the sort.
758 if (first.is_internal_page != second.is_internal_page)
759 return !first.is_internal_page;
760
761 // Being pinned is important to protect.
762 if (first.is_pinned != second.is_pinned)
763 return first.is_pinned;
764
765 // Being an app is important too, as it's the only visible surface in the
766 // window and should not be discarded.
767 if (first.is_app != second.is_app)
768 return first.is_app;
769
770 // TODO(jamescook): Incorporate sudden_termination_allowed into the sort
771 // order. This is currently not done because pages with unload handlers set
772 // sudden_termination_allowed false, and that covers too many common pages
773 // with ad networks and statistics scripts. Ideally check for beforeUnload
774 // handlers, which are likely to present a dialog asking if the user wants to
775 // discard state. crbug.com/123049.
776
777 // Being more recently active is more important.
778 return first.last_active > second.last_active;
779 }
780
781 TimeTicks TabManager::NowTicks() const { 841 TimeTicks TabManager::NowTicks() const {
782 if (!test_tick_clock_) 842 if (!test_tick_clock_)
783 return TimeTicks::Now(); 843 return TimeTicks::Now();
784 844
785 return test_tick_clock_->NowTicks(); 845 return test_tick_clock_->NowTicks();
786 } 846 }
787 847
788 void TabManager::DoChildProcessDispatch() { 848 void TabManager::DoChildProcessDispatch() {
789 // If Chrome is shutting down, do not do anything. 849 // If Chrome is shutting down, do not do anything.
790 if (g_browser_process->IsShuttingDown()) 850 if (g_browser_process->IsShuttingDown())
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
877 // TODO(georgesak): Add Linux when automatic discarding is enabled for that 937 // TODO(georgesak): Add Linux when automatic discarding is enabled for that
878 // platform. 938 // platform.
879 std::string allow_multiple_discards = variations::GetVariationParamValue( 939 std::string allow_multiple_discards = variations::GetVariationParamValue(
880 features::kAutomaticTabDiscarding.name, "AllowMultipleDiscards"); 940 features::kAutomaticTabDiscarding.name, "AllowMultipleDiscards");
881 return (allow_multiple_discards != "true"); 941 return (allow_multiple_discards != "true");
882 #else 942 #else
883 return false; 943 return false;
884 #endif 944 #endif
885 } 945 }
886 946
887 // Things to collect on the browser thread (because TabStripModel isn't thread
888 // safe):
889 // 1) whether or not a tab is pinned
890 // 2) last time a tab was selected
891 // 3) is the tab currently selected
892 TabStatsList TabManager::GetUnsortedTabStats() {
893 DCHECK_CURRENTLY_ON(BrowserThread::UI);
894 TabStatsList stats_list;
895 stats_list.reserve(32); // 99% of users have < 30 tabs open.
896
897 // TODO(chrisha): Move this code to a TabStripModel enumeration delegate!
898 if (!test_tab_strip_models_.empty()) {
899 for (size_t i = 0; i < test_tab_strip_models_.size(); ++i) {
900 AddTabStats(test_tab_strip_models_[i].first, // tab_strip_model
901 test_tab_strip_models_[i].second, // is_app
902 i == 0, // is_active
903 &stats_list);
904 }
905 } else {
906 // The code here can only be tested under a full browser test.
907 AddTabStats(&stats_list);
908 }
909
910 return stats_list;
911 }
912
913 void TabManager::AddObserver(TabManagerObserver* observer) {
914 observers_.AddObserver(observer);
915 }
916
917 void TabManager::RemoveObserver(TabManagerObserver* observer) {
918 observers_.RemoveObserver(observer);
919 }
920
921 void TabManager::OnDiscardedStateChange(content::WebContents* contents,
922 bool is_discarded) {
923 FOR_EACH_OBSERVER(TabManagerObserver, observers_,
924 OnDiscardedStateChange(contents, is_discarded));
925 }
926
927 void TabManager::set_minimum_protection_time_for_tests(
928 base::TimeDelta minimum_protection_time) {
929 minimum_protection_time_ = minimum_protection_time;
930 }
931
932 void TabManager::OnAutoDiscardableStateChange(content::WebContents* contents,
933 bool is_auto_discardable) {
934 FOR_EACH_OBSERVER(
935 TabManagerObserver, observers_,
936 OnAutoDiscardableStateChange(contents, is_auto_discardable));
937 }
938
939 bool TabManager::IsTabAutoDiscardable(content::WebContents* contents) const {
940 return GetWebContentsData(contents)->IsAutoDiscardable();
941 }
942
943 void TabManager::SetTabAutoDiscardableState(content::WebContents* contents,
944 bool state) {
945 GetWebContentsData(contents)->SetAutoDiscardableState(state);
946 }
947
948 } // namespace memory 947 } // namespace memory
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698