Skip to content

Commit 4dc421a

Browse files
committed
Prevent a tab from being discarded if it shares its BrowsingInstance
This CL add a feature parameter to the Proactive Tab Discarding and Freezing experiment to prevent discarding tabs that share their browsing instance with another tab. This might be too agressive, in practice we might just want to consider tabs under the same SiteInstance but this is not an information that we can access yet. Check this page for more details about the SiteInstance/BrowsingInstance concepts: https://www.chromium.org/developers/design-documents/process-models#Implementation_Notes UKM privacy document has been updated here (pending approval): https://docs.google.com/a/google.com/document/d/1BNQ5nLOtPuwP7oxr9r-XKNKr5iObXEiA_69WXAvuYAo/edit?disco=AAAABzM-vE0 Bug: 775644, 862203 Change-Id: Iaf5107db1d68aa4a0155ecbae7283f487c23bb7c Reviewed-on: https://chromium-review.googlesource.com/1144188 Commit-Queue: Sébastien Marchand <sebmarchand@chromium.org> Reviewed-by: Chris Hamilton <chrisha@chromium.org> Reviewed-by: Alexei Svitkine <asvitkine@chromium.org> Cr-Original-Commit-Position: refs/heads/master@{#576789}(cherry picked from commit 94d6d39) Reviewed-on: https://chromium-review.googlesource.com/1150261 Reviewed-by: Sébastien Marchand <sebmarchand@chromium.org> Cr-Commit-Position: refs/branch-heads/3497@{#85} Cr-Branched-From: 271eaf5-refs/heads/master@{#576753}
1 parent 73635a1 commit 4dc421a

File tree

8 files changed

+132
-9
lines changed

8 files changed

+132
-9
lines changed

chrome/browser/resource_coordinator/decision_details.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const char* kDecisionFailureReasonStrings[] = {
3434
"Tab is currently visible",
3535
"Tab is currently using DevTools",
3636
"Tab is currently capturing a window or screen",
37+
"Tab is sharing its BrowsingInstance with another tab",
3738
};
3839
static_assert(base::size(kDecisionFailureReasonStrings) ==
3940
static_cast<size_t>(DecisionFailureReason::MAX),
@@ -130,6 +131,9 @@ void PopulateFailureReason(
130131
case DecisionFailureReason::LIVE_STATE_DESKTOP_CAPTURE:
131132
ukm->SetFailureLiveStateDesktopCapture(1);
132133
break;
134+
case DecisionFailureReason::LIVE_STATE_SHARING_BROWSING_INSTANCE:
135+
ukm->SetFailureLiveStateSharingBrowsingInstance(1);
136+
break;
133137
case DecisionFailureReason::MAX:
134138
break;
135139
}

chrome/browser/resource_coordinator/decision_details.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ enum class DecisionFailureReason : int32_t {
7373
// The tab is opted out of the intervention as it's currently capturing a
7474
// window or screen.
7575
LIVE_STATE_DESKTOP_CAPTURE,
76+
// This tab is sharing its BrowsingInstance with another tab, and so could
77+
// want to communicate with it.
78+
LIVE_STATE_SHARING_BROWSING_INSTANCE,
7679
// This must remain last.
7780
MAX,
7881
};

chrome/browser/resource_coordinator/tab_lifecycle_unit.cc

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -883,28 +883,38 @@ void TabLifecycleUnitSource::TabLifecycleUnit::CheckIfTabIsUsedInBackground(
883883
// This ensures that the decision details lists all possible reasons that the
884884
// transition can be denied.
885885

886+
auto* web_contents = GetWebContents();
887+
886888
// Do not freeze tabs that are casting/mirroring/playing audio.
887889
IsMediaTabImpl(decision_details);
888890

891+
if (GetStaticProactiveTabFreezeAndDiscardParams()
892+
.should_protect_tabs_sharing_browsing_instance) {
893+
if (web_contents->GetSiteInstance()->GetRelatedActiveContentsCount() > 1U) {
894+
decision_details->AddReason(
895+
DecisionFailureReason::LIVE_STATE_SHARING_BROWSING_INSTANCE);
896+
}
897+
}
898+
889899
// Consult the local database to see if this tab could try to communicate with
890900
// the user while in background (don't check for the visibility here as
891901
// there's already a check for that above). Only do this for proactive
892902
// interventions.
893903
if (intervention_type == InterventionType::kProactive) {
894-
CheckIfTabCanCommunicateWithUserWhileInBackground(GetWebContents(),
904+
CheckIfTabCanCommunicateWithUserWhileInBackground(web_contents,
895905
decision_details);
896906
}
897907

898908
// Do not freeze/discard a tab that has active WebUSB connections.
899-
if (auto* usb_tab_helper = UsbTabHelper::FromWebContents(GetWebContents())) {
909+
if (auto* usb_tab_helper = UsbTabHelper::FromWebContents(web_contents)) {
900910
if (usb_tab_helper->IsDeviceConnected()) {
901911
decision_details->AddReason(
902912
DecisionFailureReason::LIVE_STATE_USING_WEB_USB);
903913
}
904914
}
905915

906916
// Do not freeze tabs that are currently using DevTools.
907-
if (DevToolsWindow::GetInstanceForInspectedWebContents(GetWebContents())) {
917+
if (DevToolsWindow::GetInstanceForInspectedWebContents(web_contents)) {
908918
decision_details->AddReason(
909919
DecisionFailureReason::LIVE_STATE_DEVTOOLS_OPEN);
910920
}

chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "chrome/browser/resource_coordinator/tab_lifecycle_unit.h"
66

77
#include <memory>
8+
#include <string>
89

910
#include "base/macros.h"
1011
#include "base/observer_list.h"
@@ -31,6 +32,7 @@
3132
#include "chrome/browser/usb/usb_tab_helper.h"
3233
#include "chrome/test/base/testing_profile.h"
3334
#include "content/public/browser/web_contents.h"
35+
#include "content/public/common/referrer.h"
3436
#include "content/public/test/web_contents_tester.h"
3537
#include "testing/gtest/include/gtest/gtest.h"
3638

@@ -648,6 +650,51 @@ TEST_F(TabLifecycleUnitTest, NotifiedOfWebContentsVisibilityChanges) {
648650
tab_lifecycle_unit.RemoveObserver(&observer);
649651
}
650652

653+
TEST_F(TabLifecycleUnitTest, CannotFreezeOrDiscardIfSharingBrowsingInstance) {
654+
TabLifecycleUnit tab_lifecycle_unit(GetSource(), &observers_,
655+
usage_clock_.get(), web_contents_,
656+
tab_strip_model_.get());
657+
TabLoadTracker::Get()->TransitionStateForTesting(web_contents_,
658+
LoadingState::LOADED);
659+
660+
// Creates a second WebContents that use the same SiteInstance.
661+
auto* site_instance = web_contents_->GetSiteInstance();
662+
std::unique_ptr<content::WebContents> contents =
663+
content::WebContentsTester::CreateTestWebContents(browser_context(),
664+
site_instance);
665+
// Navigate this second WebContents to another URL, after this these 2
666+
// WebContents will use separate SiteInstances owned by the same
667+
// BrowsingInstance.
668+
contents->GetController().LoadURL(GURL("http://another-url.com/"),
669+
content::Referrer(),
670+
ui::PAGE_TRANSITION_LINK, std::string());
671+
EXPECT_NE(web_contents_->GetSiteInstance(), contents->GetSiteInstance());
672+
EXPECT_EQ(2U,
673+
web_contents_->GetSiteInstance()->GetRelatedActiveContentsCount());
674+
675+
DecisionDetails decision_details;
676+
EXPECT_TRUE(tab_lifecycle_unit.CanFreeze(&decision_details));
677+
EXPECT_TRUE(decision_details.IsPositive());
678+
679+
{
680+
GetMutableStaticProactiveTabFreezeAndDiscardParamsForTesting()
681+
->should_protect_tabs_sharing_browsing_instance = true;
682+
decision_details.Clear();
683+
EXPECT_FALSE(tab_lifecycle_unit.CanFreeze(&decision_details));
684+
EXPECT_FALSE(decision_details.IsPositive());
685+
EXPECT_EQ(DecisionFailureReason::LIVE_STATE_SHARING_BROWSING_INSTANCE,
686+
decision_details.FailureReason());
687+
688+
decision_details.Clear();
689+
690+
EXPECT_FALSE(tab_lifecycle_unit.CanDiscard(DiscardReason::kProactive,
691+
&decision_details));
692+
EXPECT_FALSE(decision_details.IsPositive());
693+
EXPECT_EQ(DecisionFailureReason::LIVE_STATE_SHARING_BROWSING_INSTANCE,
694+
decision_details.FailureReason());
695+
}
696+
}
697+
651698
TEST_F(TabLifecycleUnitTest, CannotDiscardIfEnterpriseOptOutUsed) {
652699
TabLifecycleUnit tab_lifecycle_unit(GetSource(), &observers_,
653700
usage_clock_.get(), web_contents_,

chrome/browser/resource_coordinator/tab_manager_features.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@ const char kProactiveTabFreezeAndDiscard_ShouldProactivelyDiscardParam[] =
8989
"ShouldProactivelyDiscard";
9090
const char kProactiveTabFreezeAndDiscard_ShouldPeriodicallyUnfreezeParam[] =
9191
"ShouldPeriodicallyUnfreeze";
92+
93+
// NOTE: This parameter is disabled by default and shouldn't be enabled until
94+
// the privacy review for the UKM associated with it has been approved, see
95+
// https://docs.google.com/a/google.com/document/d/1BNQ5nLOtPuwP7oxr9r-XKNKr5iObXEiA_69WXAvuYAo/edit?disco=AAAABzM-vE0
96+
//
97+
// TODO(sebmarchand): Remove this comment once the UKM has been approved.
98+
const char
99+
kProactiveTabFreezeAndDiscard_ShouldProtectTabsSharingBrowsingInstanceParam
100+
[] = "ShouldProtectTabsSharingBrowsingInstance";
92101
const char kProactiveTabFreezeAndDiscard_LowLoadedTabCountParam[] =
93102
"LowLoadedTabCount";
94103
const char kProactiveTabFreezeAndDiscard_ModerateLoadedTabsPerGbRamParam[] =
@@ -137,6 +146,16 @@ const bool kProactiveTabFreezeAndDiscard_ShouldProactivelyDiscardDefault =
137146
false;
138147
const bool kProactiveTabFreezeAndDiscard_ShouldPeriodicallyUnfreezeDefault =
139148
false;
149+
150+
// NOTE: This parameter is disabled by default and shouldn't be enabled until
151+
// the privacy review for the UKM associated with it has been approved, see
152+
// https://docs.google.com/a/google.com/document/d/1BNQ5nLOtPuwP7oxr9r-XKNKr5iObXEiA_69WXAvuYAo/edit?disco=AAAABzM-vE0
153+
//
154+
// TODO(sebmarchand): Remove this comment once the UKM has been approved.
155+
const bool
156+
kProactiveTabFreezeAndDiscard_ShouldProtectTabsSharingBrowsingInstanceDefault =
157+
false;
158+
140159
// 50% of people cap out at 4 tabs, so for them proactive discarding won't even
141160
// be invoked. See Tabs.MaxTabsInADay.
142161
// TODO(chrisha): This should eventually be informed by the number of tabs
@@ -231,6 +250,12 @@ ProactiveTabFreezeAndDiscardParams GetProactiveTabFreezeAndDiscardParams(
231250
kProactiveTabFreezeAndDiscard_ShouldPeriodicallyUnfreezeParam,
232251
kProactiveTabFreezeAndDiscard_ShouldPeriodicallyUnfreezeDefault);
233252

253+
params.should_protect_tabs_sharing_browsing_instance =
254+
base::GetFieldTrialParamByFeatureAsBool(
255+
features::kProactiveTabFreezeAndDiscard,
256+
kProactiveTabFreezeAndDiscard_ShouldProtectTabsSharingBrowsingInstanceParam,
257+
kProactiveTabFreezeAndDiscard_ShouldProtectTabsSharingBrowsingInstanceDefault);
258+
234259
params.low_loaded_tab_count = base::GetFieldTrialParamByFeatureAsInt(
235260
features::kProactiveTabFreezeAndDiscard,
236261
kProactiveTabFreezeAndDiscard_LowLoadedTabCountParam,
@@ -294,6 +319,12 @@ GetStaticProactiveTabFreezeAndDiscardParams() {
294319
return *params;
295320
}
296321

322+
ProactiveTabFreezeAndDiscardParams*
323+
GetMutableStaticProactiveTabFreezeAndDiscardParamsForTesting() {
324+
return const_cast<ProactiveTabFreezeAndDiscardParams*>(
325+
&GetStaticProactiveTabFreezeAndDiscardParams());
326+
}
327+
297328
base::TimeDelta GetTabLoadTimeout(const base::TimeDelta& default_timeout) {
298329
int timeout_in_ms = base::GetFieldTrialParamByFeatureAsInt(
299330
features::kCustomizedTabLoadTimeout, kTabLoadTimeoutInMsParameterName,

chrome/browser/resource_coordinator/tab_manager_features.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,14 @@ extern const char kProactiveTabFreezeAndDiscardFeatureName[];
2929

3030
// Variations parameter names related to proactive discarding.
3131
// See ProactiveTabFreezeAndDiscardsParams for details.
32+
//
33+
// TODO(sebmarchand): Use the base::FeatureParam API here.
3234
extern const char kProactiveTabFreezeAndDiscard_ShouldProactivelyDiscardParam[];
3335
extern const char
3436
kProactiveTabFreezeAndDiscard_ShouldPeriodicallyUnfreezeParam[];
37+
extern const char
38+
kProactiveTabFreezeAndDiscard_ShouldProtectTabsSharingBrowsingInstanceParam
39+
[];
3540
extern const char kProactiveTabFreezeAndDiscard_LowLoadedTabCountParam[];
3641
extern const char
3742
kProactiveTabFreezeAndDiscard_ModerateLoadedTabsPerGbRamParam[];
@@ -66,6 +71,8 @@ extern const char kInfiniteSessionRestore_MinSiteEngagementToRestore[];
6671
extern const bool kProactiveTabFreezeAndDiscard_ShouldProactivelyDiscardDefault;
6772
extern const bool
6873
kProactiveTabFreezeAndDiscard_ShouldPeriodicallyUnfreezeDefault;
74+
extern const bool
75+
kProactiveTabFreezeAndDiscard_ShouldProtectTabsSharingBrowsingInstanceDefault;
6976
extern const uint32_t kProactiveTabFreezeAndDiscard_LowLoadedTabCountDefault;
7077
extern const uint32_t
7178
kProactiveTabFreezeAndDiscard_ModerateLoadedTabsPerGbRamDefault;
@@ -152,6 +159,9 @@ struct ProactiveTabFreezeAndDiscardParams {
152159
bool should_proactively_discard;
153160
// Whether frozen tabs should periodically be unfrozen to update their state.
154161
bool should_periodically_unfreeze;
162+
// Whether tabs should be protected from freezing/discarding if they share
163+
// their BrowsingInstance with another tab.
164+
bool should_protect_tabs_sharing_browsing_instance;
155165
// Tab count (inclusive) beyond which the state transitions to MODERATE.
156166
// Intended to cover the majority of simple workflows and be small enough that
157167
// it is very unlikely that memory pressure will be encountered with this many
@@ -256,6 +266,8 @@ ProactiveTabFreezeAndDiscardParams GetProactiveTabFreezeAndDiscardParams(
256266
// all the classes that need one.
257267
const ProactiveTabFreezeAndDiscardParams&
258268
GetStaticProactiveTabFreezeAndDiscardParams();
269+
ProactiveTabFreezeAndDiscardParams*
270+
GetMutableStaticProactiveTabFreezeAndDiscardParamsForTesting();
259271

260272
base::TimeDelta GetTabLoadTimeout(const base::TimeDelta& default_timeout);
261273

chrome/browser/resource_coordinator/tab_manager_features_unittest.cc

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class TabManagerFeaturesTest : public testing::Test {
5050
void ExpectProactiveTabFreezeAndDiscardParams(
5151
bool should_proactively_discard,
5252
bool should_periodically_unfreeze,
53+
bool should_protect_tabs_sharing_browsing_instance,
5354
int low_loaded_tab_count,
5455
int moderate_loaded_tab_count,
5556
int high_loaded_tab_count,
@@ -66,6 +67,8 @@ class TabManagerFeaturesTest : public testing::Test {
6667
EXPECT_EQ(should_proactively_discard, params.should_proactively_discard);
6768
EXPECT_EQ(should_periodically_unfreeze,
6869
params.should_periodically_unfreeze);
70+
EXPECT_EQ(should_protect_tabs_sharing_browsing_instance,
71+
params.should_protect_tabs_sharing_browsing_instance);
6972
EXPECT_EQ(low_loaded_tab_count, params.low_loaded_tab_count);
7073
EXPECT_EQ(moderate_loaded_tab_count, params.moderate_loaded_tab_count);
7174

@@ -131,6 +134,7 @@ class TabManagerFeaturesTest : public testing::Test {
131134
ExpectProactiveTabFreezeAndDiscardParams(
132135
kProactiveTabFreezeAndDiscard_ShouldProactivelyDiscardDefault,
133136
kProactiveTabFreezeAndDiscard_ShouldPeriodicallyUnfreezeDefault,
137+
kProactiveTabFreezeAndDiscard_ShouldProtectTabsSharingBrowsingInstanceDefault,
134138
kProactiveTabFreezeAndDiscard_LowLoadedTabCountDefault,
135139
kProactiveTabFreezeAndDiscard_ModerateLoadedTabsPerGbRamDefault *
136140
memory_in_gb,
@@ -187,6 +191,9 @@ TEST_F(TabManagerFeaturesTest,
187191
SetParam(kProactiveTabFreezeAndDiscard_ShouldProactivelyDiscardParam, "blah");
188192
SetParam(kProactiveTabFreezeAndDiscard_ShouldPeriodicallyUnfreezeParam,
189193
"blah");
194+
SetParam(
195+
kProactiveTabFreezeAndDiscard_ShouldProtectTabsSharingBrowsingInstanceParam,
196+
"bleh");
190197
SetParam(kProactiveTabFreezeAndDiscard_LowLoadedTabCountParam, "ab");
191198
SetParam(kProactiveTabFreezeAndDiscard_ModerateLoadedTabsPerGbRamParam,
192199
"27.8");
@@ -205,6 +212,9 @@ TEST_F(TabManagerFeaturesTest, GetProactiveTabFreezeAndDiscardParams) {
205212
SetParam(kProactiveTabFreezeAndDiscard_ShouldProactivelyDiscardParam, "true");
206213
SetParam(kProactiveTabFreezeAndDiscard_ShouldPeriodicallyUnfreezeParam,
207214
"true");
215+
SetParam(
216+
kProactiveTabFreezeAndDiscard_ShouldProtectTabsSharingBrowsingInstanceParam,
217+
"true");
208218
SetParam(kProactiveTabFreezeAndDiscard_LowLoadedTabCountParam, "7");
209219
SetParam(kProactiveTabFreezeAndDiscard_ModerateLoadedTabsPerGbRamParam, "4");
210220
SetParam(kProactiveTabFreezeAndDiscard_HighLoadedTabCountParam, "42");
@@ -222,17 +232,17 @@ TEST_F(TabManagerFeaturesTest, GetProactiveTabFreezeAndDiscardParams) {
222232
// |moderate_tab_count_per_gb_ram|) < |low_loaded_tab_count|).
223233
int memory_in_gb_low = 1;
224234
ExpectProactiveTabFreezeAndDiscardParams(
225-
true, true, 7, 7, 42, memory_in_gb_low, base::TimeDelta::FromSeconds(60),
226-
base::TimeDelta::FromSeconds(120), base::TimeDelta::FromSeconds(247),
227-
base::TimeDelta::FromSeconds(10), base::TimeDelta::FromSeconds(20),
228-
base::TimeDelta::FromSeconds(30));
235+
true, true, true, 7, 7, 42, memory_in_gb_low,
236+
base::TimeDelta::FromSeconds(60), base::TimeDelta::FromSeconds(120),
237+
base::TimeDelta::FromSeconds(247), base::TimeDelta::FromSeconds(10),
238+
base::TimeDelta::FromSeconds(20), base::TimeDelta::FromSeconds(30));
229239

230240
// Should snap |moderate_loaded_tab_count| to |high_loaded_tab_count|, when
231241
// the amount of physical memory is so high that (|memory_in_gb| *
232242
// |moderate_tab_count_per_gb_ram|) > |high_loaded_tab_count|).
233243
int memory_in_gb_high = 100;
234244
ExpectProactiveTabFreezeAndDiscardParams(
235-
true, true, 7, 42, 42, memory_in_gb_high,
245+
true, true, true, 7, 42, 42, memory_in_gb_high,
236246
base::TimeDelta::FromSeconds(60), base::TimeDelta::FromSeconds(120),
237247
base::TimeDelta::FromSeconds(247), base::TimeDelta::FromSeconds(10),
238248
base::TimeDelta::FromSeconds(20), base::TimeDelta::FromSeconds(30));
@@ -241,7 +251,7 @@ TEST_F(TabManagerFeaturesTest, GetProactiveTabFreezeAndDiscardParams) {
241251
// in the interval [low_loaded_tab_count, high_loaded_tab_count].
242252
int memory_in_gb_normal = 4;
243253
ExpectProactiveTabFreezeAndDiscardParams(
244-
true, true, 7, 16, 42, memory_in_gb_normal,
254+
true, true, true, 7, 16, 42, memory_in_gb_normal,
245255
base::TimeDelta::FromSeconds(60), base::TimeDelta::FromSeconds(120),
246256
base::TimeDelta::FromSeconds(247), base::TimeDelta::FromSeconds(10),
247257
base::TimeDelta::FromSeconds(20), base::TimeDelta::FromSeconds(30));

tools/metrics/ukm/ukm.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3688,6 +3688,12 @@ be describing additional metrics about the same event.
36883688
currently playing audio.
36893689
</summary>
36903690
</metric>
3691+
<metric name="FailureLiveStateSharingBrowsingInstance">
3692+
<summary>
3693+
Boolean indicating that the intervention was disallowed because the tab is
3694+
sharing its BrowsingInstance with at least one other tab.
3695+
</summary>
3696+
</metric>
36913697
<metric name="FailureLiveStateUsingWebSockets">
36923698
<summary>
36933699
Boolean indicating that the intervention was disallowed because the tab is

0 commit comments

Comments
 (0)