0

Added metrics to help with one time permissions on desktop

Add metrics that will record
- Elapsed time between grant and permission use
- Elapsed time between grant and revoke

Only for Geolocation, mic and camera permission

Bug: 1119738
Change-Id: Ia01cee7921b246844e90d789761f3beebebb98de
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2367832
Commit-Queue: Ravjit Singh Uppal <ravjit@chromium.org>
Reviewed-by: Balazs Engedy <engedy@chromium.org>
Reviewed-by: Colin Blundell <blundell@chromium.org>
Reviewed-by: Jesse Doherty <jwd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810544}
This commit is contained in:
Ravjit Singh Uppal
2020-09-25 10:33:11 +00:00
committed by Commit Bot
parent abbf0250d3
commit 884cd3901f
13 changed files with 195 additions and 1 deletions

@ -19,6 +19,7 @@
#include "chrome/common/renderer_configuration.mojom.h"
#include "components/content_settings/browser/page_specific_content_settings.h"
#include "components/permissions/permission_decision_auto_blocker.h"
#include "components/permissions/permission_uma_util.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_process_host.h"
@ -159,6 +160,25 @@ PageSpecificContentSettingsDelegate::GetMicrophoneCameraState() {
return state;
}
void PageSpecificContentSettingsDelegate::OnContentAllowed(
ContentSettingsType type) {
if (!(type == ContentSettingsType::GEOLOCATION ||
type == ContentSettingsType::MEDIASTREAM_CAMERA ||
type == ContentSettingsType::MEDIASTREAM_MIC)) {
return;
}
content_settings::SettingInfo setting_info;
GetSettingsMap()->GetWebsiteSetting(web_contents()->GetLastCommittedURL(),
web_contents()->GetLastCommittedURL(),
type, std::string(), &setting_info);
const base::Time grant_time = GetSettingsMap()->GetSettingLastModifiedDate(
setting_info.primary_pattern, setting_info.secondary_pattern, type);
if (grant_time.is_null())
return;
permissions::PermissionUmaUtil::RecordTimeElapsedBetweenGrantAndUse(
type, base::Time::Now() - grant_time);
}
void PageSpecificContentSettingsDelegate::OnContentBlocked(
ContentSettingsType type) {
if (type == ContentSettingsType::PLUGINS) {

@ -78,6 +78,7 @@ class PageSpecificContentSettingsDelegate
const std::string& media_stream_selected_video_device) override;
content_settings::PageSpecificContentSettings::MicrophoneCameraState
GetMicrophoneCameraState() override;
void OnContentAllowed(ContentSettingsType type) override;
void OnContentBlocked(ContentSettingsType type) override;
void OnCacheStorageAccessAllowed(const url::Origin& origin) override;
void OnCookieAccessAllowed(const net::CookieList& accessed_cookies) override;

@ -0,0 +1,95 @@
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/content_settings/browser/page_specific_content_settings.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/content_settings/page_specific_content_settings_delegate.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
namespace content_settings {
class PageSpecificContentSettingsTest : public ChromeRenderViewHostTestHarness {
public:
PageSpecificContentSettingsTest()
: ChromeRenderViewHostTestHarness(
base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
PageSpecificContentSettings::CreateForWebContents(
web_contents(),
std::make_unique<chrome::PageSpecificContentSettingsDelegate>(
web_contents()));
}
};
TEST_F(PageSpecificContentSettingsTest, HistogramTest) {
base::HistogramTester histograms;
const GURL test_url("https://test.com/");
const char kGeolocationHistogramName[] =
"Permissions.Usage.ElapsedTimeSinceGrant.Geolocation";
const char kMicrophoneHistogramName[] =
"Permissions.Usage.ElapsedTimeSinceGrant.AudioCapture";
const char kCameraHistogramName[] =
"Permissions.Usage.ElapsedTimeSinceGrant.VideoCapture";
NavigateAndCommit(test_url);
HostContentSettingsMap* map =
HostContentSettingsMapFactory::GetForProfile(profile());
map->SetContentSettingDefaultScope(
test_url, test_url, ContentSettingsType::GEOLOCATION, std::string(),
ContentSetting::CONTENT_SETTING_ALLOW);
map->SetContentSettingDefaultScope(
test_url, test_url, ContentSettingsType::MEDIASTREAM_MIC, std::string(),
ContentSetting::CONTENT_SETTING_ALLOW);
map->SetContentSettingDefaultScope(
test_url, test_url, ContentSettingsType::MEDIASTREAM_CAMERA,
std::string(), ContentSetting::CONTENT_SETTING_ALLOW);
task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
PageSpecificContentSettings* content_settings =
PageSpecificContentSettings::GetForFrame(web_contents()->GetMainFrame());
histograms.ExpectTotalCount(kGeolocationHistogramName, 0);
content_settings->OnContentAllowed(ContentSettingsType::GEOLOCATION);
histograms.ExpectTotalCount(kGeolocationHistogramName, 1);
EXPECT_THAT(histograms.GetAllSamples(kGeolocationHistogramName),
testing::ElementsAre(base::Bucket(1, 1)));
content_settings->OnContentAllowed(ContentSettingsType::GEOLOCATION);
// Count should stay same even after multiple usage of permission
histograms.ExpectTotalCount(kGeolocationHistogramName, 1);
PageSpecificContentSettings::MicrophoneCameraState microphone_accessed =
PageSpecificContentSettings::MICROPHONE_ACCESSED |
PageSpecificContentSettings::CAMERA_ACCESSED |
PageSpecificContentSettings::CAMERA_BLOCKED;
histograms.ExpectTotalCount(kMicrophoneHistogramName, 0);
content_settings->OnMediaStreamPermissionSet(test_url, microphone_accessed,
std::string(), std::string(),
std::string(), std::string());
histograms.ExpectTotalCount(kMicrophoneHistogramName, 1);
EXPECT_THAT(histograms.GetAllSamples(kMicrophoneHistogramName),
testing::ElementsAre(base::Bucket(1, 1)));
const PageSpecificContentSettings::MicrophoneCameraState mic_camera_accessed =
PageSpecificContentSettings::MICROPHONE_ACCESSED |
PageSpecificContentSettings::CAMERA_ACCESSED;
histograms.ExpectTotalCount(kCameraHistogramName, 0);
content_settings->OnMediaStreamPermissionSet(test_url, mic_camera_accessed,
std::string(), std::string(),
std::string(), std::string());
histograms.ExpectTotalCount(kCameraHistogramName, 1);
EXPECT_THAT(histograms.GetAllSamples(kCameraHistogramName),
testing::ElementsAre(base::Bucket(1, 1)));
content_settings->OnMediaStreamPermissionSet(test_url, mic_camera_accessed,
std::string(), std::string(),
std::string(), std::string());
// Count should stay same even after multiple usage of permission
histograms.ExpectTotalCount(kMicrophoneHistogramName, 1);
histograms.ExpectTotalCount(kCameraHistogramName, 1);
}
} // namespace content_settings

@ -3358,6 +3358,7 @@ test("unit_tests") {
"../browser/content_settings/host_content_settings_map_unittest.cc",
"../browser/content_settings/mock_settings_observer.cc",
"../browser/content_settings/mock_settings_observer.h",
"../browser/content_settings/page_specific_content_settings_unittest.cc",
"../browser/content_settings/sound_content_setting_observer_unittest.cc",
"../browser/custom_handlers/protocol_handler_registry_unittest.cc",
"../browser/custom_handlers/test_protocol_handler_registry_delegate.cc",

@ -574,10 +574,10 @@ void PageSpecificContentSettings::OnContentAllowed(ContentSettingsType type) {
status.blocked = false;
access_changed = true;
}
if (!status.allowed) {
status.allowed = true;
access_changed = true;
delegate_->OnContentAllowed(ContentSettingsType::GEOLOCATION);
}
if (access_changed)
@ -775,6 +775,8 @@ void PageSpecificContentSettings::OnMediaStreamPermissionSet(
bool mic_blocked = (new_microphone_camera_state & MICROPHONE_BLOCKED) != 0;
ContentSettingsStatus& status =
content_settings_status_[ContentSettingsType::MEDIASTREAM_MIC];
if (!status.allowed && !mic_blocked)
delegate_->OnContentAllowed(ContentSettingsType::MEDIASTREAM_MIC);
status.allowed = !mic_blocked;
status.blocked = mic_blocked;
}
@ -785,6 +787,8 @@ void PageSpecificContentSettings::OnMediaStreamPermissionSet(
bool cam_blocked = (new_microphone_camera_state & CAMERA_BLOCKED) != 0;
ContentSettingsStatus& status =
content_settings_status_[ContentSettingsType::MEDIASTREAM_CAMERA];
if (!status.allowed && !cam_blocked)
delegate_->OnContentAllowed(ContentSettingsType::MEDIASTREAM_CAMERA);
status.allowed = !cam_blocked;
status.blocked = cam_blocked;
}

@ -124,6 +124,10 @@ class PageSpecificContentSettings
// media stream request.
virtual MicrophoneCameraState GetMicrophoneCameraState() = 0;
// Notifies the delegate a particular content settings type was allowed for
// the first time on this page.
virtual void OnContentAllowed(ContentSettingsType type) = 0;
// Notifies the delegate a particular content settings type was blocked.
virtual void OnContentBlocked(ContentSettingsType type) = 0;

@ -58,6 +58,9 @@ TestPageSpecificContentSettingsDelegate::GetMicrophoneCameraState() {
return PageSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED;
}
void TestPageSpecificContentSettingsDelegate::OnContentAllowed(
ContentSettingsType type) {}
void TestPageSpecificContentSettingsDelegate::OnContentBlocked(
ContentSettingsType type) {}

@ -36,6 +36,7 @@ class TestPageSpecificContentSettingsDelegate
const std::string& media_stream_selected_video_device) override;
PageSpecificContentSettings::MicrophoneCameraState GetMicrophoneCameraState()
override;
void OnContentAllowed(ContentSettingsType type) override;
void OnContentBlocked(ContentSettingsType type) override;
void OnCacheStorageAccessAllowed(const url::Origin& origin) override;
void OnCookieAccessAllowed(const net::CookieList& accessed_cookies) override;

@ -444,6 +444,12 @@ PermissionUmaUtil::ScopedRevocationReporter::ScopedRevocationReporter(
ContentSetting initial_content_setting = settings_map->GetContentSetting(
primary_url_, secondary_url_, content_type_, std::string());
is_initially_allowed_ = initial_content_setting == CONTENT_SETTING_ALLOW;
content_settings::SettingInfo setting_info;
settings_map->GetWebsiteSetting(primary_url, secondary_url, content_type_,
std::string(), &setting_info);
last_modified_date_ = settings_map->GetSettingLastModifiedDate(
setting_info.primary_pattern, setting_info.secondary_pattern,
content_type);
}
PermissionUmaUtil::ScopedRevocationReporter::ScopedRevocationReporter(
@ -473,6 +479,13 @@ PermissionUmaUtil::ScopedRevocationReporter::~ScopedRevocationReporter() {
GURL requesting_origin = primary_url_.GetOrigin();
PermissionRevoked(content_type_, source_ui_, requesting_origin,
browser_context_);
if ((content_type_ == ContentSettingsType::GEOLOCATION ||
content_type_ == ContentSettingsType::MEDIASTREAM_CAMERA ||
content_type_ == ContentSettingsType::MEDIASTREAM_MIC) &&
!last_modified_date_.is_null()) {
RecordTimeElapsedBetweenGrantAndRevoke(
content_type_, base::Time::Now() - last_modified_date_);
}
}
}
@ -608,4 +621,22 @@ void PermissionUmaUtil::RecordPromptDecided(
}
}
void PermissionUmaUtil::RecordTimeElapsedBetweenGrantAndUse(
ContentSettingsType type,
base::TimeDelta delta) {
base::UmaHistogramCustomCounts(
"Permissions.Usage.ElapsedTimeSinceGrant." +
PermissionUtil::GetPermissionString(type),
delta.InSeconds(), 1, base::TimeDelta::FromDays(365).InSeconds(), 100);
}
void PermissionUmaUtil::RecordTimeElapsedBetweenGrantAndRevoke(
ContentSettingsType type,
base::TimeDelta delta) {
base::UmaHistogramCustomCounts(
"Permissions.Revocation.ElapsedTimeSinceGrant." +
PermissionUtil::GetPermissionString(type),
delta.InSeconds(), 1, base::TimeDelta::FromDays(365).InSeconds(), 100);
}
} // namespace permissions

@ -161,6 +161,12 @@ class PermissionUmaUtil {
PermissionAction action,
const std::vector<ContentSettingsType>& content_settings_types);
static void RecordTimeElapsedBetweenGrantAndUse(ContentSettingsType type,
base::TimeDelta delta);
static void RecordTimeElapsedBetweenGrantAndRevoke(ContentSettingsType type,
base::TimeDelta delta);
// A scoped class that will check the current resolved content setting on
// construction and report a revocation metric accordingly if the revocation
// condition is met (from ALLOW to something else).
@ -187,6 +193,7 @@ class PermissionUmaUtil {
ContentSettingsType content_type_;
PermissionSourceUI source_ui_;
bool is_initially_allowed_;
base::Time last_modified_date_;
};
private:

@ -130036,6 +130036,16 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
</summary>
</histogram>
<histogram base="true" name="Permissions.Revocation.ElapsedTimeSinceGrant"
units="seconds" expires_after="2021-08-20">
<owner>engedy@chromium.org</owner>
<owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
<summary>
Records the time elapsed since the grant of the permission until it's
revoked.
</summary>
</histogram>
<histogram name="Permissions.Serial.ChooserClosed" enum="SerialChooserOutcome"
expires_after="2021-06-21">
<owner>reillyg@chromium.org</owner>
@ -130053,6 +130063,17 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
<summary>Records when permission to access a serial port is revoked.</summary>
</histogram>
<histogram base="true" name="Permissions.Usage.ElapsedTimeSinceGrant"
units="seconds" expires_after="2021-08-20">
<owner>engedy@chromium.org</owner>
<owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
<summary>
Records the time elapsed since the grant of the permission until it's latest
usage. This histogram will be recorded only for the first usage of a given
permission after the site has loaded.
</summary>
</histogram>
<histogram base="true" name="PhoneHub.MultiDeviceFeatureState"
enum="MultiDevice_FeatureState" expires_after="2021-08-01">
<!-- Name completed by histogram_suffixes name="PhoneHubFeature" -->
@ -211568,6 +211589,8 @@ regressions. -->
<affected-histogram name="Permissions.Prompt.Ignored.PriorIgnoreCount"/>
<affected-histogram name="Permissions.Prompt.Ignored.PriorIgnoreCount2"/>
<affected-histogram name="Permissions.Requested.CrossOrigin"/>
<affected-histogram name="Permissions.Revocation.ElapsedTimeSinceGrant"/>
<affected-histogram name="Permissions.Usage.ElapsedTimeSinceGrant"/>
</histogram_suffixes>
<histogram_suffixes name="PhoneHubFeature" separator=".">

@ -94,6 +94,9 @@ PageSpecificContentSettingsDelegate::GetMicrophoneCameraState() {
MICROPHONE_CAMERA_NOT_ACCESSED;
}
void PageSpecificContentSettingsDelegate::OnContentAllowed(
ContentSettingsType type) {}
void PageSpecificContentSettingsDelegate::OnContentBlocked(
ContentSettingsType type) {}

@ -44,6 +44,7 @@ class PageSpecificContentSettingsDelegate
const std::string& media_stream_selected_video_device) override;
content_settings::PageSpecificContentSettings::MicrophoneCameraState
GetMicrophoneCameraState() override;
void OnContentAllowed(ContentSettingsType type) override;
void OnContentBlocked(ContentSettingsType type) override;
void OnCacheStorageAccessAllowed(const url::Origin& origin) override;
void OnCookieAccessAllowed(const net::CookieList& accessed_cookies) override;