summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/metrics/metrics_service.cc57
-rw-r--r--chrome/browser/metrics/metrics_service.h4
-rw-r--r--chrome/common/pref_names.cc12
-rw-r--r--chrome/common/pref_names.h7
-rw-r--r--chrome/common/pref_service.cc47
-rw-r--r--chrome/common/pref_service.h7
-rw-r--r--chrome/common/pref_service_unittest.cc8
-rw-r--r--chrome/installer/setup/uninstall.cc35
-rw-r--r--chrome/installer/util/browser_distribution.cc2
-rw-r--r--chrome/installer/util/browser_distribution.h3
-rw-r--r--chrome/installer/util/google_chrome_distribution.cc99
-rw-r--r--chrome/installer/util/google_chrome_distribution.h30
-rw-r--r--chrome/installer/util/google_chrome_distribution_unittest.cc49
-rw-r--r--chrome/installer/util/util.vcproj8
-rw-r--r--chrome/installer/util/util_constants.cc4
-rw-r--r--chrome/installer/util/util_constants.h2
-rw-r--r--chrome/test/data/pref_service/write.golden.json3
17 files changed, 339 insertions, 38 deletions
diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc
index e081bd9..220102f 100644
--- a/chrome/browser/metrics/metrics_service.cc
+++ b/chrome/browser/metrics/metrics_service.cc
@@ -303,10 +303,10 @@ class MetricsService::GetPluginListTask : public Task {
void MetricsService::RegisterPrefs(PrefService* local_state) {
DCHECK(IsSingleThreaded());
local_state->RegisterStringPref(prefs::kMetricsClientID, L"");
- local_state->RegisterStringPref(prefs::kMetricsClientIDTimestamp, L"0");
- local_state->RegisterStringPref(prefs::kStabilityLaunchTimeSec, L"0");
- local_state->RegisterStringPref(prefs::kStabilityLastTimestampSec, L"0");
- local_state->RegisterStringPref(prefs::kStabilityUptimeSec, L"0");
+ local_state->RegisterInt64Pref(prefs::kMetricsClientIDTimestamp, 0);
+ local_state->RegisterInt64Pref(prefs::kStabilityLaunchTimeSec, 0);
+ local_state->RegisterInt64Pref(prefs::kStabilityLastTimestampSec, 0);
+ local_state->RegisterInt64Pref(prefs::kStabilityUptimeSec, 0);
local_state->RegisterStringPref(prefs::kStabilityStatsVersion, L"");
local_state->RegisterBooleanPref(prefs::kStabilityExitedCleanly, true);
local_state->RegisterBooleanPref(prefs::kStabilitySessionEndCompleted, true);
@@ -336,6 +336,12 @@ void MetricsService::RegisterPrefs(PrefService* local_state) {
local_state->RegisterIntegerPref(prefs::kNumKeywords, 0);
local_state->RegisterListPref(prefs::kMetricsInitialLogs);
local_state->RegisterListPref(prefs::kMetricsOngoingLogs);
+
+ local_state->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount, 0);
+ local_state->RegisterInt64Pref(prefs::kUninstallLaunchCount, 0);
+ local_state->RegisterInt64Pref(prefs::kUninstallMetricsUptimeSec, 0);
+ local_state->RegisterInt64Pref(prefs::kUninstallLastLaunchTimeSec, 0);
+ local_state->RegisterInt64Pref(prefs::kUninstallLastObservedRunTimeSec, 0);
}
// static
@@ -592,8 +598,7 @@ void MetricsService::InitializeMetricsState() {
pref->SetString(prefs::kMetricsClientID, UTF8ToWide(client_id_));
// Might as well make a note of how long this ID has existed
- pref->SetString(prefs::kMetricsClientIDTimestamp,
- Int64ToWString(Time::Now().ToTimeT()));
+ pref->SetInt64(prefs::kMetricsClientIDTimestamp, Time::Now().ToTimeT());
}
// Update session ID
@@ -617,20 +622,29 @@ void MetricsService::InitializeMetricsState() {
// This is marked false when we get a WM_ENDSESSION.
pref->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
- int64 last_start_time = StringToInt64(
- WideToUTF16Hack(pref->GetString(prefs::kStabilityLaunchTimeSec)));
- int64 last_end_time = StringToInt64(
- WideToUTF16Hack(pref->GetString(prefs::kStabilityLastTimestampSec)));
- int64 uptime = StringToInt64(
- WideToUTF16Hack(pref->GetString(prefs::kStabilityUptimeSec)));
+ int64 last_start_time = pref->GetInt64(prefs::kStabilityLaunchTimeSec);
+ int64 last_end_time = pref->GetInt64(prefs::kStabilityLastTimestampSec);
+ int64 uptime = pref->GetInt64(prefs::kStabilityUptimeSec);
+
+ // Same idea as uptime, except this one never gets reset and is used at
+ // uninstallation.
+ int64 uninstall_metrics_uptime =
+ pref->GetInt64(prefs::kUninstallMetricsUptimeSec);
if (last_start_time && last_end_time) {
// TODO(JAR): Exclude sleep time. ... which must be gathered in UI loop.
- uptime += last_end_time - last_start_time;
- pref->SetString(prefs::kStabilityUptimeSec, Int64ToWString(uptime));
+ int64 uptime_increment = last_end_time - last_start_time;
+ uptime += uptime_increment;
+ pref->SetInt64(prefs::kStabilityUptimeSec, uptime);
+
+ uninstall_metrics_uptime += uptime_increment;
+ pref->SetInt64(prefs::kUninstallMetricsUptimeSec,
+ uninstall_metrics_uptime);
}
- pref->SetString(prefs::kStabilityLaunchTimeSec,
- Int64ToWString(Time::Now().ToTimeT()));
+ pref->SetInt64(prefs::kStabilityLaunchTimeSec, Time::Now().ToTimeT());
+
+ // Bookkeeping for the uninstall metrics.
+ IncrementLongPrefsValue(prefs::kUninstallLaunchCount);
// Save profile metrics.
PrefService* prefs = g_browser_process->local_state();
@@ -1562,8 +1576,16 @@ void MetricsService::IncrementPrefValue(const wchar_t* path) {
pref->SetInteger(path, value + 1);
}
+void MetricsService::IncrementLongPrefsValue(const wchar_t* path) {
+ PrefService* pref = g_browser_process->local_state();
+ DCHECK(pref);
+ int64 value = pref->GetInt64(path);
+ pref->SetInt64(path, value+1);
+}
+
void MetricsService::LogLoadStarted() {
IncrementPrefValue(prefs::kStabilityPageLoadCount);
+ IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount);
// We need to save the prefs, as page load count is a critical stat, and it
// might be lost due to a crash :-(.
}
@@ -1750,8 +1772,7 @@ void MetricsService::RecordBooleanPrefValue(const wchar_t* path, bool value) {
}
void MetricsService::RecordCurrentState(PrefService* pref) {
- pref->SetString(prefs::kStabilityLastTimestampSec,
- Int64ToWString(Time::Now().ToTimeT()));
+ pref->SetInt64(prefs::kStabilityLastTimestampSec, Time::Now().ToTimeT());
RecordPluginChanges(pref);
}
diff --git a/chrome/browser/metrics/metrics_service.h b/chrome/browser/metrics/metrics_service.h
index 58c491a..d5fa3c1 100644
--- a/chrome/browser/metrics/metrics_service.h
+++ b/chrome/browser/metrics/metrics_service.h
@@ -303,6 +303,10 @@ class MetricsService : public NotificationObserver,
// Reads, increments and then sets the specified integer preference.
void IncrementPrefValue(const wchar_t* path);
+ // Reads, increments and then sets the specified long preference that is
+ // stored as a string.
+ void IncrementLongPrefsValue(const wchar_t* path);
+
// Records a renderer process crash.
void LogRendererCrash();
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index bda65f9..e120347 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -369,6 +369,18 @@ const wchar_t kStabilityPluginLaunches[] = L"launches";
const wchar_t kStabilityPluginInstances[] = L"instances";
const wchar_t kStabilityPluginCrashes[] = L"crashes";
+// The keys below are strictly increasing counters over the lifetime of
+// a chrome installation. They are (optionally) sent up to the uninstall
+// survey in the event of uninstallation.
+const wchar_t kUninstallMetricsPageLoadCount[] =
+ L"uninstall_metrics.page_load_count";
+const wchar_t kUninstallLaunchCount[] = L"uninstall_metrics.launch_count";
+const wchar_t kUninstallMetricsUptimeSec[] = L"uninstall_metrics.uptime_sec";
+const wchar_t kUninstallLastLaunchTimeSec[] =
+ L"uninstall_metrics.last_launch_time_sec";
+const wchar_t kUninstallLastObservedRunTimeSec[] =
+ L"uninstall_metrics.last_observed_running_time_sec";
+
// If true, the user will be prompted to manually launch renderer processes.
const wchar_t kStartRenderersManually[] = L"renderer.start_manually";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 49367fd..718fb9a 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -123,6 +123,13 @@ extern const wchar_t kStabilityPluginLaunches[];
extern const wchar_t kStabilityPluginInstances[];
extern const wchar_t kStabilityPluginCrashes[];
+extern const wchar_t kUninstallMetricsPageLoadCount[];
+extern const wchar_t kUninstallLaunchCount[];
+
+extern const wchar_t kUninstallMetricsUptimeSec[];
+extern const wchar_t kUninstallLastLaunchTimeSec[];
+extern const wchar_t kUninstallLastObservedRunTimeSec[];
+
extern const wchar_t kStartRenderersManually[];
extern const wchar_t kBrowserWindowPlacement[];
extern const wchar_t kTaskManagerWindowPlacement[];
diff --git a/chrome/common/pref_service.cc b/chrome/common/pref_service.cc
index fd6cef7..b5bbb55 100644
--- a/chrome/common/pref_service.cc
+++ b/chrome/common/pref_service.cc
@@ -610,6 +610,53 @@ void PrefService::SetFilePath(const wchar_t* path, const FilePath& value) {
FireObserversIfChanged(path, old_value.get());
}
+void PrefService::SetInt64(const wchar_t* path, int64 value) {
+ DCHECK(CalledOnValidThread());
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+ DCHECK(false) << "Trying to write an unregistered pref: " << path;
+ return;
+ }
+ if (pref->type() != Value::TYPE_STRING) {
+ DCHECK(false) << "Wrong type for SetInt64: " << path;
+ return;
+ }
+
+ scoped_ptr<Value> old_value(GetPrefCopy(path));
+ bool rv = persistent_->SetString(path, Int64ToWString(value));
+ DCHECK(rv);
+
+ FireObserversIfChanged(path, old_value.get());
+}
+
+int64 PrefService::GetInt64(const wchar_t* path) const {
+ DCHECK(CalledOnValidThread());
+
+ std::wstring result;
+ if (transient_->GetString(path, &result))
+ return StringToInt64(WideToUTF16Hack(result));
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+#if defined(OS_WIN)
+ DCHECK(false) << "Trying to read an unregistered pref: " << path;
+#else
+ // TODO(port): remove this exception
+#endif
+ return StringToInt64(WideToUTF16Hack(result));
+ }
+ bool rv = pref->GetValue()->GetAsString(&result);
+ DCHECK(rv);
+ return StringToInt64(WideToUTF16Hack(result));
+}
+
+void PrefService::RegisterInt64Pref(const wchar_t* path, int64 default_value) {
+ Preference* pref = new Preference(persistent_.get(), path,
+ Value::CreateStringValue(Int64ToWString(default_value)));
+ RegisterPreference(pref);
+}
+
DictionaryValue* PrefService::GetMutableDictionary(const wchar_t* path) {
DCHECK(CalledOnValidThread());
diff --git a/chrome/common/pref_service.h b/chrome/common/pref_service.h
index 0a7690c..f5377d2 100644
--- a/chrome/common/pref_service.h
+++ b/chrome/common/pref_service.h
@@ -156,6 +156,13 @@ class PrefService : public NonThreadSafe {
void SetString(const wchar_t* path, const std::wstring& value);
void SetFilePath(const wchar_t* path, const FilePath& value);
+ // Int64 helper methods that actually store the given value as a string.
+ // Note that if obtaining the named value via GetDictionary or GetList, the
+ // Value type will be TYPE_STRING.
+ void SetInt64(const wchar_t* path, int64 value);
+ int64 GetInt64(const wchar_t* path) const;
+ void RegisterInt64Pref(const wchar_t* path, int64 default_value);
+
// Used to set the value of dictionary or list values in the pref tree. This
// will create a dictionary or list if one does not exist in the pref tree.
// This method returns NULL only if you're requesting an unregistered pref or
diff --git a/chrome/common/pref_service_unittest.cc b/chrome/common/pref_service_unittest.cc
index 2a43e69..e690579a 100644
--- a/chrome/common/pref_service_unittest.cc
+++ b/chrome/common/pref_service_unittest.cc
@@ -16,7 +16,7 @@
namespace {
class PrefServiceTest : public testing::Test {
-protected:
+ protected:
virtual void SetUp() {
// Name a subdirectory of the temp directory.
ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_));
@@ -98,9 +98,11 @@ TEST_F(PrefServiceTest, Basic) {
// Register test prefs.
const wchar_t kNewWindowsInTabs[] = L"tabs.new_windows_in_tabs";
const wchar_t kMaxTabs[] = L"tabs.max_tabs";
+ const wchar_t kLongIntPref[] = L"long_int.pref";
prefs.RegisterStringPref(prefs::kHomePage, L"");
prefs.RegisterBooleanPref(kNewWindowsInTabs, false);
prefs.RegisterIntegerPref(kMaxTabs, 0);
+ prefs.RegisterStringPref(kLongIntPref, L"2147483648");
std::wstring microsoft(L"http://www.microsoft.com");
std::wstring cnn(L"http://www.cnn.com");
@@ -130,6 +132,10 @@ TEST_F(PrefServiceTest, Basic) {
prefs.SetInteger(kMaxTabs, 10);
EXPECT_EQ(10, prefs.GetInteger(kMaxTabs));
+ EXPECT_EQ(2147483648LL, prefs.GetInt64(kLongIntPref));
+ prefs.SetInt64(kLongIntPref, 214748364842LL);
+ EXPECT_EQ(214748364842LL, prefs.GetInt64(kLongIntPref));
+
EXPECT_EQ(FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")),
prefs.GetFilePath(kSomeDirectory).value());
prefs.SetFilePath(kSomeDirectory, some_path);
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
index 69b5a5d..2fb0815 100644
--- a/chrome/installer/setup/uninstall.cc
+++ b/chrome/installer/setup/uninstall.cc
@@ -11,6 +11,8 @@
#include "base/registry.h"
#include "base/string_util.h"
#include "chrome/common/result_codes.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths_internal.h"
#include "chrome/installer/setup/setup.h"
#include "chrome/installer/setup/setup_constants.h"
#include "chrome/installer/util/browser_distribution.h"
@@ -45,7 +47,8 @@ void CloseAllChromeProcesses() {
}
// If asking politely didn't work, wait for 15 seconds and then kill all
- // chrome.exe. This check is just in case Chrome is ignoring WM_CLOSE messages.
+ // chrome.exe. This check is just in case Chrome is ignoring WM_CLOSE
+ // messages.
base::CleanupProcesses(installer_util::kChromeExe, 15000,
ResultCodes::HUNG, NULL);
}
@@ -83,15 +86,17 @@ void DeleteChromeShortcut(bool system_uninstall) {
// installation folder, in all other cases it returns true even in case
// of error (only logs the error).
bool DeleteFilesAndFolders(const std::wstring& exe_path, bool system_uninstall,
- const installer::Version& installed_version) {
+ const installer::Version& installed_version,
+ std::wstring* local_state_path) {
std::wstring install_path(installer::GetChromeInstallPath(system_uninstall));
if (install_path.empty()) {
LOG(ERROR) << "Could not get installation destination path.";
- return false; // Nothing else we can do for uninstall, so we return.
+ return false; // Nothing else we can do for uninstall, so we return.
} else {
LOG(INFO) << "install destination path: " << install_path;
}
+ // Move setup.exe to the temp path.
std::wstring setup_exe(installer::GetInstallerPathUnderChrome(
install_path, installed_version.GetString()));
file_util::AppendToPath(&setup_exe, file_util::GetFilenameFromPath(exe_path));
@@ -100,6 +105,16 @@ bool DeleteFilesAndFolders(const std::wstring& exe_path, bool system_uninstall,
file_util::CreateTemporaryFileName(&temp_file);
file_util::Move(setup_exe, temp_file);
+ // Move the browser's persisted local state
+ FilePath user_local_state;
+ if (chrome::GetDefaultUserDataDirectory(&user_local_state)) {
+ std::wstring user_local_file(
+ user_local_state.Append(chrome::kLocalStateFilename).value());
+
+ file_util::CreateTemporaryFileName(local_state_path);
+ file_util::CopyFile(user_local_file, *local_state_path);
+ }
+
LOG(INFO) << "Deleting install path " << install_path;
if (!file_util::Delete(install_path, true)) {
LOG(ERROR) << "Failed to delete folder (1st try): " << install_path;
@@ -269,13 +284,21 @@ installer_util::InstallStatus installer_setup::UninstallChrome(
}
// Finally delete all the files from Chrome folder after moving setup.exe
- // to a temp location.
- if (!DeleteFilesAndFolders(exe_path, system_uninstall, installed_version))
+ // and the user's Local State to a temp location.
+ std::wstring local_state_path;
+ if (!DeleteFilesAndFolders(exe_path, system_uninstall, installed_version,
+ &local_state_path))
return installer_util::UNINSTALL_FAILED;
if (!force_uninstall) {
LOG(INFO) << "Uninstallation complete. Launching Uninstall survey.";
- dist->DoPostUninstallOperations(installed_version);
+ dist->DoPostUninstallOperations(installed_version, local_state_path);
}
+
+ // Try and delete the preserved local state once the post-install
+ // operations are complete.
+ if (!local_state_path.empty())
+ file_util::Delete(local_state_path, false);
+
return installer_util::UNINSTALL_SUCCESSFUL;
}
diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc
index 64a5ef3..4d52c8c 100644
--- a/chrome/installer/util/browser_distribution.cc
+++ b/chrome/installer/util/browser_distribution.cc
@@ -23,7 +23,7 @@ BrowserDistribution* BrowserDistribution::GetDistribution() {
}
void BrowserDistribution::DoPostUninstallOperations(
- const installer::Version& version) {
+ const installer::Version& version, const std::wstring& local_data_path) {
}
std::wstring BrowserDistribution::GetApplicationName() {
diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h
index 3ce15da..f48dcd8 100644
--- a/chrome/installer/util/browser_distribution.h
+++ b/chrome/installer/util/browser_distribution.h
@@ -17,7 +17,8 @@ class BrowserDistribution {
static BrowserDistribution* GetDistribution();
- virtual void DoPostUninstallOperations(const installer::Version& version);
+ virtual void DoPostUninstallOperations(const installer::Version& version,
+ const std::wstring& local_data_path);
virtual std::wstring GetApplicationName();
diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc
index d477623..d70bcd2 100644
--- a/chrome/installer/util/google_chrome_distribution.cc
+++ b/chrome/installer/util/google_chrome_distribution.cc
@@ -16,9 +16,12 @@
#include "base/registry.h"
#include "base/string_util.h"
#include "base/wmi_util.h"
+#include "chrome/common/json_value_serializer.h"
+#include "chrome/common/pref_names.h"
#include "chrome/installer/util/l10n_string_util.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/google_update_settings.h"
+#include "chrome/installer/util/util_constants.h"
#include "installer_util_strings.h"
@@ -27,7 +30,8 @@ namespace {
// Google Update tells us is the locale. In case we fail to find
// the locale, we use US English.
std::wstring GetUninstallSurveyUrl() {
- std::wstring kSurveyUrl = L"http://www.google.com/support/chrome/bin/request.py?hl=$1&contact_type=uninstall";
+ std::wstring kSurveyUrl = L"http://www.google.com/support/chrome/bin/"
+ L"request.py?hl=$1&contact_type=uninstall";
std::wstring language;
if (!GoogleUpdateSettings::GetLanguage(&language))
@@ -37,8 +41,85 @@ std::wstring GetUninstallSurveyUrl() {
}
}
+bool GoogleChromeDistribution::BuildUninstallMetricsString(
+ DictionaryValue* uninstall_metrics_dict, std::wstring* metrics) {
+ DCHECK(NULL != metrics);
+ bool has_values = false;
+
+ DictionaryValue::key_iterator iter(uninstall_metrics_dict->begin_keys());
+ for (; iter != uninstall_metrics_dict->end_keys(); ++iter) {
+ has_values = true;
+ metrics->append(L"&");
+ metrics->append(*iter);
+ metrics->append(L"=");
+
+ std::wstring value;
+ uninstall_metrics_dict->GetString(*iter, &value);
+ metrics->append(value);
+ }
+
+ return has_values;
+}
+
+bool GoogleChromeDistribution::ExtractUninstallMetricsFromFile(
+ const std::wstring& file_path, std::wstring* uninstall_metrics_string) {
+
+ JSONFileValueSerializer json_serializer(file_path);
+
+ std::string json_error_string;
+ scoped_ptr<Value> root(json_serializer.Deserialize(NULL));
+
+ // Preferences should always have a dictionary root.
+ if (!root->IsType(Value::TYPE_DICTIONARY))
+ return false;
+
+ return ExtractUninstallMetrics(*static_cast<DictionaryValue*>(root.get()),
+ uninstall_metrics_string);
+}
+
+bool GoogleChromeDistribution::ExtractUninstallMetrics(
+ const DictionaryValue& root, std::wstring* uninstall_metrics_string) {
+ // Make sure that the user wants us reporting metrics. If not, don't
+ // add our uninstall metrics.
+ bool metrics_reporting_enabled = false;
+ if (!root.GetBoolean(prefs::kMetricsReportingEnabled,
+ &metrics_reporting_enabled) ||
+ !metrics_reporting_enabled) {
+ return false;
+ }
+
+ DictionaryValue* uninstall_metrics_dict;
+ if (!root.HasKey(installer_util::kUninstallMetricsName) ||
+ !root.GetDictionary(installer_util::kUninstallMetricsName,
+ &uninstall_metrics_dict)) {
+ return false;
+ }
+
+ if (!BuildUninstallMetricsString(uninstall_metrics_dict,
+ uninstall_metrics_string)) {
+ return false;
+ }
+
+ // We use the creation date of the metric's client id as the installation
+ // date, as this is fairly close to the first-run date for those who
+ // opt-in to metrics from the get-go. Slightly more accurate would be to
+ // have setup.exe write something somewhere at installation time.
+ // As is, the absence of this field implies that the browser was never
+ // run with an opt-in to metrics selection.
+ std::wstring installation_date;
+ if (root.GetString(prefs::kMetricsClientIDTimestamp, &installation_date)) {
+ uninstall_metrics_string->append(L"&");
+ uninstall_metrics_string->append(
+ installer_util::kUninstallInstallationDate);
+ uninstall_metrics_string->append(L"=");
+ uninstall_metrics_string->append(installation_date);
+ }
+
+ return true;
+}
+
void GoogleChromeDistribution::DoPostUninstallOperations(
- const installer::Version& version) {
+ const installer::Version& version, const std::wstring& local_data_path) {
// Send the Chrome version and OS version as params to the form.
// It would be nice to send the locale, too, but I don't see an
// easy way to get that in the existing code. It's something we
@@ -67,6 +148,12 @@ void GoogleChromeDistribution::DoPostUninstallOperations(
std::wstring command = iexplore + L" " + GetUninstallSurveyUrl() + L"&" +
kVersionParam + L"=" + kVersion + L"&" + kOSParam + L"=" + os_version;
+
+ std::wstring uninstall_metrics;
+ if (ExtractUninstallMetricsFromFile(local_data_path, &uninstall_metrics)) {
+ command += uninstall_metrics;
+ }
+
int pid = 0;
WMIProcessUtil::Launch(command, &pid);
}
@@ -81,8 +168,9 @@ std::wstring GoogleChromeDistribution::GetInstallSubDir() {
return L"Google\\Chrome";
}
-std::wstring GoogleChromeDistribution::GetNewGoogleUpdateApKey(bool diff_install,
- installer_util::InstallStatus status, const std::wstring& value) {
+std::wstring GoogleChromeDistribution::GetNewGoogleUpdateApKey(
+ bool diff_install, installer_util::InstallStatus status,
+ const std::wstring& value) {
// Magic suffix that we need to add or remove to "ap" key value.
const std::wstring kMagicSuffix = L"-full";
@@ -171,7 +259,7 @@ void GoogleChromeDistribution::UpdateDiffInstallStatus(bool system_install,
std::wstring reg_key(google_update::kRegPathClientState);
reg_key.append(L"\\");
reg_key.append(google_update::kChromeGuid);
- if (!key.Open(reg_root, reg_key.c_str(), KEY_ALL_ACCESS) ||
+ if (!key.Open(reg_root, reg_key.c_str(), KEY_ALL_ACCESS) ||
!key.ReadValue(google_update::kRegApField, &ap_key_value)) {
LOG(INFO) << "Application key not found.";
if (!incremental_install || !GetInstallReturnCode(install_status)) {
@@ -198,4 +286,3 @@ void GoogleChromeDistribution::UpdateDiffInstallStatus(bool system_install,
}
key.Close();
}
-
diff --git a/chrome/installer/util/google_chrome_distribution.h b/chrome/installer/util/google_chrome_distribution.h
index 69227d4..f0bc8bd 100644
--- a/chrome/installer/util/google_chrome_distribution.h
+++ b/chrome/installer/util/google_chrome_distribution.h
@@ -11,9 +11,14 @@
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/util_constants.h"
+#include "testing/gtest/include/gtest/gtest_prod.h" // for FRIEND_TEST
+
+class DictionaryValue;
+
class GoogleChromeDistribution : public BrowserDistribution {
public:
- virtual void DoPostUninstallOperations(const installer::Version& version);
+ virtual void DoPostUninstallOperations(const installer::Version& version,
+ const std::wstring& local_data_path);
virtual std::wstring GetApplicationName();
@@ -54,7 +59,28 @@ class GoogleChromeDistribution : public BrowserDistribution {
private:
friend class BrowserDistribution;
-
+ FRIEND_TEST(GoogleChromeDistributionTest, TestExtractUninstallMetrics);
+
+ // Extracts uninstall metrics from the JSON file located at file_path.
+ // Returns them in a form suitable for appending to a url that already
+ // has GET parameters, i.e. &metric1=foo&metric2=bar.
+ // Returns true if uninstall_metrics has been successfully populated with
+ // the uninstall metrics, false otherwise.
+ virtual bool ExtractUninstallMetricsFromFile(
+ const std::wstring& file_path, std::wstring* uninstall_metrics);
+
+ // Extracts uninstall metrics from the given JSON value.
+ virtual bool ExtractUninstallMetrics(const DictionaryValue& root,
+ std::wstring* uninstall_metrics);
+
+ // Given a DictionaryValue containing a set of uninstall metrics,
+ // this builds a URL parameter list of all the contained metrics.
+ // Returns true if at least one uninstall metric was found in
+ // uninstall_metrics_dict, false otherwise.
+ virtual bool BuildUninstallMetricsString(
+ DictionaryValue* uninstall_metrics_dict, std::wstring* metrics);
+
+ // Disallow construction from non-friends.
GoogleChromeDistribution() {}
};
diff --git a/chrome/installer/util/google_chrome_distribution_unittest.cc b/chrome/installer/util/google_chrome_distribution_unittest.cc
index 063377a..de437f4 100644
--- a/chrome/installer/util/google_chrome_distribution_unittest.cc
+++ b/chrome/installer/util/google_chrome_distribution_unittest.cc
@@ -9,6 +9,7 @@
#include "base/registry.h"
#include "base/scoped_ptr.h"
#include "base/file_util.h"
+#include "chrome/common/json_value_serializer.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/google_chrome_distribution.h"
@@ -28,7 +29,7 @@ class GoogleChromeDistributionTest : public testing::Test {
}
// Creates "ap" key with the value given as parameter. Also adds work
- // items to work_item_list given so that they can be rollbed back later.
+ // items to work_item_list given so that they can be rolled back later.
bool CreateApKey(WorkItemList* work_item_list, std::wstring value) {
HKEY reg_root = HKEY_CURRENT_USER;
std::wstring reg_key = GetApKeyPath();
@@ -155,7 +156,7 @@ TEST_F(GoogleChromeDistributionTest, UpdateDiffInstallStatusTest) {
HKEY reg_root = HKEY_CURRENT_USER;
bool ap_key_deleted = false;
RegKey key;
- if (!key.Open(HKEY_CURRENT_USER, reg_key.c_str(), KEY_ALL_ACCESS)){
+ if (!key.Open(HKEY_CURRENT_USER, reg_key.c_str(), KEY_ALL_ACCESS)) {
work_item_list->AddCreateRegKeyWorkItem(reg_root, reg_key);
if (!work_item_list->Do())
FAIL() << "Failed to create ClientState key.";
@@ -180,8 +181,52 @@ TEST_F(GoogleChromeDistributionTest, UpdateDiffInstallStatusTest) {
if (!CreateApKey(work_item_list.get(), ap_key_value))
FAIL() << "Failed to restore ap key.";
}
+}
+
+TEST_F(GoogleChromeDistributionTest, TestExtractUninstallMetrics) {
+ // A make-believe JSON preferences file.
+ std::string pref_string(
+ "{ \n"
+ " \"foo\": \"bar\",\n"
+ " \"uninstall_metrics\": { \n"
+ " \"last_launch_time_sec\": \"1235341118\","
+ " \"last_observed_running_time_sec\": \"1235341183\","
+ " \"launch_count\": \"11\","
+ " \"page_load_count\": \"68\","
+ " \"uptime_sec\": \"809\"\n"
+ " },\n"
+ " \"blah\": {\n"
+ " \"this_sentence_is_true\": false\n"
+ " },\n"
+ " \"user_experience_metrics\": { \n"
+ " \"client_id_timestamp\": \"1234567890\","
+ " \"reporting_enabled\": true\n"
+ " }\n"
+ "} \n");
+
+ // The URL string we expect to be generated from said make-believe file.
+ std::wstring expected_url_string(
+ L"&last_launch_time_sec=1235341118"
+ L"&last_observed_running_time_sec=1235341183"
+ L"&launch_count=11&page_load_count=68&uptime_sec=809&");
+ expected_url_string += installer_util::kUninstallInstallationDate;
+ expected_url_string += L"=1234567890";
+
+ JSONStringValueSerializer json_deserializer(pref_string);
+ std::string error_message;
+ scoped_ptr<Value> root(json_deserializer.Deserialize(&error_message));
+ ASSERT_TRUE(root.get());
+
+ std::wstring uninstall_metrics_string;
+ GoogleChromeDistribution* dist = static_cast<GoogleChromeDistribution*>(
+ BrowserDistribution::GetDistribution());
+ EXPECT_TRUE(
+ dist->ExtractUninstallMetrics(*static_cast<DictionaryValue*>(root.get()),
+ &uninstall_metrics_string));
+ EXPECT_EQ(expected_url_string, uninstall_metrics_string);
}
+
#endif
TEST(MasterPreferences, ParseDistroParams) {
diff --git a/chrome/installer/util/util.vcproj b/chrome/installer/util/util.vcproj
index 9c7547f..99c7fe3 100644
--- a/chrome/installer/util/util.vcproj
+++ b/chrome/installer/util/util.vcproj
@@ -225,6 +225,10 @@
>
</File>
<File
+ RelativePath="..\..\common\json_value_serializer.cc"
+ >
+ </File>
+ <File
RelativePath=".\l10n_string_util.cc"
>
</File>
@@ -257,6 +261,10 @@
>
</File>
<File
+ RelativePath="..\..\common\pref_names.cc"
+ >
+ </File>
+ <File
RelativePath=".\set_reg_value_work_item.cc"
>
</File>
diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc
index ab695e1..e10a284 100644
--- a/chrome/installer/util/util_constants.cc
+++ b/chrome/installer/util/util_constants.cc
@@ -41,7 +41,7 @@ const wchar_t kLogFile[] = L"log-file";
// Register Chrome as default browser on the system. Usually this will require
// that setup is running as admin. If running as admin we try to register
// as default browser at system level, if running as non-admin we try to
-// register as default browser only for the current user.
+// register as default browser only for the current user.
const wchar_t kMakeChromeDefault[] = L"make-chrome-default";
// Register Chrome as a valid browser on the current sytem. This option
@@ -81,4 +81,6 @@ const wchar_t kInstallerDir[] = L"Installer";
const wchar_t kUninstallStringField[] = L"UninstallString";
const wchar_t kUninstallDisplayNameField[] = L"DisplayName";
+const wchar_t kUninstallMetricsName[] = L"uninstall_metrics";
+const wchar_t kUninstallInstallationDate[] = L"installation_date";
} // namespace installer_util
diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h
index 049fdac..246a50f 100644
--- a/chrome/installer/util/util_constants.h
+++ b/chrome/installer/util/util_constants.h
@@ -93,6 +93,8 @@ extern const wchar_t kInstallerDir[];
extern const wchar_t kUninstallStringField[];
extern const wchar_t kUninstallDisplayNameField[];
+extern const wchar_t kUninstallMetricsName[];
+extern const wchar_t kUninstallInstallationDate[];
} // namespace installer_util
#endif // CHROME_INSTALLER_UTIL_UTIL_CONSTANTS_H__
diff --git a/chrome/test/data/pref_service/write.golden.json b/chrome/test/data/pref_service/write.golden.json
index 362e32d..6e635cc 100644
--- a/chrome/test/data/pref_service/write.golden.json
+++ b/chrome/test/data/pref_service/write.golden.json
@@ -1,6 +1,9 @@
{
"homepage": "http://www.cnn.com",
"some_directory": "/usr/sbin/",
+ "long_int": {
+ "pref": "214748364842"
+ },
"tabs": {
"max_tabs": 10,
"new_windows_in_tabs": false