| OLD | NEW |
| 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> |
| 11 #include <vector> | 11 #include <vector> |
| 12 | 12 |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/bind_helpers.h" | 14 #include "base/bind_helpers.h" |
| 15 #include "base/command_line.h" | 15 #include "base/command_line.h" |
| 16 #include "base/feature_list.h" | 16 #include "base/feature_list.h" |
| 17 #include "base/macros.h" | 17 #include "base/macros.h" |
| 18 #include "base/memory/memory_pressure_monitor.h" | 18 #include "base/memory/memory_pressure_monitor.h" |
| 19 #include "base/metrics/field_trial.h" | 19 #include "base/metrics/field_trial.h" |
| 20 #include "base/metrics/histogram_macros.h" | 20 #include "base/metrics/histogram_macros.h" |
| 21 #include "base/observer_list.h" | 21 #include "base/observer_list.h" |
| 22 #include "base/process/process.h" | 22 #include "base/process/process.h" |
| 23 #include "base/process/process_metrics.h" |
| 23 #include "base/strings/string16.h" | 24 #include "base/strings/string16.h" |
| 24 #include "base/strings/string_number_conversions.h" | 25 #include "base/strings/string_number_conversions.h" |
| 25 #include "base/strings/string_util.h" | 26 #include "base/strings/string_util.h" |
| 26 #include "base/strings/utf_string_conversions.h" | 27 #include "base/strings/utf_string_conversions.h" |
| 27 #include "base/threading/thread.h" | 28 #include "base/threading/thread.h" |
| 28 #include "base/threading/thread_task_runner_handle.h" | 29 #include "base/threading/thread_task_runner_handle.h" |
| 29 #include "base/time/tick_clock.h" | 30 #include "base/time/tick_clock.h" |
| 30 #include "build/build_config.h" | 31 #include "build/build_config.h" |
| 31 #include "chrome/browser/browser_process.h" | 32 #include "chrome/browser/browser_process.h" |
| 32 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" | 33 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" |
| (...skipping 630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 663 | 664 |
| 664 #if defined(OS_CHROMEOS) | 665 #if defined(OS_CHROMEOS) |
| 665 TabStatsList stats_list = GetTabStats(); | 666 TabStatsList stats_list = GetTabStats(); |
| 666 // This starts the CrOS specific OOM adjustments in /proc/<pid>/oom_score_adj. | 667 // This starts the CrOS specific OOM adjustments in /proc/<pid>/oom_score_adj. |
| 667 delegate_->AdjustOomPriorities(stats_list); | 668 delegate_->AdjustOomPriorities(stats_list); |
| 668 #endif | 669 #endif |
| 669 | 670 |
| 670 PurgeAndSuspendBackgroundedTabs(); | 671 PurgeAndSuspendBackgroundedTabs(); |
| 671 } | 672 } |
| 672 | 673 |
| 674 bool TabManager::CanPurgeAndSuspendBackgroundedTab( |
| 675 int64_t target_web_contents_id) const { |
| 676 TabStripModel* model; |
| 677 int idx = FindTabStripModelById(target_web_contents_id, &model); |
| 678 |
| 679 if (idx == -1) |
| 680 return false; |
| 681 |
| 682 WebContents* web_contents = model->GetWebContentsAt(idx); |
| 683 |
| 684 // Do not suspend tabs that are playing either playing audio or accessing the |
| 685 // microphone or camera as it's too distruptive to the user experience. |
| 686 if (IsMediaTab(web_contents)) |
| 687 return false; |
| 688 |
| 689 if (web_contents->GetContentsMimeType() == "application/pdf") |
| 690 return false; |
| 691 |
| 692 // Do not purge and suspend a tab that was explicitly disallowed to. |
| 693 // Note: reused tab discarding logic. |
| 694 if (!IsTabAutoDiscardable(web_contents)) |
| 695 return false; |
| 696 |
| 697 return true; |
| 698 } |
| 699 |
| 700 void TabManager::RecordPurgeAndSuspendMetrics( |
| 701 const base::ProcessHandle& handle) { |
| 702 #if !defined(OS_MACOSX) || defined(OS_IOS) |
| 703 std::unique_ptr<base::ProcessMetrics> process_metrics( |
| 704 base::ProcessMetrics::CreateProcessMetrics(handle)); |
| 705 #else |
| 706 std::unique_ptr<base::ProcessMetrics> process_metrics( |
| 707 base::ProcessMetrics::CreateProcessMetrics(handle, NULL)); |
| 708 #endif |
| 709 size_t private_bytes, shared_bytes; |
| 710 if (process_metrics->GetMemoryBytes(&private_bytes, &shared_bytes)) { |
| 711 UMA_HISTOGRAM_MEMORY_KB("Memory.PurgeAndSuspend.PrivateBytesKB", |
| 712 private_bytes); |
| 713 UMA_HISTOGRAM_MEMORY_KB("Memory.PurgeAndSuspend.SharedBytesKB", |
| 714 shared_bytes); |
| 715 } |
| 716 } |
| 717 |
| 673 void TabManager::PurgeAndSuspendBackgroundedTabs() { | 718 void TabManager::PurgeAndSuspendBackgroundedTabs() { |
| 674 const base::CommandLine& command_line = | 719 const base::CommandLine& command_line = |
| 675 *base::CommandLine::ForCurrentProcess(); | 720 *base::CommandLine::ForCurrentProcess(); |
| 676 if (!command_line.HasSwitch(switches::kPurgeAndSuspendTime)) | 721 if (!command_line.HasSwitch(switches::kPurgeAndSuspendTime)) |
| 677 return; | 722 return; |
| 678 int purge_and_suspend_time = 0; | 723 int purge_and_suspend_time = 0; |
| 679 if (!base::StringToInt( | 724 if (!base::StringToInt( |
| 680 command_line.GetSwitchValueASCII(switches::kPurgeAndSuspendTime), | 725 command_line.GetSwitchValueASCII(switches::kPurgeAndSuspendTime), |
| 681 &purge_and_suspend_time)) { | 726 &purge_and_suspend_time)) { |
| 682 return; | 727 return; |
| 683 } | 728 } |
| 684 if (purge_and_suspend_time <= 0) | 729 if (purge_and_suspend_time <= 0) |
| 685 return; | 730 return; |
| 686 auto purge_and_suspend_time_threshold = | 731 auto purge_and_suspend_time_threshold = |
| 687 NowTicks() - base::TimeDelta::FromSeconds(purge_and_suspend_time); | 732 NowTicks() - base::TimeDelta::FromSeconds(purge_and_suspend_time); |
| 688 auto tab_stats = GetUnsortedTabStats(); | 733 auto tab_stats = GetUnsortedTabStats(); |
| 689 for (auto& tab : tab_stats) { | 734 for (auto& tab : tab_stats) { |
| 690 if (!tab.render_process_host->IsProcessBackgrounded()) | 735 if (!tab.render_process_host->IsProcessBackgrounded()) |
| 691 continue; | 736 continue; |
| 692 // TODO(hajimehoshi): Now calling PurgeAndSuspend is implemented without | 737 // TODO(hajimehoshi): Now calling PurgeAndSuspend is implemented without |
| 693 // timers for simplicity, so PurgeAndSuspend is called even after the | 738 // timers for simplicity, so PurgeAndSuspend is called even after the |
| 694 // renderer is purged and suspended once. This should be replaced with | 739 // renderer is purged and suspended once. This should be replaced with |
| 695 // timers if we want necessary and sufficient signals. | 740 // timers if we want necessary and sufficient signals. |
| 696 if (tab.last_active > purge_and_suspend_time_threshold) | 741 if (tab.last_active > purge_and_suspend_time_threshold) |
| 697 continue; | 742 continue; |
| 698 tab.render_process_host->PurgeAndSuspend(); | 743 |
| 744 if (!CanPurgeAndSuspendBackgroundedTab(tab.tab_contents_id)) |
| 745 continue; |
| 746 |
| 747 if (tab.render_process_host->GetLastPurgeAndSuspendTime() < |
| 748 tab.last_active) { |
| 749 // If purge_and_suspend is disabled, PurgeAndSuspend() just updates |
| 750 // LastPurgeAndSuspendTime. So we can avoid invoking |
| 751 // RecordPurgeAndSuspendMetrics twice. |
| 752 tab.render_process_host->PurgeAndSuspend(); |
| 753 |
| 754 if (!task_runner_.get()) |
| 755 task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
| 756 task_runner_->PostDelayedTask( |
| 757 FROM_HERE, |
| 758 base::Bind(&TabManager::RecordPurgeAndSuspendMetrics, |
| 759 base::Unretained(this), |
| 760 base::ConstRef(tab.render_process_host->GetHandle())), |
| 761 base::TimeDelta::FromSeconds(15)); |
| 762 } |
| 699 } | 763 } |
| 700 } | 764 } |
| 701 | 765 |
| 702 WebContents* TabManager::DiscardWebContentsAt(int index, TabStripModel* model) { | 766 WebContents* TabManager::DiscardWebContentsAt(int index, TabStripModel* model) { |
| 703 // Can't discard active index. | 767 // Can't discard active index. |
| 704 if (model->active_index() == index) | 768 if (model->active_index() == index) |
| 705 return nullptr; | 769 return nullptr; |
| 706 | 770 |
| 707 WebContents* old_contents = model->GetWebContentsAt(index); | 771 WebContents* old_contents = model->GetWebContentsAt(index); |
| 708 | 772 |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 940 // platform. | 1004 // platform. |
| 941 std::string allow_multiple_discards = variations::GetVariationParamValue( | 1005 std::string allow_multiple_discards = variations::GetVariationParamValue( |
| 942 features::kAutomaticTabDiscarding.name, "AllowMultipleDiscards"); | 1006 features::kAutomaticTabDiscarding.name, "AllowMultipleDiscards"); |
| 943 return (allow_multiple_discards != "true"); | 1007 return (allow_multiple_discards != "true"); |
| 944 #else | 1008 #else |
| 945 return false; | 1009 return false; |
| 946 #endif | 1010 #endif |
| 947 } | 1011 } |
| 948 | 1012 |
| 949 } // namespace memory | 1013 } // namespace memory |
| OLD | NEW |