summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzmo@google.com <zmo@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-26 02:37:38 +0000
committerzmo@google.com <zmo@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-26 02:37:38 +0000
commitbb4bf9d76e99ba7e1c7f4246dde03e2f9cf92227 (patch)
tree3acdd3c5c16508bed92f2749916aec15f35b6281
parentb2d08988ad842790cabeb728a34473db064a660a (diff)
downloadchromium_src-bb4bf9d76e99ba7e1c7f4246dde03e2f9cf92227.zip
chromium_src-bb4bf9d76e99ba7e1c7f4246dde03e2f9cf92227.tar.gz
chromium_src-bb4bf9d76e99ba7e1c7f4246dde03e2f9cf92227.tar.bz2
With this CL, GPU blacklist auto update from the web is implemented. This allows us to blacklist bad GPU/drivers as soon as we discover them.
Note that this patch does not turn the auto update on. We will turn it on in a separate CL. Reland this patch after fixing a bug causing a XP test failure. BUG=68802 TEST=bots green TBR=kbr Review URL: http://codereview.chromium.org/6588035 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@76143 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/browser_main.cc6
-rw-r--r--chrome/browser/gpu_data_manager.cc187
-rw-r--r--chrome/browser/gpu_data_manager.h85
-rw-r--r--chrome/browser/gpu_process_host_ui_shim.cc172
-rw-r--r--chrome/browser/gpu_process_host_ui_shim.h62
-rw-r--r--chrome/browser/web_resource/gpu_blacklist_updater.cc51
-rw-r--r--chrome/browser/web_resource/gpu_blacklist_updater.h28
-rw-r--r--chrome/browser/web_resource/promo_resource_service.cc2
-rw-r--r--chrome/browser/web_resource/web_resource_service.cc9
-rw-r--r--chrome/browser/web_resource/web_resource_service.h3
-rw-r--r--chrome/browser/webui/gpu_internals_ui.cc23
-rw-r--r--chrome/chrome_browser.gypi4
-rw-r--r--chrome/common/pref_names.cc7
-rw-r--r--chrome/common/pref_names.h3
-rw-r--r--chrome/test/gpu/gpu_pixel_browsertest.cc13
-rw-r--r--content/browser/gpu_blacklist.cc31
-rw-r--r--content/browser/gpu_blacklist.h7
17 files changed, 461 insertions, 232 deletions
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index a3beb41..3a701e0 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -40,6 +40,7 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extensions_startup.h"
#include "chrome/browser/first_run/first_run.h"
+#include "chrome/browser/gpu_data_manager.h"
#include "chrome/browser/jankometer.h"
#include "chrome/browser/metrics/histogram_synchronizer.h"
#include "chrome/browser/metrics/metrics_log.h"
@@ -1811,6 +1812,11 @@ int BrowserMain(const MainFunctionParams& parameters) {
// might have shutdown because an update was available.
profile->GetCloudPrintProxyService();
+ // Need to initialize GpuDataManager to load the current GPU blacklist
+ // and schedule a GPU blacklist auto update.
+ GpuDataManager* gpu_data_manager = GpuDataManager::GetInstance();
+ DCHECK(gpu_data_manager);
+
int result_code = ResultCodes::NORMAL_EXIT;
if (parameters.ui_task) {
// We are in test mode. Run one task and enter the main message loop.
diff --git a/chrome/browser/gpu_data_manager.cc b/chrome/browser/gpu_data_manager.cc
new file mode 100644
index 0000000..1c8d120
--- /dev/null
+++ b/chrome/browser/gpu_data_manager.cc
@@ -0,0 +1,187 @@
+// Copyright (c) 2011 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 "chrome/browser/gpu_data_manager.h"
+
+#include "app/app_switches.h"
+#include "app/gfx/gl/gl_implementation.h"
+#include "base/command_line.h"
+#include "base/metrics/histogram.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/child_process_logging.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "content/browser/gpu_blacklist.h"
+#include "grit/browser_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+
+GpuDataManager::GpuDataManager()
+ : gpu_feature_flags_set_(false),
+ gpu_blacklist_cache_(NULL) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(g_browser_process);
+ PrefService* prefs = g_browser_process->local_state();
+ // If we bring up chrome normally, prefs should never be NULL; however, we
+ // we handle the case where prefs == NULL for certain tests.
+ if (prefs) {
+ prefs->RegisterDictionaryPref(prefs::kGpuBlacklist);
+ gpu_blacklist_cache_ = prefs->GetMutableDictionary(prefs::kGpuBlacklist);
+ DCHECK(gpu_blacklist_cache_);
+
+ gpu_blacklist_updater_ = new GpuBlacklistUpdater();
+ // TODO(zmo): uncomment the following line to turn on auto-updating.
+ // gpu_blacklist_updater_->StartAfterDelay();
+ }
+
+ LoadGpuBlacklist();
+ UpdateGpuBlacklist();
+}
+
+GpuDataManager::~GpuDataManager() { }
+
+GpuDataManager* GpuDataManager::GetInstance() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return Singleton<GpuDataManager>::get();
+}
+
+void GpuDataManager::UpdateGpuInfo(const GPUInfo& gpu_info) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (gpu_info_.level() >= gpu_info.level())
+ return;
+ gpu_info_ = gpu_info;
+ child_process_logging::SetGpuInfo(gpu_info);
+ RunGpuInfoUpdateCallbacks();
+}
+
+const GPUInfo& GpuDataManager::gpu_info() const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return gpu_info_;
+}
+
+GpuFeatureFlags GpuDataManager::GetGpuFeatureFlags() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ UpdateGpuFeatureFlags();
+ return gpu_feature_flags_;
+}
+
+void GpuDataManager::AddGpuInfoUpdateCallback(Callback0::Type* callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ gpu_info_update_callbacks_.insert(callback);
+}
+
+bool GpuDataManager::RemoveGpuInfoUpdateCallback(Callback0::Type* callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ std::set<Callback0::Type*>::iterator i =
+ gpu_info_update_callbacks_.find(callback);
+ if (i != gpu_info_update_callbacks_.end()) {
+ gpu_info_update_callbacks_.erase(i);
+ return true;
+ }
+ return false;
+}
+
+void GpuDataManager::RunGpuInfoUpdateCallbacks() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ std::set<Callback0::Type*>::iterator i = gpu_info_update_callbacks_.begin();
+ for (; i != gpu_info_update_callbacks_.end(); ++i) {
+ (*i)->Run();
+ }
+}
+
+bool GpuDataManager::LoadGpuBlacklist() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (gpu_blacklist_.get() != NULL)
+ return true;
+ static const base::StringPiece gpu_blacklist_json(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_GPU_BLACKLIST));
+ gpu_blacklist_.reset(new GpuBlacklist());
+ if (gpu_blacklist_->LoadGpuBlacklist(gpu_blacklist_json.as_string(), true))
+ return true;
+ gpu_blacklist_.reset(NULL);
+ return false;
+}
+
+bool GpuDataManager::UpdateGpuBlacklist() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (gpu_blacklist_cache_ == NULL)
+ return false;
+ uint16 cached_version_major, cached_version_minor;
+ if (!GpuBlacklist::GetVersion(*gpu_blacklist_cache_,
+ &cached_version_major,
+ &cached_version_minor))
+ return false;
+ if (gpu_blacklist_.get() != NULL) {
+ uint16 current_version_major, current_version_minor;
+ if (gpu_blacklist_->GetVersion(&current_version_major,
+ &current_version_minor) &&
+ (cached_version_major < current_version_major ||
+ (cached_version_major == current_version_major &&
+ cached_version_minor <= current_version_minor)))
+ return false;
+ }
+ GpuBlacklist* updated_list = new GpuBlacklist();
+ if (!updated_list->LoadGpuBlacklist(*gpu_blacklist_cache_, true)) {
+ delete updated_list;
+ return false;
+ }
+ gpu_blacklist_.reset(updated_list);
+ // Clear the flag to triger a re-computation of GpuFeatureFlags using the
+ // updated GPU blacklist.
+ gpu_feature_flags_set_ = false;
+ return true;
+}
+
+void GpuDataManager::UpdateGpuFeatureFlags() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (gpu_info_.level() == GPUInfo::kUninitialized)
+ return;
+
+ // Need to call this before checking gpu_feature_flags_set_ because it might
+ // be reset if a newer version of GPU blacklist is downloaed.
+ GpuBlacklist* gpu_blacklist = GetGpuBlacklist();
+ if (gpu_blacklist == NULL)
+ return;
+
+ if (gpu_feature_flags_set_)
+ return;
+
+ gpu_feature_flags_set_ = true;
+ gpu_feature_flags_.set_flags(0);
+
+ if (gpu_blacklist != NULL) {
+ gpu_feature_flags_ = gpu_blacklist->DetermineGpuFeatureFlags(
+ GpuBlacklist::kOsAny, NULL, gpu_info_);
+ if (gpu_feature_flags_.flags() != 0) {
+ // If gpu is blacklisted, no further GPUInfo will be collected.
+ gpu_info_.SetLevel(GPUInfo::kComplete);
+ // TODO(zmo): move histograming to GpuBlacklist::DetermineGpuFeatureFlags.
+ uint32 max_entry_id = gpu_blacklist->max_entry_id();
+ std::vector<uint32> flag_entries;
+ gpu_blacklist->GetGpuFeatureFlagEntries(
+ GpuFeatureFlags::kGpuFeatureAll, flag_entries);
+ DCHECK_GT(flag_entries.size(), 0u);
+ for (size_t i = 0; i < flag_entries.size(); ++i) {
+ UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
+ flag_entries[i], max_entry_id + 1);
+ }
+ }
+ }
+}
+
+GpuBlacklist* GpuDataManager::GetGpuBlacklist() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
+ if (browser_command_line.HasSwitch(switches::kIgnoreGpuBlacklist) ||
+ browser_command_line.GetSwitchValueASCII(
+ switches::kUseGL) == gfx::kGLImplementationOSMesaName)
+ return NULL;
+ UpdateGpuBlacklist();
+ // No need to return an empty blacklist.
+ if (gpu_blacklist_.get() != NULL && gpu_blacklist_->max_entry_id() == 0)
+ return NULL;
+ return gpu_blacklist_.get();
+}
+
diff --git a/chrome/browser/gpu_data_manager.h b/chrome/browser/gpu_data_manager.h
new file mode 100644
index 0000000..8275c4f
--- /dev/null
+++ b/chrome/browser/gpu_data_manager.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2011 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.
+
+#ifndef CHROME_BROWSER_GPU_DATA_MANAGER_H_
+#define CHROME_BROWSER_GPU_DATA_MANAGER_H_
+#pragma once
+
+#include <set>
+
+#include "base/callback.h"
+#include "base/scoped_ptr.h"
+#include "base/singleton.h"
+#include "chrome/browser/web_resource/gpu_blacklist_updater.h"
+#include "chrome/common/gpu_feature_flags.h"
+#include "chrome/common/gpu_info.h"
+
+class DictionaryValue;
+class GpuBlacklist;
+class GPUInfo;
+
+class GpuDataManager {
+ public:
+ // Getter for the singleton. This will return NULL on failure.
+ static GpuDataManager* GetInstance();
+
+ // Only update if the level is higher than the cached GPUInfo level.
+ void UpdateGpuInfo(const GPUInfo& gpu_info);
+
+ const GPUInfo& gpu_info() const;
+
+ // If necessary, compute the flags before returning them.
+ GpuFeatureFlags GetGpuFeatureFlags();
+
+ // Add a callback.
+ void AddGpuInfoUpdateCallback(Callback0::Type* callback);
+
+ // Remove a callback.
+ // Returns true if removed, or false if it was not found.
+ bool RemoveGpuInfoUpdateCallback(Callback0::Type* callback);
+
+ private:
+ friend struct DefaultSingletonTraits<GpuDataManager>;
+
+ GpuDataManager();
+ virtual ~GpuDataManager();
+
+ bool LoadGpuBlacklist();
+
+ // Check if a newer version of GPU blacklist has been downloaded from the
+ // web (and saved in the local state); if yes, use the newer version instead.
+ // Return true if a newer version is installed.
+ bool UpdateGpuBlacklist();
+
+ // Check if we should go ahead and use gpu blacklist.
+ // If not, return NULL; otherwise, update and return the current list.
+ GpuBlacklist* GetGpuBlacklist();
+
+ // If flags hasn't been set and GPUInfo is available, run through blacklist
+ // and compute the flags.
+ void UpdateGpuFeatureFlags();
+
+ // Call all callbacks.
+ void RunGpuInfoUpdateCallbacks();
+
+ bool gpu_feature_flags_set_;
+ GpuFeatureFlags gpu_feature_flags_;
+
+ GPUInfo gpu_info_;
+
+ scoped_ptr<GpuBlacklist> gpu_blacklist_;
+
+ scoped_refptr<GpuBlacklistUpdater> gpu_blacklist_updater_;
+ // This is the version cached in local state that's automatically updated
+ // from the web.
+ DictionaryValue* gpu_blacklist_cache_;
+
+ // Map of callbacks.
+ std::set<Callback0::Type*> gpu_info_update_callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuDataManager);
+};
+
+#endif // CHROME_BROWSER_GPU_DATA_MANAGER_H_
+
diff --git a/chrome/browser/gpu_process_host_ui_shim.cc b/chrome/browser/gpu_process_host_ui_shim.cc
index 431846c..ff7a237 100644
--- a/chrome/browser/gpu_process_host_ui_shim.cc
+++ b/chrome/browser/gpu_process_host_ui_shim.cc
@@ -7,23 +7,14 @@
#include "chrome/browser/gpu_process_host_ui_shim.h"
-#include "app/app_switches.h"
-#include "app/gfx/gl/gl_implementation.h"
-#include "base/command_line.h"
#include "base/id_map.h"
-#include "base/metrics/histogram.h"
#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/gpu_data_manager.h"
#include "chrome/browser/gpu_process_host.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
-#include "chrome/common/child_process_logging.h"
-#include "chrome/common/chrome_switches.h"
#include "chrome/common/gpu_messages.h"
-#include "chrome/gpu/gpu_info_collector.h"
-#include "content/browser/gpu_blacklist.h"
-#include "grit/browser_resources.h"
-#include "ui/base/resource/resource_bundle.h"
#if defined(OS_LINUX)
// These two #includes need to come after gpu_messages.h.
@@ -62,62 +53,6 @@ class SendOnIOThreadTask : public Task {
} // namespace
-////////////////////////////////////////////////////////////////////////////////
-//
-// Callback0Group
-//
-////////////////////////////////////////////////////////////////////////////////
-
-Callback0Group::Callback0Group() {
-}
-
-Callback0Group::~Callback0Group() {
-}
-
-void Callback0Group::Add(Callback0::Type* callback) {
- callbacks_.insert(callback);
-}
-
-bool Callback0Group::Remove(Callback0::Type* callback) {
- std::set<Callback0::Type*>::iterator i = callbacks_.find(callback);
- if (i != callbacks_.end()) {
- callbacks_.erase(i);
- return true;
- }
- return false;
-}
-
-void Callback0Group::Run() {
- std::set<Callback0::Type*>::iterator i = callbacks_.begin();
- for (; i != callbacks_.end(); ++i) {
- (*i)->Run();
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// GpuProcessHostUIShimManager
-//
-////////////////////////////////////////////////////////////////////////////////
-
-GpuProcessHostUIShimManager::GpuProcessHostUIShimManager() {
-}
-
-GpuProcessHostUIShimManager* GpuProcessHostUIShimManager::GetInstance() {
- return Singleton<GpuProcessHostUIShimManager>::get();
-}
-
-void GpuProcessHostUIShimManager::SetGpuInfo(const GPUInfo& gpu_info) {
- gpu_info_ = gpu_info;
- gpu_info_update_callbacks().Run();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// GpuProcessHostUIShim
-//
-////////////////////////////////////////////////////////////////////////////////
-
class GpuProcessHostUIShim::ViewSurface {
public:
explicit ViewSurface(ViewID view_id);
@@ -167,9 +102,10 @@ RenderWidgetHostView* GpuProcessHostUIShim::ViewSurface::
GpuProcessHostUIShim::GpuProcessHostUIShim()
: host_id_(++g_last_host_id),
- gpu_process_(NULL),
- gpu_feature_flags_set_(false) {
+ gpu_process_(NULL) {
g_hosts_by_id.AddWithID(this, host_id_);
+ gpu_data_manager_ = GpuDataManager::GetInstance();
+ DCHECK(gpu_data_manager_);
}
// static
@@ -185,10 +121,6 @@ GpuProcessHostUIShim* GpuProcessHostUIShim::GetForRenderer(int renderer_id) {
}
GpuProcessHostUIShim* ui_shim(new GpuProcessHostUIShim);
- if (!ui_shim->Init()) {
- delete ui_shim;
- return NULL;
- }
// If Init succeeds, post a task to create the corresponding GpuProcessHost.
// The GpuProcessHost will take ownership of the GpuProcessHostUIShim.
@@ -332,7 +264,7 @@ void GpuProcessHostUIShim::EstablishGpuChannel(
linked_ptr<EstablishChannelCallback> wrapped_callback(callback);
// If GPU features are already blacklisted, no need to establish the channel.
- if (gpu_feature_flags_.flags() != 0) {
+ if (gpu_data_manager_->GetGpuFeatureFlags().flags() != 0) {
EstablishChannelError(
wrapped_callback.release(), IPC::ChannelHandle(), NULL, GPUInfo());
return;
@@ -397,8 +329,9 @@ void GpuProcessHostUIShim::DidDestroyAcceleratedSurface(int renderer_id,
void GpuProcessHostUIShim::CollectGpuInfoAsynchronously(
GPUInfo::Level level) {
DCHECK(CalledOnValidThread());
+
// If GPU is already blacklisted, no more info will be collected.
- if (gpu_feature_flags_.flags() != 0)
+ if (gpu_data_manager_->GetGpuFeatureFlags().flags() != 0)
return;
Send(new GpuMsg_CollectGraphicsInfo(level));
}
@@ -415,7 +348,7 @@ void GpuProcessHostUIShim::SendAboutGpuHang() {
const GPUInfo& GpuProcessHostUIShim::gpu_info() const {
DCHECK(CalledOnValidThread());
- return gpu_info_;
+ return gpu_data_manager_->gpu_info();
}
GpuProcessHostUIShim::~GpuProcessHostUIShim() {
@@ -428,10 +361,6 @@ GpuProcessHostUIShim::~GpuProcessHostUIShim() {
#endif
}
-bool GpuProcessHostUIShim::Init() {
- return LoadGpuBlacklist();
-}
-
void GpuProcessHostUIShim::AddCustomLogMessage(int level,
const std::string& header,
const std::string& message) {
@@ -476,48 +405,19 @@ bool GpuProcessHostUIShim::OnControlMessageReceived(
void GpuProcessHostUIShim::OnChannelEstablished(
const IPC::ChannelHandle& channel_handle,
const GPUInfo& gpu_info) {
+ gpu_data_manager_->UpdateGpuInfo(gpu_info);
+
// The GPU process should have launched at this point and this object should
// have been notified of its process handle.
DCHECK(gpu_process_);
- uint32 max_entry_id = gpu_blacklist_->max_entry_id();
- // max_entry_id can be zero if we failed to load the GPU blacklist, don't
- // bother with histograms then.
- if (channel_handle.name.size() != 0 && !gpu_feature_flags_set_ &&
- max_entry_id != 0)
- {
- gpu_feature_flags_set_ = true;
-
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
- if (!browser_command_line.HasSwitch(switches::kIgnoreGpuBlacklist) &&
- browser_command_line.GetSwitchValueASCII(
- switches::kUseGL) != gfx::kGLImplementationOSMesaName) {
- gpu_feature_flags_ = gpu_blacklist_->DetermineGpuFeatureFlags(
- GpuBlacklist::kOsAny, NULL, gpu_info);
-
- if (gpu_feature_flags_.flags() != 0) {
- std::vector<uint32> flag_entries;
- gpu_blacklist_->GetGpuFeatureFlagEntries(
- GpuFeatureFlags::kGpuFeatureAll, flag_entries);
- DCHECK_GT(flag_entries.size(), 0u);
- for (size_t i = 0; i < flag_entries.size(); ++i) {
- UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
- flag_entries[i], max_entry_id + 1);
- }
- } else {
- // id 0 is never used by any entry, so we use it here to indicate that
- // gpu is allowed.
- UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
- 0, max_entry_id + 1);
- }
- }
- }
linked_ptr<EstablishChannelCallback> callback = channel_requests_.front();
channel_requests_.pop();
// Currently if any of the GPU features are blacklisted, we don't establish a
// GPU channel.
- if (gpu_feature_flags_.flags() != 0) {
+ if (channel_handle.name.size() != 0 &&
+ gpu_data_manager_->GetGpuFeatureFlags().flags() != 0) {
Send(new GpuMsg_CloseChannel(channel_handle));
EstablishChannelError(callback.release(),
IPC::ChannelHandle(),
@@ -559,43 +459,16 @@ void GpuProcessHostUIShim::OnDestroyCommandBuffer(
}
void GpuProcessHostUIShim::OnGraphicsInfoCollected(const GPUInfo& gpu_info) {
- gpu_info_ = gpu_info;
- if (gpu_feature_flags_.flags() != 0)
- gpu_info_.SetLevel(GPUInfo::kComplete);
- child_process_logging::SetGpuInfo(gpu_info_);
-
- GpuProcessHostUIShimManager::GetInstance()->SetGpuInfo(gpu_info);
+ gpu_data_manager_->UpdateGpuInfo(gpu_info);
}
void GpuProcessHostUIShim::OnPreliminaryGraphicsInfoCollected(
const GPUInfo& gpu_info, IPC::Message* reply_msg) {
- bool blacklisted = false;
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
- if (!browser_command_line.HasSwitch(switches::kIgnoreGpuBlacklist) &&
- browser_command_line.GetSwitchValueASCII(
- switches::kUseGL) != gfx::kGLImplementationOSMesaName) {
- gpu_feature_flags_ = gpu_blacklist_->DetermineGpuFeatureFlags(
- GpuBlacklist::kOsAny, NULL, gpu_info);
- if (gpu_feature_flags_.flags() != 0) {
- blacklisted = true;
- gpu_feature_flags_set_ = true;
- gpu_info_ = gpu_info;
- gpu_info_.SetLevel(GPUInfo::kComplete);
- child_process_logging::SetGpuInfo(gpu_info_);
- uint32 max_entry_id = gpu_blacklist_->max_entry_id();
- std::vector<uint32> flag_entries;
- gpu_blacklist_->GetGpuFeatureFlagEntries(
- GpuFeatureFlags::kGpuFeatureAll, flag_entries);
- DCHECK_GT(flag_entries.size(), 0u);
- for (size_t i = 0; i < flag_entries.size(); ++i) {
- UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
- flag_entries[i], max_entry_id + 1);
- }
- }
- }
+ gpu_data_manager_->UpdateGpuInfo(gpu_info);
+ GpuFeatureFlags flags = gpu_data_manager_->GetGpuFeatureFlags();
GpuHostMsg_PreliminaryGraphicsInfoCollected::WriteReplyParams(
- reply_msg, blacklisted);
+ reply_msg, flags.flags() != 0);
Send(reply_msg);
}
@@ -675,16 +548,3 @@ void GpuProcessHostUIShim::OnScheduleComposite(int renderer_id,
#endif
-bool GpuProcessHostUIShim::LoadGpuBlacklist() {
- if (gpu_blacklist_.get() != NULL)
- return true;
- static const base::StringPiece gpu_blacklist_json(
- ResourceBundle::GetSharedInstance().GetRawDataResource(
- IDR_GPU_BLACKLIST));
- gpu_blacklist_.reset(new GpuBlacklist());
- if (gpu_blacklist_->LoadGpuBlacklist(gpu_blacklist_json.as_string(), true))
- return true;
- gpu_blacklist_.reset(NULL);
- return false;
-}
-
diff --git a/chrome/browser/gpu_process_host_ui_shim.h b/chrome/browser/gpu_process_host_ui_shim.h
index f973860..1e9ae53 100644
--- a/chrome/browser/gpu_process_host_ui_shim.h
+++ b/chrome/browser/gpu_process_host_ui_shim.h
@@ -13,7 +13,6 @@
#include <map>
#include <queue>
-#include <set>
#include "base/callback.h"
#include "base/linked_ptr.h"
@@ -32,7 +31,7 @@ namespace gfx {
class Size;
}
-class GpuBlacklist;
+class GpuDataManager;
struct GPUCreateCommandBufferConfig;
class GPUInfo;
struct GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params;
@@ -43,55 +42,6 @@ struct ChannelHandle;
class Message;
}
-class Callback0Group
-{
- public:
- Callback0Group();
- ~Callback0Group();
-
- // Add a callback.
- void Add(Callback0::Type* callback);
-
- // Remove a callback.
- // Returns true if removed, or false if it was not found.
- bool Remove(Callback0::Type* callback);
-
- // Call all callbacks.
- void Run();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Callback0Group);
-
- // Map of callbacks.
- std::set<Callback0::Type*> callbacks_;
-};
-
-class GpuProcessHostUIShimManager
-{
- public:
- static GpuProcessHostUIShimManager* GetInstance();
-
- void SetGpuInfo(const GPUInfo& gpu_info);
-
- // This callback group is invoked when GPU info is updated.
- Callback0Group& gpu_info_update_callbacks() {
- return gpu_info_update_callbacks_;
- }
-
- // Return all known information about the GPU.
- const GPUInfo& gpu_info() const {
- return gpu_info_;
- }
-
- private:
- GpuProcessHostUIShimManager();
- friend struct DefaultSingletonTraits<GpuProcessHostUIShimManager>;
- DISALLOW_COPY_AND_ASSIGN(GpuProcessHostUIShimManager);
-
- GPUInfo gpu_info_;
- Callback0Group gpu_info_update_callbacks_;
-};
-
class GpuProcessHostUIShim
: public IPC::Channel::Listener,
public IPC::Channel::Sender,
@@ -184,12 +134,9 @@ class GpuProcessHostUIShim
void AddCustomLogMessage(int level, const std::string& header,
const std::string& message);
- bool LoadGpuBlacklist();
-
private:
GpuProcessHostUIShim();
virtual ~GpuProcessHostUIShim();
- bool Init();
// Message handlers.
bool OnControlMessageReceived(const IPC::Message& message);
@@ -222,9 +169,11 @@ class GpuProcessHostUIShim
// The handle for the GPU process or null if it is not known to be launched.
base::ProcessHandle gpu_process_;
- GPUInfo gpu_info_;
ListValue log_messages_;
+ // Cached pointer to the singleton for efficiency purpose.
+ GpuDataManager* gpu_data_manager_;
+
// These are the channel requests that we have already sent to
// the GPU process, but haven't heard back about yet.
std::queue<linked_ptr<EstablishChannelCallback> > channel_requests_;
@@ -245,9 +194,6 @@ class GpuProcessHostUIShim
class ViewSurface;
std::map<ViewID, linked_ptr<ViewSurface> > acquired_surfaces_;
- bool gpu_feature_flags_set_;
- scoped_ptr<GpuBlacklist> gpu_blacklist_;
- GpuFeatureFlags gpu_feature_flags_;
};
#endif // CHROME_BROWSER_GPU_PROCESS_HOST_UI_SHIM_H_
diff --git a/chrome/browser/web_resource/gpu_blacklist_updater.cc b/chrome/browser/web_resource/gpu_blacklist_updater.cc
new file mode 100644
index 0000000..ca297a1
--- /dev/null
+++ b/chrome/browser/web_resource/gpu_blacklist_updater.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2011 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 "chrome/browser/web_resource/gpu_blacklist_updater.h"
+
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/pref_names.h"
+
+namespace {
+
+// Delay on first fetch so we don't interfere with startup.
+static const int kStartGpuBlacklistFetchDelay = 6000;
+
+// Delay between calls to update the gpu blacklist (48 hours).
+static const int kCacheUpdateDelay = 48 * 60 * 60 * 1000;
+
+} // namespace
+
+const char* GpuBlacklistUpdater::kDefaultGpuBlacklistURL =
+ "http://cache.pack.google.com/edgedl/chrome/gpu/"
+ "software_rendering_list.json";
+
+GpuBlacklistUpdater::GpuBlacklistUpdater()
+ : WebResourceService(ProfileManager::GetDefaultProfile(),
+ g_browser_process->local_state(),
+ GpuBlacklistUpdater::kDefaultGpuBlacklistURL,
+ false, // don't append locale to URL
+ NotificationType::NOTIFICATION_TYPE_COUNT,
+ prefs::kGpuBlacklistUpdate,
+ kStartGpuBlacklistFetchDelay,
+ kCacheUpdateDelay) {
+}
+
+GpuBlacklistUpdater::~GpuBlacklistUpdater() { }
+
+void GpuBlacklistUpdater::Unpack(const DictionaryValue& parsed_json) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DictionaryValue* gpu_blacklist_cache =
+ prefs_->GetMutableDictionary(prefs::kGpuBlacklist);
+ DCHECK(gpu_blacklist_cache);
+ gpu_blacklist_cache->Clear();
+ gpu_blacklist_cache->MergeDictionary(&parsed_json);
+}
+
diff --git a/chrome/browser/web_resource/gpu_blacklist_updater.h b/chrome/browser/web_resource/gpu_blacklist_updater.h
new file mode 100644
index 0000000..136fd72
--- /dev/null
+++ b/chrome/browser/web_resource/gpu_blacklist_updater.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 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.
+
+#ifndef CHROME_BROWSER_WEB_RESOURCE_GPU_BLACKLIST_UPDATER_H_
+#define CHROME_BROWSER_WEB_RESOURCE_GPU_BLACKLIST_UPDATER_H_
+#pragma once
+
+#include "chrome/browser/web_resource/web_resource_service.h"
+
+class GpuBlacklistUpdater
+ : public WebResourceService {
+ public:
+ explicit GpuBlacklistUpdater();
+
+ // URL of the up-to-date gpu_blacklist.json file.
+ static const char* kDefaultGpuBlacklistURL;
+
+ private:
+ virtual ~GpuBlacklistUpdater();
+
+ virtual void Unpack(const DictionaryValue& parsed_json);
+
+ DISALLOW_COPY_AND_ASSIGN(GpuBlacklistUpdater);
+};
+
+#endif // CHROME_BROWSER_WEB_RESOURCE_GPU_BLACKLIST_UPDATER_H_
+
diff --git a/chrome/browser/web_resource/promo_resource_service.cc b/chrome/browser/web_resource/promo_resource_service.cc
index f694563..30a2c74 100644
--- a/chrome/browser/web_resource/promo_resource_service.cc
+++ b/chrome/browser/web_resource/promo_resource_service.cc
@@ -53,6 +53,7 @@ const char* PromoResourceService::kDefaultPromoResourceServer =
PromoResourceService::PromoResourceService(Profile* profile)
: WebResourceService(profile,
+ profile->GetPrefs(),
PromoResourceService::kDefaultPromoResourceServer,
true, // append locale to URL
NotificationType::PROMO_RESOURCE_STATE_CHANGED,
@@ -66,7 +67,6 @@ PromoResourceService::PromoResourceService(Profile* profile)
PromoResourceService::~PromoResourceService() { }
void PromoResourceService::Init() {
- prefs_->RegisterStringPref(prefs::kNTPPromoResourceCacheUpdate, "0");
prefs_->RegisterDoublePref(prefs::kNTPCustomLogoStart, 0);
prefs_->RegisterDoublePref(prefs::kNTPCustomLogoEnd, 0);
prefs_->RegisterDoublePref(prefs::kNTPPromoStart, 0);
diff --git a/chrome/browser/web_resource/web_resource_service.cc b/chrome/browser/web_resource/web_resource_service.cc
index daddae7..1026651 100644
--- a/chrome/browser/web_resource/web_resource_service.cc
+++ b/chrome/browser/web_resource/web_resource_service.cc
@@ -198,13 +198,15 @@ class WebResourceService::UnpackerClient
WebResourceService::WebResourceService(
Profile* profile,
+ PrefService* prefs,
const char* web_resource_server,
bool apply_locale_to_url,
NotificationType::Type notification_type,
const char* last_update_time_pref_name,
int start_fetch_delay,
int cache_update_delay)
- : profile_(profile),
+ : prefs_(prefs),
+ profile_(profile),
ALLOW_THIS_IN_INITIALIZER_LIST(service_factory_(this)),
in_fetch_(false),
web_resource_server_(web_resource_server),
@@ -214,8 +216,9 @@ WebResourceService::WebResourceService(
start_fetch_delay_(start_fetch_delay),
cache_update_delay_(cache_update_delay),
web_resource_update_scheduled_(false) {
+ DCHECK(prefs);
DCHECK(profile);
- prefs_ = profile_->GetPrefs();
+ prefs_->RegisterStringPref(last_update_time_pref_name, "0");
resource_dispatcher_host_ = g_browser_process->resource_dispatcher_host();
web_resource_fetcher_.reset(new WebResourceFetcher(this));
}
@@ -247,6 +250,8 @@ void WebResourceService::OnWebResourceUnpacked(
void WebResourceService::WebResourceStateChange() {
web_resource_update_scheduled_ = false;
+ if (notification_type_ == NotificationType::NOTIFICATION_TYPE_COUNT)
+ return;
NotificationService* service = NotificationService::current();
service->Notify(notification_type_,
Source<WebResourceService>(this),
diff --git a/chrome/browser/web_resource/web_resource_service.h b/chrome/browser/web_resource/web_resource_service.h
index 1b4b680..64c37e6 100644
--- a/chrome/browser/web_resource/web_resource_service.h
+++ b/chrome/browser/web_resource/web_resource_service.h
@@ -19,7 +19,10 @@ class Profile;
class WebResourceService
: public UtilityProcessHost::Client {
public:
+ // Pass notification_type = NOTIFICATION_TYPE_COUNT if notification is not
+ // required.
WebResourceService(Profile* profile,
+ PrefService* prefs,
const char* web_resource_server,
bool apply_locale_to_url_,
NotificationType::Type notification_type,
diff --git a/chrome/browser/webui/gpu_internals_ui.cc b/chrome/browser/webui/gpu_internals_ui.cc
index 2462d05..7a2f2bd 100644
--- a/chrome/browser/webui/gpu_internals_ui.cc
+++ b/chrome/browser/webui/gpu_internals_ui.cc
@@ -20,6 +20,7 @@
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/gpu_data_manager.h"
#include "chrome/browser/gpu_process_host.h"
#include "chrome/browser/gpu_process_host_ui_shim.h"
#include "chrome/browser/io_thread.h"
@@ -93,6 +94,9 @@ class GpuMessageHandler
private:
DISALLOW_COPY_AND_ASSIGN(GpuMessageHandler);
+ // Cache the Singleton for efficiency.
+ GpuDataManager* gpu_data_manager_;
+
Callback0::Type* gpu_info_update_callback_;
};
@@ -140,12 +144,13 @@ std::string GpuHTMLSource::GetMimeType(const std::string&) const {
////////////////////////////////////////////////////////////////////////////////
GpuMessageHandler::GpuMessageHandler() : gpu_info_update_callback_(NULL) {
+ gpu_data_manager_ = GpuDataManager::GetInstance();
+ DCHECK(gpu_data_manager_);
}
GpuMessageHandler::~GpuMessageHandler() {
if (gpu_info_update_callback_) {
- GpuProcessHostUIShimManager::GetInstance()->
- gpu_info_update_callbacks().Remove(gpu_info_update_callback_);
+ gpu_data_manager_->RemoveGpuInfoUpdateCallback(gpu_info_update_callback_);
delete gpu_info_update_callback_;
}
}
@@ -216,12 +221,16 @@ void GpuMessageHandler::OnCallAsync(const ListValue* args) {
}
void GpuMessageHandler::OnRequestGpuInfo(const ListValue* args) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
if (gpu_info_update_callback_ == NULL) {
// Add us to be called when GPUInfo changes and ask for updated GPUInfo.
gpu_info_update_callback_ =
NewCallback(this, &GpuMessageHandler::OnGpuInfoCollected);
- GpuProcessHostUIShimManager::GetInstance()->gpu_info_update_callbacks().Add(
- gpu_info_update_callback_);
+ gpu_data_manager_->AddGpuInfoUpdateCallback(gpu_info_update_callback_);
+ // Run callback immediately in case the info is ready and no update in the
+ // future.
+ OnGpuInfoCollected();
}
GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::GetForRenderer(0);
if (ui_shim)
@@ -362,9 +371,11 @@ Value* GpuMessageHandler::OnRequestLogMessages(const ListValue*) {
}
void GpuMessageHandler::OnGpuInfoCollected() {
-
// Get GPU Info.
- GPUInfo gpu_info = GpuProcessHostUIShimManager::GetInstance()->gpu_info();
+ const GPUInfo& gpu_info = gpu_data_manager_->gpu_info();
+
+ if (gpu_info.level() == GPUInfo::kUninitialized)
+ return;
// Send GPU Info to javascript.
Value* gpuInfoVal = GpuInfoToDict(gpu_info);
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index e2dbf29..6204ce8 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1180,6 +1180,8 @@
'browser/google/google_url_tracker.h',
'browser/google/google_util.cc',
'browser/google/google_util.h',
+ 'browser/gpu_data_manager.cc',
+ 'browser/gpu_data_manager.h',
'browser/gpu_process_host_ui_shim.cc',
'browser/gpu_process_host_ui_shim.h',
'browser/hang_monitor/hung_plugin_action.cc',
@@ -3275,6 +3277,8 @@
'browser/visitedlink/visitedlink_master.h',
'browser/web_applications/web_app.cc',
'browser/web_applications/web_app.h',
+ 'browser/web_resource/gpu_blacklist_updater.cc',
+ 'browser/web_resource/gpu_blacklist_updater.h',
'browser/web_resource/promo_resource_service.cc',
'browser/web_resource/promo_resource_service.h',
'browser/web_resource/web_resource_service.cc',
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index c6dcce6..651b355 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1094,6 +1094,13 @@ const char kNTPPromoLine[] = "ntp.promo_line";
const char kNTPPromoStart[] = "ntp.promo_start";
const char kNTPPromoEnd[] = "ntp.promo_end";
+// The most up-to-date GPU blacklist downloaded from the web, which replaces
+// the one that's installed with chrome.
+const char kGpuBlacklist[] = "gpu_blacklist";
+
+// Last time of update of gpu_blacklist.
+const char kGpuBlacklistUpdate[] = "gpu_blacklist_update";
+
const char kDevToolsDisabled[] = "devtools.disabled";
// A boolean specifying whether dev tools window should be opened docked.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 6e05d71..938240f 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -381,6 +381,9 @@ extern const char kNTPPromoGroup[];
extern const char kNTPPromoGroupTimeSlice[];
extern const char kNTPPromoBuild[];
+extern const char kGpuBlacklist[];
+extern const char kGpuBlacklistUpdate[];
+
extern const char kDevToolsDisabled[];
extern const char kDevToolsOpenDocked[];
extern const char kDevToolsSplitLocation[];
diff --git a/chrome/test/gpu/gpu_pixel_browsertest.cc b/chrome/test/gpu/gpu_pixel_browsertest.cc
index ede1c69..26fc191 100644
--- a/chrome/test/gpu/gpu_pixel_browsertest.cc
+++ b/chrome/test/gpu/gpu_pixel_browsertest.cc
@@ -14,12 +14,13 @@
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/gpu_data_manager.h"
#include "chrome/browser/gpu_process_host.h"
#include "chrome/browser/gpu_process_host_ui_shim.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/gpu_info.h"
@@ -92,14 +93,14 @@ class GPUInfoCollectedObserver {
gpu_info_collected_(false) {
gpu_info_update_callback_ =
NewCallback(this, &GPUInfoCollectedObserver::OnGpuInfoCollected);
- GpuProcessHostUIShimManager::GetInstance()->gpu_info_update_callbacks().Add(
- gpu_info_update_callback_);
+ GpuDataManager::GetInstance()->
+ AddGpuInfoUpdateCallback(gpu_info_update_callback_);
}
void OnGpuInfoCollected() {
gpu_info_collected_ = true;
- GpuProcessHostUIShimManager::GetInstance()->
- gpu_info_update_callbacks().Remove(gpu_info_update_callback_);
+ GpuDataManager::GetInstance()->
+ RemoveGpuInfoUpdateCallback(gpu_info_update_callback_);
delete gpu_info_update_callback_;
MessageLoopForUI::current()->Quit();
}
diff --git a/content/browser/gpu_blacklist.cc b/content/browser/gpu_blacklist.cc
index 544a656..771de1d 100644
--- a/content/browser/gpu_blacklist.cc
+++ b/content/browser/gpu_blacklist.cc
@@ -426,7 +426,6 @@ GpuBlacklist::~GpuBlacklist() {
bool GpuBlacklist::LoadGpuBlacklist(const std::string& json_context,
bool current_os_only) {
- std::vector<GpuBlacklistEntry*> entries;
scoped_ptr<Value> root;
root.reset(base::JSONReader::Read(json_context, false));
if (root.get() == NULL || !root->IsType(Value::TYPE_DICTIONARY))
@@ -434,14 +433,21 @@ bool GpuBlacklist::LoadGpuBlacklist(const std::string& json_context,
DictionaryValue* root_dictionary = static_cast<DictionaryValue*>(root.get());
DCHECK(root_dictionary);
+ return LoadGpuBlacklist(*root_dictionary, current_os_only);
+}
+
+bool GpuBlacklist::LoadGpuBlacklist(const DictionaryValue& parsed_json,
+ bool current_os_only) {
+ std::vector<GpuBlacklistEntry*> entries;
+
std::string version_string;
- root_dictionary->GetString("version", &version_string);
+ parsed_json.GetString("version", &version_string);
version_.reset(Version::GetVersionFromString(version_string));
if (version_.get() == NULL)
return false;
ListValue* list = NULL;
- root_dictionary->GetList("entries", &list);
+ parsed_json.GetList("entries", &list);
if (list == NULL)
return false;
@@ -556,6 +562,25 @@ bool GpuBlacklist::GetVersion(uint16* major, uint16* minor) const {
return true;
}
+bool GpuBlacklist::GetVersion(
+ const DictionaryValue& parsed_json, uint16* major, uint16* minor) {
+ DCHECK(major && minor);
+ *major = 0;
+ *minor = 0;
+ std::string version_string;
+ if (!parsed_json.GetString("version", &version_string))
+ return false;
+ scoped_ptr<Version> version(Version::GetVersionFromString(version_string));
+ if (version.get() == NULL)
+ return false;
+ const std::vector<uint16>& components_reference = version->components();
+ if (components_reference.size() != 2)
+ return false;
+ *major = components_reference[0];
+ *minor = components_reference[1];
+ return true;
+}
+
GpuBlacklist::OsType GpuBlacklist::GetOsType() {
#if defined(OS_WIN)
return kOsWin;
diff --git a/content/browser/gpu_blacklist.h b/content/browser/gpu_blacklist.h
index f732af9..7758b65 100644
--- a/content/browser/gpu_blacklist.h
+++ b/content/browser/gpu_blacklist.h
@@ -37,6 +37,8 @@ class GpuBlacklist {
// If failed, the current GpuBlacklist is un-touched.
bool LoadGpuBlacklist(const std::string& json_context,
bool current_os_only);
+ bool LoadGpuBlacklist(const DictionaryValue& parsed_json,
+ bool current_os_only);
// Collects system information and combines them with gpu_info and blacklist
// information to determine gpu feature flags.
@@ -63,6 +65,11 @@ class GpuBlacklist {
// major and minor to 0 on failure.
bool GetVersion(uint16* major, uint16* monir) const;
+ // Collects the version of the current blacklist from a parsed json file.
+ // Returns false and sets major and minor to 0 on failure.
+ static bool GetVersion(
+ const DictionaryValue& parsed_json, uint16* major, uint16* minor);
+
private:
class VersionInfo {
public: