summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordhnishi@chromium.org <dhnishi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-17 22:30:20 +0000
committerdhnishi@chromium.org <dhnishi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-17 22:30:20 +0000
commitbfcf45666488555a142ba159c1557b62f8b886a5 (patch)
tree0cd0d027090b56057091b4b6eff33d3eaa046cb5
parentf313245afd6b6568fc7456c8ee71d4dd187f8214 (diff)
downloadchromium_src-bfcf45666488555a142ba159c1557b62f8b886a5.zip
chromium_src-bfcf45666488555a142ba159c1557b62f8b886a5.tar.gz
chromium_src-bfcf45666488555a142ba159c1557b62f8b886a5.tar.bz2
Audit the last time the Geolocation and Notification content settings
have been used. This will be used as part of a resource/permission manager which will allow users to more easily see and modify which permissions are being granted to which websites. Design Doc: https://docs.google.com/document/d/1oQwmj3AU4QYhTyGrYEGr6zaZhHUfx-wqUgEcQGbUU-U/edit?usp=sharing BUG=372607 Review URL: https://codereview.chromium.org/356543003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@283909 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chrome_content_browser_client.cc14
-rw-r--r--chrome/browser/chrome_content_browser_client.h44
-rw-r--r--chrome/browser/content_settings/content_settings_pref_provider.cc97
-rw-r--r--chrome/browser/content_settings/content_settings_pref_provider.h16
-rw-r--r--chrome/browser/content_settings/content_settings_pref_provider_unittest.cc36
-rw-r--r--chrome/browser/content_settings/host_content_settings_map.cc77
-rw-r--r--chrome/browser/content_settings/host_content_settings_map.h43
-rw-r--r--chrome/browser/geolocation/geolocation_browsertest.cc47
-rw-r--r--chrome/browser/geolocation/geolocation_permission_context.cc9
-rw-r--r--chrome/browser/geolocation/geolocation_permission_context_unittest.cc138
-rw-r--r--chrome/browser/notifications/desktop_notification_service.cc11
-rw-r--r--chrome/browser/notifications/notification_browsertest.cc37
-rw-r--r--content/browser/geolocation/geolocation_dispatcher_host.cc9
-rw-r--r--content/public/browser/content_browser_client.h5
14 files changed, 548 insertions, 35 deletions
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index b0716a9..53a1881 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -119,6 +119,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/common/child_process_host.h"
#include "content/public/common/content_descriptors.h"
+#include "content/public/common/show_desktop_notification_params.h"
#include "content/public/common/url_utils.h"
#include "content/public/common/web_preferences.h"
#include "extensions/browser/extension_host.h"
@@ -2193,6 +2194,9 @@ void ChromeContentBrowserClient::ShowDesktopNotification(
DesktopNotificationServiceFactory::GetForProfile(profile);
service->ShowDesktopNotification(
params, render_frame_host, delegate, cancel_callback);
+
+ profile->GetHostContentSettingsMap()->UpdateLastUsage(
+ params.origin, params.origin, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
#else
NOTIMPLEMENTED();
#endif
@@ -2230,6 +2234,16 @@ void ChromeContentBrowserClient::RequestMidiSysExPermission(
user_gesture, result_callback);
}
+void ChromeContentBrowserClient::DidUseGeolocationPermission(
+ content::WebContents* web_contents,
+ const GURL& frame_url,
+ const GURL& main_frame_url) {
+ Profile::FromBrowserContext(web_contents->GetBrowserContext())
+ ->GetHostContentSettingsMap()
+ ->UpdateLastUsage(
+ frame_url, main_frame_url, CONTENT_SETTINGS_TYPE_GEOLOCATION);
+}
+
void ChromeContentBrowserClient::RequestProtectedMediaIdentifierPermission(
content::WebContents* web_contents,
const GURL& origin,
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 1b9b1e8..ae1828a 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -12,13 +12,10 @@
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
#include "chrome/common/chrome_version_info.h"
#include "content/public/browser/content_browser_client.h"
-#if defined(OS_ANDROID)
-#include "base/memory/scoped_ptr.h"
-#endif
-
namespace base {
class CommandLine;
}
@@ -213,6 +210,9 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
bool user_gesture,
base::Callback<void(bool)> result_callback,
base::Closure* cancel_callback) OVERRIDE;
+ virtual void DidUseGeolocationPermission(content::WebContents* web_contents,
+ const GURL& frame_url,
+ const GURL& main_frame_url) OVERRIDE;
virtual void RequestProtectedMediaIdentifierPermission(
content::WebContents* web_contents,
const GURL& origin,
@@ -295,6 +295,8 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
#endif
private:
+ friend class DisableWebRtcEncryptionFlagTest;
+
#if defined(ENABLE_WEBRTC)
// Copies disable WebRTC encryption switch depending on the channel.
static void MaybeCopyDisableWebRtcEncryptionSwitch(
@@ -304,24 +306,24 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
#endif
void FileSystemAccessed(
- const GURL& url,
- const std::vector<std::pair<int, int> >& render_frames,
- base::Callback<void(bool)> callback,
- bool allow);
+ const GURL& url,
+ const std::vector<std::pair<int, int> >& render_frames,
+ base::Callback<void(bool)> callback,
+ bool allow);
#if defined(ENABLE_EXTENSIONS)
-void GuestPermissionRequestHelper(
- const GURL& url,
- const std::vector<std::pair<int, int> >& render_frames,
- base::Callback<void(bool)> callback,
- bool allow);
+ void GuestPermissionRequestHelper(
+ const GURL& url,
+ const std::vector<std::pair<int, int> >& render_frames,
+ base::Callback<void(bool)> callback,
+ bool allow);
-static void RequestFileSystemPermissionOnUIThread(
- int render_process_id,
- int render_frame_id,
- const GURL& url,
- bool allowed_by_default,
- const base::Callback<void(bool)>& callback);
+ static void RequestFileSystemPermissionOnUIThread(
+ int render_process_id,
+ int render_frame_id,
+ const GURL& url,
+ bool allowed_by_default,
+ const base::Callback<void(bool)>& callback);
#endif
#if defined(ENABLE_PLUGINS)
@@ -344,9 +346,7 @@ static void RequestFileSystemPermissionOnUIThread(
// created. It is used only the IO thread.
prerender::PrerenderTracker* prerender_tracker_;
- base::WeakPtrFactory<ChromeContentBrowserClient> weak_factory_;
-
- friend class DisableWebRtcEncryptionFlagTest;
+ base::WeakPtrFactory<ChromeContentBrowserClient> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ChromeContentBrowserClient);
};
diff --git a/chrome/browser/content_settings/content_settings_pref_provider.cc b/chrome/browser/content_settings/content_settings_pref_provider.cc
index 0eaf685..fd5cf24 100644
--- a/chrome/browser/content_settings/content_settings_pref_provider.cc
+++ b/chrome/browser/content_settings/content_settings_pref_provider.cc
@@ -14,6 +14,8 @@
#include "base/metrics/histogram.h"
#include "base/prefs/pref_service.h"
#include "base/prefs/scoped_user_pref_update.h"
+#include "base/time/clock.h"
+#include "base/time/default_clock.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/content_settings/content_settings_rule.h"
#include "chrome/browser/content_settings/content_settings_utils.h"
@@ -40,6 +42,7 @@ typedef std::map<std::string, std::string> StringMap;
const char kPerPluginPrefName[] = "per_plugin";
const char kAudioKey[] = "audio";
const char kVideoKey[] = "video";
+const char kLastUsed[] = "last_used";
ContentSetting FixObsoleteCookiePromptMode(ContentSettingsType content_type,
ContentSetting setting) {
@@ -83,11 +86,11 @@ void PrefProvider::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
}
-PrefProvider::PrefProvider(PrefService* prefs,
- bool incognito)
- : prefs_(prefs),
- is_incognito_(incognito),
- updating_preferences_(false) {
+PrefProvider::PrefProvider(PrefService* prefs, bool incognito)
+ : prefs_(prefs),
+ clock_(new base::DefaultClock()),
+ is_incognito_(incognito),
+ updating_preferences_(false) {
DCHECK(prefs_);
// Verify preferences version.
if (!prefs_->HasPrefPath(prefs::kContentSettingsVersion)) {
@@ -290,6 +293,7 @@ void PrefProvider::UpdatePref(
if (value == NULL) {
settings_dictionary->RemoveWithoutPathExpansion(setting_path,
NULL);
+ settings_dictionary->RemoveWithoutPathExpansion(kLastUsed, NULL);
} else {
settings_dictionary->SetWithoutPathExpansion(
setting_path, value->DeepCopy());
@@ -566,6 +570,85 @@ void PrefProvider::ShutdownOnUIThread() {
prefs_ = NULL;
}
+void PrefProvider::UpdateLastUsage(
+ const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type) {
+ // Don't write if in incognito.
+ if (is_incognito_) {
+ return;
+ }
+
+ // Ensure that |lock_| is not held by this thread, since this function will
+ // send out notifications (by |~DictionaryPrefUpdate|).
+ AssertLockNotHeld();
+
+ base::AutoReset<bool> auto_reset(&updating_preferences_, true);
+ {
+ DictionaryPrefUpdate update(prefs_, prefs::kContentSettingsPatternPairs);
+ base::DictionaryValue* pattern_pairs_settings = update.Get();
+
+ std::string pattern_str(
+ CreatePatternString(primary_pattern, secondary_pattern));
+ base::DictionaryValue* settings_dictionary = NULL;
+ bool found = pattern_pairs_settings->GetDictionaryWithoutPathExpansion(
+ pattern_str, &settings_dictionary);
+
+ if (!found) {
+ settings_dictionary = new base::DictionaryValue;
+ pattern_pairs_settings->SetWithoutPathExpansion(pattern_str,
+ settings_dictionary);
+ }
+
+ base::DictionaryValue* last_used_dictionary = NULL;
+ found = settings_dictionary->GetDictionaryWithoutPathExpansion(
+ kLastUsed, &last_used_dictionary);
+
+ if (!found) {
+ last_used_dictionary = new base::DictionaryValue;
+ settings_dictionary->SetWithoutPathExpansion(kLastUsed,
+ last_used_dictionary);
+ }
+
+ std::string settings_path = GetTypeName(content_type);
+ last_used_dictionary->Set(
+ settings_path, new base::FundamentalValue(clock_->Now().ToDoubleT()));
+ }
+}
+
+base::Time PrefProvider::GetLastUsage(
+ const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type) {
+ const base::DictionaryValue* pattern_pairs_settings =
+ prefs_->GetDictionary(prefs::kContentSettingsPatternPairs);
+ std::string pattern_str(
+ CreatePatternString(primary_pattern, secondary_pattern));
+
+ const base::DictionaryValue* settings_dictionary = NULL;
+ bool found = pattern_pairs_settings->GetDictionaryWithoutPathExpansion(
+ pattern_str, &settings_dictionary);
+
+ if (!found)
+ return base::Time();
+
+ const base::DictionaryValue* last_used_dictionary = NULL;
+ found = settings_dictionary->GetDictionaryWithoutPathExpansion(
+ kLastUsed, &last_used_dictionary);
+
+ if (!found)
+ return base::Time();
+
+ double last_used_time;
+ found = last_used_dictionary->GetDoubleWithoutPathExpansion(
+ GetTypeName(content_type), &last_used_time);
+
+ if (!found)
+ return base::Time();
+
+ return base::Time::FromDoubleT(last_used_time);
+}
+
void PrefProvider::AssertLockNotHeld() const {
#if !defined(NDEBUG)
// |Lock::Acquire()| will assert if the lock is held by this thread.
@@ -574,4 +657,8 @@ void PrefProvider::AssertLockNotHeld() const {
#endif
}
+void PrefProvider::SetClockForTesting(scoped_ptr<base::Clock> clock) {
+ clock_ = clock.Pass();
+}
+
} // namespace content_settings
diff --git a/chrome/browser/content_settings/content_settings_pref_provider.h b/chrome/browser/content_settings/content_settings_pref_provider.h
index 9d8a2bc..08a9d1b 100644
--- a/chrome/browser/content_settings/content_settings_pref_provider.h
+++ b/chrome/browser/content_settings/content_settings_pref_provider.h
@@ -19,6 +19,7 @@
class PrefService;
namespace base {
+class Clock;
class DictionaryValue;
}
@@ -55,6 +56,18 @@ class PrefProvider : public ObservableProvider {
virtual void ShutdownOnUIThread() OVERRIDE;
+ // Records the last time the given pattern has used a certain content setting.
+ void UpdateLastUsage(const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type);
+
+ base::Time GetLastUsage(const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type);
+
+ // Gains ownership of |clock|.
+ void SetClockForTesting(scoped_ptr<base::Clock> clock);
+
private:
friend class DeadlockCheckerThread; // For testing.
// Reads all content settings exceptions from the preference and load them
@@ -90,6 +103,9 @@ class PrefProvider : public ObservableProvider {
// Weak; owned by the Profile and reset in ShutdownOnUIThread.
PrefService* prefs_;
+ // Can be set for testing.
+ scoped_ptr<base::Clock> clock_;
+
bool is_incognito_;
PrefChangeRegistrar pref_change_registrar_;
diff --git a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
index 395693a..a090372 100644
--- a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
@@ -14,6 +14,7 @@
#include "base/prefs/pref_service.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "base/prefs/testing_pref_store.h"
+#include "base/test/simple_test_clock.h"
#include "base/threading/platform_thread.h"
#include "base/values.h"
#include "chrome/browser/content_settings/content_settings_mock_observer.h"
@@ -444,4 +445,39 @@ TEST_F(PrefProviderTest, Deadlock) {
provider.ShutdownOnUIThread();
}
+TEST_F(PrefProviderTest, LastUsage) {
+ TestingProfile testing_profile;
+ PrefProvider pref_content_settings_provider(testing_profile.GetPrefs(),
+ false);
+ base::SimpleTestClock* test_clock = new base::SimpleTestClock;
+ test_clock->SetNow(base::Time::Now());
+
+ pref_content_settings_provider.SetClockForTesting(
+ scoped_ptr<base::Clock>(test_clock));
+ GURL host("http://example.com/");
+ ContentSettingsPattern pattern =
+ ContentSettingsPattern::FromString("[*.]example.com");
+
+ base::Time no_usage = pref_content_settings_provider.GetLastUsage(
+ pattern, pattern, CONTENT_SETTINGS_TYPE_GEOLOCATION);
+ EXPECT_EQ(no_usage.ToDoubleT(), 0);
+
+ pref_content_settings_provider.UpdateLastUsage(
+ pattern, pattern, CONTENT_SETTINGS_TYPE_GEOLOCATION);
+ base::Time first = pref_content_settings_provider.GetLastUsage(
+ pattern, pattern, CONTENT_SETTINGS_TYPE_GEOLOCATION);
+
+ test_clock->Advance(base::TimeDelta::FromSeconds(10));
+
+ pref_content_settings_provider.UpdateLastUsage(
+ pattern, pattern, CONTENT_SETTINGS_TYPE_GEOLOCATION);
+ base::Time second = pref_content_settings_provider.GetLastUsage(
+ pattern, pattern, CONTENT_SETTINGS_TYPE_GEOLOCATION);
+
+ base::TimeDelta delta = second - first;
+ EXPECT_EQ(delta.InSeconds(), 10);
+
+ pref_content_settings_provider.ShutdownOnUIThread();
+}
+
} // namespace content_settings
diff --git a/chrome/browser/content_settings/host_content_settings_map.cc b/chrome/browser/content_settings/host_content_settings_map.cc
index 3dc620a..27427aef 100644
--- a/chrome/browser/content_settings/host_content_settings_map.cc
+++ b/chrome/browser/content_settings/host_content_settings_map.cc
@@ -12,6 +12,7 @@
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/time/clock.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/content_settings/content_settings_custom_extension_provider.h"
#include "chrome/browser/content_settings/content_settings_default_provider.h"
@@ -299,6 +300,13 @@ void HostContentSettingsMap::SetContentSetting(
const std::string& resource_identifier,
ContentSetting setting) {
DCHECK(!ContentTypeHasCompoundValue(content_type));
+
+ if (setting == CONTENT_SETTING_ALLOW &&
+ (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION ||
+ content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS)) {
+ UpdateLastUsageByPattern(primary_pattern, secondary_pattern, content_type);
+ }
+
base::Value* value = NULL;
if (setting != CONTENT_SETTING_DEFAULT)
value = base::Value::CreateIntegerValue(setting);
@@ -309,6 +317,70 @@ void HostContentSettingsMap::SetContentSetting(
value);
}
+ContentSetting HostContentSettingsMap::GetContentSettingAndMaybeUpdateLastUsage(
+ const GURL& primary_url,
+ const GURL& secondary_url,
+ ContentSettingsType content_type,
+ const std::string& resource_identifier) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ ContentSetting setting = GetContentSetting(
+ primary_url, secondary_url, content_type, resource_identifier);
+ if (setting == CONTENT_SETTING_ALLOW) {
+ UpdateLastUsageByPattern(
+ ContentSettingsPattern::FromURLNoWildcard(primary_url),
+ ContentSettingsPattern::FromURLNoWildcard(secondary_url),
+ content_type);
+ }
+ return setting;
+}
+
+void HostContentSettingsMap::UpdateLastUsage(const GURL& primary_url,
+ const GURL& secondary_url,
+ ContentSettingsType content_type) {
+ UpdateLastUsageByPattern(
+ ContentSettingsPattern::FromURLNoWildcard(primary_url),
+ ContentSettingsPattern::FromURLNoWildcard(secondary_url),
+ content_type);
+}
+
+void HostContentSettingsMap::UpdateLastUsageByPattern(
+ const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type) {
+ UsedContentSettingsProviders();
+
+ GetPrefProvider()->UpdateLastUsage(
+ primary_pattern, secondary_pattern, content_type);
+}
+
+base::Time HostContentSettingsMap::GetLastUsage(
+ const GURL& primary_url,
+ const GURL& secondary_url,
+ ContentSettingsType content_type) {
+ return GetLastUsageByPattern(
+ ContentSettingsPattern::FromURLNoWildcard(primary_url),
+ ContentSettingsPattern::FromURLNoWildcard(secondary_url),
+ content_type);
+}
+
+base::Time HostContentSettingsMap::GetLastUsageByPattern(
+ const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type) {
+ UsedContentSettingsProviders();
+
+ return GetPrefProvider()->GetLastUsage(
+ primary_pattern, secondary_pattern, content_type);
+}
+
+void HostContentSettingsMap::SetPrefClockForTesting(
+ scoped_ptr<base::Clock> clock) {
+ UsedContentSettingsProviders();
+
+ GetPrefProvider()->SetClockForTesting(clock.Pass());
+}
+
void HostContentSettingsMap::AddExceptionForURL(
const GURL& primary_url,
const GURL& secondary_url,
@@ -639,3 +711,8 @@ HostContentSettingsMap::ProviderType
NOTREACHED();
return DEFAULT_PROVIDER;
}
+
+content_settings::PrefProvider* HostContentSettingsMap::GetPrefProvider() {
+ return static_cast<content_settings::PrefProvider*>(
+ content_settings_providers_[PREF_PROVIDER]);
+}
diff --git a/chrome/browser/content_settings/host_content_settings_map.h b/chrome/browser/content_settings/host_content_settings_map.h
index 8d5681a..915c4a7 100644
--- a/chrome/browser/content_settings/host_content_settings_map.h
+++ b/chrome/browser/content_settings/host_content_settings_map.h
@@ -27,11 +27,13 @@ class GURL;
class PrefService;
namespace base {
+class Clock;
class Value;
}
namespace content_settings {
class ProviderInterface;
+class PrefProvider;
}
namespace user_prefs {
@@ -199,6 +201,39 @@ class HostContentSettingsMap
return is_off_the_record_;
}
+ // Returns a single |ContentSetting| which applies to the given URLs, just as
+ // |GetContentSetting| does. If the setting is allowed, it also records the
+ // last usage to preferences.
+ //
+ // This should only be called on the UI thread, unlike |GetContentSetting|.
+ ContentSetting GetContentSettingAndMaybeUpdateLastUsage(
+ const GURL& primary_url,
+ const GURL& secondary_url,
+ ContentSettingsType content_type,
+ const std::string& resource_identifier);
+
+ // Sets the last time that a given content type has been used for the pattern
+ // which matches the URLs to the current time.
+ void UpdateLastUsage(const GURL& primary_url,
+ const GURL& secondary_url,
+ ContentSettingsType content_type);
+
+ // Returns the last time the pattern that matches the URL has requested
+ // permission for the |content_type| setting.
+ base::Time GetLastUsage(const GURL& primary_url,
+ const GURL& secondary_url,
+ ContentSettingsType content_type);
+
+ // Returns the last time the pattern has requested permission for the
+ // |content_type| setting.
+ base::Time GetLastUsageByPattern(
+ const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type);
+
+ // Passes ownership of |clock|.
+ void SetPrefClockForTesting(scoped_ptr<base::Clock> clock);
+
private:
friend class base::RefCountedThreadSafe<HostContentSettingsMap>;
friend class HostContentSettingsMapTest_NonDefaultSettings_Test;
@@ -236,6 +271,14 @@ class HostContentSettingsMap
// it is not being called too late.
void UsedContentSettingsProviders() const;
+ // Convenience method for updating the last usage of a content type for a
+ // pattern.
+ void UpdateLastUsageByPattern(const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type);
+
+ content_settings::PrefProvider* GetPrefProvider();
+
#ifndef NDEBUG
// This starts as the thread ID of the thread that constructs this
// object, and remains until used by a different thread, at which
diff --git a/chrome/browser/geolocation/geolocation_browsertest.cc b/chrome/browser/geolocation/geolocation_browsertest.cc
index 196f908..3c3b738 100644
--- a/chrome/browser/geolocation/geolocation_browsertest.cc
+++ b/chrome/browser/geolocation/geolocation_browsertest.cc
@@ -8,6 +8,8 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/simple_test_clock.h"
+#include "base/time/clock.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/content_settings/content_settings_usages_state.h"
#include "chrome/browser/content_settings/host_content_settings_map.h"
@@ -769,3 +771,48 @@ IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, TabDestroyed) {
current_browser()->tab_strip_model()->GetActiveWebContents(), script);
EXPECT_EQ(result, true);
}
+
+IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, LastUsageUpdated) {
+ ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
+ base::SimpleTestClock* clock_ = new base::SimpleTestClock();
+ current_browser()
+ ->profile()
+ ->GetHostContentSettingsMap()
+ ->SetPrefClockForTesting(scoped_ptr<base::Clock>(clock_));
+ clock_->SetNow(base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(10));
+
+ // Setting the permission should trigger the last usage.
+ current_browser()->profile()->GetHostContentSettingsMap()->SetContentSetting(
+ ContentSettingsPattern::FromURLNoWildcard(current_url()),
+ ContentSettingsPattern::FromURLNoWildcard(current_url()),
+ CONTENT_SETTINGS_TYPE_GEOLOCATION,
+ std::string(),
+ CONTENT_SETTING_ALLOW);
+
+ // Permission has been used at the starting time.
+ EXPECT_EQ(current_browser()
+ ->profile()
+ ->GetHostContentSettingsMap()
+ ->GetLastUsage(current_url().GetOrigin(),
+ current_url().GetOrigin(),
+ CONTENT_SETTINGS_TYPE_GEOLOCATION)
+ .ToDoubleT(),
+ 10);
+
+ clock_->Advance(base::TimeDelta::FromSeconds(3));
+
+ // Watching should trigger the last usage update.
+ SetFrameHost("");
+ AddGeolocationWatch(false);
+ CheckGeoposition(fake_latitude(), fake_longitude());
+
+ // Last usage has been updated.
+ EXPECT_EQ(current_browser()
+ ->profile()
+ ->GetHostContentSettingsMap()
+ ->GetLastUsage(current_url().GetOrigin(),
+ current_url().GetOrigin(),
+ CONTENT_SETTINGS_TYPE_GEOLOCATION)
+ .ToDoubleT(),
+ 13);
+}
diff --git a/chrome/browser/geolocation/geolocation_permission_context.cc b/chrome/browser/geolocation/geolocation_permission_context.cc
index 37c53e8..1e634bd 100644
--- a/chrome/browser/geolocation/geolocation_permission_context.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context.cc
@@ -209,9 +209,12 @@ void GeolocationPermissionContext::DecidePermission(
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
ContentSetting content_setting =
- profile_->GetHostContentSettingsMap()->GetContentSetting(
- requesting_frame, embedder, CONTENT_SETTINGS_TYPE_GEOLOCATION,
- std::string());
+ profile_->GetHostContentSettingsMap()
+ ->GetContentSettingAndMaybeUpdateLastUsage(
+ requesting_frame,
+ embedder,
+ CONTENT_SETTINGS_TYPE_GEOLOCATION,
+ std::string());
switch (content_setting) {
case CONTENT_SETTING_BLOCK:
PermissionDecided(id, requesting_frame, embedder, callback, false);
diff --git a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
index f011ac3..b243ce6 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
@@ -13,6 +13,8 @@
#include "base/memory/scoped_vector.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
+#include "base/test/simple_test_clock.h"
+#include "base/time/clock.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/content_settings/permission_request_id.h"
@@ -696,3 +698,139 @@ TEST_F(GeolocationPermissionContextTests, InfoBarUsesCommittedEntry) {
// Delete the tab contents.
DeleteContents();
}
+
+TEST_F(GeolocationPermissionContextTests, LastUsageAudited) {
+ GURL requesting_frame("http://www.example.com/geolocation");
+ NavigateAndCommit(requesting_frame);
+
+ base::SimpleTestClock* test_clock = new base::SimpleTestClock;
+ test_clock->SetNow(base::Time::UnixEpoch() +
+ base::TimeDelta::FromSeconds(10));
+
+ HostContentSettingsMap* map = profile()->GetHostContentSettingsMap();
+ map->SetPrefClockForTesting(scoped_ptr<base::Clock>(test_clock));
+
+ // The permission shouldn't have been used yet.
+ EXPECT_EQ(map->GetLastUsage(requesting_frame.GetOrigin(),
+ requesting_frame.GetOrigin(),
+ CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
+ 0);
+
+ EXPECT_EQ(0U, infobar_service()->infobar_count());
+ RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame);
+ ASSERT_EQ(1U, infobar_service()->infobar_count());
+ infobars::InfoBar* infobar = infobar_service()->infobar_at(0);
+ ConfirmInfoBarDelegate* infobar_delegate =
+ infobar->delegate()->AsConfirmInfoBarDelegate();
+ ASSERT_TRUE(infobar_delegate);
+ infobar_delegate->Accept();
+ CheckTabContentsState(requesting_frame, CONTENT_SETTING_ALLOW);
+ CheckPermissionMessageSent(0, true);
+
+ // Permission has been used at the starting time.
+ EXPECT_EQ(map->GetLastUsage(requesting_frame.GetOrigin(),
+ requesting_frame.GetOrigin(),
+ CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
+ 10);
+
+ test_clock->Advance(base::TimeDelta::FromSeconds(3));
+ RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame);
+
+ // Permission has been used three seconds later.
+ EXPECT_EQ(map->GetLastUsage(requesting_frame.GetOrigin(),
+ requesting_frame.GetOrigin(),
+ CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
+ 13);
+}
+
+TEST_F(GeolocationPermissionContextTests, LastUsageAuditedMultipleFrames) {
+ base::SimpleTestClock* test_clock = new base::SimpleTestClock;
+ test_clock->SetNow(base::Time::UnixEpoch() +
+ base::TimeDelta::FromSeconds(10));
+
+ HostContentSettingsMap* map = profile()->GetHostContentSettingsMap();
+ map->SetPrefClockForTesting(scoped_ptr<base::Clock>(test_clock));
+
+ GURL requesting_frame_0("http://www.example.com/geolocation");
+ GURL requesting_frame_1("http://www.example-2.com/geolocation");
+
+ // The permission shouldn't have been used yet.
+ EXPECT_EQ(map->GetLastUsage(requesting_frame_0.GetOrigin(),
+ requesting_frame_0.GetOrigin(),
+ CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
+ 0);
+ EXPECT_EQ(map->GetLastUsage(requesting_frame_1.GetOrigin(),
+ requesting_frame_0.GetOrigin(),
+ CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
+ 0);
+
+ NavigateAndCommit(requesting_frame_0);
+ EXPECT_EQ(0U, infobar_service()->infobar_count());
+
+ // Request permission for two frames.
+ RequestGeolocationPermission(
+ web_contents(), RequestID(0), requesting_frame_0);
+ RequestGeolocationPermission(
+ web_contents(), RequestID(1), requesting_frame_1);
+
+ // Ensure only one infobar is created.
+ ASSERT_EQ(1U, infobar_service()->infobar_count());
+ infobars::InfoBar* infobar_0 = infobar_service()->infobar_at(0);
+ ConfirmInfoBarDelegate* infobar_delegate_0 =
+ infobar_0->delegate()->AsConfirmInfoBarDelegate();
+
+ // Accept the first frame.
+ infobar_delegate_0->Accept();
+ CheckTabContentsState(requesting_frame_0, CONTENT_SETTING_ALLOW);
+ CheckPermissionMessageSent(0, true);
+ infobar_service()->RemoveInfoBar(infobar_0);
+
+ // Verify that accepting the first didn't accept because it's embedder
+ // in the other.
+ EXPECT_EQ(map->GetLastUsage(requesting_frame_0.GetOrigin(),
+ requesting_frame_0.GetOrigin(),
+ CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
+ 10);
+ EXPECT_EQ(map->GetLastUsage(requesting_frame_1.GetOrigin(),
+ requesting_frame_0.GetOrigin(),
+ CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
+ 0);
+
+ ASSERT_EQ(1U, infobar_service()->infobar_count());
+ infobars::InfoBar* infobar_1 = infobar_service()->infobar_at(0);
+ ConfirmInfoBarDelegate* infobar_delegate_1 =
+ infobar_1->delegate()->AsConfirmInfoBarDelegate();
+
+ test_clock->Advance(base::TimeDelta::FromSeconds(1));
+
+ // Allow the second frame.
+ infobar_delegate_1->Accept();
+ CheckTabContentsState(requesting_frame_1, CONTENT_SETTING_ALLOW);
+ CheckPermissionMessageSent(1, true);
+ infobar_service()->RemoveInfoBar(infobar_1);
+
+ // Verify that the times are different.
+ EXPECT_EQ(map->GetLastUsage(requesting_frame_0.GetOrigin(),
+ requesting_frame_0.GetOrigin(),
+ CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
+ 10);
+ EXPECT_EQ(map->GetLastUsage(requesting_frame_1.GetOrigin(),
+ requesting_frame_0.GetOrigin(),
+ CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
+ 11);
+
+ test_clock->Advance(base::TimeDelta::FromSeconds(2));
+ RequestGeolocationPermission(
+ web_contents(), RequestID(0), requesting_frame_0);
+
+ // Verify that requesting permission in one frame doesn't update other where
+ // it is the embedder.
+ EXPECT_EQ(map->GetLastUsage(requesting_frame_0.GetOrigin(),
+ requesting_frame_0.GetOrigin(),
+ CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
+ 13);
+ EXPECT_EQ(map->GetLastUsage(requesting_frame_1.GetOrigin(),
+ requesting_frame_0.GetOrigin(),
+ CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
+ 11);
+}
diff --git a/chrome/browser/notifications/desktop_notification_service.cc b/chrome/browser/notifications/desktop_notification_service.cc
index 2d605f8..e0c1bb7 100644
--- a/chrome/browser/notifications/desktop_notification_service.cc
+++ b/chrome/browser/notifications/desktop_notification_service.cc
@@ -481,11 +481,12 @@ void DesktopNotificationService::ResetAllOrigins() {
ContentSetting DesktopNotificationService::GetContentSetting(
const GURL& origin) {
- return profile_->GetHostContentSettingsMap()->GetContentSetting(
- origin,
- origin,
- CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
- NO_RESOURCE_IDENTIFIER);
+ return profile_->GetHostContentSettingsMap()
+ ->GetContentSettingAndMaybeUpdateLastUsage(
+ origin,
+ origin,
+ CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+ NO_RESOURCE_IDENTIFIER);
}
void DesktopNotificationService::RequestPermission(
diff --git a/chrome/browser/notifications/notification_browsertest.cc b/chrome/browser/notifications/notification_browsertest.cc
index af06140..cacc5e8 100644
--- a/chrome/browser/notifications/notification_browsertest.cc
+++ b/chrome/browser/notifications/notification_browsertest.cc
@@ -13,8 +13,11 @@
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/simple_test_clock.h"
+#include "base/time/clock.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/notifications/desktop_notification_service_factory.h"
@@ -778,3 +781,37 @@ IN_PROC_BROWSER_TEST_F(NotificationsTest, MAYBE_TestNotificationReplacement) {
EXPECT_EQ(base::ASCIIToUTF16("Body2"),
(*notifications.rbegin())->message());
}
+
+IN_PROC_BROWSER_TEST_F(NotificationsTest, TestLastUsage) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ HostContentSettingsMap* settings_map =
+ browser()->profile()->GetHostContentSettingsMap();
+ base::SimpleTestClock* clock = new base::SimpleTestClock();
+ settings_map->SetPrefClockForTesting(scoped_ptr<base::Clock>(clock));
+ clock->SetNow(base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(10));
+
+ // Creates a simple notification.
+ AllowAllOrigins();
+ ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
+
+ std::string result = CreateSimpleNotification(browser(), true);
+ EXPECT_NE("-1", result);
+
+ EXPECT_EQ(settings_map->GetLastUsage(GetTestPageURL().GetOrigin(),
+ GetTestPageURL().GetOrigin(),
+ CONTENT_SETTINGS_TYPE_NOTIFICATIONS)
+ .ToDoubleT(),
+ 10);
+
+ clock->Advance(base::TimeDelta::FromSeconds(3));
+
+ result = CreateSimpleNotification(browser(), true);
+ EXPECT_NE("-1", result);
+
+ EXPECT_EQ(settings_map->GetLastUsage(GetTestPageURL().GetOrigin(),
+ GetTestPageURL().GetOrigin(),
+ CONTENT_SETTINGS_TYPE_NOTIFICATIONS)
+ .ToDoubleT(),
+ 13);
+}
diff --git a/content/browser/geolocation/geolocation_dispatcher_host.cc b/content/browser/geolocation/geolocation_dispatcher_host.cc
index ad1f2fc..75abab5 100644
--- a/content/browser/geolocation/geolocation_dispatcher_host.cc
+++ b/content/browser/geolocation/geolocation_dispatcher_host.cc
@@ -130,6 +130,15 @@ void GeolocationDispatcherHost::OnLocationUpdate(
for (std::map<RenderFrameHost*, bool>::iterator i = updating_frames_.begin();
i != updating_frames_.end(); ++i) {
+ RenderFrameHost* top_frame = i->first;
+ while (top_frame->GetParent()) {
+ top_frame = top_frame->GetParent();
+ }
+ GetContentClient()->browser()->DidUseGeolocationPermission(
+ web_contents(),
+ i->first->GetLastCommittedURL().GetOrigin(),
+ top_frame->GetLastCommittedURL().GetOrigin());
+
i->first->Send(new GeolocationMsg_PositionUpdated(
i->first->GetRoutingID(), geoposition));
}
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 356c724..68fa0d6 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -453,6 +453,11 @@ class CONTENT_EXPORT ContentBrowserClient {
base::Callback<void(bool)> result_callback,
base::Closure* cancel_callback);
+ // Invoked when the Geolocation API uses its permission.
+ virtual void DidUseGeolocationPermission(WebContents* web_contents,
+ const GURL& frame_url,
+ const GURL& main_frame_url) {}
+
// Requests a permission to use system exclusive messages in MIDI events.
// |result_callback| will be invoked when the request is resolved. If
// |cancel_callback| is non-null, it's set to a callback which can be used to