| Index: chrome/browser/memory/tab_manager.cc
|
| diff --git a/chrome/browser/memory/tab_manager.cc b/chrome/browser/memory/tab_manager.cc
|
| index 582b2e667099f6fa0085f6721c4b9c69a37709c8..a2a0e0336de4cf0f6b2ea2eaffd294e0df1fc42d 100644
|
| --- a/chrome/browser/memory/tab_manager.cc
|
| +++ b/chrome/browser/memory/tab_manager.cc
|
| @@ -20,6 +20,7 @@
|
| #include "base/metrics/histogram_macros.h"
|
| #include "base/observer_list.h"
|
| #include "base/process/process.h"
|
| +#include "base/process/process_metrics.h"
|
| #include "base/strings/string16.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/string_util.h"
|
| @@ -670,6 +671,50 @@ void TabManager::UpdateTimerCallback() {
|
| PurgeAndSuspendBackgroundedTabs();
|
| }
|
|
|
| +bool TabManager::CanPurgeAndSuspendBackgroundedTab(
|
| + int64_t target_web_contents_id) const {
|
| + TabStripModel* model;
|
| + int idx = FindTabStripModelById(target_web_contents_id, &model);
|
| +
|
| + if (idx == -1)
|
| + return false;
|
| +
|
| + WebContents* web_contents = model->GetWebContentsAt(idx);
|
| +
|
| + // Do not suspend tabs that are playing either playing audio or accessing the
|
| + // microphone or camera as it's too distruptive to the user experience.
|
| + if (IsMediaTab(web_contents))
|
| + return false;
|
| +
|
| + if (web_contents->GetContentsMimeType() == "application/pdf")
|
| + return false;
|
| +
|
| + // Do not purge and suspend a tab that was explicitly disallowed to.
|
| + // Note: reused tab discarding logic.
|
| + if (!IsTabAutoDiscardable(web_contents))
|
| + return false;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void TabManager::RecordPurgeAndSuspendMetrics(
|
| + const base::ProcessHandle& handle) {
|
| +#if !defined(OS_MACOSX) || defined(OS_IOS)
|
| + std::unique_ptr<base::ProcessMetrics> process_metrics(
|
| + base::ProcessMetrics::CreateProcessMetrics(handle));
|
| +#else
|
| + std::unique_ptr<base::ProcessMetrics> process_metrics(
|
| + base::ProcessMetrics::CreateProcessMetrics(handle, NULL));
|
| +#endif
|
| + size_t private_bytes, shared_bytes;
|
| + if (process_metrics->GetMemoryBytes(&private_bytes, &shared_bytes)) {
|
| + UMA_HISTOGRAM_MEMORY_KB("Memory.PurgeAndSuspend.PrivateBytesKB",
|
| + private_bytes);
|
| + UMA_HISTOGRAM_MEMORY_KB("Memory.PurgeAndSuspend.SharedBytesKB",
|
| + shared_bytes);
|
| + }
|
| +}
|
| +
|
| void TabManager::PurgeAndSuspendBackgroundedTabs() {
|
| const base::CommandLine& command_line =
|
| *base::CommandLine::ForCurrentProcess();
|
| @@ -695,7 +740,26 @@ void TabManager::PurgeAndSuspendBackgroundedTabs() {
|
| // timers if we want necessary and sufficient signals.
|
| if (tab.last_active > purge_and_suspend_time_threshold)
|
| continue;
|
| - tab.render_process_host->PurgeAndSuspend();
|
| +
|
| + if (!CanPurgeAndSuspendBackgroundedTab(tab.tab_contents_id))
|
| + continue;
|
| +
|
| + if (tab.render_process_host->GetLastPurgeAndSuspendTime() <
|
| + tab.last_active) {
|
| + // If purge_and_suspend is disabled, PurgeAndSuspend() just updates
|
| + // LastPurgeAndSuspendTime. So we can avoid invoking
|
| + // RecordPurgeAndSuspendMetrics twice.
|
| + tab.render_process_host->PurgeAndSuspend();
|
| +
|
| + if (!task_runner_.get())
|
| + task_runner_ = base::ThreadTaskRunnerHandle::Get();
|
| + task_runner_->PostDelayedTask(
|
| + FROM_HERE,
|
| + base::Bind(&TabManager::RecordPurgeAndSuspendMetrics,
|
| + base::Unretained(this),
|
| + base::ConstRef(tab.render_process_host->GetHandle())),
|
| + base::TimeDelta::FromSeconds(15));
|
| + }
|
| }
|
| }
|
|
|
|
|