blob: fd948eb6e36fa78f7d33b390b510588bac295467 [file] [log] [blame]
Sebastien Marchand578251d2020-12-11 03:44:431// Copyright 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/performance_manager/mechanisms/page_freezer.h"
6
7#include "base/bind.h"
Sebastien Marchandd6c81d22021-03-10 02:42:398#include "base/metrics/histogram_functions.h"
Sebastien Marchand578251d2020-12-11 03:44:439#include "base/task/task_traits.h"
10#include "chrome/browser/permissions/permission_manager_factory.h"
11#include "chrome/browser/profiles/profile.h"
12#include "components/content_settings/core/common/content_settings_types.h"
13#include "components/performance_manager/public/graph/page_node.h"
14#include "components/performance_manager/public/web_contents_proxy.h"
15#include "components/permissions/permission_manager.h"
16#include "components/permissions/permission_result.h"
17#include "content/public/browser/browser_task_traits.h"
18#include "content/public/browser/browser_thread.h"
Charlene Yan753d7462021-01-26 23:39:5219#include "content/public/browser/visibility.h"
Sebastien Marchand578251d2020-12-11 03:44:4320#include "content/public/browser/web_contents.h"
Sebastien Marchandd6c81d22021-03-10 02:42:3921#include "net/http/http_request_headers.h"
Sebastien Marchand578251d2020-12-11 03:44:4322
23namespace performance_manager {
24namespace mechanism {
25namespace {
26
Sebastien Marchandd6c81d22021-03-10 02:42:3927const char kFreezingAttemptOutcomeHistogramName[] =
28 "Tabs.Freezing.MaybeFreezeOutcome";
29
30// Possible outcome of the |MaybeFreezePageOnUIThreadImpl| function.
31//
32// These values are logged to UMA. Entries should not be renumbered and
33// numeric values should never be reused. Please keep in sync with
34// "FreezingAttemptOutcome" in src/tools/metrics/histograms/enums.xml.
35enum class UMAFreezingAttemptOutcome {
36 kSuccess = 0,
37 kFailureContentsDoesntExist = 1,
38 kFailureDueToNotificationPermission = 2,
39 kFailureDueToNoStoreCacheHeaders = 3,
40
41 kMaxValue = kFailureDueToNoStoreCacheHeaders,
42};
43
Sebastien Marchand578251d2020-12-11 03:44:4344// Try to freeze a page on the UI thread.
Sebastien Marchandd6c81d22021-03-10 02:42:3945UMAFreezingAttemptOutcome MaybeFreezePageOnUIThreadImpl(
46 const WebContentsProxy& contents_proxy) {
Sebastien Marchand578251d2020-12-11 03:44:4347 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
48 content::WebContents* const contents = contents_proxy.Get();
49 if (!contents)
Sebastien Marchandd6c81d22021-03-10 02:42:3950 return UMAFreezingAttemptOutcome::kFailureContentsDoesntExist;
Sebastien Marchand578251d2020-12-11 03:44:4351
52 // Page with the notification permission shouldn't be frozen as this is a
53 // strong signal that the user wants to receive updates from this page while
54 // it's in background. This information isn't available in the PM graph, this
55 // has to be checked on the UI thread.
56 auto notif_permission =
57 PermissionManagerFactory::GetForProfile(
58 Profile::FromBrowserContext(contents->GetBrowserContext()))
59 ->GetPermissionStatus(ContentSettingsType::NOTIFICATIONS,
60 contents->GetLastCommittedURL(),
61 contents->GetLastCommittedURL());
62 if (notif_permission.content_setting == CONTENT_SETTING_ALLOW)
Sebastien Marchandd6c81d22021-03-10 02:42:3963 return UMAFreezingAttemptOutcome::kFailureDueToNotificationPermission;
64
65 // Pages that have the "Cache-Control: no-store" header should not be frozen
66 // because it could introduce a small privacy regression when returning to
67 // the tab after it has been frozen in background for a long time (e.g. the
68 // content of a banking tab could be visible for a few frames before the
69 // site realizing that the user should have been logged out a while ago).
70 auto* response_headers = contents->GetMainFrame()->GetLastResponseHeaders();
71 if (response_headers && response_headers->HasHeaderValue(
72 net::HttpRequestHeaders::kCacheControl,
73 net::HttpRequestHeaders::kNoStoreDirective)) {
74 return UMAFreezingAttemptOutcome::kFailureDueToNoStoreCacheHeaders;
75 }
Sebastien Marchand578251d2020-12-11 03:44:4376
77 contents->SetPageFrozen(true);
Sebastien Marchandd6c81d22021-03-10 02:42:3978 return UMAFreezingAttemptOutcome::kSuccess;
79}
80
81bool MaybeFreezePageOnUIThread(const WebContentsProxy& contents_proxy) {
82 auto freeze_outcome = MaybeFreezePageOnUIThreadImpl(contents_proxy);
83
84 base::UmaHistogramEnumeration(kFreezingAttemptOutcomeHistogramName,
85 freeze_outcome);
86
87 return freeze_outcome == UMAFreezingAttemptOutcome::kSuccess;
Sebastien Marchand578251d2020-12-11 03:44:4388}
89
90void UnfreezePageOnUIThread(const WebContentsProxy& contents_proxy) {
91 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
92 content::WebContents* const content = contents_proxy.Get();
93 if (!content)
94 return;
95
Charlene Yan753d7462021-01-26 23:39:5296 // A visible page is automatically unfrozen.
97 if (content->GetVisibility() == content::Visibility::VISIBLE)
98 return;
99
Sebastien Marchand578251d2020-12-11 03:44:43100 content->SetPageFrozen(false);
101}
102
103} // namespace
104
105void PageFreezer::MaybeFreezePageNode(const PageNode* page_node) {
106 DCHECK(page_node);
107 content::GetUIThreadTaskRunner({})->PostTask(
Sebastien Marchandd6c81d22021-03-10 02:42:39108 FROM_HERE, base::BindOnce(base::IgnoreResult(&MaybeFreezePageOnUIThread),
Sebastien Marchand578251d2020-12-11 03:44:43109 page_node->GetContentsProxy()));
110}
111
112void PageFreezer::UnfreezePageNode(const PageNode* page_node) {
113 DCHECK(page_node);
114 content::GetUIThreadTaskRunner({})->PostTask(
115 FROM_HERE,
116 base::BindOnce(&UnfreezePageOnUIThread, page_node->GetContentsProxy()));
117}
118
Sebastien Marchandd6c81d22021-03-10 02:42:39119void PageFreezer::MaybeFreezePageNodeWithReplyForTesting(
120 const PageNode* page_node,
121 base::OnceCallback<void(bool)> reply_cb) {
122 content::GetUIThreadTaskRunner({})->PostTaskAndReplyWithResult(
123 FROM_HERE,
124 base::BindOnce(&MaybeFreezePageOnUIThread, page_node->GetContentsProxy()),
125 std::move(reply_cb));
126}
127
Sebastien Marchand578251d2020-12-11 03:44:43128} // namespace mechanism
129} // namespace performance_manager