summaryrefslogtreecommitdiffstats
path: root/content/browser/gpu/gpu_data_manager_impl.cc
diff options
context:
space:
mode:
authorkbr@chromium.org <kbr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-20 13:14:11 +0000
committerkbr@chromium.org <kbr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-20 13:14:11 +0000
commit818915cd6f37ba0ee4e01ef37f293d5a0cce6975 (patch)
tree81d9df68c4de82b8cff3ad5f25992743039f8e9b /content/browser/gpu/gpu_data_manager_impl.cc
parent41766860ac99fc3a894728084df2f8e31054274c (diff)
downloadchromium_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.cc124
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