Add logging of Google Update configuration/statistics to UMA report.

BUG=127279

Review URL: https://chromiumcodereview.appspot.com/10381057

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@137017 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/metrics/metrics_log.cc b/chrome/browser/metrics/metrics_log.cc
index d9bb882..5ec38bed 100644
--- a/chrome/browser/metrics/metrics_log.cc
+++ b/chrome/browser/metrics/metrics_log.cc
@@ -33,6 +33,7 @@
 #include "chrome/common/metrics/proto/profiler_event.pb.h"
 #include "chrome/common/metrics/proto/system_profile.pb.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/installer/util/google_update_settings.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/gpu_data_manager.h"
 #include "content/public/common/content_client.h"
@@ -54,6 +55,7 @@
 using metrics::SystemProfileProto;
 using tracked_objects::ProcessDataSnapshot;
 typedef experiments_helper::SelectedGroupId SelectedGroupId;
+typedef SystemProfileProto::GoogleUpdate::ProductInfo ProductInfo;
 
 namespace {
 
@@ -260,8 +262,25 @@
   }
 }
 
+void ProductDataToProto(const GoogleUpdateSettings::ProductData& product_data,
+                        ProductInfo* product_info) {
+  product_info->set_version(product_data.version);
+  product_info->set_last_update_success_timestamp(
+      product_data.last_success.ToTimeT());
+  product_info->set_last_error(product_data.last_error_code);
+  product_info->set_last_extra_error(product_data.last_extra_code);
+  if (ProductInfo::InstallResult_IsValid(product_data.last_result)) {
+    product_info->set_last_result(
+        static_cast<ProductInfo::InstallResult>(product_data.last_result));
+  }
+}
+
 }  // namespace
 
+GoogleUpdateMetrics::GoogleUpdateMetrics() : is_system_install(false) {}
+
+GoogleUpdateMetrics::~GoogleUpdateMetrics() {}
+
 static base::LazyInstance<std::string>::Leaky
   g_version_extension = LAZY_INSTANCE_INITIALIZER;
 
@@ -631,6 +650,7 @@
 
 void MetricsLog::RecordEnvironment(
          const std::vector<webkit::WebPluginInfo>& plugin_list,
+         const GoogleUpdateMetrics& google_update_metrics,
          const DictionaryValue* profile_metrics) {
   DCHECK(!locked());
 
@@ -730,11 +750,12 @@
   if (profile_metrics)
     WriteAllProfilesMetrics(*profile_metrics);
 
-  RecordEnvironmentProto(plugin_list);
+  RecordEnvironmentProto(plugin_list, google_update_metrics);
 }
 
 void MetricsLog::RecordEnvironmentProto(
-    const std::vector<webkit::WebPluginInfo>& plugin_list) {
+    const std::vector<webkit::WebPluginInfo>& plugin_list,
+    const GoogleUpdateMetrics& google_update_metrics) {
   SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
   int install_date;
   bool success = base::StringToInt(GetInstallDate(GetPrefService()),
@@ -774,6 +795,8 @@
   hardware->set_primary_screen_height(display_size.height());
   hardware->set_screen_count(GetScreenCount());
 
+  WriteGoogleUpdateProto(google_update_metrics);
+
   bool write_as_xml = false;
   WritePluginList(plugin_list, write_as_xml);
 
@@ -952,3 +975,33 @@
 
   ++num_events_;
 }
+
+void MetricsLog::WriteGoogleUpdateProto(
+    const GoogleUpdateMetrics& google_update_metrics) {
+#if defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN)
+  SystemProfileProto::GoogleUpdate* google_update =
+      uma_proto()->mutable_system_profile()->mutable_google_update();
+
+  google_update->set_is_system_install(google_update_metrics.is_system_install);
+
+  if (!google_update_metrics.last_started_au.is_null()) {
+    google_update->set_last_automatic_start_timestamp(
+        google_update_metrics.last_started_au.ToTimeT());
+  }
+
+  if (!google_update_metrics.last_checked.is_null()) {
+    google_update->set_last_update_check_timestamp(
+      google_update_metrics.last_checked.ToTimeT());
+  }
+
+  if (!google_update_metrics.google_update_data.version.empty()) {
+    ProductDataToProto(google_update_metrics.google_update_data,
+                       google_update->mutable_google_update_status());
+  }
+
+  if (!google_update_metrics.product_data.version.empty()) {
+    ProductDataToProto(google_update_metrics.product_data,
+                       google_update->mutable_client_status());
+  }
+#endif  // defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN)
+}
diff --git a/chrome/browser/metrics/metrics_log.h b/chrome/browser/metrics/metrics_log.h
index 1732f03..d7f9c7d 100644
--- a/chrome/browser/metrics/metrics_log.h
+++ b/chrome/browser/metrics/metrics_log.h
@@ -14,6 +14,7 @@
 
 #include "base/basictypes.h"
 #include "chrome/common/metrics/metrics_log_base.h"
+#include "chrome/installer/util/google_update_settings.h"
 #include "content/public/common/process_type.h"
 #include "ui/gfx/size.h"
 
@@ -36,6 +37,25 @@
 struct WebPluginInfo;
 }
 
+// This is a small helper struct to pass Google Update metrics in a single
+// reference argument to MetricsLog::RecordEnvironment().
+struct GoogleUpdateMetrics {
+    GoogleUpdateMetrics();
+    ~GoogleUpdateMetrics();
+
+    // Defines whether this is a user-level or system-level install.
+    bool is_system_install;
+    // The time at which Google Update last started an automatic update check.
+    base::Time last_started_au;
+    // The time at which Google Update last successfully recieved update
+    // information from Google servers.
+    base::Time last_checked;
+    // Details about Google Update's attempts to update itself.
+    GoogleUpdateSettings::ProductData google_update_data;
+    // Details about Google Update's attempts to update this product.
+    GoogleUpdateSettings::ProductData product_data;
+};
+
 class MetricsLog : public MetricsLogBase {
  public:
   // Creates a new metrics log
@@ -59,22 +79,25 @@
   static const std::string& version_extension();
 
   // Records the current operating environment.  Takes the list of installed
-  // plugins as a parameter because that can't be obtained synchronously
-  // from the UI thread.
+  // plugins and Google Update statistics as parameters because those can't be
+  // obtained synchronously from the UI thread.
   // profile_metrics, if non-null, gives a dictionary of all profile metrics
   // that are to be recorded. Each value in profile_metrics should be a
   // dictionary giving the metrics for the profile.
   void RecordEnvironment(
       const std::vector<webkit::WebPluginInfo>& plugin_list,
+      const GoogleUpdateMetrics& google_update_metrics,
       const base::DictionaryValue* profile_metrics);
 
   // Records the current operating environment.  Takes the list of installed
-  // plugins as a parameter because that can't be obtained synchronously from
-  // the UI thread.  This is exposed as a separate method from the
-  // |RecordEnvironment()| method above because we record the environment with
-  // *each* protobuf upload, but only with the initial XML upload.
+  // plugins and Google Update statistics as parameters because those can't be
+  // obtained synchronously from the UI thread.  This is exposed as a separate
+  // method from the |RecordEnvironment()| method above because we record the
+  // environment with *each* protobuf upload, but only with the initial XML
+  // upload.
   void RecordEnvironmentProto(
-      const std::vector<webkit::WebPluginInfo>& plugin_list);
+      const std::vector<webkit::WebPluginInfo>& plugin_list,
+      const GoogleUpdateMetrics& google_update_metrics);
 
   // Records the input text, available choices, and selected entry when the
   // user uses the Omnibox to open a URL.
@@ -154,6 +177,10 @@
   void WriteProfileMetrics(const std::string& key,
                            const base::DictionaryValue& profile_metrics);
 
+  // Writes info about the Google Update install that is managing this client.
+  // This is a no-op if called on a non-Windows platform.
+  void WriteGoogleUpdateProto(const GoogleUpdateMetrics& google_update_metrics);
+
   DISALLOW_COPY_AND_ASSIGN(MetricsLog);
 };
 
diff --git a/chrome/browser/metrics/metrics_log_unittest.cc b/chrome/browser/metrics/metrics_log_unittest.cc
index e6b044e..d3d0591 100644
--- a/chrome/browser/metrics/metrics_log_unittest.cc
+++ b/chrome/browser/metrics/metrics_log_unittest.cc
@@ -17,6 +17,7 @@
 #include "chrome/common/metrics/proto/profiler_event.pb.h"
 #include "chrome/common/metrics/proto/system_profile.pb.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/installer/util/google_update_settings.h"
 #include "chrome/test/base/testing_pref_service.h"
 #include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -104,10 +105,11 @@
     TestMetricsLog log(kClientId, kSessionId);
 
     std::vector<webkit::WebPluginInfo> plugins;
+    GoogleUpdateMetrics google_update_metrics;
     if (proto_only)
-      log.RecordEnvironmentProto(plugins);
+      log.RecordEnvironmentProto(plugins, google_update_metrics);
     else
-      log.RecordEnvironment(plugins, NULL);
+      log.RecordEnvironment(plugins, google_update_metrics, NULL);
 
     const metrics::SystemProfileProto& system_profile = log.system_profile();
     ASSERT_EQ(arraysize(kFieldTrialIds),
diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc
index a904390a..c691f70 100644
--- a/chrome/browser/metrics/metrics_service.cc
+++ b/chrome/browser/metrics/metrics_service.cc
@@ -783,6 +783,48 @@
   DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
   plugins_ = plugins;
 
+  // Schedules a task on a blocking pool thread to gather Google Update
+  // statistics (requires Registry reads).
+  BrowserThread::PostBlockingPoolTask(
+      FROM_HERE,
+      base::Bind(&MetricsService::InitTaskGetGoogleUpdateData,
+                 self_ptr_factory_.GetWeakPtr(),
+                 MessageLoop::current()->message_loop_proxy()));
+}
+
+// static
+void MetricsService::InitTaskGetGoogleUpdateData(
+    base::WeakPtr<MetricsService> self,
+    base::MessageLoopProxy* target_loop) {
+  GoogleUpdateMetrics google_update_metrics;
+
+#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+  const bool system_install = GoogleUpdateSettings::IsSystemInstall();
+
+  google_update_metrics.is_system_install = system_install;
+  google_update_metrics.last_started_au =
+      GoogleUpdateSettings::GetGoogleUpdateLastStartedAU(system_install);
+  google_update_metrics.last_checked =
+      GoogleUpdateSettings::GetGoogleUpdateLastChecked(system_install);
+  GoogleUpdateSettings::GetUpdateDetailForGoogleUpdate(
+      system_install,
+      &google_update_metrics.google_update_data);
+  GoogleUpdateSettings::GetUpdateDetail(
+      system_install,
+      &google_update_metrics.product_data);
+#endif  // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+
+  target_loop->PostTask(FROM_HERE,
+      base::Bind(&MetricsService::OnInitTaskGotGoogleUpdateData,
+          self, google_update_metrics));
+}
+
+void MetricsService::OnInitTaskGotGoogleUpdateData(
+    const GoogleUpdateMetrics& google_update_metrics) {
+  DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
+
+  google_update_metrics_ = google_update_metrics;
+
   // Start the next part of the init task: fetching performance data.  This will
   // call into |FinishedReceivingProfilerData()| when the task completes.
   chrome_browser_metrics::TrackingSynchronizer::FetchProfilerDataAsynchronously(
@@ -887,7 +929,7 @@
   MetricsLog* current_log =
       static_cast<MetricsLog*>(log_manager_.current_log());
   DCHECK(current_log);
-  current_log->RecordEnvironmentProto(plugins_);
+  current_log->RecordEnvironmentProto(plugins_, google_update_metrics_);
   current_log->RecordIncrementalStabilityElements(plugins_);
   RecordCurrentHistograms();
 
@@ -1064,7 +1106,8 @@
 
   DCHECK(initial_log_.get());
   initial_log_->set_hardware_class(hardware_class_);
-  initial_log_->RecordEnvironment(plugins_, profile_dictionary_.get());
+  initial_log_->RecordEnvironment(plugins_, google_update_metrics_,
+                                  profile_dictionary_.get());
 
   // Histograms only get written to the current log, so make the new log current
   // before writing them.
diff --git a/chrome/browser/metrics/metrics_service.h b/chrome/browser/metrics/metrics_service.h
index 00966e7..82c89cf 100644
--- a/chrome/browser/metrics/metrics_service.h
+++ b/chrome/browser/metrics/metrics_service.h
@@ -18,8 +18,10 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/process_util.h"
+#include "chrome/browser/metrics/metrics_log.h"
 #include "chrome/browser/metrics/tracking_synchronizer_observer.h"
 #include "chrome/common/metrics/metrics_service_base.h"
+#include "chrome/installer/util/google_update_settings.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/common/url_fetcher_delegate.h"
@@ -30,7 +32,6 @@
 
 class BookmarkModel;
 class BookmarkNode;
-class MetricsLog;
 class MetricsReportingScheduler;
 class PrefService;
 class Profile;
@@ -167,10 +168,20 @@
   void OnInitTaskGotHardwareClass(const std::string& hardware_class);
 
   // Callback from PluginService::GetPlugins() that continues the init task by
-  // loading profiler data.
+  // launching a task to gather Google Update statistics.
   void OnInitTaskGotPluginInfo(
       const std::vector<webkit::WebPluginInfo>& plugins);
 
+  // Task launched by OnInitTaskGotPluginInfo() that continues the init task by
+  // loading Google Update statistics.  Called on a blocking pool thread.
+  static void InitTaskGetGoogleUpdateData(base::WeakPtr<MetricsService> self,
+                                          base::MessageLoopProxy* target_loop);
+
+  // Callback from InitTaskGetGoogleUpdateData() that continues the init task by
+  // loading profiler data.
+  void OnInitTaskGotGoogleUpdateData(
+      const GoogleUpdateMetrics& google_update_metrics);
+
   // TrackingSynchronizerObserver:
   virtual void ReceivedProfilerData(
       const tracked_objects::ProcessDataSnapshot& process_data,
@@ -359,6 +370,9 @@
   // The list of plugins which was retrieved on the file thread.
   std::vector<webkit::WebPluginInfo> plugins_;
 
+  // Google Update statistics, which were retrieved on a blocking pool thread.
+  GoogleUpdateMetrics google_update_metrics_;
+
   // The initial log, used to record startup metrics.
   scoped_ptr<MetricsLog> initial_log_;
 
diff --git a/chrome/common/metrics/proto/system_profile.proto b/chrome/common/metrics/proto/system_profile.proto
index 12d6960..2dd5159 100644
--- a/chrome/common/metrics/proto/system_profile.proto
+++ b/chrome/common/metrics/proto/system_profile.proto
@@ -11,7 +11,7 @@
 
 package metrics;
 
-// Next tag: 11
+// Next tag: 12
 message SystemProfileProto {
   // The time when the client was compiled/linked, in seconds since the epoch.
   optional int64 build_timestamp = 1;
@@ -126,6 +126,55 @@
   }
   optional Hardware hardware = 6;
 
+  // Information on the Google Update install that is managing this client.
+  message GoogleUpdate {
+    // Whether the Google Update install is system-level or user-level.
+    optional bool is_system_install = 1;
+
+    // The date at which Google Update last started performing an automatic
+    // update check, in seconds since the Unix epoch.
+    optional int64 last_automatic_start_timestamp = 2;
+
+    // The date at which Google Update last successfully sent an update check
+    // and recieved an intact response from the server, in seconds since the
+    // Unix epoch. (The updates don't need to be successfully installed.)
+    optional int64 last_update_check_timestamp = 3;
+
+    // Describes a product being managed by Google Update. (This can also
+    // describe Google Update itself.)
+    message ProductInfo {
+      // The current version of the product that is installed.
+      optional string version = 1;
+
+      // The date at which Google Update successfully updated this product,
+      // stored in seconds since the Unix epoch.  This is updated when an update
+      // is successfully applied, or if the server reports that no update
+      // is available.
+      optional int64 last_update_success_timestamp = 2;
+
+      // The result reported by the product updater on its last run.
+      enum InstallResult {
+        INSTALL_RESULT_SUCCESS = 0;
+        INSTALL_RESULT_FAILED_CUSTOM_ERROR = 1;
+        INSTALL_RESULT_FAILED_MSI_ERROR = 2;
+        INSTALL_RESULT_FAILED_SYSTEM_ERROR = 3;
+        INSTALL_RESULT_EXIT_CODE = 4;
+      }
+      optional InstallResult last_result = 3;
+
+      // The error code reported by the product updater on its last run.  This
+      // will typically be a error code specific to the product installer.
+      optional int32 last_error = 4;
+
+      // The extra error code reported by the product updater on its last run.
+      // This will typically be a Win32 error code.
+      optional int32 last_extra_error = 5;
+    }
+    optional ProductInfo google_update_status = 4;
+    optional ProductInfo client_status = 5;
+  }
+  optional GoogleUpdate google_update = 11;
+
   // Information on all installed plugins.
   message Plugin {
     // The plugin's self-reported name and filename (without path).
diff --git a/chrome/installer/util/google_update_constants.cc b/chrome/installer/util/google_update_constants.cc
index 761cb61..7c3c0e5 100644
--- a/chrome/installer/util/google_update_constants.cc
+++ b/chrome/installer/util/google_update_constants.cc
@@ -7,11 +7,13 @@
 namespace google_update {
 
 const wchar_t kChromeUpgradeCode[] = L"{8A69D345-D564-463C-AFF1-A69D9E530F96}";
+const wchar_t kGoogleUpdateUpgradeCode[] =
+    L"{430FD4D0-B729-4F61-AA34-91526481799D}";
 
 const wchar_t kRegPathClients[] = L"Software\\Google\\Update\\Clients";
 const wchar_t kRegPathClientState[] = L"Software\\Google\\Update\\ClientState";
-const wchar_t kRegPathClientStateMedium[]
-    = L"Software\\Google\\Update\\ClientStateMedium";
+const wchar_t kRegPathClientStateMedium[] =
+    L"Software\\Google\\Update\\ClientStateMedium";
 const wchar_t kRegPathGoogleUpdate[] = L"Software\\Google\\Update";
 
 const wchar_t kRegCommandsKey[] = L"Commands";
@@ -29,7 +31,12 @@
 const wchar_t kRegDidRunField[] = L"dr";
 const wchar_t kRegEULAAceptedField[] = L"eulaaccepted";
 const wchar_t kRegLangField[] = L"lang";
+const wchar_t kRegLastStartedAUField[] = L"LastStartedAU";
 const wchar_t kRegLastCheckedField[] = L"LastChecked";
+const wchar_t kRegLastCheckSuccessField[] = L"LastCheckSuccess";
+const wchar_t kRegLastInstallerResultField[] = L"LastInstallerResult";
+const wchar_t kRegLastInstallerErrorField[] = L"LastInstallerError";
+const wchar_t kRegLastInstallerExtraField[] = L"LastInstallerExtraCode1";
 const wchar_t kRegLastRunTimeField[] = L"lastrun";
 const wchar_t kRegMetricsId[] = L"metricsid";
 const wchar_t kRegMSIField[] = L"msi";
diff --git a/chrome/installer/util/google_update_constants.h b/chrome/installer/util/google_update_constants.h
index e7fc369..0bd945e 100644
--- a/chrome/installer/util/google_update_constants.h
+++ b/chrome/installer/util/google_update_constants.h
@@ -12,6 +12,8 @@
 
 // The GUID Google Update uses to keep track of Chrome upgrades.
 extern const wchar_t kChromeUpgradeCode[];
+// The GUID Google Update uses to keep track of Google Update self-upgrades.
+extern const wchar_t kGoogleUpdateUpgradeCode[];
 
 extern const wchar_t kRegPathClients[];
 
@@ -41,7 +43,12 @@
 extern const wchar_t kRegDidRunField[];
 extern const wchar_t kRegEULAAceptedField[];
 extern const wchar_t kRegLangField[];
+extern const wchar_t kRegLastStartedAUField[];
 extern const wchar_t kRegLastCheckedField[];
+extern const wchar_t kRegLastCheckSuccessField[];
+extern const wchar_t kRegLastInstallerResultField[];
+extern const wchar_t kRegLastInstallerErrorField[];
+extern const wchar_t kRegLastInstallerExtraField[];
 extern const wchar_t kRegMetricsId[];
 extern const wchar_t kRegMSIField[];
 extern const wchar_t kRegNameField[];
diff --git a/chrome/installer/util/google_update_settings.cc b/chrome/installer/util/google_update_settings.cc
index 2eef925..7671565a 100644
--- a/chrome/installer/util/google_update_settings.cc
+++ b/chrome/installer/util/google_update_settings.cc
@@ -548,3 +548,102 @@
 
   return cmd_line;
 }
+
+base::Time GoogleUpdateSettings::GetGoogleUpdateLastStartedAU(
+    bool system_install) {
+  const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+  RegKey update_key;
+
+  if (update_key.Open(root_key, google_update::kRegPathGoogleUpdate,
+                      KEY_QUERY_VALUE) == ERROR_SUCCESS) {
+    DWORD last_start;
+    if (update_key.ReadValueDW(google_update::kRegLastStartedAUField,
+                               &last_start) == ERROR_SUCCESS) {
+      return base::Time::FromTimeT(last_start);
+    }
+  }
+
+  return base::Time();
+}
+
+base::Time GoogleUpdateSettings::GetGoogleUpdateLastChecked(
+    bool system_install) {
+  const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+  RegKey update_key;
+
+  if (update_key.Open(root_key, google_update::kRegPathGoogleUpdate,
+                      KEY_QUERY_VALUE) == ERROR_SUCCESS) {
+    DWORD last_check;
+    if (update_key.ReadValueDW(google_update::kRegLastCheckedField,
+                               &last_check) == ERROR_SUCCESS) {
+      return base::Time::FromTimeT(last_check);
+    }
+  }
+
+  return base::Time();
+}
+
+bool GoogleUpdateSettings::GetUpdateDetailForApp(bool system_install,
+                                                 const wchar_t* app_guid,
+                                                 ProductData* data) {
+  DCHECK(app_guid);
+  DCHECK(data);
+
+  bool product_found = false;
+
+  const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+  string16 clientstate_reg_path(google_update::kRegPathClientState);
+  clientstate_reg_path.append(L"\\");
+  clientstate_reg_path.append(app_guid);
+
+  RegKey clientstate;
+  if (clientstate.Open(root_key, clientstate_reg_path.c_str(),
+                       KEY_QUERY_VALUE) == ERROR_SUCCESS) {
+    string16 version;
+    DWORD dword_value;
+    if ((clientstate.ReadValueDW(google_update::kRegLastCheckSuccessField,
+                                 &dword_value) == ERROR_SUCCESS) &&
+        (clientstate.ReadValue(google_update::kRegVersionField,
+                               &version) == ERROR_SUCCESS)) {
+      product_found = true;
+      data->version = WideToASCII(version);
+      data->last_success = base::Time::FromTimeT(dword_value);
+      data->last_result = 0;
+      data->last_error_code = 0;
+      data->last_extra_code = 0;
+
+      if (clientstate.ReadValueDW(google_update::kRegLastInstallerResultField,
+                                  &dword_value) == ERROR_SUCCESS) {
+        // Google Update convention is that if an installer writes an result
+        // code that is invalid, it is clamped to an exit code result.
+        const DWORD kMaxValidInstallResult = 4;  // INSTALLER_RESULT_EXIT_CODE
+        data->last_result = std::min(dword_value, kMaxValidInstallResult);
+      }
+      if (clientstate.ReadValueDW(google_update::kRegLastInstallerErrorField,
+                                  &dword_value) == ERROR_SUCCESS) {
+        data->last_error_code = dword_value;
+      }
+      if (clientstate.ReadValueDW(google_update::kRegLastInstallerExtraField,
+                                  &dword_value) == ERROR_SUCCESS) {
+        data->last_extra_code = dword_value;
+      }
+    }
+  }
+
+  return product_found;
+}
+
+bool GoogleUpdateSettings::GetUpdateDetailForGoogleUpdate(bool system_install,
+                                                          ProductData* data) {
+  return GetUpdateDetailForApp(system_install,
+                               google_update::kGoogleUpdateUpgradeCode,
+                               data);
+}
+
+bool GoogleUpdateSettings::GetUpdateDetail(bool system_install,
+                                           ProductData* data) {
+  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+  return GetUpdateDetailForApp(system_install,
+                               dist->GetAppGuid().c_str(),
+                               data);
+}
diff --git a/chrome/installer/util/google_update_settings.h b/chrome/installer/util/google_update_settings.h
index 2485502..d7d0288 100644
--- a/chrome/installer/util/google_update_settings.h
+++ b/chrome/installer/util/google_update_settings.h
@@ -10,6 +10,7 @@
 
 #include "base/basictypes.h"
 #include "base/string16.h"
+#include "base/time.h"
 #include "chrome/installer/util/util_constants.h"
 
 class BrowserDistribution;
@@ -31,6 +32,25 @@
     MANUAL_UPDATES_ONLY = 2,
   };
 
+  // Defines product data that is tracked/used by Google Update.
+  struct ProductData {
+    // The currently installed version.
+    std::string version;
+    // The time that Google Update last updated this product.  (This means
+    // either running an updater successfully, or doing an update check that
+    // results in no update available.)
+    base::Time last_success;
+    // The result reported by the most recent run of an installer/updater.
+    int last_result;
+    // The error code, if any, reported by the most recent run of an
+    // installer or updater.  This is typically platform independent.
+    int last_error_code;
+    // The extra error code, if any, reported by the most recent run of
+    // an installer or updater.  This is typically an error code specific
+    // to the platform -- i.e. on Windows, it will be a Win32 HRESULT.
+    int last_extra_code;
+  };
+
   // Returns true if this install is system-wide, false if it is per-user.
   static bool IsSystemInstall();
 
@@ -200,6 +220,31 @@
   // is found.
   static string16 GetUninstallCommandLine(bool system_install);
 
+  // Returns the time at which Google Update last started an automatic update
+  // check, or the null time if this information isn't available.
+  static base::Time GetGoogleUpdateLastStartedAU(bool system_install);
+
+  // Returns the time at which Google Update last successfully contacted Google
+  // servers and got a valid check response, or the null time if this
+  // information isn't available.
+  static base::Time GetGoogleUpdateLastChecked(bool system_install);
+
+  // Returns detailed update data for a product being managed by Google Update.
+  // Returns true if the |version| and |last_updated| fields in |data|
+  // are modified.  The other items are considered optional.
+  static bool GetUpdateDetailForApp(bool system_install,
+                                    const wchar_t* app_guid,
+                                    ProductData* data);
+
+  // Returns product data for Google Update.  (Equivalent to calling
+  // GetUpdateDetailForAppGuid with the app guid for Google Update itself.)
+  static bool GetUpdateDetailForGoogleUpdate(bool system_install,
+                                             ProductData* data);
+
+  // Returns product data for the current product. (Equivalent to calling
+  // GetUpdateDetailForApp with the app guid stored in BrowserDistribution.)
+  static bool GetUpdateDetail(bool system_install, ProductData* data);
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(GoogleUpdateSettings);
 };