diff options
author | kbr@chromium.org <kbr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-20 13:14:11 +0000 |
---|---|---|
committer | kbr@chromium.org <kbr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-20 13:14:11 +0000 |
commit | 818915cd6f37ba0ee4e01ef37f293d5a0cce6975 (patch) | |
tree | 81d9df68c4de82b8cff3ad5f25992743039f8e9b /content/browser/gpu/gpu_data_manager_impl.cc | |
parent | 41766860ac99fc3a894728084df2f8e31054274c (diff) | |
download | chromium_src-818915cd6f37ba0ee4e01ef37f293d5a0cce6975.zip chromium_src-818915cd6f37ba0ee4e01ef37f293d5a0cce6975.tar.gz chromium_src-818915cd6f37ba0ee4e01ef37f293d5a0cce6975.tar.bz2 |
Raise an infobar and deny access to WebGL if a GPU reset was detected while a web page containing WebGL content was visible.
The same mechanism will work for Pepper 3D but has not been hooked up for that API yet.
https://bugs.webkit.org/show_bug.cgi?id=101826 added the hooks out through the Chromium WebKit API.
BUG=125125
TEST=GPUCrashTest.ContextLossRaisesInfobar
Review URL: https://chromiumcodereview.appspot.com/11378008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@168794 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/gpu/gpu_data_manager_impl.cc')
-rw-r--r-- | content/browser/gpu/gpu_data_manager_impl.cc | 124 |
1 files changed, 123 insertions, 1 deletions
diff --git a/content/browser/gpu/gpu_data_manager_impl.cc b/content/browser/gpu/gpu_data_manager_impl.cc index 7292c5b..e175df5 100644 --- a/content/browser/gpu/gpu_data_manager_impl.cc +++ b/content/browser/gpu/gpu_data_manager_impl.cc @@ -69,6 +69,11 @@ void DisplayReconfigCallback(CGDirectDisplayID display, } #endif // OS_MACOSX +// Block all domains' use of 3D APIs for this many milliseconds if +// approaching a threshold where system stability might be compromised. +const int64 kBlockAllDomainsMs = 10000; +const int kNumResetsWithinDuration = 1; + } // namespace anonymous // static @@ -90,7 +95,8 @@ GpuDataManagerImpl::GpuDataManagerImpl() software_rendering_(false), card_blacklisted_(false), update_histograms_(true), - window_count_(0) { + window_count_(0), + domain_blocking_enabled_(true) { CommandLine* command_line = CommandLine::ForCurrentProcess(); if (command_line->HasSwitch(switches::kDisableAcceleratedCompositing)) { command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas); @@ -342,6 +348,30 @@ uint32 GpuDataManagerImpl::GetWindowCount() const { return window_count_; } +void GpuDataManagerImpl::UnblockDomainFrom3DAPIs(const GURL& url) { + // This method must do two things: + // + // 1. If the specific domain is blocked, then unblock it. + // + // 2. Reset our notion of how many GPU resets have occurred recently. + // This is necessary even if the specific domain was blocked. + // Otherwise, if we call Are3DAPIsBlocked with the same domain right + // after unblocking it, it will probably still be blocked because of + // the recent GPU reset caused by that domain. + // + // These policies could be refined, but at a certain point the behavior + // will become difficult to explain. + std::string domain = GetDomainFromURL(url); + + base::AutoLock auto_lock(gpu_info_lock_); + blocked_domains_.erase(domain); + timestamps_of_gpu_resets_.clear(); +} + +void GpuDataManagerImpl::DisableDomainBlockingFor3DAPIsForTesting() { + domain_blocking_enabled_ = false; +} + void GpuDataManagerImpl::AppendRendererCommandLine( CommandLine* command_line) const { DCHECK(command_line); @@ -471,6 +501,16 @@ bool GpuDataManagerImpl::IsUsingAcceleratedSurface() const { } #endif +void GpuDataManagerImpl::BlockDomainFrom3DAPIs( + const GURL& url, DomainGuilt guilt) { + BlockDomainFrom3DAPIsAtTime(url, guilt, base::Time::Now()); +} + +GpuDataManagerImpl::DomainBlockStatus +GpuDataManagerImpl::Are3DAPIsBlocked(const GURL& url) const { + return Are3DAPIsBlockedAtTime(url, base::Time::Now()); +} + void GpuDataManagerImpl::AppendPluginCommandLine( CommandLine* command_line) const { DCHECK(command_line); @@ -572,4 +612,86 @@ void GpuDataManagerImpl::BlacklistCard() { NotifyGpuInfoUpdate(); } +std::string GpuDataManagerImpl::GetDomainFromURL(const GURL& url) const { + // For the moment, we just use the host, or its IP address, as the + // entry in the set, rather than trying to figure out the top-level + // domain. This does mean that a.foo.com and b.foo.com will be + // treated independently in the blocking of a given domain, but it + // would require a third-party library to reliably figure out the + // top-level domain from a URL. + if (!url.has_host()) { + return std::string(); + } + + return url.host(); +} + +void GpuDataManagerImpl::BlockDomainFrom3DAPIsAtTime( + const GURL& url, DomainGuilt guilt, base::Time at_time) { + if (!domain_blocking_enabled_) + return; + + std::string domain = GetDomainFromURL(url); + + base::AutoLock auto_lock(gpu_info_lock_); + DomainBlockEntry& entry = blocked_domains_[domain]; + entry.last_guilt = guilt; + timestamps_of_gpu_resets_.push_back(at_time); +} + +GpuDataManagerImpl::DomainBlockStatus +GpuDataManagerImpl::Are3DAPIsBlockedAtTime( + const GURL& url, base::Time at_time) const { + if (!domain_blocking_enabled_) + return DOMAIN_BLOCK_STATUS_NOT_BLOCKED; + + // Note: adjusting the policies in this code will almost certainly + // require adjusting the associated unit tests. + std::string domain = GetDomainFromURL(url); + + base::AutoLock auto_lock(gpu_info_lock_); + { + DomainBlockMap::const_iterator iter = blocked_domains_.find(domain); + if (iter != blocked_domains_.end()) { + // Err on the side of caution, and assume that if a particular + // domain shows up in the block map, it's there for a good + // reason and don't let its presence there automatically expire. + return DOMAIN_BLOCK_STATUS_BLOCKED; + } + } + + // Look at the timestamps of the recent GPU resets to see if there are + // enough within the threshold which would cause us to blacklist all + // domains. This doesn't need to be overly precise -- if time goes + // backward due to a system clock adjustment, that's fine. + // + // TODO(kbr): make this pay attention to the TDR thresholds in the + // Windows registry, but make sure it continues to be testable. + std::list<base::Time>::iterator iter = timestamps_of_gpu_resets_.begin(); + int num_resets_within_timeframe = 0; + while (iter != timestamps_of_gpu_resets_.end()) { + base::Time time = *iter; + base::TimeDelta delta_t = at_time - time; + + // If this entry has "expired", just remove it. + if (delta_t.InMilliseconds() > kBlockAllDomainsMs) { + iter = timestamps_of_gpu_resets_.erase(iter); + continue; + } + + ++num_resets_within_timeframe; + ++iter; + } + + if (num_resets_within_timeframe >= kNumResetsWithinDuration) { + return DOMAIN_BLOCK_STATUS_ALL_DOMAINS_BLOCKED; + } + + return DOMAIN_BLOCK_STATUS_NOT_BLOCKED; +} + +int64 GpuDataManagerImpl::GetBlockAllDomainsDurationInMs() const { + return kBlockAllDomainsMs; +} + } // namespace content |