[CSC] Avoid automatic embargo
At the moment, Captured Surface Control APIs permissions only persist
for the duration of the capture, so embargo must likewise not persist
across capture sessions.
Bug: 1521259, 1466247
Change-Id: I9ba01cb762014a0c8b0488f5c31e97deb1f3d6c1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5233494
Commit-Queue: Elad Alon <eladalon@chromium.org>
Reviewed-by: Andy Paicu <andypaicu@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1251748}
diff --git a/chrome/browser/display_capture/captured_surface_control_permission_context.cc b/chrome/browser/display_capture/captured_surface_control_permission_context.cc
index 2184dcc..8e29a52 100644
--- a/chrome/browser/display_capture/captured_surface_control_permission_context.cc
+++ b/chrome/browser/display_capture/captured_surface_control_permission_context.cc
@@ -17,6 +17,10 @@
ContentSettingsType::CAPTURED_SURFACE_CONTROL,
blink::mojom::PermissionsPolicyFeature::kCapturedSurfaceControl) {}
+bool CapturedSurfaceControlPermissionContext::UsesAutomaticEmbargo() const {
+ return false;
+}
+
void CapturedSurfaceControlPermissionContext::UpdateContentSetting(
const GURL& requesting_origin,
const GURL& embedding_origin,
diff --git a/chrome/browser/display_capture/captured_surface_control_permission_context.h b/chrome/browser/display_capture/captured_surface_control_permission_context.h
index 36a0a87..9409e94 100644
--- a/chrome/browser/display_capture/captured_surface_control_permission_context.h
+++ b/chrome/browser/display_capture/captured_surface_control_permission_context.h
@@ -21,6 +21,8 @@
CapturedSurfaceControlPermissionContext& operator=(
const CapturedSurfaceControlPermissionContext&) = delete;
+ bool UsesAutomaticEmbargo() const override;
+
protected:
void UpdateContentSetting(const GURL& requesting_origin,
const GURL& embedding_origin,
diff --git a/components/permissions/permission_context_base.cc b/components/permissions/permission_context_base.cc
index 7f94718..62fb026 100644
--- a/components/permissions/permission_context_base.cc
+++ b/components/permissions/permission_context_base.cc
@@ -258,7 +258,11 @@
base::OnceClosure delete_callback) const {
return std::make_unique<PermissionRequest>(
std::move(request_data), std::move(permission_decided_callback),
- std::move(delete_callback));
+ std::move(delete_callback), UsesAutomaticEmbargo());
+}
+
+bool PermissionContextBase::UsesAutomaticEmbargo() const {
+ return true;
}
content::PermissionResult PermissionContextBase::GetPermissionStatus(
@@ -341,13 +345,15 @@
content::PermissionStatusSource::UNSPECIFIED);
}
- absl::optional<content::PermissionResult> result =
- PermissionsClient::Get()
- ->GetPermissionDecisionAutoBlocker(browser_context_)
- ->GetEmbargoResult(requesting_origin, content_settings_type_);
- if (result) {
- DCHECK(result->status == PermissionStatus::DENIED);
- return result.value();
+ if (UsesAutomaticEmbargo()) {
+ absl::optional<content::PermissionResult> result =
+ PermissionsClient::Get()
+ ->GetPermissionDecisionAutoBlocker(browser_context_)
+ ->GetEmbargoResult(requesting_origin, content_settings_type_);
+ if (result) {
+ DCHECK(result->status == PermissionStatus::DENIED);
+ return result.value();
+ }
}
return content::PermissionResult(
PermissionStatus::ASK, content::PermissionStatusSource::UNSPECIFIED);
diff --git a/components/permissions/permission_context_base.h b/components/permissions/permission_context_base.h
index 1af620c7..b667b6d 100644
--- a/components/permissions/permission_context_base.h
+++ b/components/permissions/permission_context_base.h
@@ -204,6 +204,9 @@
PermissionRequest::PermissionDecidedCallback permission_decided_callback,
base::OnceClosure delete_callback) const;
+ // Implementors can override this method to avoid using automatic embargo.
+ virtual bool UsesAutomaticEmbargo() const;
+
base::ObserverList<permissions::Observer> permission_observers_;
// Set by subclasses to inform the base class that they will handle adding
diff --git a/components/permissions/permission_context_base_unittest.cc b/components/permissions/permission_context_base_unittest.cc
index 45cce03..5588117 100644
--- a/components/permissions/permission_context_base_unittest.cc
+++ b/components/permissions/permission_context_base_unittest.cc
@@ -122,6 +122,8 @@
respond_permission_ = std::move(callback);
}
+ void SetUsesAutomaticEmbargo(bool value) { uses_automatic_embargo_ = value; }
+
protected:
void UpdateTabContext(const PermissionRequestID& id,
const GURL& requesting_origin,
@@ -131,6 +133,8 @@
bool IsRestrictedToSecureOrigins() const override { return false; }
+ bool UsesAutomaticEmbargo() const override { return uses_automatic_embargo_; }
+
private:
std::vector<ContentSetting> decisions_;
bool tab_context_updated_;
@@ -138,6 +142,7 @@
// Callback for responding to a permission once the request has been completed
// (valid URL, kill switch disabled)
base::OnceClosure respond_permission_;
+ bool uses_automatic_embargo_ = true;
};
class TestKillSwitchPermissionContext : public TestPermissionContext {
@@ -550,6 +555,82 @@
result.source);
}
+ void TestVariationBlockOnSeveralDismissalsAutomaticEmbargoOff_TestContent() {
+ GURL url("https://www.google.com");
+ SetUpUrl(url);
+ base::HistogramTester histograms;
+
+ std::map<std::string, std::string> params;
+ params
+ [PermissionDecisionAutoBlocker::GetPromptDismissCountKeyForTesting()] =
+ "5";
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ features::kBlockPromptsIfDismissedOften, params);
+
+ std::map<std::string, std::string> actual_params;
+ EXPECT_TRUE(base::GetFieldTrialParamsByFeature(
+ features::kBlockPromptsIfDismissedOften, &actual_params));
+ EXPECT_EQ(params, actual_params);
+
+ EXPECT_TRUE(base::GetFieldTrialParamsByFeature(
+ features::kBlockPromptsIfDismissedOften, &actual_params));
+ EXPECT_EQ(params, actual_params);
+
+ for (uint32_t i = 0; i < 5; ++i) {
+ TestPermissionContext permission_context(browser_context(),
+ ContentSettingsType::MIDI_SYSEX);
+ permission_context.SetUsesAutomaticEmbargo(false);
+
+ const PermissionRequestID id(
+ web_contents()->GetPrimaryMainFrame()->GetGlobalId(),
+ PermissionRequestID::RequestLocalId(i + 1));
+ permission_context.SetRespondPermissionCallback(
+ base::BindOnce(&PermissionContextBaseTests::RespondToPermission,
+ base::Unretained(this), &permission_context, id, url,
+ CONTENT_SETTING_ASK));
+ permission_context.RequestPermission(
+ PermissionRequestData(&permission_context, id,
+ /*user_gesture=*/true, url),
+ base::BindOnce(&TestPermissionContext::TrackPermissionDecision,
+ base::Unretained(&permission_context)));
+
+ EXPECT_EQ(1u, permission_context.decisions().size());
+ ASSERT_EQ(CONTENT_SETTING_ASK, permission_context.decisions()[0]);
+ EXPECT_TRUE(permission_context.tab_context_updated());
+ content::PermissionResult result = permission_context.GetPermissionStatus(
+ nullptr /* render_frame_host */, url, url);
+
+ histograms.ExpectTotalCount(
+ "Permissions.Prompt.Dismissed.PriorDismissCount2.MidiSysEx", i + 1);
+ histograms.ExpectBucketCount(
+ "Permissions.Prompt.Dismissed.PriorDismissCount2.MidiSysEx", 0,
+ i + 1);
+
+ histograms.ExpectUniqueSample(
+ "Permissions.AutoBlocker.EmbargoPromptSuppression",
+ static_cast<int>(PermissionEmbargoStatus::NOT_EMBARGOED), i + 1);
+ histograms.ExpectTotalCount("Permissions.AutoBlocker.EmbargoStatus",
+ i + 1);
+
+ EXPECT_EQ(PermissionStatus::ASK, result.status);
+ EXPECT_EQ(content::PermissionStatusSource::UNSPECIFIED, result.source);
+ histograms.ExpectUniqueSample(
+ "Permissions.AutoBlocker.EmbargoStatus",
+ static_cast<int>(PermissionEmbargoStatus::NOT_EMBARGOED), i + 1);
+ }
+
+ // Ensure that we DO NOT finish in the block state (unlike when automatic
+ // embargo is enabled).
+ TestPermissionContext permission_context(browser_context(),
+ ContentSettingsType::MIDI_SYSEX);
+ permission_context.SetUsesAutomaticEmbargo(false);
+ content::PermissionResult result = permission_context.GetPermissionStatus(
+ nullptr /* render_frame_host */, url, url);
+ EXPECT_EQ(PermissionStatus::ASK, result.status);
+ EXPECT_EQ(content::PermissionStatusSource::UNSPECIFIED, result.source);
+ }
+
void TestRequestPermissionInvalidUrl(
ContentSettingsType content_settings_type) {
base::HistogramTester histograms;
@@ -778,6 +859,11 @@
TestVariationBlockOnSeveralDismissals_TestContent();
}
+// Test that contexts that disable the automatic blocker are not blocker.
+TEST_F(PermissionContextBaseTests, TestDismissVariationsWithoutEmbargo) {
+ TestVariationBlockOnSeveralDismissalsAutomaticEmbargoOff_TestContent();
+}
+
// Simulates non-valid requesting URL.
// The permission should be denied but not saved for future use.
TEST_F(PermissionContextBaseTests, TestNonValidRequestingUrl) {
diff --git a/components/permissions/permission_request.cc b/components/permissions/permission_request.cc
index 13916710..c71defe 100644
--- a/components/permissions/permission_request.cc
+++ b/components/permissions/permission_request.cc
@@ -36,10 +36,12 @@
PermissionRequest::PermissionRequest(
PermissionRequestData request_data,
PermissionDecidedCallback permission_decided_callback,
- base::OnceClosure delete_callback)
+ base::OnceClosure delete_callback,
+ bool uses_automatic_embargo)
: data_(std::move(request_data)),
permission_decided_callback_(std::move(permission_decided_callback)),
- delete_callback_(std::move(delete_callback)) {}
+ delete_callback_(std::move(delete_callback)),
+ uses_automatic_embargo_(uses_automatic_embargo) {}
PermissionRequest::~PermissionRequest() {
DCHECK(delete_callback_.is_null());
diff --git a/components/permissions/permission_request.h b/components/permissions/permission_request.h
index 31b7605..eae05c47 100644
--- a/components/permissions/permission_request.h
+++ b/components/permissions/permission_request.h
@@ -60,7 +60,8 @@
PermissionRequest(PermissionRequestData request_data,
PermissionDecidedCallback permission_decided_callback,
- base::OnceClosure delete_callback);
+ base::OnceClosure delete_callback,
+ bool uses_automatic_embargo);
PermissionRequest(const PermissionRequest&) = delete;
PermissionRequest& operator=(const PermissionRequest&) = delete;
@@ -201,6 +202,8 @@
// identify the permission being requested.
virtual std::u16string GetPermissionNameTextFragment() const;
+ bool uses_automatic_embargo() const { return uses_automatic_embargo_; }
+
protected:
// Sets whether this request is permission element initiated, for testing
// subclasses only.
@@ -217,6 +220,8 @@
// caller.
base::OnceClosure delete_callback_;
+ const bool uses_automatic_embargo_ = true;
+
base::WeakPtrFactory<PermissionRequest> weak_factory_{this};
};
diff --git a/components/permissions/permission_request_manager.cc b/components/permissions/permission_request_manager.cc
index cb42e633..12bcea2 100644
--- a/components/permissions/permission_request_manager.cc
+++ b/components/permissions/permission_request_manager.cc
@@ -1058,10 +1058,6 @@
prediction_grant_likelihood_, was_decision_held_back_, ignore_reason,
did_show_prompt_, did_click_manage_, did_click_learn_more_);
- PermissionDecisionAutoBlocker* autoblocker =
- PermissionsClient::Get()->GetPermissionDecisionAutoBlocker(
- browser_context);
-
absl::optional<QuietUiReason> quiet_ui_reason;
if (ShouldCurrentRequestUseQuietUI())
quiet_ui_reason = ReasonForUsingQuietUi();
@@ -1084,27 +1080,8 @@
request->GetGestureType(), quiet_ui_reason, time_since_shown,
web_contents());
- PermissionEmbargoStatus embargo_status =
- PermissionEmbargoStatus::NOT_EMBARGOED;
- if (permission_action == PermissionAction::DISMISSED &&
- !request->IsEmbeddedPermissionElementInitiated()) {
- if (autoblocker->RecordDismissAndEmbargo(
- request->requesting_origin(), request->GetContentSettingsType(),
- ShouldCurrentRequestUseQuietUI())) {
- embargo_status = PermissionEmbargoStatus::REPEATED_DISMISSALS;
- }
- } else if (permission_action == PermissionAction::IGNORED &&
- !request->IsEmbeddedPermissionElementInitiated()) {
- if (autoblocker->RecordIgnoreAndEmbargo(
- request->requesting_origin(), request->GetContentSettingsType(),
- ShouldCurrentRequestUseQuietUI())) {
- embargo_status = PermissionEmbargoStatus::REPEATED_IGNORES;
- }
- } else if (permission_action == PermissionAction::GRANTED_ONCE) {
- autoblocker->RemoveEmbargoAndResetCounts(
- request->requesting_origin(), request->GetContentSettingsType());
- }
- PermissionUmaUtil::RecordEmbargoStatus(embargo_status);
+ PermissionUmaUtil::RecordEmbargoStatus(RecordActionAndGetEmbargoStatus(
+ browser_context, request, permission_action));
}
// IGNORED is not a decision on the prompt and it occurs because of external
@@ -1518,6 +1495,41 @@
return view_->ShouldFinalizeRequestAfterDecided();
}
+PermissionEmbargoStatus
+PermissionRequestManager::RecordActionAndGetEmbargoStatus(
+ content::BrowserContext* browser_context,
+ PermissionRequest* request,
+ PermissionAction permission_action) {
+ if (!request->uses_automatic_embargo()) {
+ return PermissionEmbargoStatus::NOT_EMBARGOED;
+ }
+
+ PermissionDecisionAutoBlocker* const autoblocker =
+ PermissionsClient::Get()->GetPermissionDecisionAutoBlocker(
+ browser_context);
+
+ if (permission_action == PermissionAction::DISMISSED &&
+ !request->IsEmbeddedPermissionElementInitiated()) {
+ if (autoblocker->RecordDismissAndEmbargo(
+ request->requesting_origin(), request->GetContentSettingsType(),
+ ShouldCurrentRequestUseQuietUI())) {
+ return PermissionEmbargoStatus::REPEATED_DISMISSALS;
+ }
+ } else if (permission_action == PermissionAction::IGNORED &&
+ !request->IsEmbeddedPermissionElementInitiated()) {
+ if (autoblocker->RecordIgnoreAndEmbargo(request->requesting_origin(),
+ request->GetContentSettingsType(),
+ ShouldCurrentRequestUseQuietUI())) {
+ return PermissionEmbargoStatus::REPEATED_IGNORES;
+ }
+ } else if (permission_action == PermissionAction::GRANTED_ONCE) {
+ autoblocker->RemoveEmbargoAndResetCounts(request->requesting_origin(),
+ request->GetContentSettingsType());
+ }
+
+ return PermissionEmbargoStatus::NOT_EMBARGOED;
+}
+
WEB_CONTENTS_USER_DATA_KEY_IMPL(PermissionRequestManager);
} // namespace permissions
diff --git a/components/permissions/permission_request_manager.h b/components/permissions/permission_request_manager.h
index ee443d6f..40b4e4c 100644
--- a/components/permissions/permission_request_manager.h
+++ b/components/permissions/permission_request_manager.h
@@ -408,6 +408,12 @@
// permission decision.
bool ShouldFinalizeRequestAfterDecided(PermissionAction action) const;
+ // Calculate and record the PermissionEmbargoStatus.
+ PermissionEmbargoStatus RecordActionAndGetEmbargoStatus(
+ content::BrowserContext* browser_context,
+ PermissionRequest* request,
+ PermissionAction permission_action);
+
// Factory to be used to create views when needed.
PermissionPrompt::Factory view_factory_;